diff options
| author | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-08-16 13:18:03 +0200 |
|---|---|---|
| committer | Grzegorz Bizon <grzesiek.bizon@gmail.com> | 2017-08-16 13:18:03 +0200 |
| commit | 32d0983a4ea3ce61b78e4d11d61892989ac4cb35 (patch) | |
| tree | 3fe78e7302579c38046a7fbfd79ee1d78d8aecd3 /spec | |
| parent | 13a15e7009e292919109ea911640a627dbd0e327 (diff) | |
| parent | 04f7f394d3825e3290f523dce28d42b7c87fc9bb (diff) | |
| download | gitlab-ce-32d0983a4ea3ce61b78e4d11d61892989ac4cb35.tar.gz | |
Merge branch 'master' into backstage/gb/migrate-stages-statuses
* master: (1000 commits)
Fix username autocomplete group name with no avatar alignment
Fix 'Projected tags' typo in protected_tags_spec.rb
Many Repo Fixes
Repo Editor Fixes
Docs: New index for permissions
link article from CI index
link tech articles from the landing page
new articles come first
fix relative link
fix date format
Fixed changed files dropdown not being shown
Update publication date
Remove deprecated field from workhorse API responses
Fix API responses when dealing with txt files
Make sure MySQL would not use CURRENT_TIMESTAMP
Add two more project templates
Allow usage of any_projects? with an Array
Copyedit Artifactory and GitLab article
Rename Artifactory and GitLab article file
Display GPG status loading spinner only when Ajax request is made
...
Diffstat (limited to 'spec')
1008 files changed, 12466 insertions, 4113 deletions
diff --git a/spec/bin/changelog_spec.rb b/spec/bin/changelog_spec.rb index 91aff0db7cc..6d8b9865dcb 100644 --- a/spec/bin/changelog_spec.rb +++ b/spec/bin/changelog_spec.rb @@ -4,56 +4,90 @@ load File.expand_path('../../bin/changelog', __dir__) describe 'bin/changelog' do describe ChangelogOptionParser do - it 'parses --ammend' do - options = described_class.parse(%w[foo bar --amend]) + describe '.parse' do + it 'parses --amend' do + options = described_class.parse(%w[foo bar --amend]) - expect(options.amend).to eq true - end + expect(options.amend).to eq true + end - it 'parses --force and -f' do - %w[--force -f].each do |flag| - options = described_class.parse(%W[foo #{flag} bar]) + it 'parses --force and -f' do + %w[--force -f].each do |flag| + options = described_class.parse(%W[foo #{flag} bar]) - expect(options.force).to eq true + expect(options.force).to eq true + end end - end - it 'parses --merge-request and -m' do - %w[--merge-request -m].each do |flag| - options = described_class.parse(%W[foo #{flag} 1234 bar]) + it 'parses --merge-request and -m' do + %w[--merge-request -m].each do |flag| + options = described_class.parse(%W[foo #{flag} 1234 bar]) - expect(options.merge_request).to eq 1234 + expect(options.merge_request).to eq 1234 + end end - end - it 'parses --dry-run and -n' do - %w[--dry-run -n].each do |flag| - options = described_class.parse(%W[foo #{flag} bar]) + it 'parses --dry-run and -n' do + %w[--dry-run -n].each do |flag| + options = described_class.parse(%W[foo #{flag} bar]) - expect(options.dry_run).to eq true + expect(options.dry_run).to eq true + end end - end - it 'parses --git-username and -u' do - allow(described_class).to receive(:git_user_name).and_return('Jane Doe') + it 'parses --git-username and -u' do + allow(described_class).to receive(:git_user_name).and_return('Jane Doe') - %w[--git-username -u].each do |flag| - options = described_class.parse(%W[foo #{flag} bar]) + %w[--git-username -u].each do |flag| + options = described_class.parse(%W[foo #{flag} bar]) - expect(options.author).to eq 'Jane Doe' + expect(options.author).to eq 'Jane Doe' + end + end + + it 'parses --type and -t' do + %w[--type -t].each do |flag| + options = described_class.parse(%W[foo #{flag} security]) + + expect(options.type).to eq 'security' + end end - end - it 'parses -h' do - expect do - expect { described_class.parse(%w[foo -h bar]) }.to output.to_stdout - end.to raise_error(SystemExit) + it 'parses -h' do + expect do + expect { described_class.parse(%w[foo -h bar]) }.to output.to_stdout + end.to raise_error(SystemExit) + end + + it 'assigns title' do + options = described_class.parse(%W[foo -m 1 bar\n -u baz\r\n --amend]) + + expect(options.title).to eq 'foo bar baz' + end end - it 'assigns title' do - options = described_class.parse(%W[foo -m 1 bar\n -u baz\r\n --amend]) + describe '.read_type' do + let(:type) { '1' } - expect(options.title).to eq 'foo bar baz' + it 'reads type from $stdin' do + expect($stdin).to receive(:getc).and_return(type) + expect do + expect(described_class.read_type).to eq('added') + end.to output.to_stdout + end + + context 'invalid type given' do + let(:type) { '99' } + + it 'shows error message and exits the program' do + allow($stdin).to receive(:getc).and_return(type) + expect do + expect do + expect { described_class.read_type }.to raise_error(SystemExit) + end.to output("Invalid category index, please select an index between 1 and 7\n").to_stderr + end.to output.to_stdout + end + end end end end diff --git a/spec/config/mail_room_spec.rb b/spec/config/mail_room_spec.rb index a31e44fa928..74634dac713 100644 --- a/spec/config/mail_room_spec.rb +++ b/spec/config/mail_room_spec.rb @@ -20,12 +20,12 @@ describe 'mail_room.yml' do YAML.load(output) end - before(:each) do + before do stub_env('GITLAB_REDIS_QUEUES_CONFIG_FILE', absolute_path(queues_config_path)) clear_queues_raw_config end - after(:each) do + after do clear_queues_raw_config end diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb index ddf38967dd7..0dad95e418f 100644 --- a/spec/controllers/admin/groups_controller_spec.rb +++ b/spec/controllers/admin/groups_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Admin::GroupsController do let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } let(:admin) { create(:admin) } before do diff --git a/spec/controllers/admin/health_check_controller_spec.rb b/spec/controllers/admin/health_check_controller_spec.rb new file mode 100644 index 00000000000..0b8e0c8a065 --- /dev/null +++ b/spec/controllers/admin/health_check_controller_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe Admin::HealthCheckController, broken_storage: true do + let(:admin) { create(:admin) } + + before do + sign_in(admin) + end + + describe 'GET show' do + it 'loads the git storage health information' do + get :show + + expect(assigns[:failing_storage_statuses]).not_to be_nil + end + end + + describe 'POST reset_storage_health' do + it 'resets all storage health information' do + expect(Gitlab::Git::Storage::CircuitBreaker).to receive(:reset_all!) + + post :reset_storage_health + end + end +end diff --git a/spec/controllers/admin/projects_controller_spec.rb b/spec/controllers/admin/projects_controller_spec.rb index 2c35d394b74..373260b3978 100644 --- a/spec/controllers/admin/projects_controller_spec.rb +++ b/spec/controllers/admin/projects_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Admin::ProjectsController do - let!(:project) { create(:empty_project, :public) } + let!(:project) { create(:project, :public) } before do sign_in(create(:admin)) @@ -12,12 +12,24 @@ describe Admin::ProjectsController do it 'retrieves the project for the given visibility level' do get :index, visibility_level: [Gitlab::VisibilityLevel::PUBLIC] + expect(response.body).to match(project.name) end it 'does not retrieve the project' do get :index, visibility_level: [Gitlab::VisibilityLevel::INTERNAL] + expect(response.body).not_to match(project.name) end + + it 'does not respond with projects pending deletion' do + pending_delete_project = create(:project, pending_delete: true) + + get :index + + expect(response).to have_http_status(200) + expect(response.body).not_to match(pending_delete_project.name) + expect(response.body).to match(project.name) + end end end diff --git a/spec/controllers/admin/services_controller_spec.rb b/spec/controllers/admin/services_controller_spec.rb index 4ca0cfc74e9..249bd948847 100644 --- a/spec/controllers/admin/services_controller_spec.rb +++ b/spec/controllers/admin/services_controller_spec.rb @@ -8,7 +8,7 @@ describe Admin::ServicesController do end describe 'GET #edit' do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } Service.available_services_names.each do |service_name| context "#{service_name}" do @@ -27,7 +27,7 @@ describe Admin::ServicesController do end describe "#update" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:service) do RedmineService.create( project: project, diff --git a/spec/controllers/admin/users_controller_spec.rb b/spec/controllers/admin/users_controller_spec.rb index 69928a906c6..3d21b695af4 100644 --- a/spec/controllers/admin/users_controller_spec.rb +++ b/spec/controllers/admin/users_controller_spec.rb @@ -9,7 +9,7 @@ describe Admin::UsersController do end describe 'DELETE #user with projects' do - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let!(:issue) { create(:issue, author: user) } before do @@ -127,7 +127,7 @@ describe Admin::UsersController do describe 'POST create' do it 'creates the user' do - expect{ post :create, user: attributes_for(:user) }.to change{ User.count }.by(1) + expect { post :create, user: attributes_for(:user) }.to change { User.count }.by(1) end it 'shows only one error message for an invalid email' do diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 1641bddea11..331903a5543 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -108,6 +108,30 @@ describe ApplicationController do end end + describe 'rescue from Gitlab::Git::Storage::Inaccessible' do + controller(described_class) do + def index + raise Gitlab::Git::Storage::Inaccessible.new('broken', 100) + end + end + + it 'renders a 503 when storage is not available' do + sign_in(create(:user)) + + get :index + + expect(response.status).to eq(503) + end + + it 'renders includes a Retry-After header' do + sign_in(create(:user)) + + get :index + + expect(response.headers['Retry-After']).to eq(100) + end + end + describe 'response format' do controller(described_class) do def index diff --git a/spec/controllers/autocomplete_controller_spec.rb b/spec/controllers/autocomplete_controller_spec.rb index 58486f33229..2fbab1e4040 100644 --- a/spec/controllers/autocomplete_controller_spec.rb +++ b/spec/controllers/autocomplete_controller_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe AutocompleteController do - let!(:project) { create(:empty_project) } - let!(:user) { create(:user) } + let(:project) { create(:project) } + let(:user) { project.owner } context 'GET users' do let!(:user2) { create(:user) } @@ -11,7 +11,6 @@ describe AutocompleteController do context 'project members' do before do sign_in(user) - project.add_master(user) end describe 'GET #users with project ID' do @@ -19,11 +18,11 @@ describe AutocompleteController do get(:users, project_id: project.id) end - let(:body) { JSON.parse(response.body) } - - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 2 } - it { expect(body.map { |u| u["username"] }).to include(user.username) } + it 'returns the project members' do + expect(json_response).to be_kind_of(Array) + expect(json_response.size).to eq(1) + expect(json_response.map { |u| u["username"] }).to include(user.username) + end end describe 'GET #users with unknown project' do @@ -39,20 +38,20 @@ describe AutocompleteController do let(:group) { create(:group) } before do - sign_in(user) group.add_owner(user) + sign_in(user) end - let(:body) { JSON.parse(response.body) } - describe 'GET #users with group ID' do before do get(:users, group_id: group.id) end - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 1 } - it { expect(body.first["username"]).to eq user.username } + it 'returns the group members' do + expect(json_response).to be_kind_of(Array) + expect(json_response.size).to eq(1) + expect(json_response.first["username"]).to eq user.username + end end describe 'GET #users with unknown group ID' do @@ -65,23 +64,22 @@ describe AutocompleteController do end context 'non-member login for public project' do - let!(:project) { create(:project, :public) } + let(:project) { create(:project, :public) } before do sign_in(non_member) - project.add_master(user) end - let(:body) { JSON.parse(response.body) } - describe 'GET #users with project ID' do before do get(:users, project_id: project.id, current_user: true) end - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 3 } - it { expect(body.map { |u| u['username'] }).to include(user.username, non_member.username) } + it 'returns the project members and non-members' do + expect(json_response).to be_kind_of(Array) + expect(json_response.size).to eq(2) + expect(json_response.map { |u| u['username'] }).to include(user.username, non_member.username) + end end end @@ -91,10 +89,8 @@ describe AutocompleteController do get(:users) end - let(:body) { JSON.parse(response.body) } - - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq User.count } + it { expect(json_response).to be_kind_of(Array) } + it { expect(json_response.size).to eq User.count } end context 'user order' do @@ -106,7 +102,7 @@ describe AutocompleteController do sign_in(user) get(:users, search: 'user') - response_usernames = JSON.parse(response.body).map { |user| user['username'] } + response_usernames = json_response.map { |user| user['username'] } expect(response_usernames.take(3)).to match_array([user.username, reported_user.username, user1.username]) end @@ -120,15 +116,12 @@ describe AutocompleteController do get(:users, per_page: per_page) end - let(:body) { JSON.parse(response.body) } - - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq per_page } + it { expect(json_response).to be_kind_of(Array) } + it { expect(json_response.size).to eq(per_page) } end context 'unauthenticated user' do let(:public_project) { create(:project, :public) } - let(:body) { JSON.parse(response.body) } describe 'GET #users with public project' do before do @@ -136,8 +129,8 @@ describe AutocompleteController do get(:users, project_id: public_project.id) end - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 2 } + it { expect(json_response).to be_kind_of(Array) } + it { expect(json_response.size).to eq 2 } end describe 'GET #users with project' do @@ -170,8 +163,8 @@ describe AutocompleteController do get(:users) end - it { expect(body).to be_kind_of(Array) } - it { expect(body.size).to eq 0 } + it { expect(json_response).to be_kind_of(Array) } + it { expect(json_response).to be_empty } end describe 'GET #users with todo filter' do @@ -179,14 +172,12 @@ describe AutocompleteController do get :users, todo_filter: true expect(response.status).to eq 200 - expect(body).to be_kind_of(Array) + expect(json_response).to be_kind_of(Array) end end end context 'author of issuable included' do - let(:body) { JSON.parse(response.body) } - context 'authenticated' do before do sign_in(user) @@ -195,13 +186,13 @@ describe AutocompleteController do it 'includes the author' do get(:users, author_id: non_member.id) - expect(body.first["username"]).to eq non_member.username + expect(json_response.first["username"]).to eq non_member.username end it 'rejects non existent user ids' do get(:users, author_id: 99999) - expect(body.collect { |u| u['id'] }).not_to include(99999) + expect(json_response.collect { |u| u['id'] }).not_to include(99999) end end @@ -209,7 +200,7 @@ describe AutocompleteController do it 'returns empty result' do get(:users, author_id: non_member.id) - expect(body).to be_empty + expect(json_response).to be_empty end end end @@ -222,10 +213,9 @@ describe AutocompleteController do it 'skips the user IDs passed' do get(:users, skip_users: [user, user2].map(&:id)) - other_user_ids = [non_member, project.owner, project.creator].map(&:id) - response_user_ids = JSON.parse(response.body).map { |user| user['id'] } + response_user_ids = json_response.map { |user| user['id'] } - expect(response_user_ids).to contain_exactly(*other_user_ids) + expect(response_user_ids).to contain_exactly(non_member.id) end end end @@ -249,17 +239,15 @@ describe AutocompleteController do get(:projects, project_id: project.id) end - let(:body) { JSON.parse(response.body) } - - it do - expect(body).to be_kind_of(Array) - expect(body.size).to eq 2 + it 'returns projects' do + expect(json_response).to be_kind_of(Array) + expect(json_response.size).to eq(2) - expect(body.first['id']).to eq 0 - expect(body.first['name_with_namespace']).to eq 'No project' + expect(json_response.first['id']).to eq(0) + expect(json_response.first['name_with_namespace']).to eq 'No project' - expect(body.last['id']).to eq authorized_project.id - expect(body.last['name_with_namespace']).to eq authorized_project.name_with_namespace + expect(json_response.last['id']).to eq authorized_project.id + expect(json_response.last['name_with_namespace']).to eq authorized_project.name_with_namespace end end end @@ -275,14 +263,12 @@ describe AutocompleteController do get(:projects, project_id: project.id, search: 'rugged') end - let(:body) { JSON.parse(response.body) } + it 'returns projects' do + expect(json_response).to be_kind_of(Array) + expect(json_response.size).to eq(2) - it do - expect(body).to be_kind_of(Array) - expect(body.size).to eq 2 - - expect(body.last['id']).to eq authorized_search_project.id - expect(body.last['name_with_namespace']).to eq authorized_search_project.name_with_namespace + expect(json_response.last['id']).to eq authorized_search_project.id + expect(json_response.last['name_with_namespace']).to eq authorized_search_project.name_with_namespace end end end @@ -304,11 +290,9 @@ describe AutocompleteController do get(:projects, project_id: project.id) end - let(:body) { JSON.parse(response.body) } - - it do - expect(body).to be_kind_of(Array) - expect(body.size).to eq 3 # Of a total of 4 + it 'returns projects' do + expect(json_response).to be_kind_of(Array) + expect(json_response.size).to eq 3 # Of a total of 4 end end end @@ -328,17 +312,15 @@ describe AutocompleteController do get(:projects, project_id: project.id, offset_id: authorized_project.id) end - let(:body) { JSON.parse(response.body) } - - it do - expect(body.detect { |item| item['id'] == 0 }).to be_nil # 'No project' is not there - expect(body.detect { |item| item['id'] == authorized_project.id }).to be_nil # Offset project is not there either + it 'returns "No project"' do + expect(json_response.detect { |item| item['id'] == 0 }).to be_nil # 'No project' is not there + expect(json_response.detect { |item| item['id'] == authorized_project.id }).to be_nil # Offset project is not there either end end end context 'authorized projects without admin_issue ability' do - before(:each) do + before do authorized_project.add_guest(user) expect(user.can?(:admin_issue, authorized_project)).to eq(false) @@ -349,13 +331,10 @@ describe AutocompleteController do get(:projects, project_id: project.id) end - let(:body) { JSON.parse(response.body) } - - it do - expect(body).to be_kind_of(Array) - expect(body.size).to eq 1 # 'No project' - - expect(body.first['id']).to eq 0 + it 'returns a single "No project"' do + expect(json_response).to be_kind_of(Array) + expect(json_response.size).to eq(1) # 'No project' + expect(json_response.first['id']).to eq 0 end end end diff --git a/spec/controllers/dashboard/labels_controller_spec.rb b/spec/controllers/dashboard/labels_controller_spec.rb index 2b63933008f..a3bfb2f3a87 100644 --- a/spec/controllers/dashboard/labels_controller_spec.rb +++ b/spec/controllers/dashboard/labels_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Dashboard::LabelsController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let!(:label) { create(:label, project: project) } @@ -11,7 +11,7 @@ describe Dashboard::LabelsController do end describe "#index" do - let!(:unrelated_label) { create(:label, project: create(:empty_project, :public)) } + let!(:unrelated_label) { create(:label, project: create(:project, :public)) } it 'returns global labels for projects the user has a relationship with' do get :index, format: :json diff --git a/spec/controllers/dashboard/milestones_controller_spec.rb b/spec/controllers/dashboard/milestones_controller_spec.rb index 424f39fd3b8..2dcb67d50f4 100644 --- a/spec/controllers/dashboard/milestones_controller_spec.rb +++ b/spec/controllers/dashboard/milestones_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Dashboard::MilestonesController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:project_milestone) { create(:milestone, project: project) } let(:milestone) do diff --git a/spec/controllers/dashboard/todos_controller_spec.rb b/spec/controllers/dashboard/todos_controller_spec.rb index 4a48621abe1..c8c6b9f41bf 100644 --- a/spec/controllers/dashboard/todos_controller_spec.rb +++ b/spec/controllers/dashboard/todos_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Dashboard::TodosController do let(:user) { create(:user) } let(:author) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:todo_service) { TodoService.new } before do @@ -14,7 +14,7 @@ describe Dashboard::TodosController do describe 'GET #index' do context 'project authorization' do it 'renders 404 when user does not have read access on given project' do - unauthorized_project = create(:empty_project, :private) + unauthorized_project = create(:project, :private) get :index, project_id: unauthorized_project.id @@ -34,7 +34,7 @@ describe Dashboard::TodosController do end it 'renders 200 when user has access on given project' do - authorized_project = create(:empty_project, :public) + authorized_project = create(:project, :public) get :index, project_id: authorized_project.id diff --git a/spec/controllers/explore/projects_controller_spec.rb b/spec/controllers/explore/projects_controller_spec.rb index 9dceeca168d..2845f258f6f 100644 --- a/spec/controllers/explore/projects_controller_spec.rb +++ b/spec/controllers/explore/projects_controller_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Explore::ProjectsController do describe 'GET #trending' do context 'sorting by update date' do - let(:project1) { create(:empty_project, :public, updated_at: 3.days.ago) } - let(:project2) { create(:empty_project, :public, updated_at: 1.day.ago) } + let(:project1) { create(:project, :public, updated_at: 3.days.ago) } + let(:project2) { create(:project, :public, updated_at: 1.day.ago) } before do create(:trending_project, project: project1) diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb index aad67dd0164..fbbc67f3ae0 100644 --- a/spec/controllers/groups/milestones_controller_spec.rb +++ b/spec/controllers/groups/milestones_controller_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Groups::MilestonesController do let(:group) { create(:group) } - let!(:project) { create(:empty_project, group: group) } - let!(:project2) { create(:empty_project, group: group) } + let!(:project) { create(:project, group: group) } + let!(:project2) { create(:project, group: group) } let(:user) { create(:user) } let(:title) { 'è‚¯å®šä¸æ˜¯ä¸æ–‡çš„问题' } let(:milestone) do diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index c4092303a67..c2ada8c8df7 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe GroupsController do let(:user) { create(:user) } let(:group) { create(:group, :public) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } let!(:group_member) { create(:group_member, group: group, user: user) } describe 'GET #index' do diff --git a/spec/controllers/import/bitbucket_controller_spec.rb b/spec/controllers/import/bitbucket_controller_spec.rb index 8ef10dabd4c..e8707760a5a 100644 --- a/spec/controllers/import/bitbucket_controller_spec.rb +++ b/spec/controllers/import/bitbucket_controller_spec.rb @@ -52,7 +52,7 @@ describe Import::BitbucketController do end it "assigns variables" do - @project = create(:empty_project, import_type: 'bitbucket', creator_id: user.id) + @project = create(:project, import_type: 'bitbucket', creator_id: user.id) allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo]) get :status @@ -63,7 +63,7 @@ describe Import::BitbucketController do end it "does not show already added project" do - @project = create(:empty_project, import_type: 'bitbucket', creator_id: user.id, import_source: 'asd/vim') + @project = create(:project, import_type: 'bitbucket', creator_id: user.id, import_source: 'asd/vim') allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo]) get :status diff --git a/spec/controllers/import/fogbugz_controller_spec.rb b/spec/controllers/import/fogbugz_controller_spec.rb index fffbc805335..5f0f6dea821 100644 --- a/spec/controllers/import/fogbugz_controller_spec.rb +++ b/spec/controllers/import/fogbugz_controller_spec.rb @@ -16,7 +16,7 @@ describe Import::FogbugzController do end it 'assigns variables' do - @project = create(:empty_project, import_type: 'fogbugz', creator_id: user.id) + @project = create(:project, import_type: 'fogbugz', creator_id: user.id) stub_client(repos: [@repo]) get :status @@ -26,7 +26,7 @@ describe Import::FogbugzController do end it 'does not show already added project' do - @project = create(:empty_project, import_type: 'fogbugz', creator_id: user.id, import_source: 'vim') + @project = create(:project, import_type: 'fogbugz', creator_id: user.id, import_source: 'vim') stub_client(repos: [@repo]) get :status diff --git a/spec/controllers/import/gitlab_controller_spec.rb b/spec/controllers/import/gitlab_controller_spec.rb index 997107dadea..faf1e6f63ea 100644 --- a/spec/controllers/import/gitlab_controller_spec.rb +++ b/spec/controllers/import/gitlab_controller_spec.rb @@ -36,7 +36,7 @@ describe Import::GitlabController do end it "assigns variables" do - @project = create(:empty_project, import_type: 'gitlab', creator_id: user.id) + @project = create(:project, import_type: 'gitlab', creator_id: user.id) stub_client(projects: [@repo]) get :status @@ -46,7 +46,7 @@ describe Import::GitlabController do end it "does not show already added project" do - @project = create(:empty_project, import_type: 'gitlab', creator_id: user.id, import_source: 'asd/vim') + @project = create(:project, import_type: 'gitlab', creator_id: user.id, import_source: 'asd/vim') stub_client(projects: [@repo]) get :status diff --git a/spec/controllers/import/google_code_controller_spec.rb b/spec/controllers/import/google_code_controller_spec.rb index c96fb90f70e..4241db6e771 100644 --- a/spec/controllers/import/google_code_controller_spec.rb +++ b/spec/controllers/import/google_code_controller_spec.rb @@ -27,7 +27,7 @@ describe Import::GoogleCodeController do end it "assigns variables" do - @project = create(:empty_project, import_type: 'google_code', creator_id: user.id) + @project = create(:project, import_type: 'google_code', creator_id: user.id) stub_client(repos: [@repo], incompatible_repos: []) get :status @@ -38,7 +38,7 @@ describe Import::GoogleCodeController do end it "does not show already added project" do - @project = create(:empty_project, import_type: 'google_code', creator_id: user.id, import_source: 'vim') + @project = create(:project, import_type: 'google_code', creator_id: user.id, import_source: 'vim') stub_client(repos: [@repo], incompatible_repos: []) get :status diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb index e478a253b3f..e00403118a0 100644 --- a/spec/controllers/invites_controller_spec.rb +++ b/spec/controllers/invites_controller_spec.rb @@ -24,7 +24,7 @@ describe InvitesController do describe 'GET #decline' do it 'declines user' do get :decline, id: token - expect{member.reload}.to raise_error ActiveRecord::RecordNotFound + expect {member.reload}.to raise_error ActiveRecord::RecordNotFound expect(response).to have_http_status(302) expect(flash[:notice]).to include 'You have declined the invitation to join' diff --git a/spec/controllers/notification_settings_controller_spec.rb b/spec/controllers/notification_settings_controller_spec.rb index 6b690407ce3..bef815ee1f7 100644 --- a/spec/controllers/notification_settings_controller_spec.rb +++ b/spec/controllers/notification_settings_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe NotificationSettingsController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:group) { create(:group, :internal) } let(:user) { create(:user) } @@ -99,7 +99,7 @@ describe NotificationSettingsController do end context 'not authorized' do - let(:private_project) { create(:empty_project, :private) } + let(:private_project) { create(:project, :private) } before do sign_in(user) diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb index 8b71d6518bb..f5ea097af8b 100644 --- a/spec/controllers/projects/avatars_controller_spec.rb +++ b/spec/controllers/projects/avatars_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::AvatarsController do - let(:project) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb index 02bbc48dc59..64b9af7b845 100644 --- a/spec/controllers/projects/blob_controller_spec.rb +++ b/spec/controllers/projects/blob_controller_spec.rb @@ -35,6 +35,26 @@ describe Projects::BlobController do end end + context 'with file path and JSON format' do + context "valid branch, valid file" do + let(:id) { 'master/README.md' } + + before do + get(:show, + namespace_id: project.namespace, + project_id: project, + id: id, + format: :json) + end + + it do + expect(response).to be_ok + expect(json_response).to have_key 'html' + expect(json_response).to have_key 'raw_path' + end + end + end + context 'with tree path' do before do get(:show, @@ -48,7 +68,7 @@ describe Projects::BlobController do let(:id) { 'markdown/doc' } it 'redirects' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc") + .to redirect_to("/#{project.full_path}/tree/markdown/doc") end end end @@ -193,7 +213,7 @@ describe Projects::BlobController do context "when user doesn't have access" do before do - other_project = create(:empty_project) + other_project = create(:project, :repository) merge_request.update!(source_project: other_project, target_project: other_project) end diff --git a/spec/controllers/projects/boards/issues_controller_spec.rb b/spec/controllers/projects/boards/issues_controller_spec.rb index dc3b72c6de4..3f6c1092163 100644 --- a/spec/controllers/projects/boards/issues_controller_spec.rb +++ b/spec/controllers/projects/boards/issues_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::Boards::IssuesController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/controllers/projects/boards/lists_controller_spec.rb b/spec/controllers/projects/boards/lists_controller_spec.rb index 0f2664262e8..65beec16307 100644 --- a/spec/controllers/projects/boards/lists_controller_spec.rb +++ b/spec/controllers/projects/boards/lists_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::Boards::ListsController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } let(:guest) { create(:user) } diff --git a/spec/controllers/projects/boards_controller_spec.rb b/spec/controllers/projects/boards_controller_spec.rb index aed3a45c413..9e2e9a39481 100644 --- a/spec/controllers/projects/boards_controller_spec.rb +++ b/spec/controllers/projects/boards_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::BoardsController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb index 9cd4e9dbf84..745d051a5c1 100644 --- a/spec/controllers/projects/branches_controller_spec.rb +++ b/spec/controllers/projects/branches_controller_spec.rb @@ -33,7 +33,7 @@ describe Projects::BranchesController do let(:ref) { "master" } it 'redirects' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/merge_branch") + .to redirect_to("/#{project.full_path}/tree/merge_branch") end end @@ -42,7 +42,7 @@ describe Projects::BranchesController do let(:ref) { "master" } it 'redirects' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/alert('merge');") + .to redirect_to("/#{project.full_path}/tree/alert('merge');") end end @@ -82,7 +82,7 @@ describe Projects::BranchesController do issue_iid: issue.iid expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/1-feature-branch") + .to redirect_to("/#{project.full_path}/tree/1-feature-branch") end it 'posts a system note' do @@ -96,7 +96,7 @@ describe Projects::BranchesController do end context 'repository-less project' do - let(:project) { create :empty_project } + let(:project) { create :project } it 'redirects to newly created branch' do result = { status: :success, branch: double(name: branch) } diff --git a/spec/controllers/projects/deploy_keys_controller_spec.rb b/spec/controllers/projects/deploy_keys_controller_spec.rb index efe1a78415b..c3208357694 100644 --- a/spec/controllers/projects/deploy_keys_controller_spec.rb +++ b/spec/controllers/projects/deploy_keys_controller_spec.rb @@ -24,8 +24,8 @@ describe Projects::DeployKeysController do end context 'when json requested' do - let(:project2) { create(:empty_project, :internal)} - let(:project_private) { create(:empty_project, :private)} + let(:project2) { create(:project, :internal)} + let(:project_private) { create(:project, :private)} let(:deploy_key_internal) do create(:deploy_key, key: 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCdMHEHyhRjbhEZVddFn6lTWdgEy5Q6Bz4nwGB76xWZI5YT/1WJOMEW+sL5zYd31kk7sd3FJ5L9ft8zWMWrr/iWXQikC2cqZK24H1xy+ZUmrRuJD4qGAaIVoyyzBL+avL+lF8J5lg6YSw8gwJY/lX64/vnJHUlWw2n5BF8IFOWhiw== dummy@gitlab.com') diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb index 0dbfcf97f6f..3daff1eeea3 100644 --- a/spec/controllers/projects/deployments_controller_spec.rb +++ b/spec/controllers/projects/deployments_controller_spec.rb @@ -4,7 +4,7 @@ describe Projects::DeploymentsController do include ApiHelpers let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:environment) { create(:environment, name: 'production', project: project) } before do diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index f88f50c3cc6..5a95f4f6199 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::EnvironmentsController do set(:user) { create(:user) } - set(:project) { create(:empty_project) } + set(:project) { create(:project) } set(:environment) do create(:environment, name: 'production', project: project) diff --git a/spec/controllers/projects/graphs_controller_spec.rb b/spec/controllers/projects/graphs_controller_spec.rb index e0de62e4454..5af03ae118c 100644 --- a/spec/controllers/projects/graphs_controller_spec.rb +++ b/spec/controllers/projects/graphs_controller_spec.rb @@ -24,37 +24,4 @@ describe Projects::GraphsController do expect(response).to redirect_to action: :charts end end - - describe 'GET charts' do - let(:linguist_repository) do - double(languages: { - 'Ruby' => 1000, - 'CoffeeScript' => 350, - 'NSIS' => 15 - }) - end - - let(:expected_values) do - nsis_color = "##{Digest::SHA256.hexdigest('NSIS')[0...6]}" - [ - # colors from Linguist: - { label: "Ruby", color: "#701516", highlight: "#701516" }, - { label: "CoffeeScript", color: "#244776", highlight: "#244776" }, - # colors from SHA256 fallback: - { label: "NSIS", color: nsis_color, highlight: nsis_color } - ] - end - - before do - allow(Linguist::Repository).to receive(:new).and_return(linguist_repository) - end - - it 'sets the correct colour according to language' do - get(:charts, namespace_id: project.namespace, project_id: project, id: 'master') - - expected_values.each do |val| - expect(assigns(:languages)).to include(a_hash_including(val)) - end - end - end end diff --git a/spec/controllers/projects/group_links_controller_spec.rb b/spec/controllers/projects/group_links_controller_spec.rb index 019a50882ab..f8c792cd0f0 100644 --- a/spec/controllers/projects/group_links_controller_spec.rb +++ b/spec/controllers/projects/group_links_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Projects::GroupLinksController do let(:group) { create(:group, :private) } let(:group2) { create(:group, :private) } - let(:project) { create(:empty_project, :private, group: group2) } + let(:project) { create(:project, :private, group: group2) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects/hooks_controller_spec.rb b/spec/controllers/projects/hooks_controller_spec.rb index b93ab220f4d..07174660f46 100644 --- a/spec/controllers/projects/hooks_controller_spec.rb +++ b/spec/controllers/projects/hooks_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::HooksController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb index 9be61342616..2a5ec6d584b 100644 --- a/spec/controllers/projects/imports_controller_spec.rb +++ b/spec/controllers/projects/imports_controller_spec.rb @@ -5,7 +5,7 @@ describe Projects::ImportsController do describe 'GET #show' do context 'when repository does not exists' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do sign_in(user) diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb index 2c57f3bcf8d..b571b11dcac 100644 --- a/spec/controllers/projects/issues_controller_spec.rb +++ b/spec/controllers/projects/issues_controller_spec.rb @@ -1,7 +1,7 @@ require('spec_helper') describe Projects::IssuesController do - let(:project) { create(:project_empty_repo) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:issue) { create(:issue, project: project) } @@ -234,7 +234,7 @@ describe Projects::IssuesController do end context 'when moving issue to another private project' do - let(:another_project) { create(:empty_project, :private) } + let(:another_project) { create(:project, :private) } context 'when user has access to move issue' do before do @@ -292,13 +292,13 @@ describe Projects::IssuesController do it 'rejects an issue recognized as a spam' do expect(Gitlab::Recaptcha).to receive(:load_configurations!).and_return(true) - expect { update_spam_issue }.not_to change{ issue.reload.title } + expect { update_spam_issue }.not_to change { issue.reload.title } end it 'rejects an issue recognized as a spam when recaptcha disabled' do stub_application_setting(recaptcha_enabled: false) - expect { update_spam_issue }.not_to change{ issue.reload.title } + expect { update_spam_issue }.not_to change { issue.reload.title } end it 'creates a spam log' do @@ -358,7 +358,7 @@ describe Projects::IssuesController do end it 'accepts an issue after recaptcha is verified' do - expect{ update_verified_issue }.to change{ issue.reload.title }.to(spammy_title) + expect { update_verified_issue }.to change { issue.reload.title }.to(spammy_title) end it 'marks spam log as recaptcha_verified' do @@ -594,7 +594,7 @@ describe Projects::IssuesController do describe 'POST #create' do def post_new_issue(issue_attrs = {}, additional_params = {}) sign_in(user) - project = create(:empty_project, :public) + project = create(:project, :public) project.team << [user, :developer] post :create, { @@ -817,7 +817,7 @@ describe Projects::IssuesController do context "when the user is owner" do let(:owner) { create(:user) } let(:namespace) { create(:namespace, owner: owner) } - let(:project) { create(:empty_project, namespace: namespace) } + let(:project) { create(:project, namespace: namespace) } before do sign_in(owner) @@ -841,7 +841,7 @@ describe Projects::IssuesController do describe 'POST #toggle_award_emoji' do before do sign_in(user) - project.team << [user, :developer] + project.add_developer(user) end it "toggles the award emoji" do @@ -855,6 +855,8 @@ describe Projects::IssuesController do end describe 'POST create_merge_request' do + let(:project) { create(:project, :repository) } + before do project.add_developer(user) sign_in(user) diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 5a295ae47a6..fdd7e6f173f 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Projects::JobsController do include ApiHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:user) { create(:user) } diff --git a/spec/controllers/projects/labels_controller_spec.rb b/spec/controllers/projects/labels_controller_spec.rb index f19ad4c2c81..f4e2dca883d 100644 --- a/spec/controllers/projects/labels_controller_spec.rb +++ b/spec/controllers/projects/labels_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::LabelsController do let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } let(:user) { create(:user) } before do @@ -73,7 +73,7 @@ describe Projects::LabelsController do describe 'POST #generate' do context 'personal project' do - let(:personal_project) { create(:empty_project, namespace: user.namespace) } + let(:personal_project) { create(:project, namespace: user.namespace) } it 'creates labels' do post :generate, namespace_id: personal_project.namespace.to_param, project_id: personal_project diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index 12e413db902..4eea7041d29 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MattermostsController do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user) } before do diff --git a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb index 9278ac8edd8..393d38c6e6b 100644 --- a/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/conflicts_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequests::ConflictsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } let(:merge_request_with_conflicts) do diff --git a/spec/controllers/projects/merge_requests/creations_controller_spec.rb b/spec/controllers/projects/merge_requests/creations_controller_spec.rb index f9d8f0f5fcf..fc4cec53374 100644 --- a/spec/controllers/projects/merge_requests/creations_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/creations_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequests::CreationsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:fork_project) { create(:forked_project_with_submodules) } @@ -83,7 +83,7 @@ describe Projects::MergeRequests::CreationsController do end context 'when the source branch is in a different project to the target' do - let(:other_project) { create(:project) } + let(:other_project) { create(:project, :repository) } before do other_project.team << [user, :master] diff --git a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb index 53fe2bdb189..fad2c8f3ab7 100644 --- a/spec/controllers/projects/merge_requests/diffs_controller_spec.rb +++ b/spec/controllers/projects/merge_requests/diffs_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequests::DiffsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } @@ -36,7 +36,7 @@ describe Projects::MergeRequests::DiffsController do context 'with forked projects with submodules' do render_views - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:fork_project) { create(:forked_project_with_submodules) } let(:merge_request) { create(:merge_request_with_diffs, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) } @@ -145,7 +145,7 @@ describe Projects::MergeRequests::DiffsController do end context 'when the merge request belongs to a different project' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } before do other_project.team << [user, :master] diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 2fce4b7a85f..bb67db268fa 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MergeRequestsController do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { project.owner } let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } let(:merge_request_with_conflicts) do @@ -106,7 +106,7 @@ describe Projects::MergeRequestsController do end describe 'GET index' do - let!(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } + let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project) } def get_merge_requests(page = nil) get :index, @@ -150,6 +150,8 @@ describe Projects::MergeRequestsController do context 'when filtering by opened state' do context 'with opened merge requests' do it 'lists those merge requests' do + expect(merge_request).to be_persisted + get_merge_requests expect(assigns(:merge_requests)).to include(merge_request) @@ -191,7 +193,7 @@ describe Projects::MergeRequestsController do end context 'there is no source project' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:fork_project) { create(:forked_project_with_submodules) } let(:merge_request) { create(:merge_request, source_project: fork_project, source_branch: 'add-submodule-version-bump', target_branch: 'master', target_project: project) } @@ -429,7 +431,7 @@ describe Projects::MergeRequestsController do context "when the user is owner" do let(:owner) { create(:user) } let(:namespace) { create(:namespace, owner: owner) } - let(:project) { create(:project, namespace: namespace) } + let(:project) { create(:project, :repository, namespace: namespace) } before do sign_in owner @@ -587,7 +589,7 @@ describe Projects::MergeRequestsController do describe 'GET ci_environments_status' do context 'the environment is from a forked project' do - let!(:forked) { create(:project) } + let!(:forked) { create(:project, :repository) } let!(:environment) { create(:environment, project: forked) } let!(:deployment) { create(:deployment, environment: environment, sha: forked.commit.id, ref: 'master') } let(:admin) { create(:admin) } @@ -609,7 +611,7 @@ describe Projects::MergeRequestsController do end it 'links to the environment on that project' do - expect(json_response.first['url']).to match /#{forked.path_with_namespace}/ + expect(json_response.first['url']).to match /#{forked.full_path}/ end end end diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index bb5a340cd96..62f1fb1f697 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::MilestonesController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:milestone) { create(:milestone, project: project) } let(:issue) { create(:issue, project: project, milestone: milestone) } diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb index 3b88d5b0d7d..f280c55059c 100644 --- a/spec/controllers/projects/notes_controller_spec.rb +++ b/spec/controllers/projects/notes_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::NotesController do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:note) { create(:note, noteable: issue, project: project) } @@ -167,10 +167,10 @@ describe Projects::NotesController do end context 'when creating a commit comment from an MR fork' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:fork_project) do - create(:project).tap do |fork| + create(:project, :repository).tap do |fork| create(:forked_project_link, forked_to_project: fork, forked_from_project: project) end end diff --git a/spec/controllers/projects/pages_controller_spec.rb b/spec/controllers/projects/pages_controller_spec.rb index df35d8e86b9..4d0111302f3 100644 --- a/spec/controllers/projects/pages_controller_spec.rb +++ b/spec/controllers/projects/pages_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::PagesController do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:request_params) do { diff --git a/spec/controllers/projects/pages_domains_controller_spec.rb b/spec/controllers/projects/pages_domains_controller_spec.rb index 920189be381..ad4d7da3bdd 100644 --- a/spec/controllers/projects/pages_domains_controller_spec.rb +++ b/spec/controllers/projects/pages_domains_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::PagesDomainsController do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:pages_domain) { create(:pages_domain, project: project) } let(:request_params) do diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb index 41bf5580993..4ac0559c679 100644 --- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb +++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Projects::PipelineSchedulesController do include AccessMatchersForController - set(:project) { create(:empty_project, :public) } + set(:project) { create(:project, :public) } let!(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project) } describe 'GET #index' do diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index c8de275ca3e..f9d77c7ad03 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -4,7 +4,7 @@ describe Projects::PipelinesController do include ApiHelpers let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:feature) { ProjectFeature::DISABLED } before do @@ -61,7 +61,7 @@ describe Projects::PipelinesController do create_build('post deploy', 3, 'pages 0') end - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:pipeline) do create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id) end diff --git a/spec/controllers/projects/project_members_controller_spec.rb b/spec/controllers/projects/project_members_controller_spec.rb index 8671d7a78dd..3cb1bec5ea2 100644 --- a/spec/controllers/projects/project_members_controller_spec.rb +++ b/spec/controllers/projects/project_members_controller_spec.rb @@ -2,7 +2,7 @@ require('spec_helper') describe Projects::ProjectMembersController do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } describe 'GET index' do it 'should have the project_members address with a 200 status code' do @@ -158,7 +158,7 @@ describe Projects::ProjectMembersController do end context 'and is an owner' do - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } before do project.team << [user, :master] @@ -261,7 +261,7 @@ describe Projects::ProjectMembersController do end describe 'POST apply_import' do - let(:another_project) { create(:empty_project, :private) } + let(:another_project) { create(:project, :private) } let(:member) { create(:user) } before do diff --git a/spec/controllers/projects/prometheus_controller_spec.rb b/spec/controllers/projects/prometheus_controller_spec.rb index eddf7275975..8407a53272a 100644 --- a/spec/controllers/projects/prometheus_controller_spec.rb +++ b/spec/controllers/projects/prometheus_controller_spec.rb @@ -2,7 +2,7 @@ require('spec_helper') describe Projects::PrometheusController do let(:user) { create(:user) } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let(:prometheus_service) { double('prometheus_service') } diff --git a/spec/controllers/projects/registry/repositories_controller_spec.rb b/spec/controllers/projects/registry/repositories_controller_spec.rb index 464302824a8..2805968dcd9 100644 --- a/spec/controllers/projects/registry/repositories_controller_spec.rb +++ b/spec/controllers/projects/registry/repositories_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::Registry::RepositoriesController do let(:user) { create(:user) } - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } before do sign_in(user) diff --git a/spec/controllers/projects/registry/tags_controller_spec.rb b/spec/controllers/projects/registry/tags_controller_spec.rb index a823516830e..f4af3587d23 100644 --- a/spec/controllers/projects/registry/tags_controller_spec.rb +++ b/spec/controllers/projects/registry/tags_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::Registry::TagsController do let(:user) { create(:user) } - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } before do sign_in(user) diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb index 9c55d159fa0..f712d1e0d63 100644 --- a/spec/controllers/projects/repositories_controller_spec.rb +++ b/spec/controllers/projects/repositories_controller_spec.rb @@ -6,7 +6,7 @@ describe Projects::RepositoriesController do describe "GET archive" do context 'as a guest' do it 'responds with redirect in correct format' do - get :archive, namespace_id: project.namespace, project_id: project, format: "zip" + get :archive, namespace_id: project.namespace, project_id: project, format: "zip", ref: 'master' expect(response.header["Content-Type"]).to start_with('text/html') expect(response).to be_redirect diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb index 0fa249e4405..2b6f988fd9c 100644 --- a/spec/controllers/projects/runners_controller_spec.rb +++ b/spec/controllers/projects/runners_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::RunnersController do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:runner) { create(:ci_runner) } let(:params) do diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb index 5a9d8a75f3e..4e9b0c09ff2 100644 --- a/spec/controllers/projects/services_controller_spec.rb +++ b/spec/controllers/projects/services_controller_spec.rb @@ -28,7 +28,7 @@ describe Projects::ServicesController do context 'success' do context 'with empty project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'with chat notification service' do let(:service) { project.create_microsoft_teams_service(webhook: 'http://webhook.com') } diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb index e9a91cff1b3..a8f4b79b64c 100644 --- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb +++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb @@ -1,7 +1,7 @@ require('spec_helper') describe Projects::Settings::CiCdController do - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects/settings/integrations_controller_spec.rb b/spec/controllers/projects/settings/integrations_controller_spec.rb index 65f7bb34f4a..e0f9a5b24a6 100644 --- a/spec/controllers/projects/settings/integrations_controller_spec.rb +++ b/spec/controllers/projects/settings/integrations_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::Settings::IntegrationsController do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects/todos_controller_spec.rb b/spec/controllers/projects/todos_controller_spec.rb index c5a4153d991..41d211ed1bb 100644 --- a/spec/controllers/projects/todos_controller_spec.rb +++ b/spec/controllers/projects/todos_controller_spec.rb @@ -2,7 +2,7 @@ require('spec_helper') describe Projects::TodosController do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project) } @@ -67,7 +67,7 @@ describe Projects::TodosController do end it "doesn't create todo" do - expect{ go }.not_to change { user.todos.count } + expect { go }.not_to change { user.todos.count } expect(response).to have_http_status(404) end end @@ -135,7 +135,7 @@ describe Projects::TodosController do end it "doesn't create todo" do - expect{ go }.not_to change { user.todos.count } + expect { go }.not_to change { user.todos.count } expect(response).to have_http_status(404) end end diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb index 16cd2e076e5..775f3998f5d 100644 --- a/spec/controllers/projects/tree_controller_spec.rb +++ b/spec/controllers/projects/tree_controller_spec.rb @@ -81,7 +81,7 @@ describe Projects::TreeController do context 'redirect to blob' do let(:id) { 'master/README.md' } it 'redirects' do - redirect_url = "/#{project.path_with_namespace}/blob/master/README.md" + redirect_url = "/#{project.full_path}/blob/master/README.md" expect(subject) .to redirect_to(redirect_url) end @@ -107,7 +107,7 @@ describe Projects::TreeController do it 'redirects to the new directory' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/#{branch_name}/#{path}") + .to redirect_to("/#{project.full_path}/tree/#{branch_name}/#{path}") expect(flash[:notice]).to eq('The directory has been successfully created.') end end @@ -118,7 +118,7 @@ describe Projects::TreeController do it 'does not allow overwriting of existing files' do expect(subject) - .to redirect_to("/#{project.path_with_namespace}/tree/master") + .to redirect_to("/#{project.full_path}/tree/master") expect(flash[:alert]).to eq('A file with this name already exists') end end diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb index cd6961a7bd5..488bcf31371 100644 --- a/spec/controllers/projects/uploads_controller_spec.rb +++ b/spec/controllers/projects/uploads_controller_spec.rb @@ -1,7 +1,7 @@ require('spec_helper') describe Projects::UploadsController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb index da06fcb7cfb..6957fb43c19 100644 --- a/spec/controllers/projects/variables_controller_spec.rb +++ b/spec/controllers/projects/variables_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::VariablesController do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 192cca45d99..c0e48046937 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -1,8 +1,8 @@ require('spec_helper') describe ProjectsController do - let(:project) { create(:empty_project) } - let(:public_project) { create(:empty_project, :public) } + let(:project) { create(:project) } + let(:public_project) { create(:project, :public) } let(:user) { create(:user) } let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } @@ -34,7 +34,7 @@ describe ProjectsController do end context "user does not have access to project" do - let(:private_project) { create(:empty_project, :private) } + let(:private_project) { create(:project, :private) } it "does not initialize notification setting" do get :show, namespace_id: private_project.namespace, id: private_project @@ -107,6 +107,20 @@ describe ProjectsController do end end + context 'when the storage is not available', broken_storage: true do + let(:project) { create(:project, :broken_storage) } + before do + project.add_developer(user) + sign_in(user) + end + + it 'renders a 503' do + get :show, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(503) + end + end + context "project with empty repo" do let(:empty_project) { create(:project_empty_repo, :public) } @@ -176,7 +190,7 @@ describe ProjectsController do end context "when the url contains .atom" do - let(:public_project_with_dot_atom) { build(:empty_project, :public, name: 'my.atom', path: 'my.atom') } + let(:public_project_with_dot_atom) { build(:project, :public, name: 'my.atom', path: 'my.atom') } it 'expects an error creating the project' do expect(public_project_with_dot_atom).not_to be_valid @@ -185,7 +199,7 @@ describe ProjectsController do context 'when the project is pending deletions' do it 'renders a 404 error' do - project = create(:empty_project, pending_delete: true) + project = create(:project, pending_delete: true) sign_in(user) get :show, namespace_id: project.namespace, id: project @@ -254,7 +268,7 @@ describe ProjectsController do describe '#transfer' do render_views - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:admin) { create(:admin) } let(:new_namespace) { create(:namespace) } @@ -311,8 +325,8 @@ describe ProjectsController do end context "when the project is forked" do - let(:project) { create(:project) } - let(:fork_project) { create(:project, forked_from_project: project) } + let(:project) { create(:project, :repository) } + let(:fork_project) { create(:project, :repository, forked_from_project: project) } let(:merge_request) do create(:merge_request, source_project: fork_project, @@ -390,7 +404,7 @@ describe ProjectsController do end context 'with forked project' do - let(:project_fork) { create(:project, namespace: user.namespace) } + let(:project_fork) { create(:project, :repository, namespace: user.namespace) } before do create(:forked_project_link, forked_to_project: project_fork) @@ -430,7 +444,7 @@ describe ProjectsController do end describe "GET refs" do - let(:public_project) { create(:project, :public) } + let(:public_project) { create(:project, :public, :repository) } it "gets a list of branches and tags" do get :refs, namespace_id: public_project.namespace, id: public_project @@ -564,6 +578,118 @@ describe ProjectsController do end end + describe '#export' do + before do + sign_in(user) + + project.add_master(user) + end + + context 'when project export is enabled' do + it 'returns 302' do + get :export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(302) + end + end + + context 'when project export is disabled' do + before do + stub_application_setting(project_export_enabled?: false) + end + + it 'returns 404' do + get :export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(404) + end + end + end + + describe '#download_export' do + before do + sign_in(user) + + project.add_master(user) + end + + context 'when project export is enabled' do + it 'returns 302' do + get :download_export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(302) + end + end + + context 'when project export is disabled' do + before do + stub_application_setting(project_export_enabled?: false) + end + + it 'returns 404' do + get :download_export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(404) + end + end + end + + describe '#remove_export' do + before do + sign_in(user) + + project.add_master(user) + end + + context 'when project export is enabled' do + it 'returns 302' do + post :remove_export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(302) + end + end + + context 'when project export is disabled' do + before do + stub_application_setting(project_export_enabled?: false) + end + + it 'returns 404' do + post :remove_export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(404) + end + end + end + + describe '#generate_new_export' do + before do + sign_in(user) + + project.add_master(user) + end + + context 'when project export is enabled' do + it 'returns 302' do + post :generate_new_export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(302) + end + end + + context 'when project export is disabled' do + before do + stub_application_setting(project_export_enabled?: false) + end + + it 'returns 404' do + post :generate_new_export, namespace_id: project.namespace, id: project + + expect(response).to have_http_status(404) + end + end + end + def project_moved_message(redirect_route, project) "Project '#{redirect_route.path}' was moved to '#{project.full_path}'. Please update any links and bookmarks that may still have the old path." end diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 634563fc290..5a4ab39ab86 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -5,7 +5,7 @@ describe RegistrationsController do let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } } context 'email confirmation' do - around(:each) do |example| + around do |example| perform_enqueued_jobs do example.run end @@ -15,7 +15,7 @@ describe RegistrationsController do it 'signs the user in' do allow_any_instance_of(ApplicationSetting).to receive(:send_user_confirmation_email).and_return(false) - expect { post(:create, user_params) }.not_to change{ ActionMailer::Base.deliveries.size } + expect { post(:create, user_params) }.not_to change { ActionMailer::Base.deliveries.size } expect(subject.current_user).not_to be_nil end end diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index a3708ad0908..37f961d0c94 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -8,7 +8,7 @@ describe SearchController do end it 'finds issue comments' do - project = create(:empty_project, :public) + project = create(:project, :public) note = create(:note_on_issue, project: project) get :show, project_id: project.id, scope: 'notes', search: note.note @@ -23,7 +23,7 @@ describe SearchController do end it "doesn't expose comments on issues" do - project = create(:empty_project, :public, :issues_private) + project = create(:project, :public, :issues_private) note = create(:note_on_issue, project: project) get :show, project_id: project.id, scope: 'notes', search: note.note @@ -33,7 +33,7 @@ describe SearchController do end it "doesn't expose comments on merge_requests" do - project = create(:empty_project, :public, :merge_requests_private) + project = create(:project, :public, :merge_requests_private) note = create(:note_on_merge_request, project: project) get :show, project_id: project.id, scope: 'notes', search: note.note @@ -42,7 +42,7 @@ describe SearchController do end it "doesn't expose comments on snippets" do - project = create(:empty_project, :public, :snippets_private) + project = create(:project, :public, :snippets_private) note = create(:note_on_project_snippet, project: project) get :show, project_id: project.id, scope: 'notes', search: note.note diff --git a/spec/controllers/sent_notifications_controller_spec.rb b/spec/controllers/sent_notifications_controller_spec.rb index 5d2734b8827..31593ce7311 100644 --- a/spec/controllers/sent_notifications_controller_spec.rb +++ b/spec/controllers/sent_notifications_controller_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe SentNotificationsController do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:sent_notification) { create(:sent_notification, project: project, noteable: issue, recipient: user) } let(:issue) do diff --git a/spec/controllers/snippets/notes_controller_spec.rb b/spec/controllers/snippets/notes_controller_spec.rb index 1c494b8c7ab..225753333ee 100644 --- a/spec/controllers/snippets/notes_controller_spec.rb +++ b/spec/controllers/snippets/notes_controller_spec.rb @@ -138,7 +138,7 @@ describe Snippets::NotesController do end it "deletes the note" do - expect{ delete :destroy, request_params }.to change{ Note.count }.from(1).to(0) + expect { delete :destroy, request_params }.to change { Note.count }.from(1).to(0) end context 'system note' do @@ -147,7 +147,7 @@ describe Snippets::NotesController do end it "does not delete the note" do - expect{ delete :destroy, request_params }.not_to change{ Note.count } + expect { delete :destroy, request_params }.not_to change { Note.count } end end end @@ -166,7 +166,7 @@ describe Snippets::NotesController do end it "does not update the note" do - expect{ delete :destroy, request_params }.not_to change{ Note.count } + expect { delete :destroy, request_params }.not_to change { Note.count } end end end diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb index 475ceda11fe..7c5d059760f 100644 --- a/spec/controllers/snippets_controller_spec.rb +++ b/spec/controllers/snippets_controller_spec.rb @@ -186,8 +186,8 @@ describe SnippetsController do end context 'when the snippet description contains a file' do - let(:picture_file) { '/system/temp/secret56/picture.jpg' } - let(:text_file) { '/system/temp/secret78/text.txt' } + let(:picture_file) { '/-/system/temp/secret56/picture.jpg' } + let(:text_file) { '/-/system/temp/secret78/text.txt' } let(:description) do "Description with picture:  and "\ "text: [text.txt](/uploads#{text_file})" @@ -208,8 +208,8 @@ describe SnippetsController do snippet = subject expected_description = "Description with picture: "\ - " and "\ - "text: [text.txt](/uploads/system/personal_snippet/#{snippet.id}/secret78/text.txt)" + " and "\ + "text: [text.txt](/uploads/-/system/personal_snippet/#{snippet.id}/secret78/text.txt)" expect(snippet.description).to eq(expected_description) end diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 96f719e2b82..b29f3d861be 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -102,7 +102,7 @@ describe UploadsController do subject expect(response.body).to match '\"alt\":\"rails_sample\"' - expect(response.body).to match "\"url\":\"/uploads/system/temp" + expect(response.body).to match "\"url\":\"/uploads/-/system/temp" end it 'does not create an Upload record' do @@ -119,7 +119,7 @@ describe UploadsController do subject expect(response.body).to match '\"alt\":\"doc_sample.txt\"' - expect(response.body).to match "\"url\":\"/uploads/system/temp" + expect(response.body).to match "\"url\":\"/uploads/-/system/temp" end it 'does not create an Upload record' do @@ -131,7 +131,7 @@ describe UploadsController do describe "GET show" do context 'Content-Disposition security measures' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } context 'for PNG files' do it 'returns Content-Disposition: inline' do @@ -203,7 +203,7 @@ describe UploadsController do end context "when viewing a project avatar" do - let!(:project) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let!(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } context "when the project is public" do before do diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 7aeb6efd86d..2cecd2646fc 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -86,14 +86,20 @@ describe UsersController do end context 'forked project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:forked_project) { Projects::ForkService.new(project, user).execute } before do sign_in(user) project.team << [user, :developer] - EventCreateService.new.push(project, user, []) - EventCreateService.new.push(forked_project, user, []) + + push_data = Gitlab::DataBuilder::Push.build_sample(project, user) + + fork_push_data = Gitlab::DataBuilder::Push + .build_sample(forked_project, user) + + EventCreateService.new.push(project, user, push_data) + EventCreateService.new.push(forked_project, user, fork_push_data) end it 'includes forked projects' do @@ -104,7 +110,7 @@ describe UsersController do end describe 'GET #calendar_activities' do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/factories/boards.rb b/spec/factories/boards.rb index 4df9aef2846..1ec042a6ab4 100644 --- a/spec/factories/boards.rb +++ b/spec/factories/boards.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :board do - project factory: :empty_project + project after(:create) do |board| board.lists.create(list_type: :closed) diff --git a/spec/factories/ci/pipeline_schedule.rb b/spec/factories/ci/pipeline_schedule.rb index a716da46ac6..564fef6833b 100644 --- a/spec/factories/ci/pipeline_schedule.rb +++ b/spec/factories/ci/pipeline_schedule.rb @@ -5,7 +5,7 @@ FactoryGirl.define do ref 'master' active true description "pipeline schedule" - project factory: :empty_project + project trait :nightly do cron '0 1 * * *' diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index 35803f0c37f..e83a0e599a8 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -5,7 +5,7 @@ FactoryGirl.define do sha '97de212e80737a608d939f648d959671fb0a0142' status 'pending' - project factory: :empty_project + project factory :ci_pipeline_without_jobs do after(:build) do |pipeline| diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb index 33a17cf7ed5..fa76d0ecd8c 100644 --- a/spec/factories/ci/runner_projects.rb +++ b/spec/factories/ci/runner_projects.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :ci_runner_project, class: Ci::RunnerProject do runner factory: :ci_runner - project factory: :empty_project + project end end diff --git a/spec/factories/ci/variables.rb b/spec/factories/ci/variables.rb index f83366136fd..d8fd513ffcf 100644 --- a/spec/factories/ci/variables.rb +++ b/spec/factories/ci/variables.rb @@ -7,6 +7,6 @@ FactoryGirl.define do protected true end - project factory: :empty_project + project end end diff --git a/spec/factories/commits.rb b/spec/factories/commits.rb index 89e260cf65b..f4f12a095fc 100644 --- a/spec/factories/commits.rb +++ b/spec/factories/commits.rb @@ -3,7 +3,7 @@ require_relative '../support/repo_helpers' FactoryGirl.define do factory :commit do git_commit RepoHelpers.sample_commit - project factory: :empty_project + project initialize_with do new(git_commit, project) diff --git a/spec/factories/conversational_development_index_metrics.rb b/spec/factories/conversational_development_index_metrics.rb index a5412629195..3806c43ba15 100644 --- a/spec/factories/conversational_development_index_metrics.rb +++ b/spec/factories/conversational_development_index_metrics.rb @@ -2,32 +2,42 @@ FactoryGirl.define do factory :conversational_development_index_metric, class: ConversationalDevelopmentIndex::Metric do leader_issues 9.256 instance_issues 1.234 + percentage_issues 13.331 leader_notes 30.33333 instance_notes 28.123 + percentage_notes 92.713 leader_milestones 16.2456 instance_milestones 1.234 + percentage_milestones 7.595 leader_boards 5.2123 instance_boards 3.254 + percentage_boards 62.429 leader_merge_requests 1.2 instance_merge_requests 0.6 + percentage_merge_requests 50.0 leader_ci_pipelines 12.1234 instance_ci_pipelines 2.344 + percentage_ci_pipelines 19.334 leader_environments 3.3333 instance_environments 2.2222 + percentage_environments 66.672 leader_deployments 1.200 instance_deployments 0.771 + percentage_deployments 64.25 leader_projects_prometheus_active 0.111 instance_projects_prometheus_active 0.109 + percentage_projects_prometheus_active 98.198 leader_service_desk_issues 15.891 instance_service_desk_issues 13.345 + percentage_service_desk_issues 83.978 end end diff --git a/spec/factories/deploy_keys_projects.rb b/spec/factories/deploy_keys_projects.rb index 75f8982ecd9..27cece487bd 100644 --- a/spec/factories/deploy_keys_projects.rb +++ b/spec/factories/deploy_keys_projects.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :deploy_keys_project do deploy_key - project factory: :empty_project + project end end diff --git a/spec/factories/deployments.rb b/spec/factories/deployments.rb index 29ad1af9fd9..e5abfd67d60 100644 --- a/spec/factories/deployments.rb +++ b/spec/factories/deployments.rb @@ -10,6 +10,10 @@ FactoryGirl.define do after(:build) do |deployment, evaluator| deployment.project ||= deployment.environment.project + + unless deployment.project.repository_exists? + allow(deployment.project.repository).to receive(:fetch_ref) + end end end end diff --git a/spec/factories/environments.rb b/spec/factories/environments.rb index d8d699fb3aa..9034476d094 100644 --- a/spec/factories/environments.rb +++ b/spec/factories/environments.rb @@ -2,12 +2,10 @@ FactoryGirl.define do factory :environment, class: Environment do sequence(:name) { |n| "environment#{n}" } - project factory: :empty_project + association :project, :repository sequence(:external_url) { |n| "https://env#{n}.example.gitlab.com" } trait :with_review_app do |environment| - project - transient do ref 'master' end diff --git a/spec/factories/events.rb b/spec/factories/events.rb index 55727d6b62c..ad9f7e2caef 100644 --- a/spec/factories/events.rb +++ b/spec/factories/events.rb @@ -1,7 +1,8 @@ FactoryGirl.define do factory :event do - project factory: :empty_project + project author factory: :user + action Event::JOINED trait(:created) { action Event::CREATED } trait(:updated) { action Event::UPDATED } @@ -20,4 +21,19 @@ FactoryGirl.define do target factory: :closed_issue end end + + factory :push_event, class: PushEvent do + project factory: :project_empty_repo + author factory: :user + action Event::PUSHED + end + + factory :push_event_payload do + event + commit_count 1 + action :pushed + ref_type :branch + ref 'master' + commit_to '3cdce97ed87c91368561584e7358f4d46e3e173c' + end end diff --git a/spec/factories/file_uploaders.rb b/spec/factories/file_uploaders.rb index d397dd705a5..622571390d2 100644 --- a/spec/factories/file_uploaders.rb +++ b/spec/factories/file_uploaders.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :file_uploader do skip_create - project factory: :empty_project + project secret nil transient do diff --git a/spec/factories/forked_project_links.rb b/spec/factories/forked_project_links.rb index 66b0f248959..9b34651a4ae 100644 --- a/spec/factories/forked_project_links.rb +++ b/spec/factories/forked_project_links.rb @@ -1,7 +1,7 @@ FactoryGirl.define do factory :forked_project_link do - association :forked_to_project, factory: :project - association :forked_from_project, factory: :project + association :forked_to_project, factory: [:project, :repository] + association :forked_from_project, factory: [:project, :repository] after(:create) do |link| link.forked_from_project.reload @@ -9,7 +9,7 @@ FactoryGirl.define do end trait :forked_to_empty_project do - association :forked_to_project, factory: :empty_project + association :forked_to_project, factory: [:project, :repository] end end end diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index a16695cb7c1..7c3b80198f9 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :issue do title { generate(:title) } author - project factory: :empty_project + project trait :confidential do confidential true diff --git a/spec/factories/label_priorities.rb b/spec/factories/label_priorities.rb index f25939d2d3e..7430466fc57 100644 --- a/spec/factories/label_priorities.rb +++ b/spec/factories/label_priorities.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :label_priority do - project factory: :empty_project + project label sequence(:priority) end diff --git a/spec/factories/labels.rb b/spec/factories/labels.rb index 22c2a1f15e2..416317d677b 100644 --- a/spec/factories/labels.rb +++ b/spec/factories/labels.rb @@ -5,7 +5,7 @@ FactoryGirl.define do end factory :label, traits: [:base_label], class: ProjectLabel do - project factory: :empty_project + project transient do priority nil diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index 1bc530d06db..cbec716d6ea 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -68,6 +68,17 @@ FactoryGirl.define do merge_user author end + after(:build) do |merge_request| + target_project = merge_request.target_project + source_project = merge_request.source_project + + # Fake `write_ref` if we don't have repository + # We have too many existing tests replying on this behaviour + unless [target_project, source_project].all?(&:repository_exists?) + allow(merge_request).to receive(:write_ref) + end + end + factory :merged_merge_request, traits: [:merged] factory :closed_merge_request, traits: [:closed] factory :reopened_merge_request, traits: [:opened] diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb index 113665ff11b..2f75bf12cd7 100644 --- a/spec/factories/milestones.rb +++ b/spec/factories/milestones.rb @@ -17,7 +17,7 @@ FactoryGirl.define do state "closed" end - after(:build) do |milestone, evaluator| + after(:build, :stub) do |milestone, evaluator| if evaluator.group milestone.group = evaluator.group elsif evaluator.group_id @@ -27,7 +27,7 @@ FactoryGirl.define do elsif evaluator.project_id milestone.project_id = evaluator.project_id else - milestone.project = create(:empty_project) + milestone.project = create(:project) end end diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index 046974dcd6e..f0d05504b7e 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -4,7 +4,7 @@ include ActionDispatch::TestProcess FactoryGirl.define do factory :note do - project factory: :empty_project + project note { generate(:title) } author on_issue diff --git a/spec/factories/notification_settings.rb b/spec/factories/notification_settings.rb index b5e96d18b8f..e9171528d86 100644 --- a/spec/factories/notification_settings.rb +++ b/spec/factories/notification_settings.rb @@ -1,8 +1,7 @@ FactoryGirl.define do factory :notification_setting do - source factory: :empty_project + source factory: :project user level 3 - events [] end end diff --git a/spec/factories/project_group_links.rb b/spec/factories/project_group_links.rb index 50341d943f5..e73cc05f9d7 100644 --- a/spec/factories/project_group_links.rb +++ b/spec/factories/project_group_links.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :project_group_link do - project factory: :empty_project + project group end end diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index d754e980931..accae636a3a 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :project_hook do url { generate(:url) } enable_ssl_verification false - project factory: :empty_project + project trait :token do token { SecureRandom.hex(10) } diff --git a/spec/factories/project_members.rb b/spec/factories/project_members.rb index fe4518caadf..9cf3a1e8e8a 100644 --- a/spec/factories/project_members.rb +++ b/spec/factories/project_members.rb @@ -1,7 +1,7 @@ FactoryGirl.define do factory :project_member do user - project factory: :empty_project + project master trait(:guest) { access_level ProjectMember::GUEST } diff --git a/spec/factories/project_wikis.rb b/spec/factories/project_wikis.rb index ae222d5e69a..38fcab7466d 100644 --- a/spec/factories/project_wikis.rb +++ b/spec/factories/project_wikis.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :project_wiki do skip_create - project factory: :empty_project + project user factory: :user initialize_with { new(project, user) } end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 485ed48d2de..4a2034b31b3 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -5,15 +5,50 @@ FactoryGirl.define do # # Project does not have bare repository. # Use this factory if you don't need repository in tests - factory :empty_project, class: 'Project' do + factory :project, class: 'Project' do sequence(:name) { |n| "project#{n}" } path { name.downcase.gsub(/\s/, '_') } - namespace - creator - # Behaves differently to nil due to cache_has_external_issue_tracker has_external_issue_tracker false + # Associations + namespace + creator { group ? create(:user) : namespace&.owner } + + # Nest Project Feature attributes + transient do + wiki_access_level ProjectFeature::ENABLED + builds_access_level ProjectFeature::ENABLED + snippets_access_level ProjectFeature::ENABLED + issues_access_level ProjectFeature::ENABLED + merge_requests_access_level ProjectFeature::ENABLED + repository_access_level ProjectFeature::ENABLED + end + + after(:create) do |project, evaluator| + # Builds and MRs can't have higher visibility level than repository access level. + builds_access_level = [evaluator.builds_access_level, evaluator.repository_access_level].min + merge_requests_access_level = [evaluator.merge_requests_access_level, evaluator.repository_access_level].min + + project.project_feature.update_columns( + wiki_access_level: evaluator.wiki_access_level, + builds_access_level: builds_access_level, + snippets_access_level: evaluator.snippets_access_level, + issues_access_level: evaluator.issues_access_level, + merge_requests_access_level: merge_requests_access_level, + repository_access_level: evaluator.repository_access_level) + + # Normally the class Projects::CreateService is used for creating + # projects, and this class takes care of making sure the owner and current + # user have access to the project. Our specs don't use said service class, + # thus we must manually refresh things here. + unless project.group || project.pending_delete + project.add_master(project.owner) + end + + project.group&.refresh_members_authorized_projects + end + trait :public do visibility_level Gitlab::VisibilityLevel::PUBLIC end @@ -54,8 +89,46 @@ FactoryGirl.define do avatar { File.open(Rails.root.join('spec/fixtures/dk.png')) } end + trait :broken_storage do + after(:create) do |project| + project.update_column(:repository_storage, 'broken') + end + end + + # Test repository - https://gitlab.com/gitlab-org/gitlab-test trait :repository do - # no-op... for now! + path { 'gitlabhq' } + + test_repo + + transient do + create_templates nil + end + + after :create do |project, evaluator| + if evaluator.create_templates + templates_path = "#{evaluator.create_templates}_templates" + + project.repository.create_file( + project.creator, + ".gitlab/#{templates_path}/bug.md", + 'something valid', + message: 'test 3', + branch_name: 'master') + project.repository.create_file( + project.creator, + ".gitlab/#{templates_path}/template_test.md", + 'template_test', + message: 'test 1', + branch_name: 'master') + project.repository.create_file( + project.creator, + ".gitlab/#{templates_path}/feature_proposal.md", + 'feature_proposal', + message: 'test 2', + branch_name: 'master') + end + end end trait :empty_repo do @@ -64,7 +137,7 @@ FactoryGirl.define do # We delete hooks so that gitlab-shell will not try to authenticate with # an API that isn't running - FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.path_with_namespace}.git", 'hooks')) + FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.disk_path}.git", 'hooks')) end end @@ -72,7 +145,7 @@ FactoryGirl.define do after(:create) do |project| raise "Failed to create repository!" unless project.create_repository - FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.path_with_namespace}.git", 'refs')) + FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.disk_path}.git", 'refs')) end end @@ -102,103 +175,24 @@ FactoryGirl.define do trait(:repository_enabled) { repository_access_level ProjectFeature::ENABLED } trait(:repository_disabled) { repository_access_level ProjectFeature::DISABLED } trait(:repository_private) { repository_access_level ProjectFeature::PRIVATE } - - # Nest Project Feature attributes - transient do - wiki_access_level ProjectFeature::ENABLED - builds_access_level ProjectFeature::ENABLED - snippets_access_level ProjectFeature::ENABLED - issues_access_level ProjectFeature::ENABLED - merge_requests_access_level ProjectFeature::ENABLED - repository_access_level ProjectFeature::ENABLED - end - - after(:create) do |project, evaluator| - # Builds and MRs can't have higher visibility level than repository access level. - builds_access_level = [evaluator.builds_access_level, evaluator.repository_access_level].min - merge_requests_access_level = [evaluator.merge_requests_access_level, evaluator.repository_access_level].min - - project.project_feature - .update_attributes!( - wiki_access_level: evaluator.wiki_access_level, - builds_access_level: builds_access_level, - snippets_access_level: evaluator.snippets_access_level, - issues_access_level: evaluator.issues_access_level, - merge_requests_access_level: merge_requests_access_level, - repository_access_level: evaluator.repository_access_level - ) - - # Normally the class Projects::CreateService is used for creating - # projects, and this class takes care of making sure the owner and current - # user have access to the project. Our specs don't use said service class, - # thus we must manually refresh things here. - owner = project.owner - - if owner && owner.is_a?(User) && !project.pending_delete - project.members.create!(user: owner, access_level: Gitlab::Access::MASTER) - end - - project.group&.refresh_members_authorized_projects - end end # Project with empty repository # # This is a case when you just created a project # but not pushed any code there yet - factory :project_empty_repo, parent: :empty_project do + factory :project_empty_repo, parent: :project do empty_repo end # Project with broken repository # # Project with an invalid repository state - factory :project_broken_repo, parent: :empty_project do + factory :project_broken_repo, parent: :project do broken_repo end - # Project with test repository - # - # Test repository source can be found at - # https://gitlab.com/gitlab-org/gitlab-test - factory :project, parent: :empty_project do - path { 'gitlabhq' } - - test_repo - - transient do - create_template nil - end - - after :create do |project, evaluator| - if evaluator.create_template - args = evaluator.create_template - - project.add_user(args[:user], args[:access]) - - project.repository.create_file( - args[:user], - ".gitlab/#{args[:path]}/bug.md", - 'something valid', - message: 'test 3', - branch_name: 'master') - project.repository.create_file( - args[:user], - ".gitlab/#{args[:path]}/template_test.md", - 'template_test', - message: 'test 1', - branch_name: 'master') - project.repository.create_file( - args[:user], - ".gitlab/#{args[:path]}/feature_proposal.md", - 'feature_proposal', - message: 'test 2', - branch_name: 'master') - end - end - end - - factory :forked_project_with_submodules, parent: :empty_project do + factory :forked_project_with_submodules, parent: :project do path { 'forked-gitlabhq' } after :create do |project| @@ -228,11 +222,11 @@ FactoryGirl.define do jira_service end - factory :kubernetes_project, parent: :empty_project do + factory :kubernetes_project, parent: :project do kubernetes_service end - factory :prometheus_project, parent: :empty_project do + factory :prometheus_project, parent: :project do after :create do |project| project.create_prometheus_service( active: true, diff --git a/spec/factories/protected_branches.rb b/spec/factories/protected_branches.rb index 3dbace4b38a..fe0cbfc4444 100644 --- a/spec/factories/protected_branches.rb +++ b/spec/factories/protected_branches.rb @@ -57,5 +57,11 @@ FactoryGirl.define do protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MASTER) end end + + trait :no_one_can_merge do + after(:create) do |protected_branch| + protected_branch.merge_access_levels.first.update!(access_level: Gitlab::Access::NO_ACCESS) + end + end end end diff --git a/spec/factories/releases.rb b/spec/factories/releases.rb index 6a6d6fa171f..74497dc82c0 100644 --- a/spec/factories/releases.rb +++ b/spec/factories/releases.rb @@ -2,6 +2,6 @@ FactoryGirl.define do factory :release do tag "v1.1.0" description "Awesome release" - project factory: :empty_project + project end end diff --git a/spec/factories/sent_notifications.rb b/spec/factories/sent_notifications.rb index 99253be5a22..c2febf5b438 100644 --- a/spec/factories/sent_notifications.rb +++ b/spec/factories/sent_notifications.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :sent_notification do - project factory: :empty_project + project recipient factory: :user noteable { create(:issue, project: project) } reply_key { SentNotification.reply_key } diff --git a/spec/factories/services.rb b/spec/factories/services.rb index 30bc25cf88a..c2674ce2d11 100644 --- a/spec/factories/services.rb +++ b/spec/factories/services.rb @@ -1,11 +1,11 @@ FactoryGirl.define do factory :service do - project factory: :empty_project + project type 'Service' end factory :custom_issue_tracker_service, class: CustomIssueTrackerService do - project factory: :empty_project + project type 'CustomIssueTrackerService' category 'issue_tracker' active true @@ -17,7 +17,7 @@ FactoryGirl.define do end factory :kubernetes_service do - project factory: :empty_project + project active true properties({ api_url: 'https://kubernetes.example.com', @@ -26,7 +26,7 @@ FactoryGirl.define do end factory :prometheus_service do - project factory: :empty_project + project active true properties({ api_url: 'https://prometheus.example.com/' @@ -34,7 +34,7 @@ FactoryGirl.define do end factory :jira_service do - project factory: :empty_project + project active true properties( url: 'https://jira.example.com', @@ -43,7 +43,7 @@ FactoryGirl.define do end factory :hipchat_service do - project factory: :empty_project + project type 'HipchatService' token 'test_token' end diff --git a/spec/factories/snippets.rb b/spec/factories/snippets.rb index f6ce99d50f9..075bccd7f94 100644 --- a/spec/factories/snippets.rb +++ b/spec/factories/snippets.rb @@ -20,7 +20,7 @@ FactoryGirl.define do end factory :project_snippet, parent: :snippet, class: :ProjectSnippet do - project factory: :empty_project + project end factory :personal_snippet, parent: :snippet, class: :PersonalSnippet do diff --git a/spec/factories/subscriptions.rb b/spec/factories/subscriptions.rb index b11b0a0a17b..1ae7fc9f384 100644 --- a/spec/factories/subscriptions.rb +++ b/spec/factories/subscriptions.rb @@ -1,7 +1,7 @@ FactoryGirl.define do factory :subscription do user - project factory: :empty_project + project subscribable factory: :issue end end diff --git a/spec/factories/todos.rb b/spec/factories/todos.rb index c1ac3bb84ad..4975befbfe3 100644 --- a/spec/factories/todos.rb +++ b/spec/factories/todos.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :todo do - project factory: :empty_project + project author user target factory: :issue @@ -45,7 +45,7 @@ FactoryGirl.define do end factory :on_commit_todo, class: Todo do - project factory: :empty_project + project author user action { Todo::ASSIGNED } diff --git a/spec/factories/users.rb b/spec/factories/users.rb index e60fe713bc3..4000cd085b7 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,5 +1,5 @@ FactoryGirl.define do - factory :user, aliases: [:author, :assignee, :recipient, :owner, :creator, :resource_owner] do + factory :user, aliases: [:author, :assignee, :recipient, :owner, :resource_owner] do email { generate(:email) } name { generate(:name) } username { generate(:username) } @@ -8,6 +8,10 @@ FactoryGirl.define do confirmation_token { nil } can_create_group true + after(:stub) do |user| + user.notification_email = user.email + end + before(:create) do |user| user.ensure_rss_token end diff --git a/spec/features/admin/admin_disables_git_access_protocol_spec.rb b/spec/features/admin/admin_disables_git_access_protocol_spec.rb index 931f4ec3d24..9ea3cfa72c6 100644 --- a/spec/features/admin/admin_disables_git_access_protocol_spec.rb +++ b/spec/features/admin/admin_disables_git_access_protocol_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' feature 'Admin disables Git access protocol' do include StubENV - let(:project) { create(:empty_project, :empty_repo) } + let(:project) { create(:project, :empty_repo) } let(:admin) { create(:admin) } background do diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb index 2e1bfcdcec3..3768727d8ae 100644 --- a/spec/features/admin/admin_groups_spec.rb +++ b/spec/features/admin/admin_groups_spec.rb @@ -165,7 +165,7 @@ feature 'Admin Groups' do describe 'shared projects' do it 'renders shared project' do - empty_project = create(:empty_project) + empty_project = create(:project) empty_project.project_group_links.create!( group_access: Gitlab::Access::MASTER, group: group diff --git a/spec/features/admin/admin_health_check_spec.rb b/spec/features/admin/admin_health_check_spec.rb index 106e7370a98..37fd3e171eb 100644 --- a/spec/features/admin/admin_health_check_spec.rb +++ b/spec/features/admin/admin_health_check_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature "Admin Health Check" do +feature "Admin Health Check", feature: true, broken_storage: true do include StubENV before do @@ -55,4 +55,26 @@ feature "Admin Health Check" do expect(page).to have_content('The server is on fire') end end + + context 'with repository storage failures' do + before do + # Track a failure + Gitlab::Git::Storage::CircuitBreaker.for_storage('broken').perform { nil } rescue nil + visit admin_health_check_path + end + + it 'shows storage failure information' do + hostname = Gitlab::Environment.hostname + + expect(page).to have_content('broken: failed storage access attempt on host:') + expect(page).to have_content("#{hostname}: 1 of 10 failures.") + end + + it 'allows resetting storage failures' do + click_button 'Reset git storage health information' + + expect(page).to have_content('Git storage health information has been reset') + expect(page).not_to have_content('failed storage access attempt') + end + end end diff --git a/spec/features/admin/admin_hook_logs_spec.rb b/spec/features/admin/admin_hook_logs_spec.rb index 7910d5fb72b..710822ac042 100644 --- a/spec/features/admin/admin_hook_logs_spec.rb +++ b/spec/features/admin/admin_hook_logs_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Admin::HookLogs' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:system_hook) { create(:system_hook) } let(:hook_log) { create(:web_hook_log, web_hook: system_hook, internal_error_message: 'some error') } diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index 141109fd464..30fcb334b60 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Admin::Hooks' do before do - @project = create(:empty_project) + @project = create(:project) sign_in(create(:admin)) @system_hook = create(:system_hook) diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index 4f69eafcb9d..77710f80036 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -4,7 +4,7 @@ describe "Admin::Projects" do include Select2Helper let(:user) { create :user } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:current_user) { create(:admin) } before do @@ -12,7 +12,7 @@ describe "Admin::Projects" do end describe "GET /admin/projects" do - let!(:archived_project) { create :empty_project, :public, :archived } + let!(:archived_project) { create :project, :public, :archived } before do expect(project).to be_persisted diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb index 46bab3763cc..e3bb16af38a 100644 --- a/spec/features/admin/admin_runners_spec.rb +++ b/spec/features/admin/admin_runners_spec.rb @@ -65,8 +65,8 @@ describe "Admin Runners" do let(:runner) { FactoryGirl.create :ci_runner } before do - @project1 = FactoryGirl.create(:empty_project) - @project2 = FactoryGirl.create(:empty_project) + @project1 = FactoryGirl.create(:project) + @project2 = FactoryGirl.create(:project) visit admin_runner_path(runner) end diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index c1eced417cf..5db42175c15 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -35,6 +35,7 @@ feature 'Admin updates settings' do fill_in 'Help page text', with: 'Example text' check 'Hide marketing-related entries from help' fill_in 'Support page URL', with: 'http://example.com/help' + uncheck 'Project export enabled' click_button 'Save' expect(current_application_settings.gravatar_enabled).to be_falsey @@ -42,6 +43,7 @@ feature 'Admin updates settings' do expect(current_application_settings.help_page_text).to eq "Example text" expect(current_application_settings.help_page_hide_commercial_content).to be_truthy expect(current_application_settings.help_page_support_url).to eq "http://example.com/help" + expect(current_application_settings.project_export_enabled).to be_falsey expect(page).to have_content "Application settings saved successfully" end @@ -69,6 +71,14 @@ feature 'Admin updates settings' do expect(find('#service_push_channel').value).to eq '#test_channel' end + context 'sign-in restrictions', :js do + it 'de-activates oauth sign-in source' do + find('.btn', text: 'GitLab.com').click + + expect(find('.btn', text: 'GitLab.com')).not_to have_css('.active') + end + end + def check_all_events page.check('Active') page.check('Push') diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 97ffc54415c..034682dae27 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -32,11 +32,13 @@ describe 'Admin > Users > Impersonation Tokens', js: true do check "api" check "read_user" - expect { click_on "Create impersonation token" }.to change { PersonalAccessTokensFinder.new(impersonation: true).execute.count } + click_on "Create impersonation token" + expect(active_impersonation_tokens).to have_text(name) expect(active_impersonation_tokens).to have_text('In') expect(active_impersonation_tokens).to have_text('api') expect(active_impersonation_tokens).to have_text('read_user') + expect(PersonalAccessTokensFinder.new(impersonation: true).execute.count).to equal(1) end end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 0dde8bb696c..e2e2b13cf8a 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -257,7 +257,7 @@ describe "Admin::Users" do describe "GET /admin/users/:id/projects" do let(:group) { create(:group) } - let!(:project) { create(:empty_project, group: group) } + let!(:project) { create(:project, group: group) } before do group.add_developer(user) diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb index 5b3ee6ee822..c2b7543a690 100644 --- a/spec/features/admin/admin_uses_repository_checks_spec.rb +++ b/spec/features/admin/admin_uses_repository_checks_spec.rb @@ -9,7 +9,7 @@ feature 'Admin uses repository checks' do end scenario 'to trigger a single check' do - project = create(:empty_project) + project = create(:project) visit_admin_project_page(project) page.within('.repository-check') do @@ -20,7 +20,7 @@ feature 'Admin uses repository checks' do end scenario 'to see a single failed repository check' do - project = create(:empty_project) + project = create(:project) project.update_columns( last_repository_check_failed: true, last_repository_check_at: Time.now diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb index d70da7f09e9..5aae2dbaf91 100644 --- a/spec/features/atom/dashboard_issues_spec.rb +++ b/spec/features/atom/dashboard_issues_spec.rb @@ -4,8 +4,8 @@ describe "Dashboard Issues Feed" do describe "GET /issues" do let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') } let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') } - let!(:project1) { create(:empty_project) } - let!(:project2) { create(:empty_project) } + let!(:project1) { create(:project) } + let!(:project2) { create(:project) } before do project1.team << [user, :master] diff --git a/spec/features/atom/dashboard_spec.rb b/spec/features/atom/dashboard_spec.rb index a7c12853981..321c8a2a670 100644 --- a/spec/features/atom/dashboard_spec.rb +++ b/spec/features/atom/dashboard_spec.rb @@ -19,7 +19,7 @@ describe "Dashboard Feed" do end context 'feed content' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project, author: user, description: '') } let(:note) { create(:note, noteable: issue, author: user, note: 'Bug confirmed', project: project) } diff --git a/spec/features/atom/issues_spec.rb b/spec/features/atom/issues_spec.rb index 59e20d7e24d..3eeb4d35131 100644 --- a/spec/features/atom/issues_spec.rb +++ b/spec/features/atom/issues_spec.rb @@ -5,7 +5,7 @@ describe 'Issues Feed' do let!(:user) { create(:user, email: 'private1@example.com', public_email: 'public1@example.com') } let!(:assignee) { create(:user, email: 'private2@example.com', public_email: 'public2@example.com') } let!(:group) { create(:group) } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:issue) { create(:issue, author: user, assignees: [assignee], project: project) } before do diff --git a/spec/features/boards/add_issues_modal_spec.rb b/spec/features/boards/add_issues_modal_spec.rb index c87469696da..a6ad5981f8f 100644 --- a/spec/features/boards/add_issues_modal_spec.rb +++ b/spec/features/boards/add_issues_modal_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe 'Issue Boards add issue modal', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } let!(:planning) { create(:label, project: project, name: 'Planning') } diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index c3711c9b2c5..ce458431c55 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -4,7 +4,7 @@ describe 'Issue Boards', js: true do include DragTo let(:group) { create(:group, :nested) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } let!(:user2) { create(:user) } @@ -233,7 +233,7 @@ describe 'Issue Boards', js: true do wait_for_board_cards(4, 1) expect(find('.board:nth-child(3)')).to have_content(issue6.title) - expect(find('.board:nth-child(3)').all('.card').last).not_to have_content(development.title) + expect(find('.board:nth-child(3)').all('.card').last).to have_content(development.title) end it 'issue moves between lists' do @@ -244,7 +244,7 @@ describe 'Issue Boards', js: true do wait_for_board_cards(4, 1) expect(find('.board:nth-child(2)')).to have_content(issue7.title) - expect(find('.board:nth-child(2)').all('.card').first).not_to have_content(planning.title) + expect(find('.board:nth-child(2)').all('.card').first).to have_content(planning.title) end it 'issue moves from closed' do diff --git a/spec/features/boards/issue_ordering_spec.rb b/spec/features/boards/issue_ordering_spec.rb index f4be56a4463..4cbb48e2e6e 100644 --- a/spec/features/boards/issue_ordering_spec.rb +++ b/spec/features/boards/issue_ordering_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Issue Boards', :js do include DragTo - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } let(:label) { create(:label, project: project) } diff --git a/spec/features/boards/keyboard_shortcut_spec.rb b/spec/features/boards/keyboard_shortcut_spec.rb index 415eda0e058..61b53aa5d1e 100644 --- a/spec/features/boards/keyboard_shortcut_spec.rb +++ b/spec/features/boards/keyboard_shortcut_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe 'Issue Boards shortcut', js: true do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do create(:board, project: project) diff --git a/spec/features/boards/modal_filter_spec.rb b/spec/features/boards/modal_filter_spec.rb index 1c8b9c46569..422d96175f7 100644 --- a/spec/features/boards/modal_filter_spec.rb +++ b/spec/features/boards/modal_filter_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe 'Issue Boards add issue modal filtering', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:board) { create(:board, project: project) } let(:planning) { create(:label, project: project, name: 'Planning') } let!(:list1) { create(:list, board: board, label: planning, position: 0) } diff --git a/spec/features/boards/new_issue_spec.rb b/spec/features/boards/new_issue_spec.rb index 1dbe3dbda11..f67372337ec 100644 --- a/spec/features/boards/new_issue_spec.rb +++ b/spec/features/boards/new_issue_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe 'Issue Boards new issue', js: true do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:board) { create(:board, project: project) } let!(:list) { create(:list, board: board, position: 0) } let(:user) { create(:user) } diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index 3f58fe1c32c..c3bf50ef9d1 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Issue Boards', js: true do let(:user) { create(:user) } let(:user2) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let!(:milestone) { create(:milestone, project: project) } let!(:development) { create(:label, project: project, name: 'Development') } let!(:bug) { create(:label, project: project, name: 'Bug') } @@ -15,10 +15,12 @@ describe 'Issue Boards', js: true do let!(:list) { create(:list, board: board, label: development, position: 0) } let(:card) { find('.board:nth-child(2)').first('.card') } - before do - Timecop.freeze + around do |example| + Timecop.freeze { example.run } + end - project.team << [user, :master] + before do + project.add_master(user) sign_in(user) @@ -26,10 +28,6 @@ describe 'Issue Boards', js: true do wait_for_requests end - after do - Timecop.return - end - it 'shows sidebar when clicking issue' do click_card(card) @@ -257,7 +255,7 @@ describe 'Issue Boards', js: true do end end - expect(card).to have_selector('.label', count: 2) + expect(card).to have_selector('.label', count: 3) expect(card).to have_content(bug.title) end @@ -283,7 +281,7 @@ describe 'Issue Boards', js: true do end end - expect(card).to have_selector('.label', count: 3) + expect(card).to have_selector('.label', count: 4) expect(card).to have_content(bug.title) expect(card).to have_content(regression.title) end @@ -308,7 +306,7 @@ describe 'Issue Boards', js: true do end end - expect(card).not_to have_selector('.label') + expect(card).to have_selector('.label', count: 1) expect(card).not_to have_content(stretch.title) end end diff --git a/spec/features/boards/sub_group_project_spec.rb b/spec/features/boards/sub_group_project_spec.rb index f54f2234203..11a54079f4f 100644 --- a/spec/features/boards/sub_group_project_spec.rb +++ b/spec/features/boards/sub_group_project_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Sub-group project issue boards', :js do let(:group) { create(:group) } let(:nested_group_1) { create(:group, parent: group) } - let(:project) { create(:empty_project, group: nested_group_1) } + let(:project) { create(:project, group: nested_group_1) } let(:board) { create(:board, project: project) } let(:label) { create(:label, project: project) } let(:user) { create(:user) } diff --git a/spec/features/calendar_spec.rb b/spec/features/calendar_spec.rb index 1e7fd7b62bd..9a597a2d690 100644 --- a/spec/features/calendar_spec.rb +++ b/spec/features/calendar_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Contributions Calendar', :js do let(:user) { create(:user) } - let(:contributed_project) { create(:empty_project, :public) } + let(:contributed_project) { create(:project, :public) } let(:issue_note) { create(:note, project: contributed_project) } # Ex/ Sunday Jan 1, 2016 @@ -42,14 +42,14 @@ feature 'Contributions Calendar', :js do end def push_code_contribution - push_params = { - project: contributed_project, - action: Event::PUSHED, - author_id: user.id, - data: { commit_count: 3 } - } - - Event.create(push_params) + event = create(:push_event, project: contributed_project, author: user) + + create(:push_event_payload, + event: event, + commit_from: '11f9ac0a48b62cef25eedede4c1819964f08d5ce', + commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + commit_count: 3, + ref: 'master') end def note_comment_contribution diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 15ec6f20763..0c9fcc60d30 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -282,7 +282,7 @@ describe 'Commits' do end # verified and the gpg user has a gitlab profile - click_on 'Verified' + click_on 'Verified', match: :first within '.popover' do expect(page).to have_content 'This commit was signed with a verified signature.' expect(page).to have_content 'Nannie Bernhard' @@ -295,7 +295,7 @@ describe 'Commits' do visit project_commits_path(project, :'signed-commits') - click_on 'Verified' + click_on 'Verified', match: :first within '.popover' do expect(page).to have_content 'This commit was signed with a verified signature.' expect(page).to have_content 'Nannie Bernhard' diff --git a/spec/features/container_registry_spec.rb b/spec/features/container_registry_spec.rb index 8f59ce3d2e7..ae39ba4da6b 100644 --- a/spec/features/container_registry_spec.rb +++ b/spec/features/container_registry_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe "Container Registry" do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:container_repository) do create(:container_repository, name: 'my/image') diff --git a/spec/features/cycle_analytics_spec.rb b/spec/features/cycle_analytics_spec.rb index 5c60cca10b9..bfe9dac3bd4 100644 --- a/spec/features/cycle_analytics_spec.rb +++ b/spec/features/cycle_analytics_spec.rb @@ -24,6 +24,12 @@ feature 'Cycle Analytics', js: true do expect(page).to have_content('Introducing Cycle Analytics') end + it 'shows pipeline summary' do + expect(new_issues_counter).to have_content('-') + expect(commits_counter).to have_content('-') + expect(deploys_counter).to have_content('-') + end + it 'shows active stage with empty message' do expect(page).to have_selector('.stage-nav-item.active', text: 'Issue') expect(page).to have_content("We don't have enough data to show this stage.") @@ -42,6 +48,12 @@ feature 'Cycle Analytics', js: true do visit project_cycle_analytics_path(project) end + it 'shows pipeline summary' do + expect(new_issues_counter).to have_content('1') + expect(commits_counter).to have_content('2') + expect(deploys_counter).to have_content('1') + end + it 'shows data on each stage' do expect_issue_to_be_present @@ -63,6 +75,20 @@ feature 'Cycle Analytics', js: true do click_stage('Production') expect_issue_to_be_present end + + context "when I change the time period observed" do + before do + _two_weeks_old_issue = create(:issue, project: project, created_at: 2.weeks.ago) + + click_button('Last 30 days') + click_link('Last 7 days') + wait_for_requests + end + + it 'shows only relevant data' do + expect(new_issues_counter).to have_content('1') + end + end end context "when my preferred language is Spanish" do @@ -109,6 +135,18 @@ feature 'Cycle Analytics', js: true do end end + def new_issues_counter + find(:xpath, "//p[contains(text(),'New Issue')]/preceding-sibling::h3") + end + + def commits_counter + find(:xpath, "//p[contains(text(),'Commits')]/preceding-sibling::h3") + end + + def deploys_counter + find(:xpath, "//p[contains(text(),'Deploy')]/preceding-sibling::h3") + end + def expect_issue_to_be_present expect(find('.stage-events')).to have_content(issue.title) expect(find('.stage-events')).to have_content(issue.author.name) diff --git a/spec/features/dashboard/activity_spec.rb b/spec/features/dashboard/activity_spec.rb index a96270c9147..582868bac1e 100644 --- a/spec/features/dashboard/activity_spec.rb +++ b/spec/features/dashboard/activity_spec.rb @@ -17,33 +17,25 @@ feature 'Dashboard > Activity' do end context 'event filters', :js do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:merge_request) do create(:merge_request, author: user, source_project: project, target_project: project) end - let(:push_event_data) do - { - before: Gitlab::Git::BLANK_SHA, - after: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e', - ref: 'refs/heads/new_design', - user_id: user.id, - user_name: user.name, - repository: { - name: project.name, - url: 'localhost/rubinius', - description: '', - homepage: 'localhost/rubinius', - private: true - } - } - end - let(:note) { create(:note, project: project, noteable: merge_request) } let!(:push_event) do - create(:event, :pushed, data: push_event_data, project: project, author: user) + event = create(:push_event, project: project, author: user) + + create(:push_event_payload, + event: event, + action: :created, + commit_to: '0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e', + ref: 'new_design', + commit_count: 1) + + event end let!(:merged_event) do diff --git a/spec/features/dashboard/archived_projects_spec.rb b/spec/features/dashboard/archived_projects_spec.rb index ceac6a0a27c..814ec0e59c7 100644 --- a/spec/features/dashboard/archived_projects_spec.rb +++ b/spec/features/dashboard/archived_projects_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe 'Dashboard Archived Project' do let(:user) { create :user } let(:project) { create :project} - let(:archived_project) { create(:empty_project, :archived) } + let(:archived_project) { create(:project, :archived) } before do project.team << [user, :master] diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb index 05dcdd93f37..b6dce1b8ec4 100644 --- a/spec/features/dashboard/datetime_on_tooltips_spec.rb +++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Tooltips on .timeago dates', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } let(:created_date) { Date.yesterday.to_time } let(:expected_format) { created_date.in_time_zone.strftime('%b %-d, %Y %l:%M%P') } diff --git a/spec/features/dashboard/issuables_counter_spec.rb b/spec/features/dashboard/issuables_counter_spec.rb index ae68b0f65d5..b431f72fcc9 100644 --- a/spec/features/dashboard/issuables_counter_spec.rb +++ b/spec/features/dashboard/issuables_counter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Navigation bar counter', :use_clean_rails_memory_store_caching do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project) } diff --git a/spec/features/dashboard/issues_filter_spec.rb b/spec/features/dashboard/issues_filter_spec.rb index 0ce642f32f2..facb67ae787 100644 --- a/spec/features/dashboard/issues_filter_spec.rb +++ b/spec/features/dashboard/issues_filter_spec.rb @@ -4,7 +4,7 @@ feature 'Dashboard Issues filtering', :js do include SortingHelper let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:milestone) { create(:milestone, project: project) } let!(:issue) { create(:issue, project: project, author: user, assignees: [user]) } diff --git a/spec/features/dashboard/issues_spec.rb b/spec/features/dashboard/issues_spec.rb index 82adde6258f..795335aa106 100644 --- a/spec/features/dashboard/issues_spec.rb +++ b/spec/features/dashboard/issues_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' RSpec.describe 'Dashboard Issues' do let(:current_user) { create :user } let(:user) { current_user } # Shared examples depend on this being available - let!(:public_project) { create(:empty_project, :public) } - let(:project) { create(:empty_project) } - let(:project_with_issues_disabled) { create(:empty_project, :issues_disabled) } + let!(:public_project) { create(:project, :public) } + let(:project) { create(:project) } + let(:project_with_issues_disabled) { create(:project, :issues_disabled) } let!(:authored_issue) { create :issue, author: current_user, project: project } let!(:authored_issue_on_public_project) { create :issue, author: current_user, project: public_project } let!(:assigned_issue) { create :issue, assignees: [current_user], project: project } @@ -79,12 +79,21 @@ RSpec.describe 'Dashboard Issues' do end end - it 'shows the new issue page', :js do + it 'shows the new issue page', js: true do find('.new-project-item-select-button').trigger('click') + wait_for_requests - find('.select2-results li').click - expect(page).to have_current_path("/#{project.path_with_namespace}/issues/new") + project_path = "/#{project.path_with_namespace}" + project_json = { name: project.name_with_namespace, url: project_path }.to_json + + # similate selection, and prevent overlap by dropdown menu + execute_script("$('.project-item-select').val('#{project_json}').trigger('change');") + execute_script("$('#select2-drop-mask').remove();") + + find('.new-project-item-link').trigger('click') + + expect(page).to have_current_path("#{project_path}/issues/new") page.within('#content-body') do expect(page).to have_selector('.issue-form') diff --git a/spec/features/dashboard/label_filter_spec.rb b/spec/features/dashboard/label_filter_spec.rb index 8e19fb93665..b1a207682c3 100644 --- a/spec/features/dashboard/label_filter_spec.rb +++ b/spec/features/dashboard/label_filter_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe 'Dashboard > label filter', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } - let(:project2) { create(:empty_project, name: 'test2', path: 'test2', namespace: user.namespace) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } + let(:project2) { create(:project, name: 'test2', path: 'test2', namespace: user.namespace) } let(:label) { create(:label, title: 'bug', color: '#ff0000') } let(:label2) { create(:label, title: 'bug') } diff --git a/spec/features/dashboard/merge_requests_spec.rb b/spec/features/dashboard/merge_requests_spec.rb index 42d6fadc0c1..b4992dd54a1 100644 --- a/spec/features/dashboard/merge_requests_spec.rb +++ b/spec/features/dashboard/merge_requests_spec.rb @@ -5,9 +5,9 @@ feature 'Dashboard Merge Requests' do include SortingHelper let(:current_user) { create :user } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } - let(:public_project) { create(:empty_project, :public, :repository) } + let(:public_project) { create(:project, :public, :repository) } let(:forked_project) { Projects::ForkService.new(public_project, current_user).execute } before do @@ -16,7 +16,7 @@ feature 'Dashboard Merge Requests' do end context 'new merge request dropdown' do - let(:project_with_disabled_merge_requests) { create(:empty_project, :merge_requests_disabled) } + let(:project_with_disabled_merge_requests) { create(:project, :merge_requests_disabled) } before do project_with_disabled_merge_requests.add_master(current_user) diff --git a/spec/features/dashboard/milestone_filter_spec.rb b/spec/features/dashboard/milestone_filter_spec.rb index 5ebef1eb097..c965b565ca3 100644 --- a/spec/features/dashboard/milestone_filter_spec.rb +++ b/spec/features/dashboard/milestone_filter_spec.rb @@ -4,7 +4,7 @@ feature 'Dashboard > milestone filter', :js do include FilterItemSelectHelper let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } let(:milestone) { create(:milestone, title: 'v1.0', project: project) } let(:milestone2) { create(:milestone, title: 'v2.0', project: project) } let!(:issue) { create :issue, author: user, project: project, milestone: milestone } diff --git a/spec/features/dashboard/milestone_tabs_spec.rb b/spec/features/dashboard/milestone_tabs_spec.rb index cf32d705365..6fcde35f541 100644 --- a/spec/features/dashboard/milestone_tabs_spec.rb +++ b/spec/features/dashboard/milestone_tabs_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Dashboard milestone tabs', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:label) { create(:label, project: project) } let(:project_milestone) { create(:milestone, project: project) } let(:milestone) do diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb index 488f7397c69..41d37376cfb 100644 --- a/spec/features/dashboard/milestones_spec.rb +++ b/spec/features/dashboard/milestones_spec.rb @@ -13,7 +13,7 @@ feature 'Dashboard > Milestones' do describe 'as logged-in user' do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let!(:milestone) { create(:milestone, project: project) } before do project.team << [user, :master] diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb index f3b538e490e..4a004107408 100644 --- a/spec/features/dashboard/project_member_activity_index_spec.rb +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Project member activity', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public, name: 'x', namespace: user.namespace) } + let(:project) { create(:project, :public, name: 'x', namespace: user.namespace) } before do project.team << [user, :master] diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index abb9e5eef96..06a43909053 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Dashboard Projects' do let(:user) { create(:user) } - let(:project) { create(:project, name: 'awesome stuff') } + let(:project) { create(:project, :repository, name: 'awesome stuff') } let(:project2) { create(:project, :public, name: 'Community project') } before do diff --git a/spec/features/dashboard/snippets_spec.rb b/spec/features/dashboard/snippets_spec.rb index c29bcc7c9e9..fb4263d74c4 100644 --- a/spec/features/dashboard/snippets_spec.rb +++ b/spec/features/dashboard/snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Dashboard snippets' do context 'when the project has snippets' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) } before do allow(Snippet).to receive(:default_per_page).and_return(1) diff --git a/spec/features/dashboard/todos/target_state_spec.rb b/spec/features/dashboard/todos/target_state_spec.rb index 93da36c08fc..030a86d1c01 100644 --- a/spec/features/dashboard/todos/target_state_spec.rb +++ b/spec/features/dashboard/todos/target_state_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' feature 'Dashboard > Todo target states' do let(:user) { create(:user) } let(:author) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } before do sign_in(user) diff --git a/spec/features/dashboard/todos/todos_filtering_spec.rb b/spec/features/dashboard/todos/todos_filtering_spec.rb index 0a363259fe7..54d477f7274 100644 --- a/spec/features/dashboard/todos/todos_filtering_spec.rb +++ b/spec/features/dashboard/todos/todos_filtering_spec.rb @@ -4,8 +4,8 @@ feature 'Dashboard > User filters todos', js: true do let(:user_1) { create(:user, username: 'user_1', name: 'user_1') } let(:user_2) { create(:user, username: 'user_2', name: 'user_2') } - let(:project_1) { create(:empty_project, name: 'project_1') } - let(:project_2) { create(:empty_project, name: 'project_2') } + let(:project_1) { create(:project, name: 'project_1') } + let(:project_2) { create(:project, name: 'project_2') } let(:issue) { create(:issue, title: 'issue', project: project_1) } diff --git a/spec/features/dashboard/todos/todos_sorting_spec.rb b/spec/features/dashboard/todos/todos_sorting_spec.rb index d49a78b290f..b7d39a872b0 100644 --- a/spec/features/dashboard/todos/todos_sorting_spec.rb +++ b/spec/features/dashboard/todos/todos_sorting_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Dashboard > User sorts todos' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) } let(:label_2) { create(:label, title: 'label_2', project: project, priority: 2) } diff --git a/spec/features/dashboard/todos/todos_spec.rb b/spec/features/dashboard/todos/todos_spec.rb index c2a61cf5aff..30bab7eeaa7 100644 --- a/spec/features/dashboard/todos/todos_spec.rb +++ b/spec/features/dashboard/todos/todos_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Dashboard Todos' do let(:user) { create(:user) } let(:author) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, due_date: Date.today) } context 'User does not have todos' do @@ -212,7 +212,7 @@ feature 'Dashboard Todos' do note1 = create(:note_on_issue, note: "Hello #{label1.to_reference(format: :name)}", noteable_id: issue.id, noteable_type: 'Issue', project: issue.project) create(:todo, :mentioned, project: project, target: issue, user: user, note_id: note1.id) - project2 = create(:empty_project, :public) + project2 = create(:project, :public) label2 = create(:label, project: project2) issue2 = create(:issue, project: project2) note2 = create(:note_on_issue, note: "Test #{label2.to_reference(format: :name)}", noteable_id: issue2.id, noteable_type: 'Issue', project: project2) diff --git a/spec/features/dashboard/user_filters_projects_spec.rb b/spec/features/dashboard/user_filters_projects_spec.rb index a88fe207e0e..c352b6ded14 100644 --- a/spec/features/dashboard/user_filters_projects_spec.rb +++ b/spec/features/dashboard/user_filters_projects_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' describe 'Dashboard > User filters projects' do let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'Victorialand', namespace: user.namespace) } + let(:project) { create(:project, name: 'Victorialand', namespace: user.namespace) } let(:user2) { create(:user) } - let(:project2) { create(:empty_project, name: 'Treasure', namespace: user2.namespace) } + let(:project2) { create(:project, name: 'Treasure', namespace: user2.namespace) } before do project.team << [user, :master] diff --git a/spec/features/discussion_comments/commit_spec.rb b/spec/features/discussion_comments/commit_spec.rb index fa83ad5d17c..0375d0bf8ff 100644 --- a/spec/features/discussion_comments/commit_spec.rb +++ b/spec/features/discussion_comments/commit_spec.rb @@ -4,7 +4,7 @@ describe 'Discussion Comments Merge Request', :js do include RepoHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } before do diff --git a/spec/features/discussion_comments/issue_spec.rb b/spec/features/discussion_comments/issue_spec.rb index f52ba9c4d09..9812eaf3420 100644 --- a/spec/features/discussion_comments/issue_spec.rb +++ b/spec/features/discussion_comments/issue_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Discussion Comments Issue', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } before do diff --git a/spec/features/discussion_comments/merge_request_spec.rb b/spec/features/discussion_comments/merge_request_spec.rb index 042f39f47e0..b0019c32189 100644 --- a/spec/features/discussion_comments/merge_request_spec.rb +++ b/spec/features/discussion_comments/merge_request_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Discussion Comments Merge Request', :js do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } before do diff --git a/spec/features/discussion_comments/snippets_spec.rb b/spec/features/discussion_comments/snippets_spec.rb index 50ba13499d9..1e6389d9a13 100644 --- a/spec/features/discussion_comments/snippets_spec.rb +++ b/spec/features/discussion_comments/snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Discussion Comments Issue', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:snippet) { create(:project_snippet, :private, project: project, author: user) } before do diff --git a/spec/features/explore/groups_list_spec.rb b/spec/features/explore/groups_list_spec.rb index 84f41eca999..b5325301968 100644 --- a/spec/features/explore/groups_list_spec.rb +++ b/spec/features/explore/groups_list_spec.rb @@ -5,7 +5,7 @@ describe 'Explore Groups page', :js do let!(:group) { create(:group) } let!(:public_group) { create(:group, :public) } let!(:private_group) { create(:group, :private) } - let!(:empty_project) { create(:empty_project, group: public_group) } + let!(:empty_project) { create(:project, group: public_group) } before do group.add_owner(user) diff --git a/spec/features/explore/new_menu_spec.rb b/spec/features/explore/new_menu_spec.rb index b1ccf80c28e..2cd06258e22 100644 --- a/spec/features/explore/new_menu_spec.rb +++ b/spec/features/explore/new_menu_spec.rb @@ -4,7 +4,7 @@ feature 'Top Plus Menu', :js do let(:user) { create(:user) } let(:group) { create(:group) } let(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } - let(:public_project) { create(:empty_project, :public) } + let(:public_project) { create(:project, :public) } before do group.add_owner(user) diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 300296a2b94..53b3bb3b65f 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe "GitLab Flavored Markdown" do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:fred) do create(:user, name: 'fred') do |user| diff --git a/spec/features/global_search_spec.rb b/spec/features/global_search_spec.rb index 627a930c997..f04e13adba7 100644 --- a/spec/features/global_search_spec.rb +++ b/spec/features/global_search_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Global search' do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } before do project.team << [user, :master] diff --git a/spec/features/groups/empty_states_spec.rb b/spec/features/groups/empty_states_spec.rb index e2c7907528b..243e8536168 100644 --- a/spec/features/groups/empty_states_spec.rb +++ b/spec/features/groups/empty_states_spec.rb @@ -9,7 +9,7 @@ feature 'Groups Merge Requests Empty States' do end context 'group has a project' do - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } before do project.add_master(user) @@ -38,7 +38,7 @@ feature 'Groups Merge Requests Empty States' do it 'should show a new merge request button' do within '.empty-state' do - expect(page).to have_content('New merge request') + expect(page).to have_content('create merge request') end end @@ -63,7 +63,7 @@ feature 'Groups Merge Requests Empty States' do it 'should not show a new merge request button' do within '.empty-state' do - expect(page).not_to have_link('New merge request') + expect(page).not_to have_link('create merge request') end end end diff --git a/spec/features/groups/group_settings_spec.rb b/spec/features/groups/group_settings_spec.rb index 121df1ec635..d0316cfb18d 100644 --- a/spec/features/groups/group_settings_spec.rb +++ b/spec/features/groups/group_settings_spec.rb @@ -49,7 +49,7 @@ feature 'Edit group settings' do end context 'with a project' do - given!(:project) { create(:empty_project, group: group) } + given!(:project) { create(:project, group: group) } given(:old_project_full_path) { "/#{group.path}/#{project.path}" } given(:new_project_full_path) { "/#{new_group_path}/#{project.path}" } @@ -57,7 +57,7 @@ feature 'Edit group settings' do TestEnv.clean_test_path end - after(:example) do + after do TestEnv.clean_test_path end diff --git a/spec/features/groups/issues_spec.rb b/spec/features/groups/issues_spec.rb index 449a99a2c7b..cdf7aceb13c 100644 --- a/spec/features/groups/issues_spec.rb +++ b/spec/features/groups/issues_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' feature 'Group issues page' do + include FilteredSearchHelpers + let(:path) { issues_group_path(group) } let(:issuable) { create(:issue, project: project, title: "this is my created issuable")} @@ -31,12 +33,10 @@ feature 'Group issues page' do let(:path) { issues_group_path(group) } it 'filters by only group users' do - click_button('Assignee') - - wait_for_requests + filtered_search.set('assignee:') - expect(find('.dropdown-menu-assignee')).to have_link(user.name) - expect(find('.dropdown-menu-assignee')).not_to have_link(user2.name) + expect(find('#js-dropdown-assignee .filter-dropdown')).to have_content(user.name) + expect(find('#js-dropdown-assignee .filter-dropdown')).not_to have_content(user2.name) end end end diff --git a/spec/features/groups/members/request_access_spec.rb b/spec/features/groups/members/request_access_spec.rb index 6141981023c..1f3c7fd3859 100644 --- a/spec/features/groups/members/request_access_spec.rb +++ b/spec/features/groups/members/request_access_spec.rb @@ -4,7 +4,7 @@ feature 'Groups > Members > Request access' do let(:user) { create(:user) } let(:owner) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } - let!(:project) { create(:empty_project, :private, namespace: group) } + let!(:project) { create(:project, :private, namespace: group) } background do group.add_owner(owner) diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index 574bbe0e0e1..32b3e13c624 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -5,14 +5,12 @@ feature 'Group milestones', :js do let!(:project) { create(:project_empty_repo, group: group) } let(:user) { create(:group_member, :master, user: create(:user), group: group ).user } - before do - Timecop.freeze - - sign_in(user) + around do |example| + Timecop.freeze { example.run } end - after do - Timecop.return + before do + sign_in(user) end context 'create a milestone' do diff --git a/spec/features/issuables/close_reopen_report_toggle_spec.rb b/spec/features/issuables/close_reopen_report_toggle_spec.rb index 0e43eed8699..3df77a104e8 100644 --- a/spec/features/issuables/close_reopen_report_toggle_spec.rb +++ b/spec/features/issuables/close_reopen_report_toggle_spec.rb @@ -42,7 +42,7 @@ describe 'Issuables Close/Reopen/Report toggle' do end context 'on an issue' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issuable) { create(:issue, project: project) } before do @@ -59,7 +59,7 @@ describe 'Issuables Close/Reopen/Report toggle' do end context 'when user doesnt have permission to update' do - let(:cant_project) { create(:empty_project) } + let(:cant_project) { create(:project) } let(:cant_issuable) { create(:issue, project: cant_project) } before do diff --git a/spec/features/issuables/default_sort_order_spec.rb b/spec/features/issuables/default_sort_order_spec.rb index 7c20c96528e..b72b690110f 100644 --- a/spec/features/issuables/default_sort_order_spec.rb +++ b/spec/features/issuables/default_sort_order_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Projects > Issuables > Default sort order' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:first_created_issuable) { issuables.order_created_asc.first } let(:last_created_issuable) { issuables.order_created_desc.first } diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 557de721222..2f45ef856a5 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe 'issuable list' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } issuable_types = [:issue, :merge_request] diff --git a/spec/features/issuables/markdown_references_spec.rb b/spec/features/issuables/markdown_references_spec.rb index 169381d703a..dd4e10a9886 100644 --- a/spec/features/issuables/markdown_references_spec.rb +++ b/spec/features/issuables/markdown_references_spec.rb @@ -2,10 +2,10 @@ require 'rails_helper' describe 'Markdown References', :js do let(:user) { create(:user) } - let(:actual_project) { create(:project, :public) } + let(:actual_project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, target_project: actual_project, source_project: actual_project)} let(:issue_actual_project) { create(:issue, project: actual_project) } - let!(:other_project) { create(:empty_project, :public) } + let!(:other_project) { create(:project, :public) } let!(:issue_other_project) { create(:issue, project: other_project) } let(:issues) { [issue_actual_project, issue_other_project] } diff --git a/spec/features/issues/award_emoji_spec.rb b/spec/features/issues/award_emoji_spec.rb index 6cb0bf6fdfd..134e618feac 100644 --- a/spec/features/issues/award_emoji_spec.rb +++ b/spec/features/issues/award_emoji_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe 'Awards Emoji' do - let!(:project) { create(:empty_project, :public) } + let!(:project) { create(:project, :public) } let!(:user) { create(:user) } let(:issue) do create(:issue, diff --git a/spec/features/issues/award_spec.rb b/spec/features/issues/award_spec.rb index 740281c1050..e95eb19f7d1 100644 --- a/spec/features/issues/award_spec.rb +++ b/spec/features/issues/award_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Issue awards', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } describe 'logged in' do diff --git a/spec/features/issues/bulk_assignment_labels_spec.rb b/spec/features/issues/bulk_assignment_labels_spec.rb index 5acf8fdae84..b2229b44f99 100644 --- a/spec/features/issues/bulk_assignment_labels_spec.rb +++ b/spec/features/issues/bulk_assignment_labels_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Issues > Labels bulk assignment' do let(:user) { create(:user) } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:issue1) { create(:issue, project: project, title: "Issue 1") } let!(:issue2) { create(:issue, project: project, title: "Issue 2") } let!(:bug) { create(:label, project: project, title: 'bug') } @@ -353,7 +353,7 @@ feature 'Issues > Labels bulk assignment' do context 'cannot bulk assign labels' do it do - expect(page).not_to have_button 'Edit Issues' + expect(page).not_to have_button 'Edit issues' expect(page).not_to have_css '.check-all-issues' expect(page).not_to have_css '.issue-check' end @@ -411,7 +411,7 @@ feature 'Issues > Labels bulk assignment' do def enable_bulk_update visit project_issues_path(project) - click_button 'Edit Issues' + click_button 'Edit issues' end def disable_bulk_update diff --git a/spec/features/issues/create_branch_merge_request_spec.rb b/spec/features/issues/create_branch_merge_request_spec.rb index f59f687cf51..546dc7e8a49 100644 --- a/spec/features/issues/create_branch_merge_request_spec.rb +++ b/spec/features/issues/create_branch_merge_request_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Create Branch/Merge Request Dropdown on issue page', js: true do +feature 'Create Branch/Merge Request Dropdown on issue page', :feature, :js do let(:user) { create(:user) } let!(:project) { create(:project, :repository) } let(:issue) { create(:issue, project: project, title: 'Cherry-Coloured Funk') } @@ -14,10 +14,14 @@ feature 'Create Branch/Merge Request Dropdown on issue page', js: true do it 'allows creating a merge request from the issue page' do visit project_issue_path(project, issue) - select_dropdown_option('create-mr') - - expect(page).to have_content('WIP: Resolve "Cherry-Coloured Funk"') - expect(current_path).to eq(project_merge_request_path(project, MergeRequest.first)) + perform_enqueued_jobs do + select_dropdown_option('create-mr') + + expect(page).to have_content('WIP: Resolve "Cherry-Coloured Funk"') + expect(current_path).to eq(project_merge_request_path(project, MergeRequest.first)) + + wait_for_requests + end visit project_issue_path(project, issue) diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb index a403d885de0..a69bd8a09b7 100644 --- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Dropdown assignee', :js do include FilteredSearchHelpers - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user, name: 'administrator', username: 'root') } let!(:user_john) { create(:user, name: 'John', username: 'th0mas') } let!(:user_jacob) { create(:user, name: 'Jacob', username: 'otter32') } diff --git a/spec/features/issues/filtered_search/dropdown_author_spec.rb b/spec/features/issues/filtered_search/dropdown_author_spec.rb index b7d9bbd7e1d..4bbf18e1dbe 100644 --- a/spec/features/issues/filtered_search/dropdown_author_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_author_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Dropdown author', js: true do include FilteredSearchHelpers - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user, name: 'administrator', username: 'root') } let!(:user_john) { create(:user, name: 'John', username: 'th0mas') } let!(:user_jacob) { create(:user, name: 'Jacob', username: 'otter32') } diff --git a/spec/features/issues/filtered_search/dropdown_hint_spec.rb b/spec/features/issues/filtered_search/dropdown_hint_spec.rb index 292fd683271..04d6dea4b8c 100644 --- a/spec/features/issues/filtered_search/dropdown_hint_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_hint_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Dropdown hint', :js do include FilteredSearchHelpers - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user) } let(:filtered_search) { find('.filtered-search') } let(:js_dropdown_hint) { '#js-dropdown-hint' } diff --git a/spec/features/issues/filtered_search/dropdown_label_spec.rb b/spec/features/issues/filtered_search/dropdown_label_spec.rb index e8f005d7752..67eb0ef0119 100644 --- a/spec/features/issues/filtered_search/dropdown_label_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_label_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Dropdown label', js: true do include FilteredSearchHelpers - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:filtered_search) { find('.filtered-search') } let(:js_dropdown_label) { '#js-dropdown-label' } diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb index ace73f4b1a6..456eb05f241 100644 --- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb +++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Dropdown milestone', :js do include FilteredSearchHelpers - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user) } let!(:milestone) { create(:milestone, title: 'v1.0', project: project) } let!(:uppercase_milestone) { create(:milestone, title: 'CAP_MILESTONE', project: project) } diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index 265bcb3a8e5..cd2cbf4bfe7 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -5,7 +5,7 @@ describe 'Filter issues', js: true do include FilteredSearchHelpers let!(:group) { create(:group) } - let!(:project) { create(:empty_project, group: group) } + let!(:project) { create(:project, group: group) } let!(:user) { create(:user, username: 'joe', name: 'Joe') } let!(:user2) { create(:user, username: 'jane') } let!(:label) { create(:label, project: project) } diff --git a/spec/features/issues/filtered_search/recent_searches_spec.rb b/spec/features/issues/filtered_search/recent_searches_spec.rb index 5842bb22beb..5eeecaeda47 100644 --- a/spec/features/issues/filtered_search/recent_searches_spec.rb +++ b/spec/features/issues/filtered_search/recent_searches_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe 'Recent searches', js: true do include FilteredSearchHelpers - let(:project_1) { create(:empty_project, :public) } - let(:project_2) { create(:empty_project, :public) } + let(:project_1) { create(:project, :public) } + let(:project_2) { create(:project, :public) } let(:project_1_local_storage_key) { "#{project_1.full_path}-issue-recent-searches" } before do diff --git a/spec/features/issues/filtered_search/search_bar_spec.rb b/spec/features/issues/filtered_search/search_bar_spec.rb index 115875d72ce..aa9d0d842de 100644 --- a/spec/features/issues/filtered_search/search_bar_spec.rb +++ b/spec/features/issues/filtered_search/search_bar_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Search bar', js: true do include FilteredSearchHelpers - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user) } let(:filtered_search) { find('.filtered-search') } diff --git a/spec/features/issues/filtered_search/visual_tokens_spec.rb b/spec/features/issues/filtered_search/visual_tokens_spec.rb index d00d0a9c81b..52efe944b69 100644 --- a/spec/features/issues/filtered_search/visual_tokens_spec.rb +++ b/spec/features/issues/filtered_search/visual_tokens_spec.rb @@ -4,7 +4,7 @@ describe 'Visual tokens', js: true do include FilteredSearchHelpers include WaitForRequests - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user, name: 'administrator', username: 'root') } let!(:user_rock) { create(:user, name: 'The Rock', username: 'rock') } let!(:milestone_nine) { create(:milestone, title: '9.0', project: project) } diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 0ba02ba42ba..4297bfff3d9 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -4,7 +4,7 @@ describe 'New/edit issue', :js do include ActionView::Helpers::JavaScriptHelper include FormHelper - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:user) { create(:user)} let!(:user2) { create(:user)} let!(:milestone) { create(:milestone, project: project) } @@ -276,7 +276,7 @@ describe 'New/edit issue', :js do describe 'sub-group project' do let(:group) { create(:group) } let(:nested_group_1) { create(:group, parent: group) } - let(:sub_group_project) { create(:empty_project, group: nested_group_1) } + let(:sub_group_project) { create(:project, group: nested_group_1) } before do sub_group_project.add_master(user) diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index 1b36f16e8b6..b84635c5134 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'GFM autocomplete', js: true do let(:user) { create(:user, name: '💃speciÄ…l someone💃', username: 'someone.special') } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:label) { create(:label, project: project, title: 'special+') } let(:issue) { create(:issue, project: project) } diff --git a/spec/features/issues/group_label_sidebar_spec.rb b/spec/features/issues/group_label_sidebar_spec.rb index a8ac1d605cb..9c10f78f67a 100644 --- a/spec/features/issues/group_label_sidebar_spec.rb +++ b/spec/features/issues/group_label_sidebar_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'Group label on issue' do it 'renders link to the project issues page' do group = create(:group) - project = create(:empty_project, :public, namespace: group) + project = create(:project, :public, namespace: group) feature = create(:group_label, group: group, title: 'feature') issue = create(:labeled_issue, project: project, labels: [feature]) label_link = project_issues_path(project, label_name: [feature.name]) diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index a7a7e02b59c..28b636f9359 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Issue Detail', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project, author: user) } context 'when user displays the issue' do diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb index 28f93cfd971..af11b474842 100644 --- a/spec/features/issues/issue_sidebar_spec.rb +++ b/spec/features/issues/issue_sidebar_spec.rb @@ -4,7 +4,7 @@ feature 'Issue Sidebar' do include MobileHelpers let(:group) { create(:group, :nested) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} let!(:label) { create(:label, project: project, title: 'bug') } @@ -130,8 +130,8 @@ feature 'Issue Sidebar' do it 'adds new label' do page.within('.block.labels') do fill_in 'new_label_name', with: 'wontfix' - page.find(".suggest-colors a", match: :first).click - click_button 'Create' + page.find('.suggest-colors a', match: :first).trigger('click') + page.find('button', text: 'Create').trigger('click') page.within('.dropdown-page-one') do expect(page).to have_content 'wontfix' @@ -142,8 +142,8 @@ feature 'Issue Sidebar' do it 'shows error message if label title is taken' do page.within('.block.labels') do fill_in 'new_label_name', with: label.title - page.find('.suggest-colors a', match: :first).click - click_button 'Create' + page.find('.suggest-colors a', match: :first).trigger('click') + page.find('button', text: 'Create').trigger('click') page.within('.dropdown-page-two') do expect(page).to have_content 'Title has already been taken' diff --git a/spec/features/issues/markdown_toolbar_spec.rb b/spec/features/issues/markdown_toolbar_spec.rb index 0f869970460..8c23fcd483b 100644 --- a/spec/features/issues/markdown_toolbar_spec.rb +++ b/spec/features/issues/markdown_toolbar_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' feature 'Issue markdown toolbar', js: true do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } diff --git a/spec/features/issues/move_spec.rb b/spec/features/issues/move_spec.rb index 2ab7d1a71b7..494c309c9ea 100644 --- a/spec/features/issues/move_spec.rb +++ b/spec/features/issues/move_spec.rb @@ -25,8 +25,8 @@ feature 'issue move to another project' do context 'user has permission to move issue' do let!(:mr) { create(:merge_request, source_project: old_project) } - let(:new_project) { create(:empty_project) } - let(:new_project_search) { create(:empty_project) } + let(:new_project) { create(:project) } + let(:new_project_search) { create(:project) } let(:text) { "Text with #{mr.to_reference}" } let(:cross_reference) { old_project.to_reference(new_project) } @@ -63,8 +63,8 @@ feature 'issue move to another project' do end context 'user does not have permission to move the issue to a project', js: true do - let!(:private_project) { create(:empty_project, :private) } - let(:another_project) { create(:empty_project) } + let!(:private_project) { create(:project, :private) } + let(:another_project) { create(:project) } background { another_project.team << [user, :guest] } scenario 'browsing projects in projects select' do diff --git a/spec/features/issues/note_polling_spec.rb b/spec/features/issues/note_polling_spec.rb index b524260750e..62dbc3efb01 100644 --- a/spec/features/issues/note_polling_spec.rb +++ b/spec/features/issues/note_polling_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Issue notes polling', :js do include NoteInteractionHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } describe 'creates' do @@ -133,8 +133,6 @@ feature 'Issue notes polling', :js do def click_edit_action(note) note_element = find("#note_#{note.id}") - open_more_actions_dropdown(note) - note_element.find('.js-note-edit').click end end diff --git a/spec/features/issues/notes_on_issues_spec.rb b/spec/features/issues/notes_on_issues_spec.rb index 29c9b99030a..05c93a19253 100644 --- a/spec/features/issues/notes_on_issues_spec.rb +++ b/spec/features/issues/notes_on_issues_spec.rb @@ -35,21 +35,21 @@ describe 'Create notes on issues', :js do context 'mentioning issue on a private project' do it_behaves_like 'notes with reference' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:mention) { create(:issue, project: project) } end end context 'mentioning issue on an internal project' do it_behaves_like 'notes with reference' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } let(:mention) { create(:issue, project: project) } end end context 'mentioning issue on a public project' do it_behaves_like 'notes with reference' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:mention) { create(:issue, project: project) } end end diff --git a/spec/features/issues/spam_issues_spec.rb b/spec/features/issues/spam_issues_spec.rb index 7a05e8b2ccc..332ce78b138 100644 --- a/spec/features/issues/spam_issues_spec.rb +++ b/spec/features/issues/spam_issues_spec.rb @@ -3,7 +3,7 @@ require 'rails_helper' describe 'New issue', js: true do include StubENV - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user)} before do diff --git a/spec/features/issues/todo_spec.rb b/spec/features/issues/todo_spec.rb index 2460ae817f9..8405f1cd48d 100644 --- a/spec/features/issues/todo_spec.rb +++ b/spec/features/issues/todo_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' feature 'Manually create a todo item from issue', js: true do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} diff --git a/spec/features/issues/update_issues_spec.rb b/spec/features/issues/update_issues_spec.rb index 389151e63f0..bcc6e9bab0f 100644 --- a/spec/features/issues/update_issues_spec.rb +++ b/spec/features/issues/update_issues_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' feature 'Multiple issue updating from issues#index', :js do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:issue) { create(:issue, project: project) } let!(:user) { create(:user)} @@ -14,7 +14,7 @@ feature 'Multiple issue updating from issues#index', :js do it 'sets to closed' do visit project_issues_path(project) - click_button 'Edit Issues' + click_button 'Edit issues' find('#check-all-issues').click find('.js-issue-status').click @@ -27,7 +27,7 @@ feature 'Multiple issue updating from issues#index', :js do create_closed visit project_issues_path(project, state: 'closed') - click_button 'Edit Issues' + click_button 'Edit issues' find('#check-all-issues').click find('.js-issue-status').click @@ -41,7 +41,7 @@ feature 'Multiple issue updating from issues#index', :js do it 'updates to current user' do visit project_issues_path(project) - click_button 'Edit Issues' + click_button 'Edit issues' find('#check-all-issues').click click_update_assignee_button @@ -57,7 +57,7 @@ feature 'Multiple issue updating from issues#index', :js do create_assigned visit project_issues_path(project) - click_button 'Edit Issues' + click_button 'Edit issues' find('#check-all-issues').click click_update_assignee_button @@ -73,7 +73,7 @@ feature 'Multiple issue updating from issues#index', :js do it 'updates milestone' do visit project_issues_path(project) - click_button 'Edit Issues' + click_button 'Edit issues' find('#check-all-issues').click find('.issues-bulk-update .js-milestone-select').click @@ -89,7 +89,7 @@ feature 'Multiple issue updating from issues#index', :js do expect(first('.issue')).to have_content milestone.title - click_button 'Edit Issues' + click_button 'Edit issues' find('#check-all-issues').click find('.issues-bulk-update .js-milestone-select').click diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index d28ad52ff56..4b63cc844f3 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -9,7 +9,7 @@ feature 'Issues > User uses quick actions', js: true do describe 'issue-only commands' do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } before do project.team << [user, :master] diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 722237481ea..3c8e37ff920 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -6,7 +6,7 @@ describe 'Issues' do include SortingHelper let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } before do sign_in(user) @@ -367,7 +367,7 @@ describe 'Issues' do end describe 'when I want to reset my incoming email token' do - let(:project1) { create(:empty_project, namespace: user.namespace) } + let(:project1) { create(:project, namespace: user.namespace) } let!(:issue) { create(:issue, project: project1) } before do @@ -706,4 +706,29 @@ describe 'Issues' do expect(page).to have_text("updated title") end end + + describe 'confidential issue#show', js: true do + it 'shows confidential sibebar information as confidential and can be turned off' do + issue = create(:issue, :confidential, project: project) + + visit project_issue_path(project, issue) + + expect(page).to have_css('.confidential-issue-warning') + expect(page).to have_css('.is-confidential') + expect(page).not_to have_css('.is-not-confidential') + + find('.confidential-edit').click + expect(page).to have_css('.confidential-warning-message') + + within('.confidential-warning-message') do + find('.btn-close').click + end + + wait_for_requests + + visit project_issue_path(project, issue) + + expect(page).not_to have_css('.is-confidential') + end + end end diff --git a/spec/features/merge_requests/closes_issues_spec.rb b/spec/features/merge_requests/closes_issues_spec.rb index 0e97254eada..299b4f5708a 100644 --- a/spec/features/merge_requests/closes_issues_spec.rb +++ b/spec/features/merge_requests/closes_issues_spec.rb @@ -26,17 +26,11 @@ feature 'Merge Request closing issues message', js: true do wait_for_requests end - context 'not closing or mentioning any issue' do - it 'does not display closing issue message' do - expect(page).not_to have_css('.mr-widget-footer') - end - end - context 'closing issues but not mentioning any other issue' do let(:merge_request_description) { "Description\n\nclosing #{issue_1.to_reference}, #{issue_2.to_reference}" } it 'does not display closing issue message' do - expect(page).to have_content("Closes issues #{issue_1.to_reference} and #{issue_2.to_reference}") + expect(page).to have_content("Closes #{issue_1.to_reference} and #{issue_2.to_reference}") end end @@ -44,7 +38,7 @@ feature 'Merge Request closing issues message', js: true do let(:merge_request_description) { "Description\n\nRefers to #{issue_1.to_reference} and #{issue_2.to_reference}" } it 'does not display closing issue message' do - expect(page).to have_content("Issues #{issue_1.to_reference} and #{issue_2.to_reference} are mentioned but will not be closed.") + expect(page).to have_content("Mentions #{issue_1.to_reference} and #{issue_2.to_reference}") end end @@ -52,8 +46,8 @@ feature 'Merge Request closing issues message', js: true do let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" } it 'does not display closing issue message' do - expect(page).to have_content("Closes issue #{issue_1.to_reference}.") - expect(page).to have_content("Issue #{issue_2.to_reference} is mentioned but will not be closed.") + expect(page).to have_content("Closes #{issue_1.to_reference}") + expect(page).to have_content("Mentions #{issue_2.to_reference}") end end @@ -61,7 +55,7 @@ feature 'Merge Request closing issues message', js: true do let(:merge_request_title) { "closing #{issue_1.to_reference}, #{issue_2.to_reference}" } it 'does not display closing issue message' do - expect(page).to have_content("Closes issues #{issue_1.to_reference} and #{issue_2.to_reference}") + expect(page).to have_content("Closes #{issue_1.to_reference} and #{issue_2.to_reference}") end end @@ -69,7 +63,7 @@ feature 'Merge Request closing issues message', js: true do let(:merge_request_title) { "Refers to #{issue_1.to_reference} and #{issue_2.to_reference}" } it 'does not display closing issue message' do - expect(page).to have_content("Issues #{issue_1.to_reference} and #{issue_2.to_reference} are mentioned but will not be closed.") + expect(page).to have_content("Mentions #{issue_1.to_reference} and #{issue_2.to_reference}") end end @@ -77,8 +71,8 @@ feature 'Merge Request closing issues message', js: true do let(:merge_request_title) { "closes #{issue_1.to_reference}\n\n refers to #{issue_2.to_reference}" } it 'does not display closing issue message' do - expect(page).to have_content("Closes issue #{issue_1.to_reference}. Issue #{issue_2.to_reference} is mentioned but will not be closed.") - expect(page).to have_content("Issue #{issue_2.to_reference} is mentioned but will not be closed.") + expect(page).to have_content("Closes #{issue_1.to_reference}") + expect(page).to have_content("Mentions #{issue_2.to_reference}") end end end diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb index 11a74276898..d7f3d91e625 100644 --- a/spec/features/merge_requests/create_new_mr_spec.rb +++ b/spec/features/merge_requests/create_new_mr_spec.rb @@ -67,8 +67,8 @@ feature 'Create New Merge Request', js: true do visit project_new_merge_request_path(project, merge_request: { target_project_id: private_project.id }) - expect(page).not_to have_content private_project.path_with_namespace - expect(page).to have_content project.path_with_namespace + expect(page).not_to have_content private_project.full_path + expect(page).to have_content project.full_path end end @@ -78,8 +78,8 @@ feature 'Create New Merge Request', js: true do visit project_new_merge_request_path(project, merge_request: { source_project_id: private_project.id }) - expect(page).not_to have_content private_project.path_with_namespace - expect(page).to have_content project.path_with_namespace + expect(page).not_to have_content private_project.full_path + expect(page).to have_content project.full_path end end diff --git a/spec/features/merge_requests/diff_notes_avatars_spec.rb b/spec/features/merge_requests/diff_notes_avatars_spec.rb index 2d9419d6124..c4f02311f13 100644 --- a/spec/features/merge_requests/diff_notes_avatars_spec.rb +++ b/spec/features/merge_requests/diff_notes_avatars_spec.rb @@ -157,7 +157,7 @@ feature 'Diff note avatars', js: true do end page.within find("[id='#{position.line_code(project.repository)}']") do - find('.diff-notes-collapse').click + find('.diff-notes-collapse').trigger('click') expect(page).to have_selector('img.js-diff-comment-avatar', count: 3) expect(find('.diff-comments-more-count')).to have_content '+1' diff --git a/spec/features/merge_requests/diffs_spec.rb b/spec/features/merge_requests/diffs_spec.rb index 201be4b9e40..a8f5dc275e4 100644 --- a/spec/features/merge_requests/diffs_spec.rb +++ b/spec/features/merge_requests/diffs_spec.rb @@ -5,7 +5,7 @@ feature 'Diffs URL', js: true do let(:merge_request) { create(:merge_request, source_project: project) } context 'when visit with */* as accept header' do - before(:each) do + before do page.driver.add_header('Accept', '*/*') end diff --git a/spec/features/merge_requests/discussion_spec.rb b/spec/features/merge_requests/discussion_spec.rb index d1cc43e0690..05789bbd31d 100644 --- a/spec/features/merge_requests/discussion_spec.rb +++ b/spec/features/merge_requests/discussion_spec.rb @@ -26,7 +26,7 @@ feature 'Merge Request Discussions' do let(:outdated_diff_refs) { project.commit("874797c3a73b60d2187ed6e2fcabd289ff75171e").diff_refs } - before(:each) do + before do visit project_merge_request_path(project, merge_request) end @@ -71,7 +71,7 @@ feature 'Merge Request Discussions' do end end - before(:each) do + before do visit project_merge_request_path(project, merge_request) end diff --git a/spec/features/merge_requests/filter_by_labels_spec.rb b/spec/features/merge_requests/filter_by_labels_spec.rb index 1d52a4659ad..9912e8165e6 100644 --- a/spec/features/merge_requests/filter_by_labels_spec.rb +++ b/spec/features/merge_requests/filter_by_labels_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Merge Request filtering by Labels', js: true do +feature 'Merge Request filtering by Labels', :js do include FilteredSearchHelpers include MergeRequestHelpers @@ -12,9 +12,9 @@ feature 'Merge Request filtering by Labels', js: true do let!(:feature) { create(:label, project: project, title: 'feature') } let!(:enhancement) { create(:label, project: project, title: 'enhancement') } - let!(:mr1) { create(:merge_request, title: "Bugfix1", source_project: project, target_project: project, source_branch: "bugfix1") } - let!(:mr2) { create(:merge_request, title: "Bugfix2", source_project: project, target_project: project, source_branch: "bugfix2") } - let!(:mr3) { create(:merge_request, title: "Feature1", source_project: project, target_project: project, source_branch: "feature1") } + let!(:mr1) { create(:merge_request, title: "Bugfix1", source_project: project, target_project: project, source_branch: "fix") } + let!(:mr2) { create(:merge_request, title: "Bugfix2", source_project: project, target_project: project, source_branch: "wip") } + let!(:mr3) { create(:merge_request, title: "Feature1", source_project: project, target_project: project, source_branch: "improve/awesome") } before do mr1.labels << bug @@ -25,7 +25,7 @@ feature 'Merge Request filtering by Labels', js: true do mr3.title = "Feature1" mr3.labels << feature - project.team << [user, :master] + project.add_master(user) sign_in(user) visit project_merge_requests_path(project) diff --git a/spec/features/merge_requests/filter_merge_requests_spec.rb b/spec/features/merge_requests/filter_merge_requests_spec.rb index f0019be86ad..3686131fee4 100644 --- a/spec/features/merge_requests/filter_merge_requests_spec.rb +++ b/spec/features/merge_requests/filter_merge_requests_spec.rb @@ -12,7 +12,7 @@ describe 'Filter merge requests' do let!(:wontfix) { create(:label, project: project, title: "Won't fix") } before do - project.team << [user, :master] + project.add_master(user) group.add_developer(user) sign_in(user) create(:merge_request, source_project: project, target_project: project) @@ -170,7 +170,7 @@ describe 'Filter merge requests' do describe 'filter merge requests by text' do before do - create(:merge_request, title: "Bug", source_project: project, target_project: project, source_branch: "bug") + create(:merge_request, title: "Bug", source_project: project, target_project: project, source_branch: "wip") bug_label = create(:label, project: project, title: 'bug') milestone = create(:milestone, title: "8", project: project) @@ -179,7 +179,7 @@ describe 'Filter merge requests' do title: "Bug 2", source_project: project, target_project: project, - source_branch: "bug2", + source_branch: "fix", milestone: milestone, author: user, assignee: user) @@ -259,12 +259,12 @@ describe 'Filter merge requests' do end end - describe 'filter merge requests and sort', js: true do + describe 'filter merge requests and sort', :js do before do bug_label = create(:label, project: project, title: 'bug') - mr1 = create(:merge_request, title: "Frontend", source_project: project, target_project: project, source_branch: "Frontend") - mr2 = create(:merge_request, title: "Bug 2", source_project: project, target_project: project, source_branch: "bug2") + mr1 = create(:merge_request, title: "Frontend", source_project: project, target_project: project, source_branch: "wip") + mr2 = create(:merge_request, title: "Bug 2", source_project: project, target_project: project, source_branch: "fix") mr1.labels << bug_label mr2.labels << bug_label diff --git a/spec/features/merge_requests/form_spec.rb b/spec/features/merge_requests/form_spec.rb index 6ffb05c5030..89410b0e90f 100644 --- a/spec/features/merge_requests/form_spec.rb +++ b/spec/features/merge_requests/form_spec.rb @@ -41,7 +41,7 @@ describe 'New/edit merge request', :js do expect(page).to have_content user2.name end - click_link 'Assign to me' + find('a', text: 'Assign to me').trigger('click') expect(find('input[name="merge_request[assignee_id]"]', visible: false).value).to match(user.id.to_s) page.within '.js-assignee-search' do expect(page).to have_content user.name diff --git a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb index 574f5fe353e..ac46cc1f0e4 100644 --- a/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb +++ b/spec/features/merge_requests/merge_when_pipeline_succeeds_spec.rb @@ -41,8 +41,8 @@ feature 'Merge When Pipeline Succeeds', :js do it 'activates the Merge when pipeline succeeds feature' do click_button "Merge when pipeline succeeds" - expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds." - expect(page).to have_content "The source branch will not be removed." + expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds" + expect(page).to have_content "The source branch will not be removed" expect(page).to have_selector ".js-cancel-auto-merge" visit_merge_request(merge_request) # Needed to refresh the page expect(page).to have_content /enabled an automatic merge when the pipeline for \h{8} succeeds/i @@ -97,11 +97,11 @@ feature 'Merge When Pipeline Succeeds', :js do describe 'enabling Merge when pipeline succeeds via dropdown' do it 'activates the Merge when pipeline succeeds feature' do - click_button 'Select merge moment' + find('.js-merge-moment').click click_link 'Merge when pipeline succeeds' - expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds." - expect(page).to have_content "The source branch will not be removed." + expect(page).to have_content "Set by #{user.name} to be merged automatically when the pipeline succeeds" + expect(page).to have_content "The source branch will not be removed" expect(page).to have_link "Cancel automatic merge" end end diff --git a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb index 5c6eec44ff7..59e67420333 100644 --- a/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb +++ b/spec/features/merge_requests/only_allow_merge_if_build_succeeds_spec.rb @@ -43,7 +43,7 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', js: t wait_for_requests expect(page).to have_button 'Merge when pipeline succeeds' - expect(page).not_to have_button 'Select merge moment' + expect(page).not_to have_button '.js-merge-moment' end end @@ -56,7 +56,7 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', js: t wait_for_requests expect(page).to have_css('button[disabled="disabled"]', text: 'Merge') - expect(page).to have_content('Please retry the job or push a new commit to fix the failure.') + expect(page).to have_content('Please retry the job or push a new commit to fix the failure') end end @@ -69,7 +69,7 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', js: t wait_for_requests expect(page).not_to have_button 'Merge' - expect(page).to have_content('Please retry the job or push a new commit to fix the failure.') + expect(page).to have_content('Please retry the job or push a new commit to fix the failure') end end @@ -113,7 +113,7 @@ feature 'Only allow merge requests to be merged if the pipeline succeeds', js: t expect(page).to have_button 'Merge when pipeline succeeds' - click_button 'Select merge moment' + page.find('.js-merge-moment').click expect(page).to have_content 'Merge immediately' end end diff --git a/spec/features/merge_requests/pipelines_spec.rb b/spec/features/merge_requests/pipelines_spec.rb index b3d6cf8deb4..347ce788b36 100644 --- a/spec/features/merge_requests/pipelines_spec.rb +++ b/spec/features/merge_requests/pipelines_spec.rb @@ -1,45 +1,88 @@ require 'spec_helper' feature 'Pipelines for Merge Requests', js: true do - given(:user) { create(:user) } - given(:merge_request) { create(:merge_request) } - given(:project) { merge_request.target_project } + describe 'pipeline tab' do + given(:user) { create(:user) } + given(:merge_request) { create(:merge_request) } + given(:project) { merge_request.target_project } - before do - project.team << [user, :master] - sign_in user - end - - context 'with pipelines' do - let!(:pipeline) do - create(:ci_empty_pipeline, - project: merge_request.source_project, - ref: merge_request.source_branch, - sha: merge_request.diff_head_sha) + before do + project.team << [user, :master] + sign_in user end - before do - visit project_merge_request_path(project, merge_request) + context 'with pipelines' do + let!(:pipeline) do + create(:ci_empty_pipeline, + project: merge_request.source_project, + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha) + end + + before do + visit project_merge_request_path(project, merge_request) + end + + scenario 'user visits merge request pipelines tab' do + page.within('.merge-request-tabs') do + click_link('Pipelines') + end + wait_for_requests + + expect(page).to have_selector('.stage-cell') + end end - scenario 'user visits merge request pipelines tab' do - page.within('.merge-request-tabs') do - click_link('Pipelines') + context 'without pipelines' do + before do + visit project_merge_request_path(project, merge_request) end - wait_for_requests - expect(page).to have_selector('.stage-cell') + scenario 'user visits merge request page' do + page.within('.merge-request-tabs') do + expect(page).to have_no_link('Pipelines') + end + end end end - context 'without pipelines' do - before do - visit project_merge_request_path(project, merge_request) + describe 'race condition' do + given(:project) { create(:project, :repository) } + given(:user) { create(:user) } + given(:build_push_data) { { ref: 'feature', checkout_sha: TestEnv::BRANCH_SHA['feature'] } } + + given(:merge_request_params) do + { "source_branch" => "feature", "source_project_id" => project.id, + "target_branch" => "master", "target_project_id" => project.id, "title" => "A" } + end + + background do + project.add_master(user) + sign_in user end - scenario 'user visits merge request page' do - page.within('.merge-request-tabs') do - expect(page).to have_no_link('Pipelines') + context 'when pipeline and merge request were created simultaneously' do + background do + stub_ci_pipeline_to_return_yaml_file + + threads = [] + + threads << Thread.new do + @merge_request = MergeRequests::CreateService.new(project, user, merge_request_params).execute + end + + threads << Thread.new do + @pipeline = Ci::CreatePipelineService.new(project, user, build_push_data).execute(:push) + end + + threads.each { |thr| thr.join } + end + + scenario 'user sees pipeline in merge request widget' do + visit project_merge_request_path(project, @merge_request) + + expect(page.find(".ci-widget")).to have_content(TestEnv::BRANCH_SHA['feature']) + expect(page.find(".ci-widget")).to have_content("##{@pipeline.id}") end end end diff --git a/spec/features/merge_requests/reset_filters_spec.rb b/spec/features/merge_requests/reset_filters_spec.rb index c1b90e5f875..eed95816bdf 100644 --- a/spec/features/merge_requests/reset_filters_spec.rb +++ b/spec/features/merge_requests/reset_filters_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -feature 'Merge requests filter clear button', js: true do +feature 'Merge requests filter clear button', :js do include FilteredSearchHelpers include MergeRequestHelpers include IssueHelpers @@ -9,8 +9,8 @@ feature 'Merge requests filter clear button', js: true do let!(:user) { create(:user) } let!(:milestone) { create(:milestone, project: project) } let!(:bug) { create(:label, project: project, name: 'bug')} - let!(:mr1) { create(:merge_request, title: "Feature", source_project: project, target_project: project, source_branch: "Feature", milestone: milestone, author: user, assignee: user) } - let!(:mr2) { create(:merge_request, title: "Bugfix1", source_project: project, target_project: project, source_branch: "Bugfix1") } + let!(:mr1) { create(:merge_request, title: "Feature", source_project: project, target_project: project, source_branch: "improve/awesome", milestone: milestone, author: user, assignee: user) } + let!(:mr2) { create(:merge_request, title: "Bugfix1", source_project: project, target_project: project, source_branch: "fix") } let(:merge_request_css) { '.merge-request' } let(:clear_search_css) { '.filtered-search-box .clear-search' } diff --git a/spec/features/merge_requests/update_merge_requests_spec.rb b/spec/features/merge_requests/update_merge_requests_spec.rb index cf30a687df8..e6dc284cba7 100644 --- a/spec/features/merge_requests/update_merge_requests_spec.rb +++ b/spec/features/merge_requests/update_merge_requests_spec.rb @@ -98,7 +98,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do end def change_status(text) - click_button 'Edit Merge Requests' + click_button 'Edit merge requests' find('#check-all-issues').click find('.js-issue-status').click find('.dropdown-menu-status a', text: text).click @@ -106,7 +106,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do end def change_assignee(text) - click_button 'Edit Merge Requests' + click_button 'Edit merge requests' find('#check-all-issues').click find('.js-update-assignee').click wait_for_requests @@ -119,7 +119,7 @@ feature 'Multiple merge requests updating from merge_requests#index' do end def change_milestone(text) - click_button 'Edit Merge Requests' + click_button 'Edit merge requests' find('#check-all-issues').click find('.issues-bulk-update .js-milestone-select').click find('.dropdown-menu-milestone a', text: text).click diff --git a/spec/features/merge_requests/user_lists_merge_requests_spec.rb b/spec/features/merge_requests/user_lists_merge_requests_spec.rb index d62b035b40b..20008b4e7f9 100644 --- a/spec/features/merge_requests/user_lists_merge_requests_spec.rb +++ b/spec/features/merge_requests/user_lists_merge_requests_spec.rb @@ -24,12 +24,10 @@ describe 'Projects > Merge requests > User lists merge requests' do milestone: create(:milestone, due_date: '2013-12-12'), created_at: 2.minutes.ago, updated_at: 2.minutes.ago) - # lfs in itself is not a great choice for the title if one wants to match the whole body content later on - # just think about the scenario when faker generates 'Chester Runolfsson' as the user's name create(:merge_request, - title: 'merge_lfs', + title: 'merge-test', source_project: project, - source_branch: 'merge_lfs', + source_branch: 'merge-test', created_at: 3.minutes.ago, updated_at: 10.seconds.ago) end @@ -38,7 +36,7 @@ describe 'Projects > Merge requests > User lists merge requests' do visit_merge_requests(project, assignee_id: IssuableFinder::NONE) expect(current_path).to eq(project_merge_requests_path(project)) - expect(page).to have_content 'merge_lfs' + expect(page).to have_content 'merge-test' expect(page).not_to have_content 'fix' expect(page).not_to have_content 'markdown' expect(count_merge_requests).to eq(1) @@ -47,7 +45,7 @@ describe 'Projects > Merge requests > User lists merge requests' do it 'filters on a specific assignee' do visit_merge_requests(project, assignee_id: user.id) - expect(page).not_to have_content 'merge_lfs' + expect(page).not_to have_content 'merge-test' expect(page).to have_content 'fix' expect(page).to have_content 'markdown' expect(count_merge_requests).to eq(2) @@ -57,14 +55,14 @@ describe 'Projects > Merge requests > User lists merge requests' do visit_merge_requests(project, sort: sort_value_recently_created) expect(first_merge_request).to include('fix') - expect(last_merge_request).to include('merge_lfs') + expect(last_merge_request).to include('merge-test') expect(count_merge_requests).to eq(3) end it 'sorts by oldest' do visit_merge_requests(project, sort: sort_value_oldest_created) - expect(first_merge_request).to include('merge_lfs') + expect(first_merge_request).to include('merge-test') expect(last_merge_request).to include('fix') expect(count_merge_requests).to eq(3) end @@ -72,7 +70,7 @@ describe 'Projects > Merge requests > User lists merge requests' do it 'sorts by last updated' do visit_merge_requests(project, sort: sort_value_recently_updated) - expect(first_merge_request).to include('merge_lfs') + expect(first_merge_request).to include('merge-test') expect(count_merge_requests).to eq(3) end diff --git a/spec/features/merge_requests/user_posts_diff_notes_spec.rb b/spec/features/merge_requests/user_posts_diff_notes_spec.rb index 1cfd78663e5..f89dd38e5cd 100644 --- a/spec/features/merge_requests/user_posts_diff_notes_spec.rb +++ b/spec/features/merge_requests/user_posts_diff_notes_spec.rb @@ -71,7 +71,7 @@ feature 'Merge requests > User posts diff notes', :js do end context 'with an unfolded line' do - before(:each) do + before do find('.js-unfold', match: :first).click wait_for_requests end @@ -120,7 +120,7 @@ feature 'Merge requests > User posts diff notes', :js do end context 'with an unfolded line' do - before(:each) do + before do find('.js-unfold', match: :first).click wait_for_requests end diff --git a/spec/features/merge_requests/user_posts_notes_spec.rb b/spec/features/merge_requests/user_posts_notes_spec.rb index 74d21822a59..d7cda73ab40 100644 --- a/spec/features/merge_requests/user_posts_notes_spec.rb +++ b/spec/features/merge_requests/user_posts_notes_spec.rb @@ -75,7 +75,6 @@ describe 'Merge requests > User posts notes', :js do describe 'editing the note' do before do find('.note').hover - open_more_actions_dropdown(note) find('.js-note-edit').click end @@ -104,7 +103,6 @@ describe 'Merge requests > User posts notes', :js do wait_for_requests find('.note').hover - open_more_actions_dropdown(note) find('.js-note-edit').click @@ -132,7 +130,6 @@ describe 'Merge requests > User posts notes', :js do describe 'deleting an attachment' do before do find('.note').hover - open_more_actions_dropdown(note) find('.js-note-edit').click end diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb index 43cab65d287..95c50df1896 100644 --- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb @@ -3,17 +3,17 @@ require 'rails_helper' feature 'Merge Requests > User uses quick actions', js: true do include QuickActionsHelpers - let(:user) { create(:user) } - let(:project) { create(:project, :public, :repository) } - let(:merge_request) { create(:merge_request, source_project: project) } - let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } - it_behaves_like 'issuable record that supports quick actions in its description and notes', :merge_request do let(:issuable) { create(:merge_request, source_project: project) } let(:new_url_opts) { { merge_request: { source_branch: 'feature', target_branch: 'master' } } } end describe 'merge-request-only commands' do + let(:user) { create(:user) } + let(:project) { create(:project, :public, :repository) } + let(:merge_request) { create(:merge_request, source_project: project) } + let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } + before do project.team << [user, :master] sign_in(user) diff --git a/spec/features/merge_requests/widget_spec.rb b/spec/features/merge_requests/widget_spec.rb index 69e31c7481f..fd991293ee9 100644 --- a/spec/features/merge_requests/widget_spec.rb +++ b/spec/features/merge_requests/widget_spec.rb @@ -219,4 +219,17 @@ describe 'Merge request', :js do expect(page).to have_field('remove-source-branch-input', disabled: true) end end + + context 'ongoing merge process' do + it 'shows Merging state' do + allow_any_instance_of(MergeRequest).to receive(:merge_ongoing?).and_return(true) + + visit project_merge_request_path(project, merge_request) + + wait_for_requests + + expect(page).not_to have_button('Merge') + expect(page).to have_content('This merge request is in the process of being merged') + end + end end diff --git a/spec/features/milestone_spec.rb b/spec/features/milestone_spec.rb index 1d05184d6fc..6c9dc67ad74 100644 --- a/spec/features/milestone_spec.rb +++ b/spec/features/milestone_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Milestone' do let(:group) { create(:group, :public) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:user) { create(:user) } before do diff --git a/spec/features/milestones/show_spec.rb b/spec/features/milestones/show_spec.rb index 199a5ba83b3..20303359c46 100644 --- a/spec/features/milestones/show_spec.rb +++ b/spec/features/milestones/show_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe 'Milestone show' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:milestone) { create(:milestone, project: project) } let(:labels) { create_list(:label, 2, project: project) } let(:issue_params) { { project: project, assignees: [user], author: user, milestone: milestone, labels: labels } } diff --git a/spec/features/participants_autocomplete_spec.rb b/spec/features/participants_autocomplete_spec.rb index 81b0a2f541b..a22d548eef3 100644 --- a/spec/features/participants_autocomplete_spec.rb +++ b/spec/features/participants_autocomplete_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Member autocomplete', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:author) { create(:user) } let(:note) { create(:note, noteable: noteable, project: noteable.project) } diff --git a/spec/features/password_reset_spec.rb b/spec/features/password_reset_spec.rb index 5e1e7dc078f..b45972b7f6b 100644 --- a/spec/features/password_reset_spec.rb +++ b/spec/features/password_reset_spec.rb @@ -16,7 +16,7 @@ feature 'Password reset' do user.send_reset_password_instructions user.update_attribute(:reset_password_sent_at, 5.minutes.ago) - expect{ forgot_password(user) }.to change{ user.reset_password_sent_at } + expect { forgot_password(user) }.to change { user.reset_password_sent_at } expect(page).to have_content(I18n.t('devise.passwords.send_paranoid_instructions')) expect(current_path).to eq new_user_session_path end @@ -27,7 +27,7 @@ feature 'Password reset' do # Reload because PG handles datetime less precisely than Ruby/Rails user.reload - expect{ forgot_password(user) }.not_to change{ user.reset_password_sent_at } + expect { forgot_password(user) }.not_to change { user.reset_password_sent_at } expect(page).to have_content(I18n.t('devise.passwords.send_paranoid_instructions')) expect(current_path).to eq new_user_session_path end diff --git a/spec/features/profiles/account_spec.rb b/spec/features/profiles/account_spec.rb index 56c1f7ae9c7..dcd0449dbcb 100644 --- a/spec/features/profiles/account_spec.rb +++ b/spec/features/profiles/account_spec.rb @@ -27,7 +27,7 @@ feature 'Profile > Account' do end context 'with a project' do - given!(:project) { create(:empty_project, namespace: user.namespace) } + given!(:project) { create(:project, namespace: user.namespace) } given(:new_project_path) { "/#{new_username}/#{project.path}" } given(:old_project_path) { "/#{user.username}/#{project.path}" } @@ -35,7 +35,7 @@ feature 'Profile > Account' do TestEnv.clean_test_path end - after(:example) do + after do TestEnv.clean_test_path end diff --git a/spec/features/profiles/preferences_spec.rb b/spec/features/profiles/preferences_spec.rb index 9123aa9d155..c935cdfd5c4 100644 --- a/spec/features/profiles/preferences_spec.rb +++ b/spec/features/profiles/preferences_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe 'Profile > Preferences' do +describe 'Profile > Preferences', :js do let(:user) { create(:user) } before do @@ -8,28 +8,32 @@ describe 'Profile > Preferences' do visit profile_preferences_path end - describe 'User changes their syntax highlighting theme', js: true do + describe 'User changes their syntax highlighting theme' do it 'creates a flash message' do choose 'user_color_scheme_id_5' + wait_for_requests + expect_preferences_saved_message end it 'updates their preference' do choose 'user_color_scheme_id_5' - allowing_for_delay do - visit page.current_path - expect(page).to have_checked_field('user_color_scheme_id_5') - end + wait_for_requests + refresh + + expect(page).to have_checked_field('user_color_scheme_id_5') end end - describe 'User changes their default dashboard', js: true do + describe 'User changes their default dashboard' do it 'creates a flash message' do select 'Starred Projects', from: 'user_dashboard' click_button 'Save' + wait_for_requests + expect_preferences_saved_message end @@ -37,12 +41,12 @@ describe 'Profile > Preferences' do select 'Starred Projects', from: 'user_dashboard' click_button 'Save' - allowing_for_delay do - find('#logo').click + wait_for_requests + + find('#logo').click - expect(page).to have_content("You don't have starred projects yet") - expect(page.current_path).to eq starred_dashboard_projects_path - end + expect(page).to have_content("You don't have starred projects yet") + expect(page.current_path).to eq starred_dashboard_projects_path find('.shortcuts-activity').trigger('click') diff --git a/spec/features/profiles/user_visits_notifications_tab_spec.rb b/spec/features/profiles/user_visits_notifications_tab_spec.rb index e98cec79d87..48c1787c8b7 100644 --- a/spec/features/profiles/user_visits_notifications_tab_spec.rb +++ b/spec/features/profiles/user_visits_notifications_tab_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'User visits the notifications tab', js: true do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/features/projects/activity/rss_spec.rb b/spec/features/projects/activity/rss_spec.rb index b054f543dc6..84c2faa2015 100644 --- a/spec/features/projects/activity/rss_spec.rb +++ b/spec/features/projects/activity/rss_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Project Activity RSS' do let(:user) { create(:user) } - let(:project) { create(:empty_project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let(:path) { activity_project_path(project) } before do diff --git a/spec/features/projects/artifacts/browse_spec.rb b/spec/features/projects/artifacts/browse_spec.rb index f5f7eba8e40..42b47cb3301 100644 --- a/spec/features/projects/artifacts/browse_spec.rb +++ b/spec/features/projects/artifacts/browse_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Browse artifact', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } diff --git a/spec/features/projects/artifacts/download_spec.rb b/spec/features/projects/artifacts/download_spec.rb index c1bba8c15c4..f1bdb2812c6 100644 --- a/spec/features/projects/artifacts/download_spec.rb +++ b/spec/features/projects/artifacts/download_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Download artifact', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, status: :success, project: project) } let(:job) { create(:ci_build, :artifacts, :success, pipeline: pipeline) } diff --git a/spec/features/projects/artifacts/file_spec.rb b/spec/features/projects/artifacts/file_spec.rb index 4c268b876ea..b2be10a7e0c 100644 --- a/spec/features/projects/artifacts/file_spec.rb +++ b/spec/features/projects/artifacts/file_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Artifact file', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:build) { create(:ci_build, :artifacts, pipeline: pipeline) } diff --git a/spec/features/projects/artifacts/raw_spec.rb b/spec/features/projects/artifacts/raw_spec.rb index 128e39e7803..0bec6e9ad31 100644 --- a/spec/features/projects/artifacts/raw_spec.rb +++ b/spec/features/projects/artifacts/raw_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Raw artifact', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:job) { create(:ci_build, :artifacts, pipeline: pipeline) } diff --git a/spec/features/projects/badges/coverage_spec.rb b/spec/features/projects/badges/coverage_spec.rb index 8cf4bfbf978..368a046f741 100644 --- a/spec/features/projects/badges/coverage_spec.rb +++ b/spec/features/projects/badges/coverage_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'test coverage badge' do given!(:user) { create(:user) } - given!(:project) { create(:empty_project, :private) } + given!(:project) { create(:project, :private) } context 'when user has access to view badge' do background do diff --git a/spec/features/projects/blobs/edit_spec.rb b/spec/features/projects/blobs/edit_spec.rb index 9855cfd85c4..62ac9fd0e95 100644 --- a/spec/features/projects/blobs/edit_spec.rb +++ b/spec/features/projects/blobs/edit_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Editing file blob', js: true do include TreeHelper - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:merge_request) { create(:merge_request, source_project: project, source_branch: 'feature', target_branch: 'master') } let(:branch) { 'master' } let(:file_path) { project.repository.ls_files(project.repository.root_ref)[1] } diff --git a/spec/features/projects/developer_views_empty_project_instructions_spec.rb b/spec/features/projects/developer_views_empty_project_instructions_spec.rb index 7145e286229..fe8567ce348 100644 --- a/spec/features/projects/developer_views_empty_project_instructions_spec.rb +++ b/spec/features/projects/developer_views_empty_project_instructions_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' feature 'Developer views empty project instructions' do - let(:project) { create(:empty_project, :empty_repo) } + let(:project) { create(:project, :empty_repo) } let(:developer) { create(:user) } background do diff --git a/spec/features/projects/edit_spec.rb b/spec/features/projects/edit_spec.rb index 4b5436027f9..d3b1d1f7be3 100644 --- a/spec/features/projects/edit_spec.rb +++ b/spec/features/projects/edit_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' feature 'Project edit', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do project.team << [user, :master] @@ -20,7 +20,7 @@ feature 'Project edit', js: true do end context 'given project with merge_requests_disabled access level' do - let(:project) { create(:empty_project, :merge_requests_disabled) } + let(:project) { create(:project, :merge_requests_disabled) } it 'hides merge requests section' do expect(page).to have_selector('.merge-requests-feature', visible: false) @@ -36,7 +36,7 @@ feature 'Project edit', js: true do end context 'given project with builds_disabled access level' do - let(:project) { create(:empty_project, :builds_disabled) } + let(:project) { create(:project, :builds_disabled) } it 'hides builds select section' do expect(page).to have_selector('.builds-feature', visible: false) diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb index c6b7e611a5c..56addd64056 100644 --- a/spec/features/projects/environments/environment_spec.rb +++ b/spec/features/projects/environments/environment_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Environment' do - given(:project) { create(:empty_project) } + given(:project) { create(:project) } given(:user) { create(:user) } given(:role) { :developer } diff --git a/spec/features/projects/environments/environments_spec.rb b/spec/features/projects/environments/environments_spec.rb index 36cf307fbe2..1c59e57c0a4 100644 --- a/spec/features/projects/environments/environments_spec.rb +++ b/spec/features/projects/environments/environments_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Environments page', :js do - given(:project) { create(:empty_project) } + given(:project) { create(:project) } given(:user) { create(:user) } given(:role) { :developer } diff --git a/spec/features/projects/features_visibility_spec.rb b/spec/features/projects/features_visibility_spec.rb index 37fa61d038e..24691629063 100644 --- a/spec/features/projects/features_visibility_spec.rb +++ b/spec/features/projects/features_visibility_spec.rb @@ -20,21 +20,25 @@ describe 'Edit Project Settings' do visit edit_project_path(project) select 'Disabled', from: "project_project_feature_attributes_#{tool_name}_access_level" - click_button 'Save changes' + page.within('.sharing-permissions') do + click_button 'Save changes' + end wait_for_requests expect(page).not_to have_selector(".shortcuts-#{shortcut_name}") select 'Everyone with access', from: "project_project_feature_attributes_#{tool_name}_access_level" - click_button 'Save changes' + page.within('.sharing-permissions') do + click_button 'Save changes' + end wait_for_requests expect(page).to have_selector(".shortcuts-#{shortcut_name}") select 'Only team members', from: "project_project_feature_attributes_#{tool_name}_access_level" - click_button 'Save changes' + page.within('.sharing-permissions') do + click_button 'Save changes' + end wait_for_requests expect(page).to have_selector(".shortcuts-#{shortcut_name}") - - sleep 0.1 end end end @@ -174,7 +178,11 @@ describe 'Edit Project Settings' do it "disables repository related features" do select "Disabled", from: "project_project_feature_attributes_repository_access_level" - expect(find(".edit-project")).to have_selector("select.disabled", count: 2) + page.within('.sharing-permissions') do + click_button "Save changes" + end + + expect(find(".sharing-permissions")).to have_selector("select.disabled", count: 2) end it "shows empty features project homepage" do @@ -182,7 +190,9 @@ describe 'Edit Project Settings' do select "Disabled", from: "project_project_feature_attributes_issues_access_level" select "Disabled", from: "project_project_feature_attributes_wiki_access_level" - click_button "Save changes" + page.within('.sharing-permissions') do + click_button "Save changes" + end wait_for_requests visit project_path(project) @@ -195,7 +205,9 @@ describe 'Edit Project Settings' do select "Disabled", from: "project_project_feature_attributes_issues_access_level" select "Disabled", from: "project_project_feature_attributes_wiki_access_level" - click_button "Save changes" + page.within('.sharing-permissions') do + click_button "Save changes" + end wait_for_requests visit activity_project_path(project) @@ -236,7 +248,9 @@ describe 'Edit Project Settings' do end def save_changes_and_check_activity_tab - click_button "Save changes" + page.within('.sharing-permissions') do + click_button "Save changes" + end wait_for_requests visit activity_project_path(project) @@ -249,7 +263,7 @@ describe 'Edit Project Settings' do # Regression spec for https://gitlab.com/gitlab-org/gitlab-ce/issues/24056 describe 'project statistic visibility' do - let!(:project) { create(:empty_project, :private) } + let!(:project) { create(:project, :private) } before do project.team << [member, :guest] diff --git a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb index 1f4b3763b40..7bcab01c739 100644 --- a/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb +++ b/spec/features/projects/files/project_owner_sees_link_to_create_license_file_in_empty_project_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'project owner sees a link to create a license file in empty project', js: true do let(:project_master) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } background do project.team << [project_master, :master] sign_in(project_master) diff --git a/spec/features/projects/gfm_autocomplete_load_spec.rb b/spec/features/projects/gfm_autocomplete_load_spec.rb index b63e5ae46ee..cff3b1f5743 100644 --- a/spec/features/projects/gfm_autocomplete_load_spec.rb +++ b/spec/features/projects/gfm_autocomplete_load_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'GFM autocomplete loading', js: true do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do sign_in(create(:admin)) diff --git a/spec/features/projects/group_links_spec.rb b/spec/features/projects/group_links_spec.rb index 698baad97ff..5195d027a9f 100644 --- a/spec/features/projects/group_links_spec.rb +++ b/spec/features/projects/group_links_spec.rb @@ -4,7 +4,7 @@ feature 'Project group links', :js do include Select2Helper let(:master) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:group) { create(:group) } background do @@ -35,7 +35,7 @@ feature 'Project group links', :js do context 'nested group project' do let!(:nested_group) { create(:group, parent: group) } let!(:another_group) { create(:group) } - let!(:project) { create(:empty_project, namespace: nested_group) } + let!(:project) { create(:project, namespace: nested_group) } background do group.add_master(master) diff --git a/spec/features/projects/guest_navigation_menu_spec.rb b/spec/features/projects/guest_navigation_menu_spec.rb index 1c5f89fa898..2385e1d9333 100644 --- a/spec/features/projects/guest_navigation_menu_spec.rb +++ b/spec/features/projects/guest_navigation_menu_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Guest navigation menu' do - let(:project) { create(:empty_project, :private, public_builds: false) } + let(:project) { create(:project, :private, public_builds: false) } let(:guest) { create(:user) } before do diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index f924725870b..6a324d32ca7 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -10,7 +10,7 @@ feature 'Import/Export - project import integration test', js: true do allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) end - after(:each) do + after do FileUtils.rm_rf(export_path, secure: true) end @@ -29,8 +29,9 @@ feature 'Import/Export - project import integration test', js: true do fill_in :project_path, with: 'test-project-path', visible: true click_link 'GitLab export' - expect(page).to have_content('GitLab project export') + expect(page).to have_content('Import an exported GitLab project') expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=test-project-path") + expect(Gitlab::ImportExport).to receive(:import_upload_path).with(filename: /\A\h{32}_test-project-path\z/).and_call_original attach_file('file', file) @@ -46,7 +47,7 @@ feature 'Import/Export - project import integration test', js: true do end scenario 'invalid project' do - project = create(:empty_project, namespace: namespace) + project = create(:project, namespace: namespace) visit new_project_path @@ -60,17 +61,6 @@ feature 'Import/Export - project import integration test', js: true do expect(page).to have_content('Project could not be imported') end end - - scenario 'project with no name' do - create(:empty_project, namespace: namespace) - - visit new_project_path - - select2(namespace.id, from: '#project_namespace_id') - - # Check for tooltip disabled import button - expect(find('.import_gitlab_project')['title']).to eq('Please enter a valid project name.') - end end context 'when limited to the default user namespace' do diff --git a/spec/features/projects/import_export/namespace_export_file_spec.rb b/spec/features/projects/import_export/namespace_export_file_spec.rb index 3917e72c39e..691b0e1e4ca 100644 --- a/spec/features/projects/import_export/namespace_export_file_spec.rb +++ b/spec/features/projects/import_export/namespace_export_file_spec.rb @@ -4,7 +4,7 @@ feature 'Import/Export - Namespace export file cleanup', js: true do let(:export_path) { "#{Dir.tmpdir}/import_file_spec" } let(:config_hash) { YAML.load_file(Gitlab::ImportExport.config_file).deep_stringify_keys } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } background do allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) diff --git a/spec/features/projects/issuable_counts_caching_spec.rb b/spec/features/projects/issuable_counts_caching_spec.rb index 703d1cbd327..1804d9dc244 100644 --- a/spec/features/projects/issuable_counts_caching_spec.rb +++ b/spec/features/projects/issuable_counts_caching_spec.rb @@ -4,7 +4,7 @@ describe 'Issuable counts caching', :use_clean_rails_memory_store_caching do let!(:member) { create(:user) } let!(:member_2) { create(:user) } let!(:non_member) { create(:user) } - let!(:project) { create(:empty_project, :public) } + let!(:project) { create(:project, :public) } let!(:open_issue) { create(:issue, project: project) } let!(:confidential_issue) { create(:issue, :confidential, project: project, author: non_member) } let!(:closed_issue) { create(:issue, :closed, project: project) } diff --git a/spec/features/projects/issues/list_spec.rb b/spec/features/projects/issues/list_spec.rb index c2ca62508a4..9fc03f49f5b 100644 --- a/spec/features/projects/issues/list_spec.rb +++ b/spec/features/projects/issues/list_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Issues List' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } background do project.team << [user, :developer] diff --git a/spec/features/projects/issues/rss_spec.rb b/spec/features/projects/issues/rss_spec.rb index d274a1760a4..58eeef8c258 100644 --- a/spec/features/projects/issues/rss_spec.rb +++ b/spec/features/projects/issues/rss_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Project Issues RSS' do - let(:project) { create(:empty_project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } + let(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) } let(:path) { project_issues_path(project) } before do diff --git a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb index 2b0aead440c..0292a3192d8 100644 --- a/spec/features/projects/labels/issues_sorted_by_priority_spec.rb +++ b/spec/features/projects/labels/issues_sorted_by_priority_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Issue prioritization' do let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } # Labels let(:label_1) { create(:label, title: 'label_1', project: project, priority: 1) } diff --git a/spec/features/projects/labels/subscription_spec.rb b/spec/features/projects/labels/subscription_spec.rb index 3115a643d5d..5716d151250 100644 --- a/spec/features/projects/labels/subscription_spec.rb +++ b/spec/features/projects/labels/subscription_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Labels subscription' do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let!(:bug) { create(:label, project: project, title: 'bug') } let!(:feature) { create(:group_label, group: group, title: 'feature') } diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index 223f94ff9f9..8f85e972027 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -5,7 +5,7 @@ feature 'Prioritize labels' do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let!(:bug) { create(:label, project: project, title: 'bug') } let!(:wontfix) { create(:label, project: project, title: 'wontfix') } let!(:feature) { create(:group_label, group: group, title: 'feature') } diff --git a/spec/features/projects/members/anonymous_user_sees_members_spec.rb b/spec/features/projects/members/anonymous_user_sees_members_spec.rb index a26e7becdb9..bf0990d675d 100644 --- a/spec/features/projects/members/anonymous_user_sees_members_spec.rb +++ b/spec/features/projects/members/anonymous_user_sees_members_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Anonymous user sees members' do let(:user) { create(:user) } let(:group) { create(:group, :public) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } background do project.team << [user, :master] diff --git a/spec/features/projects/members/group_links_spec.rb b/spec/features/projects/members/group_links_spec.rb index acda5808313..1c348b987d4 100644 --- a/spec/features/projects/members/group_links_spec.rb +++ b/spec/features/projects/members/group_links_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Anonymous user sees members', js: true do let(:user) { create(:user) } let(:group) { create(:group, :public) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } background do project.team << [user, :master] diff --git a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb index 1fb5e000239..6b450fa4e45 100644 --- a/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_leave_group_project_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Group member cannot leave group project' do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } background do group.add_developer(user) diff --git a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb index 8e3520f9f15..296a80a3c60 100644 --- a/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb +++ b/spec/features/projects/members/group_member_cannot_request_access_to_his_group_project_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Group member cannot request access to his group project' do let(:user) { create(:user) } let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } scenario 'owner does not see the request access button' do group.add_owner(user) diff --git a/spec/features/projects/members/group_members_spec.rb b/spec/features/projects/members/group_members_spec.rb index 154f9f4a26c..c140fece41d 100644 --- a/spec/features/projects/members/group_members_spec.rb +++ b/spec/features/projects/members/group_members_spec.rb @@ -4,7 +4,7 @@ feature 'Projects members' do let(:user) { create(:user) } let(:developer) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } - let(:project) { create(:empty_project, :public, :access_requestable, creator: user, group: group) } + let(:project) { create(:project, :public, :access_requestable, creator: user, group: group) } let(:project_invitee) { create(:project_member, project: project, invite_token: '123', invite_email: 'test1@abc.com', user: nil) } let(:group_invitee) { create(:group_member, group: group, invite_token: '123', invite_email: 'test2@abc.com', user: nil) } let(:project_requester) { create(:user) } diff --git a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb index 6865d721201..c8988aa63a7 100644 --- a/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb +++ b/spec/features/projects/members/group_requester_cannot_request_access_to_project_spec.rb @@ -4,7 +4,7 @@ feature 'Projects > Members > Group requester cannot request access to project', let(:user) { create(:user) } let(:owner) { create(:user) } let(:group) { create(:group, :public, :access_requestable) } - let(:project) { create(:empty_project, :public, :access_requestable, namespace: group) } + let(:project) { create(:project, :public, :access_requestable, namespace: group) } background do group.add_owner(owner) diff --git a/spec/features/projects/members/list_spec.rb b/spec/features/projects/members/list_spec.rb index f9c54d267b5..237c059e595 100644 --- a/spec/features/projects/members/list_spec.rb +++ b/spec/features/projects/members/list_spec.rb @@ -6,7 +6,7 @@ feature 'Project members list' do let(:user1) { create(:user, name: 'John Doe') } let(:user2) { create(:user, name: 'Mary Jane') } let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } background do sign_in(user1) diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index b4381ea373e..cd621b6b3ce 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -5,7 +5,7 @@ feature 'Projects > Members > Master adds member with expiration date', js: true include ActiveSupport::Testing::TimeHelpers let(:master) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:new_member) { create(:user) } background do diff --git a/spec/features/projects/members/master_manages_access_requests_spec.rb b/spec/features/projects/members/master_manages_access_requests_spec.rb index 0f96a7cc70d..eb3c8034873 100644 --- a/spec/features/projects/members/master_manages_access_requests_spec.rb +++ b/spec/features/projects/members/master_manages_access_requests_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Master manages access requests' do let(:user) { create(:user) } let(:master) { create(:user) } - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } background do project.request_access(user) diff --git a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb index 7f39f5b2513..04806f8fd9e 100644 --- a/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/member_cannot_request_access_to_his_project_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Members > Member cannot request access to his project' do let(:member) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } background do project.team << [member, :developer] diff --git a/spec/features/projects/members/owner_cannot_leave_project_spec.rb b/spec/features/projects/members/owner_cannot_leave_project_spec.rb index 8b6d0aafcf8..15162d01c44 100644 --- a/spec/features/projects/members/owner_cannot_leave_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_leave_project_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Projects > Members > Owner cannot leave project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } background do sign_in(project.owner) diff --git a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb index d838af6d976..c27925c8dc4 100644 --- a/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb +++ b/spec/features/projects/members/owner_cannot_request_access_to_his_project_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Projects > Members > Owner cannot request access to his project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } background do sign_in(project.owner) diff --git a/spec/features/projects/members/sorting_spec.rb b/spec/features/projects/members/sorting_spec.rb index 45c2647e6e2..afa173c59e5 100644 --- a/spec/features/projects/members/sorting_spec.rb +++ b/spec/features/projects/members/sorting_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Members > Sorting' do let(:master) { create(:user, name: 'John Doe') } let(:developer) { create(:user, name: 'Mary Jane', last_sign_in_at: 5.days.ago) } - let(:project) { create(:empty_project, namespace: master.namespace, creator: master) } + let(:project) { create(:project, namespace: master.namespace, creator: master) } background do create(:project_member, :developer, user: developer, project: project, created_at: 3.days.ago) diff --git a/spec/features/projects/milestones/milestone_spec.rb b/spec/features/projects/milestones/milestone_spec.rb index b1c38ecc9ab..30de3e83fbb 100644 --- a/spec/features/projects/milestones/milestone_spec.rb +++ b/spec/features/projects/milestones/milestone_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Project milestone' do let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } let(:milestone) { create(:milestone, project: project) } before do diff --git a/spec/features/projects/milestones/milestones_sorting_spec.rb b/spec/features/projects/milestones/milestones_sorting_spec.rb index 4bd1929ac1e..c531b81e04d 100644 --- a/spec/features/projects/milestones/milestones_sorting_spec.rb +++ b/spec/features/projects/milestones/milestones_sorting_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Milestones sorting', :js do include SortingHelper let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } before do # Milestones diff --git a/spec/features/projects/milestones/new_spec.rb b/spec/features/projects/milestones/new_spec.rb index 7cfcccda439..f7900210fe6 100644 --- a/spec/features/projects/milestones/new_spec.rb +++ b/spec/features/projects/milestones/new_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Creating a new project milestone', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project, name: 'test', namespace: user.namespace) } + let(:project) { create(:project, name: 'test', namespace: user.namespace) } before do login_as(user) diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index 42f23ee5dec..013ed6f2e58 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Pages' do - given(:project) { create(:empty_project) } + given(:project) { create(:project) } given(:user) { create(:user) } given(:role) { :master } diff --git a/spec/features/projects/pipeline_schedules_spec.rb b/spec/features/projects/pipeline_schedules_spec.rb index 605415d2af4..24b335a7068 100644 --- a/spec/features/projects/pipeline_schedules_spec.rb +++ b/spec/features/projects/pipeline_schedules_spec.rb @@ -219,6 +219,25 @@ feature 'Pipeline Schedules', :js do end end end + + context 'when active is true and next_run_at is NULL' do + background do + create(:ci_pipeline_schedule, project: project, owner: user).tap do |pipeline_schedule| + pipeline_schedule.update_attribute(:cron, nil) # Consequently next_run_at will be nil + end + end + + scenario 'user edit and recover the problematic pipeline schedule' do + visit_pipelines_schedules + find(".content-list .pipeline-schedule-table-row:nth-child(1) .btn-group a[title='Edit']").click + fill_in 'schedule_cron', with: '* 1 2 3 4' + click_button 'Save pipeline schedule' + + page.within('.pipeline-schedule-table-row:nth-child(1)') do + expect(page).to have_css(".next-run-cell time") + end + end + end end context 'logged in as non-member' do diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 0b626749275..acbc5b046e6 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Pipeline', :js do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 59dff22eca3..f7b40cb1820 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Pipelines', :js do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when user is logged in' do let(:user) { create(:user) } diff --git a/spec/features/projects/project_settings_spec.rb b/spec/features/projects/project_settings_spec.rb index 6001bcfff0a..80d91e5915f 100644 --- a/spec/features/projects/project_settings_spec.rb +++ b/spec/features/projects/project_settings_spec.rb @@ -4,7 +4,7 @@ describe 'Edit Project Settings' do include Select2Helper let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace, path: 'gitlab', name: 'sample') } + let(:project) { create(:project, namespace: user.namespace, path: 'gitlab', name: 'sample') } before do sign_in(user) @@ -14,7 +14,9 @@ describe 'Edit Project Settings' do it 'shows errors for invalid project name' do visit edit_project_path(project) fill_in 'project_name_edit', with: 'foo&bar' - click_button 'Save changes' + page.within('.general-settings') do + click_button 'Save changes' + end expect(page).to have_field 'project_name_edit', with: 'foo&bar' expect(page).to have_content "Name can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'." expect(page).to have_button 'Save changes' @@ -23,7 +25,9 @@ describe 'Edit Project Settings' do it 'shows a successful notice when the project is updated' do visit edit_project_path(project) fill_in 'project_name_edit', with: 'hello world' - click_button 'Save changes' + page.within('.general-settings') do + click_button 'Save changes' + end expect(page).to have_content "Project 'hello world' was successfully updated." end end @@ -61,7 +65,7 @@ describe 'Edit Project Settings' do TestEnv.clean_test_path end - after(:example) do + after do TestEnv.clean_test_path end @@ -86,7 +90,7 @@ describe 'Edit Project Settings' do it 'overrides the redirect' do old_path = project_path(project) rename_project(project, path: 'bar') - new_project = create(:empty_project, namespace: user.namespace, path: 'gitlabhq', name: 'quz') + new_project = create(:project, namespace: user.namespace, path: 'gitlabhq', name: 'quz') visit old_path expect(current_path).to eq(old_path) expect(find('h1.title')).to have_content(new_project.name) @@ -103,11 +107,11 @@ describe 'Edit Project Settings' do TestEnv.clean_test_path end - before(:example) do + before do group.add_owner(user) end - after(:example) do + after do TestEnv.clean_test_path end @@ -132,7 +136,7 @@ describe 'Edit Project Settings' do it 'overrides the redirect' do old_path = project_path(project) transfer_project(project, group) - new_project = create(:empty_project, namespace: user.namespace, path: 'gitlabhq', name: 'quz') + new_project = create(:project, namespace: user.namespace, path: 'gitlabhq', name: 'quz') visit old_path expect(current_path).to eq(old_path) expect(find('h1.title')).to have_content(new_project.name) diff --git a/spec/features/projects/services/jira_service_spec.rb b/spec/features/projects/services/jira_service_spec.rb index ecaa69c49dd..65e3a487d4b 100644 --- a/spec/features/projects/services/jira_service_spec.rb +++ b/spec/features/projects/services/jira_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Setup Jira service', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:service) { project.create_jira_service } let(:url) { 'http://jira.example.com' } diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index 134d7e5e8b7..95d5e8b14b9 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Setup Mattermost slash commands', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:service) { project.create_mattermost_slash_commands_service } let(:mattermost_enabled) { true } diff --git a/spec/features/projects/services/slack_service_spec.rb b/spec/features/projects/services/slack_service_spec.rb index 824cae261e0..c10ec5e2987 100644 --- a/spec/features/projects/services/slack_service_spec.rb +++ b/spec/features/projects/services/slack_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Projects > Slack service > Setup events' do let(:user) { create(:user) } let(:service) { SlackService.new } - let(:project) { create(:empty_project, slack_service: service) } + let(:project) { create(:project, slack_service: service) } background do service.fields diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb index 6002c589fba..a8baf126269 100644 --- a/spec/features/projects/services/slack_slash_command_spec.rb +++ b/spec/features/projects/services/slack_slash_command_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Slack slash commands' do given(:user) { create(:user) } - given(:project) { create(:empty_project) } + given(:project) { create(:project) } given(:service) { project.create_slack_slash_commands_service } background do diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb index 1de4918e142..d932c4e4d9a 100644 --- a/spec/features/projects/settings/integration_settings_spec.rb +++ b/spec/features/projects/settings/integration_settings_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Integration settings' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:role) { :developer } let(:integrations_path) { project_settings_integrations_path(project) } diff --git a/spec/features/projects/settings/merge_requests_settings_spec.rb b/spec/features/projects/settings/merge_requests_settings_spec.rb index 796e2026905..104ce08d9f3 100644 --- a/spec/features/projects/settings/merge_requests_settings_spec.rb +++ b/spec/features/projects/settings/merge_requests_settings_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Project settings > Merge Requests', :js do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } background do @@ -20,6 +20,9 @@ feature 'Project settings > Merge Requests', :js do expect(page).to have_content('Only allow merge requests to be merged if all discussions are resolved') select 'Disabled', from: "project_project_feature_attributes_merge_requests_access_level" + within('.sharing-permissions-form') do + click_on('Save changes') + end expect(page).not_to have_content('Only allow merge requests to be merged if the pipeline succeeds') expect(page).not_to have_content('Only allow merge requests to be merged if all discussions are resolved') @@ -37,6 +40,9 @@ feature 'Project settings > Merge Requests', :js do expect(page).to have_content('Only allow merge requests to be merged if all discussions are resolved') select 'Everyone with access', from: "project_project_feature_attributes_builds_access_level" + within('.sharing-permissions-form') do + click_on('Save changes') + end expect(page).to have_content('Only allow merge requests to be merged if the pipeline succeeds') expect(page).to have_content('Only allow merge requests to be merged if all discussions are resolved') @@ -55,6 +61,9 @@ feature 'Project settings > Merge Requests', :js do expect(page).not_to have_content('Only allow merge requests to be merged if all discussions are resolved') select 'Everyone with access', from: "project_project_feature_attributes_merge_requests_access_level" + within('.sharing-permissions-form') do + click_on('Save changes') + end expect(page).to have_content('Only allow merge requests to be merged if the pipeline succeeds') expect(page).to have_content('Only allow merge requests to be merged if all discussions are resolved') @@ -73,7 +82,9 @@ feature 'Project settings > Merge Requests', :js do scenario 'when unchecked sets :printing_merge_request_link_enabled to false' do uncheck('project_printing_merge_request_link_enabled') - click_on('Save') + within('.merge-request-settings-form') do + click_on('Save changes') + end # Wait for save to complete and page to reload checkbox = find_field('project_printing_merge_request_link_enabled') diff --git a/spec/features/projects/settings/pipelines_settings_spec.rb b/spec/features/projects/settings/pipelines_settings_spec.rb index f24d7ff64d0..232d796a200 100644 --- a/spec/features/projects/settings/pipelines_settings_spec.rb +++ b/spec/features/projects/settings/pipelines_settings_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature "Pipelines settings" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:role) { :developer } diff --git a/spec/features/projects/settings/visibility_settings_spec.rb b/spec/features/projects/settings/visibility_settings_spec.rb index 1e705d211ea..1756c7d00fe 100644 --- a/spec/features/projects/settings/visibility_settings_spec.rb +++ b/spec/features/projects/settings/visibility_settings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Visibility settings', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace, visibility_level: 20) } + let(:project) { create(:project, namespace: user.namespace, visibility_level: 20) } context 'as owner' do before do diff --git a/spec/features/projects/shortcuts_spec.rb b/spec/features/projects/shortcuts_spec.rb index 2c6d0a56311..bf18c444c3d 100644 --- a/spec/features/projects/shortcuts_spec.rb +++ b/spec/features/projects/shortcuts_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' feature 'Project shortcuts' do - let(:project) { create(:empty_project, name: 'Victorialand') } + let(:project) { create(:project, name: 'Victorialand') } let(:user) { create(:user) } describe 'On a project', js: true do diff --git a/spec/features/projects/snippets/create_snippet_spec.rb b/spec/features/projects/snippets/create_snippet_spec.rb index 7f0e7e3116c..3e79dba3f19 100644 --- a/spec/features/projects/snippets/create_snippet_spec.rb +++ b/spec/features/projects/snippets/create_snippet_spec.rb @@ -4,7 +4,7 @@ feature 'Create Snippet', :js do include DropzoneHelper let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } def fill_form fill_in 'project_snippet_title', with: 'My Snippet Title' diff --git a/spec/features/projects/snippets_spec.rb b/spec/features/projects/snippets_spec.rb index 0822684a42c..1cfbbb4cb62 100644 --- a/spec/features/projects/snippets_spec.rb +++ b/spec/features/projects/snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Project snippets', :js do context 'when the project has snippets' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) } let!(:other_snippet) { create(:project_snippet) } diff --git a/spec/features/projects/sub_group_issuables_spec.rb b/spec/features/projects/sub_group_issuables_spec.rb index 262dcc0abff..aaf64d42515 100644 --- a/spec/features/projects/sub_group_issuables_spec.rb +++ b/spec/features/projects/sub_group_issuables_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Subgroup Issuables', :js, :nested_groups do let!(:group) { create(:group, name: 'group') } let!(:subgroup) { create(:group, parent: group, name: 'subgroup') } - let!(:project) { create(:empty_project, namespace: subgroup, name: 'project') } + let!(:project) { create(:project, namespace: subgroup, name: 'project') } let(:user) { create(:user) } before do diff --git a/spec/features/projects/tags/download_buttons_spec.rb b/spec/features/projects/tags/download_buttons_spec.rb index a6c5a486bcc..d38a5b1324b 100644 --- a/spec/features/projects/tags/download_buttons_spec.rb +++ b/spec/features/projects/tags/download_buttons_spec.rb @@ -5,7 +5,7 @@ feature 'Download buttons in tags page' do given(:role) { :developer } given(:status) { 'success' } given(:tag) { 'v1.0.0' } - given(:project) { create(:project) } + given(:project) { create(:project, :repository) } given(:pipeline) do create(:ci_pipeline, diff --git a/spec/features/projects/user_edits_files_spec.rb b/spec/features/projects/user_edits_files_spec.rb index 8ae89c980b9..3129aad8473 100644 --- a/spec/features/projects/user_edits_files_spec.rb +++ b/spec/features/projects/user_edits_files_spec.rb @@ -1,10 +1,6 @@ require 'spec_helper' describe 'User edits files' do - let(:fork_message) do - "You're not allowed to make changes to this project directly. "\ - "A fork of this project has been created that you can make changes in, so you can submit a merge request." - end let(:project) { create(:project, :repository, name: 'Shop') } let(:project2) { create(:project, :repository, name: 'Another Project', path: 'another-project') } let(:project_tree_path_root_ref) { project_tree_path(project, project.repository.root_ref) } @@ -24,6 +20,9 @@ describe 'User edits files' do it 'inserts a content of a file', js: true do click_link('.gitignore') find('.js-edit-blob').click + + wait_for_requests + execute_script("ace.edit('editor').setValue('*.rbca')") expect(evaluate_script('ace.edit("editor").getValue()')).to eq('*.rbca') @@ -39,6 +38,9 @@ describe 'User edits files' do it 'commits an edited file', js: true do click_link('.gitignore') find('.js-edit-blob').click + + wait_for_requests + execute_script("ace.edit('editor').setValue('*.rbca')") fill_in(:commit_message, with: 'New commit message', visible: true) click_button('Commit changes') @@ -53,6 +55,9 @@ describe 'User edits files' do it 'commits an edited file to a new branch', js: true do click_link('.gitignore') find('.js-edit-blob').click + + wait_for_requests + execute_script("ace.edit('editor').setValue('*.rbca')") fill_in(:commit_message, with: 'New commit message', visible: true) fill_in(:branch_name, with: 'new_branch_name', visible: true) @@ -69,6 +74,9 @@ describe 'User edits files' do it 'shows the diff of an edited file', js: true do click_link('.gitignore') find('.js-edit-blob').click + + wait_for_requests + execute_script("ace.edit('editor').setValue('*.rbca')") click_link('Preview changes') @@ -91,7 +99,12 @@ describe 'User edits files' do click_link('Fork') - expect(page).to have_content(fork_message) + expect(page).to have_content( + "You're not allowed to make changes to this project directly. "\ + "A fork of this project has been created that you can make changes in, so you can submit a merge request." + ) + + wait_for_requests execute_script("ace.edit('editor').setValue('*.rbca')") @@ -106,6 +119,9 @@ describe 'User edits files' do expect(page).to have_button('Cancel') click_link('Fork') + + wait_for_requests + execute_script("ace.edit('editor').setValue('*.rbca')") fill_in(:commit_message, with: 'New commit message', visible: true) click_button('Commit changes') diff --git a/spec/features/projects/wiki/markdown_preview_spec.rb b/spec/features/projects/wiki/markdown_preview_spec.rb index dbe98a38197..9a4ccf3c54d 100644 --- a/spec/features/projects/wiki/markdown_preview_spec.rb +++ b/spec/features/projects/wiki/markdown_preview_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Wiki > User previews markdown changes', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let(:wiki_content) do <<-HEREDOC [regular link](regular) @@ -38,10 +38,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/e/f/relative\">relative link 3</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>") end end @@ -60,10 +60,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") end end @@ -82,10 +82,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") end end end @@ -115,10 +115,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/e/f/relative\">relative link 3</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/relative\">relative link 1</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/relative\">relative link 2</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a/b/c/e/f/relative\">relative link 3</a>") end end @@ -132,10 +132,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") end end @@ -149,10 +149,10 @@ feature 'Projects > Wiki > User previews markdown changes', js: true do expect(page).to have_content("regular link") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") - expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/regular\">regular link</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/relative\">relative link 1</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>") + expect(page.html).to include("<a href=\"/#{project.full_path}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>") end end end diff --git a/spec/features/projects/wiki/shortcuts_spec.rb b/spec/features/projects/wiki/shortcuts_spec.rb index 2c668185666..eaff5f876b6 100644 --- a/spec/features/projects/wiki/shortcuts_spec.rb +++ b/spec/features/projects/wiki/shortcuts_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Wiki shortcuts', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let(:wiki_page) do WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute end diff --git a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb index 78c619f6301..9d66f482c8d 100644 --- a/spec/features/projects/wiki/user_creates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_creates_wiki_page_spec.rb @@ -11,7 +11,7 @@ feature 'Projects > Wiki > User creates wiki page', :js do end context 'in the user namespace' do - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } context 'when wiki is empty' do before do @@ -157,7 +157,7 @@ feature 'Projects > Wiki > User creates wiki page', :js do end context 'in a group namespace' do - let(:project) { create(:empty_project, namespace: create(:group, :public)) } + let(:project) { create(:project, namespace: create(:group, :public)) } context 'when wiki is empty' do before do diff --git a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb index 9c58e336605..9a92622ba2b 100644 --- a/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_git_access_wiki_page_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Projects > Wiki > User views Git access wiki page' do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:wiki_page) do WikiPages::CreateService.new( project, @@ -20,7 +20,7 @@ describe 'Projects > Wiki > User views Git access wiki page' do visit project_wiki_path(project, wiki_page) click_link 'Clone repository' - expect(page).to have_text("Clone repository #{project.wiki.path_with_namespace}") + expect(page).to have_text("Clone repository #{project.wiki.full_path}") expect(page).to have_text(project.wiki.http_url_to_repo) end end diff --git a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb index 8271428582d..64a80aec205 100644 --- a/spec/features/projects/wiki/user_updates_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_updates_wiki_page_spec.rb @@ -12,7 +12,7 @@ feature 'Projects > Wiki > User updates wiki page' do end context 'in the user namespace' do - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } context 'the home page' do scenario 'success when the wiki content is not empty' do @@ -55,7 +55,7 @@ feature 'Projects > Wiki > User updates wiki page' do scenario 'page has been updated since the user opened the edit page' do click_link 'Edit' - wiki_page.update('Update') + wiki_page.update(content: 'Update') click_button 'Save changes' @@ -64,7 +64,7 @@ feature 'Projects > Wiki > User updates wiki page' do end context 'in a group namespace' do - let(:project) { create(:empty_project, namespace: create(:group, :public)) } + let(:project) { create(:project, namespace: create(:group, :public)) } scenario 'the home page' do click_link 'Edit' diff --git a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb index 4f94ab1a609..92e96f11219 100644 --- a/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb +++ b/spec/features/projects/wiki/user_views_project_wiki_page_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Projects > Wiki > User views the wiki page' do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:old_page_version_id) { wiki_page.versions.last.id } let(:wiki_page) do WikiPages::CreateService.new( diff --git a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb index 8d1e6f66039..cf9fe4c1ad1 100644 --- a/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb +++ b/spec/features/projects/wiki/user_views_wiki_in_project_page_spec.rb @@ -10,7 +10,7 @@ describe 'Projects > Wiki > User views wiki in project page' do context 'when repository is disabled for project' do let(:project) do - create(:empty_project, + create(:project, :repository_disabled, :merge_requests_disabled, :builds_disabled) diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb index 3295f7f9174..d3d7915bebf 100644 --- a/spec/features/projects_spec.rb +++ b/spec/features/projects_spec.rb @@ -1,6 +1,27 @@ require 'spec_helper' feature 'Project' do + describe 'creating from template' do + let(:user) { create(:user) } + let(:template) { Gitlab::ProjectTemplate.find(:rails) } + + before do + sign_in user + visit new_project_path + end + + it "allows creation from templates" do + page.choose(template.name) + fill_in("project_path", with: template.name) + + page.within '#content-body' do + click_button "Create project" + end + + expect(page).to have_content 'This project Loading..' + end + end + describe 'description' do let(:project) { create(:project, :repository) } let(:path) { project_path(project) } @@ -36,7 +57,7 @@ feature 'Project' do describe 'remove forked relationship', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } before do sign_in user @@ -57,7 +78,7 @@ feature 'Project' do describe 'removal', js: true do let(:user) { create(:user, username: 'test', name: 'test') } - let(:project) { create(:empty_project, namespace: user.namespace, name: 'project1') } + let(:project) { create(:project, namespace: user.namespace, name: 'project1') } before do sign_in(user) @@ -76,7 +97,7 @@ feature 'Project' do describe 'project title' do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } before do sign_in(user) @@ -92,8 +113,8 @@ feature 'Project' do describe 'project title' do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } - let(:project2) { create(:empty_project, namespace: user.namespace, path: 'test') } + let(:project) { create(:project, namespace: user.namespace) } + let(:project2) { create(:project, namespace: user.namespace, path: 'test') } let(:issue) { create(:issue, project: project) } context 'on issues page', js: true do @@ -146,6 +167,21 @@ feature 'Project' do end end + describe 'activity view' do + let(:user) { create(:user, project_view: 'activity') } + let(:project) { create(:project, :repository) } + + before do + project.team << [user, :master] + sign_in user + visit project_path(project) + end + + it 'loads activity', :js do + expect(page).to have_selector('.event-item') + end + end + def remove_with_confirm(button_text, confirm_with) click_button button_text fill_in 'confirm_name_input', with: confirm_with diff --git a/spec/features/protected_tags_spec.rb b/spec/features/protected_tags_spec.rb index c9ba1a8c088..8abd4403065 100644 --- a/spec/features/protected_tags_spec.rb +++ b/spec/features/protected_tags_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Projected Tags', js: true do +feature 'Protected Tags', js: true do let(:user) { create(:user, :admin) } let(:project) { create(:project, :repository) } diff --git a/spec/features/reportable_note/commit_spec.rb b/spec/features/reportable_note/commit_spec.rb index 1074eb62b33..3bf25221e36 100644 --- a/spec/features/reportable_note/commit_spec.rb +++ b/spec/features/reportable_note/commit_spec.rb @@ -4,7 +4,7 @@ describe 'Reportable note on commit', :js do include RepoHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.add_master(user) diff --git a/spec/features/reportable_note/issue_spec.rb b/spec/features/reportable_note/issue_spec.rb index 9964a32db2e..21e96f6f103 100644 --- a/spec/features/reportable_note/issue_spec.rb +++ b/spec/features/reportable_note/issue_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Reportable note on issue', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let!(:note) { create(:note_on_issue, noteable: issue, project: project) } diff --git a/spec/features/reportable_note/merge_request_spec.rb b/spec/features/reportable_note/merge_request_spec.rb index a491abdb6cb..bb296546e06 100644 --- a/spec/features/reportable_note/merge_request_spec.rb +++ b/spec/features/reportable_note/merge_request_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Reportable note on merge request', :js do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } before do diff --git a/spec/features/reportable_note/snippets_spec.rb b/spec/features/reportable_note/snippets_spec.rb index 9a14024684c..f1e48ed46be 100644 --- a/spec/features/reportable_note/snippets_spec.rb +++ b/spec/features/reportable_note/snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Reportable note on snippets', :js do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do project.add_master(user) diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 1725b70acf3..cac31c34ad1 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -9,13 +9,13 @@ describe "Runners" do describe "specific runners" do before do - @project = FactoryGirl.create :empty_project, shared_runners_enabled: false + @project = FactoryGirl.create :project, shared_runners_enabled: false @project.team << [user, :master] - @project2 = FactoryGirl.create :empty_project + @project2 = FactoryGirl.create :project @project2.team << [user, :master] - @project3 = FactoryGirl.create :empty_project + @project3 = FactoryGirl.create :project @project3.team << [user, :developer] @shared_runner = FactoryGirl.create :ci_runner, :shared @@ -70,7 +70,7 @@ describe "Runners" do describe "shared runners" do before do - @project = FactoryGirl.create :empty_project, shared_runners_enabled: false + @project = FactoryGirl.create :project, shared_runners_enabled: false @project.team << [user, :master] visit runners_path(@project) end @@ -87,7 +87,7 @@ describe "Runners" do before do stub_application_setting(shared_runners_text: shared_runners_text) - project = FactoryGirl.create :empty_project, shared_runners_enabled: false + project = FactoryGirl.create :project, shared_runners_enabled: false project.team << [user, :master] visit runners_path(project) end @@ -99,7 +99,7 @@ describe "Runners" do describe "show page" do before do - @project = FactoryGirl.create :empty_project + @project = FactoryGirl.create :project @project.team << [user, :master] @specific_runner = FactoryGirl.create :ci_runner @project.runners << @specific_runner @@ -113,7 +113,7 @@ describe "Runners" do end feature 'configuring runners ability to picking untagged jobs' do - given(:project) { create(:empty_project) } + given(:project) { create(:project) } given(:runner) { create(:ci_runner) } background do diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb index b29f19f1562..9b49fc2225d 100644 --- a/spec/features/search_spec.rb +++ b/spec/features/search_spec.rb @@ -4,7 +4,7 @@ describe "Search" do include FilteredSearchHelpers let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let!(:issue) { create(:issue, project: project, assignees: [user]) } let!(:issue2) { create(:issue, project: project, author: user) } @@ -20,7 +20,7 @@ describe "Search" do context 'search filters', js: true do let(:group) { create(:group) } - let!(:group_project) { create(:empty_project, group: group) } + let!(:group_project) { create(:project, group: group) } before do group.add_owner(user) diff --git a/spec/features/security/group/internal_access_spec.rb b/spec/features/security/group/internal_access_spec.rb index bf7be33013e..5067f0b0a49 100644 --- a/spec/features/security/group/internal_access_spec.rb +++ b/spec/features/security/group/internal_access_spec.rb @@ -4,7 +4,7 @@ describe 'Internal Group access' do include AccessMatchers let(:group) { create(:group, :internal) } - let(:project) { create(:empty_project, :internal, group: group) } + let(:project) { create(:project, :internal, group: group) } let(:project_guest) do create(:user) do |user| project.add_guest(user) diff --git a/spec/features/security/group/private_access_spec.rb b/spec/features/security/group/private_access_spec.rb index c399d7a0851..ff32413dc7e 100644 --- a/spec/features/security/group/private_access_spec.rb +++ b/spec/features/security/group/private_access_spec.rb @@ -4,7 +4,7 @@ describe 'Private Group access' do include AccessMatchers let(:group) { create(:group, :private) } - let(:project) { create(:empty_project, :private, group: group) } + let(:project) { create(:project, :private, group: group) } let(:project_guest) do create(:user) do |user| project.add_guest(user) diff --git a/spec/features/security/group/public_access_spec.rb b/spec/features/security/group/public_access_spec.rb index 63e4d7ca65c..16d114fb3f7 100644 --- a/spec/features/security/group/public_access_spec.rb +++ b/spec/features/security/group/public_access_spec.rb @@ -4,7 +4,7 @@ describe 'Public Group access' do include AccessMatchers let(:group) { create(:group, :public) } - let(:project) { create(:empty_project, :public, group: group) } + let(:project) { create(:project, :public, group: group) } let(:project_guest) do create(:user) do |user| project.add_guest(user) diff --git a/spec/features/security/project/snippet/internal_access_spec.rb b/spec/features/security/project/snippet/internal_access_spec.rb index 178782af56c..d7dc99c0a57 100644 --- a/spec/features/security/project/snippet/internal_access_spec.rb +++ b/spec/features/security/project/snippet/internal_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe "Internal Project Snippets Access" do include AccessMatchers - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } let(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.owner) } let(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) } diff --git a/spec/features/security/project/snippet/private_access_spec.rb b/spec/features/security/project/snippet/private_access_spec.rb index 7725c25ca1f..3ec1a388185 100644 --- a/spec/features/security/project/snippet/private_access_spec.rb +++ b/spec/features/security/project/snippet/private_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe "Private Project Snippets Access" do include AccessMatchers - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:private_snippet) { create(:project_snippet, :private, project: project, author: project.owner) } diff --git a/spec/features/security/project/snippet/public_access_spec.rb b/spec/features/security/project/snippet/public_access_spec.rb index 52aec75dcd0..39b104bfe27 100644 --- a/spec/features/security/project/snippet/public_access_spec.rb +++ b/spec/features/security/project/snippet/public_access_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe "Public Project Snippets Access" do include AccessMatchers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:public_snippet) { create(:project_snippet, :public, project: project, author: project.owner) } let(:internal_snippet) { create(:project_snippet, :internal, project: project, author: project.owner) } diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb index f1d0905738b..c0c293dee78 100644 --- a/spec/features/snippets/notes_on_personal_snippets_spec.rb +++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb @@ -91,11 +91,7 @@ describe 'Comments on personal snippets', :js do context 'when editing a note' do it 'changes the text' do - open_more_actions_dropdown(snippet_notes[0]) - - page.within("#notes-list li#note_#{snippet_notes[0].id}") do - click_on 'Edit comment' - end + find('.js-note-edit').click page.within('.current-note-edit-form') do fill_in 'note[note]', with: 'new content' diff --git a/spec/features/snippets/user_creates_snippet_spec.rb b/spec/features/snippets/user_creates_snippet_spec.rb index a919f5fa20b..d732383a1e1 100644 --- a/spec/features/snippets/user_creates_snippet_spec.rb +++ b/spec/features/snippets/user_creates_snippet_spec.rb @@ -41,7 +41,7 @@ feature 'User creates snippet', :js do expect(page).to have_content('My Snippet') link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] - expect(link).to match(%r{/uploads/system/temp/\h{32}/banana_sample\.gif\z}) + expect(link).to match(%r{/uploads/-/system/temp/\h{32}/banana_sample\.gif\z}) visit(link) expect(page.status_code).to eq(200) @@ -59,7 +59,7 @@ feature 'User creates snippet', :js do wait_for_requests link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] - expect(link).to match(%r{/uploads/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) + expect(link).to match(%r{/uploads/-/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) visit(link) expect(page.status_code).to eq(200) @@ -84,7 +84,7 @@ feature 'User creates snippet', :js do end expect(page).to have_content('Hello World!') link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] - expect(link).to match(%r{/uploads/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) + expect(link).to match(%r{/uploads/-/system/personal_snippet/#{Snippet.last.id}/\h{32}/banana_sample\.gif\z}) visit(link) expect(page.status_code).to eq(200) diff --git a/spec/features/snippets/user_edits_snippet_spec.rb b/spec/features/snippets/user_edits_snippet_spec.rb index 26070e508e2..71de6b6bd1c 100644 --- a/spec/features/snippets/user_edits_snippet_spec.rb +++ b/spec/features/snippets/user_edits_snippet_spec.rb @@ -33,7 +33,7 @@ feature 'User edits snippet', :js do wait_for_requests link = find('a.no-attachment-icon img[alt="banana_sample"]')['src'] - expect(link).to match(%r{/uploads/system/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z}) + expect(link).to match(%r{/uploads/-/system/personal_snippet/#{snippet.id}/\h{32}/banana_sample\.gif\z}) end it 'updates the snippet to make it internal' do diff --git a/spec/features/snippets_spec.rb b/spec/features/snippets_spec.rb index ae3b876f87c..96c50f6c804 100644 --- a/spec/features/snippets_spec.rb +++ b/spec/features/snippets_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Snippets' do context 'when the project has snippets' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let!(:snippets) { create_list(:project_snippet, 2, :public, author: project.owner, project: project) } before do allow(Snippet).to receive(:default_per_page).and_return(1) diff --git a/spec/features/tags/master_creates_tag_spec.rb b/spec/features/tags/master_creates_tag_spec.rb index 35e1ca32f67..39d79a3327b 100644 --- a/spec/features/tags/master_creates_tag_spec.rb +++ b/spec/features/tags/master_creates_tag_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Master creates tag' do let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:project, :repository, namespace: user.namespace) } before do project.team << [user, :master] diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb index e3c904ef3aa..4d6fc13557f 100644 --- a/spec/features/tags/master_deletes_tag_spec.rb +++ b/spec/features/tags/master_deletes_tag_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Master deletes tag' do let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:project, :repository, namespace: user.namespace) } before do project.team << [user, :master] diff --git a/spec/features/tags/master_updates_tag_spec.rb b/spec/features/tags/master_updates_tag_spec.rb index d6e84a1c685..b93ad44dfd3 100644 --- a/spec/features/tags/master_updates_tag_spec.rb +++ b/spec/features/tags/master_updates_tag_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' feature 'Master updates tag' do let(:user) { create(:user) } - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:project, :repository, namespace: user.namespace) } before do project.team << [user, :master] diff --git a/spec/features/tags/master_views_tags_spec.rb b/spec/features/tags/master_views_tags_spec.rb index 27936bc7f52..9edc7ced163 100644 --- a/spec/features/tags/master_views_tags_spec.rb +++ b/spec/features/tags/master_views_tags_spec.rb @@ -26,7 +26,7 @@ feature 'Master views tags' do end context 'when project has tags' do - let(:project) { create(:project, namespace: user.namespace) } + let(:project) { create(:project, :repository, namespace: user.namespace) } let(:repository) { project.repository } before do diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index 7e198ce0677..580258f77eb 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' feature 'Task Lists' do include Warden::Test::Helpers - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:user2) { create(:user) } @@ -52,8 +52,8 @@ feature 'Task Lists' do before do Warden.test_mode! - project.team << [user, :master] - project.team << [user2, :guest] + project.add_master(user) + project.add_guest(user2) login_as(user) end diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb index 604fe326e96..47664de469a 100644 --- a/spec/features/triggers_spec.rb +++ b/spec/features/triggers_spec.rb @@ -9,7 +9,7 @@ feature 'Triggers', js: true do before do sign_in(user) - @project = create(:empty_project) + @project = create(:project) @project.team << [user, :master] @project.team << [user2, :master] @project.team << [guest_user, :guest] @@ -82,7 +82,7 @@ feature 'Triggers', js: true do end describe 'trigger "Take ownership" workflow' do - before(:each) do + before do create(:ci_trigger, owner: user2, project: @project, description: trigger_title) visit project_settings_ci_cd_path(@project) end @@ -104,7 +104,7 @@ feature 'Triggers', js: true do end describe 'trigger "Revoke" workflow' do - before(:each) do + before do create(:ci_trigger, owner: user2, project: @project, description: trigger_title) visit project_settings_ci_cd_path(@project) end diff --git a/spec/features/unsubscribe_links_spec.rb b/spec/features/unsubscribe_links_spec.rb index d728dc59b3f..392d8e3e1c1 100644 --- a/spec/features/unsubscribe_links_spec.rb +++ b/spec/features/unsubscribe_links_spec.rb @@ -5,7 +5,7 @@ describe 'Unsubscribe links' do let(:recipient) { create(:user) } let(:author) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:params) { { title: 'A bug!', description: 'Fix it!', assignees: [recipient] } } let(:issue) { Issues::CreateService.new(project, author, params).execute } diff --git a/spec/features/uploads/user_uploads_file_to_note_spec.rb b/spec/features/uploads/user_uploads_file_to_note_spec.rb index 0654923d9a6..53cad623a35 100644 --- a/spec/features/uploads/user_uploads_file_to_note_spec.rb +++ b/spec/features/uploads/user_uploads_file_to_note_spec.rb @@ -4,7 +4,7 @@ feature 'User uploads file to note' do include DropzoneHelper let(:user) { create(:user) } - let(:project) { create(:empty_project, creator: user, namespace: user.namespace) } + let(:project) { create(:project, creator: user, namespace: user.namespace) } let(:issue) { create(:issue, project: project, author: user) } before do diff --git a/spec/features/user_callout_spec.rb b/spec/features/user_callout_spec.rb index 93768aa46df..37d66b618af 100644 --- a/spec/features/user_callout_spec.rb +++ b/spec/features/user_callout_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'User Callouts', js: true do let(:user) { create(:user) } let(:another_user) { create(:user) } - let(:project) { create(:empty_project, path: 'gitlab', name: 'sample') } + let(:project) { create(:project, path: 'gitlab', name: 'sample') } before do sign_in(user) diff --git a/spec/features/users/projects_spec.rb b/spec/features/users/projects_spec.rb index b961d2337ed..f079771cee1 100644 --- a/spec/features/users/projects_spec.rb +++ b/spec/features/users/projects_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe 'Projects tab on a user profile', :js do let(:user) { create(:user) } - let!(:project) { create(:empty_project, namespace: user.namespace) } - let!(:project2) { create(:empty_project, namespace: user.namespace) } + let!(:project) { create(:project, namespace: user.namespace) } + let!(:project2) { create(:project, namespace: user.namespace) } before do allow(Project).to receive(:default_per_page).and_return(1) diff --git a/spec/features/users_spec.rb b/spec/features/users_spec.rb index ff004d85272..15b89dac572 100644 --- a/spec/features/users_spec.rb +++ b/spec/features/users_spec.rb @@ -73,7 +73,7 @@ feature 'Users', js: true do let(:loading_icon) { '.fa.fa-spinner' } let(:username_input) { 'new_user_username' } - before(:each) do + before do visit new_user_session_path click_link 'Register' end @@ -104,7 +104,7 @@ feature 'Users', js: true do end def errors_on_page(page) - page.find('#error_explanation').find('ul').all('li').map{ |item| item.text }.join("\n") + page.find('#error_explanation').find('ul').all('li').map { |item| item.text }.join("\n") end def number_of_errors_on_page(page) diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb index dd770fe5043..6794bf4f4ba 100644 --- a/spec/features/variables_spec.rb +++ b/spec/features/variables_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'Project variables', js: true do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:variable) { create(:ci_variable, key: 'test_key', value: 'test value') } before do diff --git a/spec/finders/access_requests_finder_spec.rb b/spec/finders/access_requests_finder_spec.rb index 1d0c15392b2..0789d3a9b44 100644 --- a/spec/finders/access_requests_finder_spec.rb +++ b/spec/finders/access_requests_finder_spec.rb @@ -5,7 +5,7 @@ describe AccessRequestsFinder do let(:access_requester) { create(:user) } let(:project) do - create(:empty_project, :public, :access_requestable) do |project| + create(:project, :public, :access_requestable) do |project| project.request_access(access_requester) end end diff --git a/spec/finders/admin/projects_finder_spec.rb b/spec/finders/admin/projects_finder_spec.rb index 296d6c51d04..28e36330029 100644 --- a/spec/finders/admin/projects_finder_spec.rb +++ b/spec/finders/admin/projects_finder_spec.rb @@ -6,19 +6,19 @@ describe Admin::ProjectsFinder do let(:group) { create(:group, :public) } let!(:private_project) do - create(:empty_project, :private, name: 'A', path: 'A') + create(:project, :private, name: 'A', path: 'A') end let!(:internal_project) do - create(:empty_project, :internal, group: group, name: 'B', path: 'B') + create(:project, :internal, group: group, name: 'B', path: 'B') end let!(:public_project) do - create(:empty_project, :public, group: group, name: 'C', path: 'C') + create(:project, :public, group: group, name: 'C', path: 'C') end let!(:shared_project) do - create(:empty_project, :private, name: 'D', path: 'D') + create(:project, :private, name: 'D', path: 'D') end let(:params) { {} } @@ -38,9 +38,15 @@ describe Admin::ProjectsFinder do it { is_expected.to match_array([shared_project, public_project, internal_project, private_project]) } end + context 'with pending delete project' do + let!(:pending_delete_project) { create(:project, pending_delete: true) } + + it { is_expected.not_to include(pending_delete_project) } + end + context 'filter by namespace_id' do let(:namespace) { create(:namespace) } - let!(:project_in_namespace) { create(:empty_project, namespace: namespace) } + let!(:project_in_namespace) { create(:project, namespace: namespace) } let(:params) { { namespace_id: namespace.id } } it { is_expected.to eq([project_in_namespace]) } @@ -99,7 +105,7 @@ describe Admin::ProjectsFinder do end context 'filter by archived' do - let!(:archived_project) { create(:empty_project, :public, :archived, name: 'E', path: 'E') } + let!(:archived_project) { create(:project, :public, :archived, name: 'E', path: 'E') } context 'archived=false' do let(:params) { { archived: false } } @@ -115,7 +121,7 @@ describe Admin::ProjectsFinder do end context 'filter by personal' do - let!(:personal_project) { create(:empty_project, namespace: user.namespace) } + let!(:personal_project) { create(:project, namespace: user.namespace) } let(:params) { { personal: true } } it { is_expected.to eq([personal_project]) } diff --git a/spec/finders/contributed_projects_finder_spec.rb b/spec/finders/contributed_projects_finder_spec.rb index 34f665826b6..60ea98e61c7 100644 --- a/spec/finders/contributed_projects_finder_spec.rb +++ b/spec/finders/contributed_projects_finder_spec.rb @@ -6,16 +6,16 @@ describe ContributedProjectsFinder do let(:finder) { described_class.new(source_user) } - let!(:public_project) { create(:empty_project, :public) } - let!(:private_project) { create(:empty_project, :private) } + let!(:public_project) { create(:project, :public) } + let!(:private_project) { create(:project, :private) } before do private_project.add_master(source_user) private_project.add_developer(current_user) public_project.add_master(source_user) - create(:event, :pushed, project: public_project, target: public_project, author: source_user) - create(:event, :pushed, project: private_project, target: private_project, author: source_user) + create(:push_event, project: public_project, author: source_user) + create(:push_event, project: private_project, author: source_user) end describe 'without a current user' do diff --git a/spec/finders/environments_finder_spec.rb b/spec/finders/environments_finder_spec.rb index 0c063f6d5ee..3a8a1e7de74 100644 --- a/spec/finders/environments_finder_spec.rb +++ b/spec/finders/environments_finder_spec.rb @@ -12,7 +12,7 @@ describe EnvironmentsFinder do context 'tagged deployment' do before do - create(:deployment, environment: environment, ref: '1.0', tag: true, sha: project.commit.id) + create(:deployment, environment: environment, ref: 'v1.1.0', tag: true, sha: project.commit.id) end it 'returns environment when with_tags is set' do diff --git a/spec/finders/events_finder_spec.rb b/spec/finders/events_finder_spec.rb index 30a2bd14f10..18d6c0cfd74 100644 --- a/spec/finders/events_finder_spec.rb +++ b/spec/finders/events_finder_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe EventsFinder do let(:user) { create(:user) } let(:other_user) { create(:user) } - let(:project1) { create(:empty_project, :private, creator_id: user.id, namespace: user.namespace) } - let(:project2) { create(:empty_project, :private, creator_id: user.id, namespace: user.namespace) } + let(:project1) { create(:project, :private, creator_id: user.id, namespace: user.namespace) } + let(:project2) { create(:project, :private, creator_id: user.id, namespace: user.namespace) } let(:closed_issue) { create(:closed_issue, project: project1, author: user) } let(:opened_merge_request) { create(:merge_request, source_project: project2, author: user) } let!(:closed_issue_event) { create(:event, project: project1, author: user, target: closed_issue, action: Event::CLOSED, created_at: Date.new(2016, 12, 30)) } diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb index 3c7c9bdcd08..c6d257bc479 100644 --- a/spec/finders/group_projects_finder_spec.rb +++ b/spec/finders/group_projects_finder_spec.rb @@ -7,11 +7,11 @@ describe GroupProjectsFinder do let(:finder) { described_class.new(group: group, current_user: current_user, options: options) } - let!(:public_project) { create(:empty_project, :public, group: group, path: '1') } - let!(:private_project) { create(:empty_project, :private, group: group, path: '2') } - let!(:shared_project_1) { create(:empty_project, :public, path: '3') } - let!(:shared_project_2) { create(:empty_project, :private, path: '4') } - let!(:shared_project_3) { create(:empty_project, :internal, path: '5') } + let!(:public_project) { create(:project, :public, group: group, path: '1') } + let!(:private_project) { create(:project, :private, group: group, path: '2') } + let!(:shared_project_1) { create(:project, :public, path: '3') } + let!(:shared_project_2) { create(:project, :private, path: '4') } + let!(:shared_project_3) { create(:project, :internal, path: '5') } before do shared_project_1.project_group_links.create(group_access: Gitlab::Access::MASTER, group: group) diff --git a/spec/finders/groups_finder_spec.rb b/spec/finders/groups_finder_spec.rb index 9e70cccc3c4..abc470788e1 100644 --- a/spec/finders/groups_finder_spec.rb +++ b/spec/finders/groups_finder_spec.rb @@ -80,7 +80,7 @@ describe GroupsFinder do context 'authorized to private project' do context 'project one level deep' do - let!(:subproject) { create(:empty_project, :private, namespace: private_subgroup) } + let!(:subproject) { create(:project, :private, namespace: private_subgroup) } before do subproject.add_guest(user) end @@ -98,7 +98,7 @@ describe GroupsFinder do context 'project two levels deep' do let!(:private_subsubgroup) { create(:group, :private, parent: private_subgroup) } - let!(:subsubproject) { create(:empty_project, :private, namespace: private_subsubgroup) } + let!(:subsubproject) { create(:project, :private, namespace: private_subsubgroup) } before do subsubproject.add_guest(user) end diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index bef4fd44331..8769a52863c 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe IssuesFinder do set(:user) { create(:user) } set(:user2) { create(:user) } - set(:project1) { create(:empty_project) } - set(:project2) { create(:empty_project) } + set(:project1) { create(:project) } + set(:project2) { create(:project) } set(:milestone) { create(:milestone, project: project1) } set(:label) { create(:label, project: project2) } set(:issue1) { create(:issue, author: user, assignees: [user], project: project1, milestone: milestone, title: 'gitlab', created_at: 1.week.ago) } @@ -87,9 +87,9 @@ describe IssuesFinder do context 'filtering by upcoming milestone' do let(:params) { { milestone_title: Milestone::Upcoming.name } } - let(:project_no_upcoming_milestones) { create(:empty_project, :public) } - let(:project_next_1_1) { create(:empty_project, :public) } - let(:project_next_8_8) { create(:empty_project, :public) } + let(:project_no_upcoming_milestones) { create(:project, :public) } + let(:project_next_1_1) { create(:project, :public) } + let(:project_next_8_8) { create(:project, :public) } let(:yesterday) { Date.today - 1.day } let(:tomorrow) { Date.today + 1.day } @@ -121,9 +121,9 @@ describe IssuesFinder do context 'filtering by started milestone' do let(:params) { { milestone_title: Milestone::Started.name } } - let(:project_no_started_milestones) { create(:empty_project, :public) } - let(:project_started_1_and_2) { create(:empty_project, :public) } - let(:project_started_8) { create(:empty_project, :public) } + let(:project_no_started_milestones) { create(:project, :public) } + let(:project_started_1_and_2) { create(:project, :public) } + let(:project_started_8) { create(:project, :public) } let(:yesterday) { Date.today - 1.day } let(:tomorrow) { Date.today + 1.day } @@ -268,7 +268,7 @@ describe IssuesFinder do it 'finds issues user can access due to group' do group = create(:group) - project = create(:empty_project, group: group) + project = create(:project, group: group) issue = create(:issue, project: project) group.add_user(user, :owner) @@ -296,7 +296,7 @@ describe IssuesFinder do let(:scope) { nil } it "doesn't return team-only issues to non team members" do - project = create(:empty_project, :public, :issues_private) + project = create(:project, :public, :issues_private) issue = create(:issue, project: project) expect(issues).not_to include(issue) @@ -315,7 +315,7 @@ describe IssuesFinder do describe '#with_confidentiality_access_check' do let(:guest) { create(:user) } set(:authorized_user) { create(:user) } - set(:project) { create(:empty_project, namespace: authorized_user.namespace) } + set(:project) { create(:project, namespace: authorized_user.namespace) } set(:public_issue) { create(:issue, project: project) } set(:confidential_issue) { create(:issue, project: project, confidential: true) } diff --git a/spec/finders/joined_groups_finder_spec.rb b/spec/finders/joined_groups_finder_spec.rb index 4c389746252..29a47e005a6 100644 --- a/spec/finders/joined_groups_finder_spec.rb +++ b/spec/finders/joined_groups_finder_spec.rb @@ -42,7 +42,7 @@ describe JoinedGroupsFinder do context 'if profile visitor is in one of the private group projects' do before do - project = create(:empty_project, :private, group: private_group, name: 'B', path: 'B') + project = create(:project, :private, group: private_group, name: 'B', path: 'B') project.add_user(profile_visitor, Gitlab::Access::DEVELOPER) end diff --git a/spec/finders/labels_finder_spec.rb b/spec/finders/labels_finder_spec.rb index 95d96354b77..afa2a40ed2a 100644 --- a/spec/finders/labels_finder_spec.rb +++ b/spec/finders/labels_finder_spec.rb @@ -6,11 +6,11 @@ describe LabelsFinder do let(:group_2) { create(:group) } let(:group_3) { create(:group) } - let(:project_1) { create(:empty_project, namespace: group_1) } - let(:project_2) { create(:empty_project, namespace: group_2) } - let(:project_3) { create(:empty_project) } - let(:project_4) { create(:empty_project, :public) } - let(:project_5) { create(:empty_project, namespace: group_1) } + let(:project_1) { create(:project, namespace: group_1) } + let(:project_2) { create(:project, namespace: group_2) } + let(:project_3) { create(:project) } + let(:project_4) { create(:project, :public) } + let(:project_5) { create(:project, namespace: group_1) } let!(:project_label_1) { create(:label, project: project_1, title: 'Label 1') } let!(:project_label_2) { create(:label, project: project_2, title: 'Label 2') } @@ -68,7 +68,7 @@ describe LabelsFinder do context 'as an administrator' do it 'does not return labels from another project' do # Purposefully creating a project with _nothing_ associated to it - isolated_project = create(:empty_project) + isolated_project = create(:project) admin = create(:admin) # project_3 has a label associated to it, which we don't want coming diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb index b46218bf72e..b54155a6704 100644 --- a/spec/finders/merge_requests_finder_spec.rb +++ b/spec/finders/merge_requests_finder_spec.rb @@ -4,9 +4,9 @@ describe MergeRequestsFinder do let(:user) { create :user } let(:user2) { create :user } - let(:project1) { create(:empty_project) } - let(:project2) { create(:empty_project, forked_from_project: project1) } - let(:project3) { create(:empty_project, :archived, forked_from_project: project1) } + let(:project1) { create(:project) } + let(:project2) { create(:project, forked_from_project: project1) } + let(:project3) { create(:project, :archived, forked_from_project: project1) } let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) } let!(:merge_request2) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1, state: 'closed') } @@ -67,7 +67,7 @@ describe MergeRequestsFinder do end context 'with created_after and created_before params' do - let(:project4) { create(:empty_project, forked_from_project: project1) } + let(:project4) { create(:project, forked_from_project: project1) } let!(:new_merge_request) do create(:merge_request, diff --git a/spec/finders/milestones_finder_spec.rb b/spec/finders/milestones_finder_spec.rb index 32ec983c5b8..8ae08656e01 100644 --- a/spec/finders/milestones_finder_spec.rb +++ b/spec/finders/milestones_finder_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe MilestonesFinder do let(:group) { create(:group) } - let(:project_1) { create(:empty_project, namespace: group) } - let(:project_2) { create(:empty_project, namespace: group) } + let(:project_1) { create(:project, namespace: group) } + let(:project_2) { create(:project, namespace: group) } let!(:milestone_1) { create(:milestone, group: group, title: 'one test', due_date: Date.today) } let!(:milestone_2) { create(:milestone, group: group) } let!(:milestone_3) { create(:milestone, project: project_1, state: 'active', due_date: Date.tomorrow) } diff --git a/spec/finders/move_to_project_finder_spec.rb b/spec/finders/move_to_project_finder_spec.rb index dea87980e25..e577083a2d0 100644 --- a/spec/finders/move_to_project_finder_spec.rb +++ b/spec/finders/move_to_project_finder_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' describe MoveToProjectFinder do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } - let(:no_access_project) { create(:empty_project) } - let(:guest_project) { create(:empty_project) } - let(:reporter_project) { create(:empty_project) } - let(:developer_project) { create(:empty_project) } - let(:master_project) { create(:empty_project) } + let(:no_access_project) { create(:project) } + let(:guest_project) { create(:project) } + let(:reporter_project) { create(:project) } + let(:developer_project) { create(:project) } + let(:master_project) { create(:project) } subject { described_class.new(user) } @@ -37,7 +37,7 @@ describe MoveToProjectFinder do it 'does not return archived projects' do reporter_project.team << [user, :reporter] reporter_project.archive! - other_reporter_project = create(:empty_project) + other_reporter_project = create(:project) other_reporter_project.team << [user, :reporter] expect(subject.execute(project).to_a).to eq([other_reporter_project]) @@ -46,7 +46,7 @@ describe MoveToProjectFinder do it 'does not return projects for which issues are disabled' do reporter_project.team << [user, :reporter] reporter_project.update_attributes(issues_enabled: false) - other_reporter_project = create(:empty_project) + other_reporter_project = create(:project) other_reporter_project.team << [user, :reporter] expect(subject.execute(project).to_a).to eq([other_reporter_project]) @@ -83,10 +83,10 @@ describe MoveToProjectFinder do end it 'returns projects matching a search query' do - foo_project = create(:empty_project) + foo_project = create(:project) foo_project.team << [user, :master] - wadus_project = create(:empty_project, name: 'wadus') + wadus_project = create(:project, name: 'wadus') wadus_project.team << [user, :master] expect(subject.execute(project).to_a).to eq([wadus_project, foo_project]) diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb index ba6bbb3bce0..900fa2b12d1 100644 --- a/spec/finders/notes_finder_spec.rb +++ b/spec/finders/notes_finder_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe NotesFinder do let(:user) { create :user } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do project.team << [user, :master] @@ -43,7 +43,7 @@ describe NotesFinder do context 'on restricted projects' do let(:project) do - create(:empty_project, + create(:project, :public, :issues_private, :snippets_private, @@ -156,7 +156,7 @@ describe NotesFinder do end describe '.search' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:note) { create(:note_on_issue, note: 'WoW', project: project) } it 'returns notes with matching content' do diff --git a/spec/finders/personal_projects_finder_spec.rb b/spec/finders/personal_projects_finder_spec.rb index 304b0fb67fb..d0113ba87df 100644 --- a/spec/finders/personal_projects_finder_spec.rb +++ b/spec/finders/personal_projects_finder_spec.rb @@ -4,14 +4,14 @@ describe PersonalProjectsFinder do let(:source_user) { create(:user) } let(:current_user) { create(:user) } let(:finder) { described_class.new(source_user) } - let!(:public_project) { create(:empty_project, :public, namespace: source_user.namespace) } + let!(:public_project) { create(:project, :public, namespace: source_user.namespace) } let!(:private_project) do - create(:empty_project, :private, namespace: source_user.namespace, path: 'mepmep') + create(:project, :private, namespace: source_user.namespace, path: 'mepmep') end let!(:internal_project) do - create(:empty_project, :internal, namespace: source_user.namespace, path: 'C') + create(:project, :internal, namespace: source_user.namespace, path: 'C') end before do diff --git a/spec/finders/pipeline_schedules_finder_spec.rb b/spec/finders/pipeline_schedules_finder_spec.rb index e184a87c9c7..b9538649b3f 100644 --- a/spec/finders/pipeline_schedules_finder_spec.rb +++ b/spec/finders/pipeline_schedules_finder_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe PipelineSchedulesFinder do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:active_schedule) { create(:ci_pipeline_schedule, project: project) } let!(:inactive_schedule) { create(:ci_pipeline_schedule, :inactive, project: project) } diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb index 03d98459e8c..a5de586e869 100644 --- a/spec/finders/projects_finder_spec.rb +++ b/spec/finders/projects_finder_spec.rb @@ -6,19 +6,19 @@ describe ProjectsFinder do let(:group) { create(:group, :public) } let!(:private_project) do - create(:empty_project, :private, name: 'A', path: 'A') + create(:project, :private, name: 'A', path: 'A') end let!(:internal_project) do - create(:empty_project, :internal, group: group, name: 'B', path: 'B') + create(:project, :internal, group: group, name: 'B', path: 'B') end let!(:public_project) do - create(:empty_project, :public, group: group, name: 'C', path: 'C') + create(:project, :public, group: group, name: 'C', path: 'C') end let!(:shared_project) do - create(:empty_project, :private, name: 'D', path: 'D') + create(:project, :private, name: 'D', path: 'D') end let(:params) { {} } @@ -90,7 +90,7 @@ describe ProjectsFinder do end describe 'filter by personal' do - let!(:personal_project) { create(:empty_project, namespace: user.namespace) } + let!(:personal_project) { create(:project, namespace: user.namespace) } let(:params) { { personal: true } } it { is_expected.to eq([personal_project]) } @@ -109,7 +109,7 @@ describe ProjectsFinder do end describe 'filter by archived' do - let!(:archived_project) { create(:empty_project, :public, :archived, name: 'E', path: 'E') } + let!(:archived_project) { create(:project, :public, :archived, name: 'E', path: 'E') } context 'non_archived=true' do let(:params) { { non_archived: true } } @@ -139,7 +139,7 @@ describe ProjectsFinder do describe 'filter by owned' do let(:params) { { owned: true } } - let!(:owned_project) { create(:empty_project, :private, namespace: current_user.namespace) } + let!(:owned_project) { create(:project, :private, namespace: current_user.namespace) } it { is_expected.to eq([owned_project]) } end diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb index 35f1683eef9..7ae7b7d2140 100644 --- a/spec/finders/snippets_finder_spec.rb +++ b/spec/finders/snippets_finder_spec.rb @@ -5,8 +5,8 @@ describe SnippetsFinder do let(:user1) { create :user } let(:group) { create :group, :public } - let(:project1) { create(:empty_project, :public, group: group) } - let(:project2) { create(:empty_project, :private, group: group) } + let(:project1) { create(:project, :public, group: group) } + let(:project2) { create(:project, :private, group: group) } context 'all snippets visible to a user' do let!(:snippet1) { create(:personal_snippet, :private) } diff --git a/spec/finders/todos_finder_spec.rb b/spec/finders/todos_finder_spec.rb index 8be447418b0..884ce22091e 100644 --- a/spec/finders/todos_finder_spec.rb +++ b/spec/finders/todos_finder_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe TodosFinder do describe '#execute' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:finder) { described_class } before do diff --git a/spec/fixtures/api/schemas/entities/merge_request.json b/spec/fixtures/api/schemas/entities/merge_request.json index 7ffa82fc4bd..2f12b671dec 100644 --- a/spec/fixtures/api/schemas/entities/merge_request.json +++ b/spec/fixtures/api/schemas/entities/merge_request.json @@ -19,7 +19,6 @@ "human_time_estimate": { "type": ["integer", "null"] }, "human_total_time_spent": { "type": ["integer", "null"] }, "in_progress_merge_commit_sha": { "type": ["string", "null"] }, - "locked_at": { "type": ["string", "null"] }, "merge_error": { "type": ["string", "null"] }, "merge_commit_sha": { "type": ["string", "null"] }, "merge_params": { "type": ["object", "null"] }, @@ -94,7 +93,8 @@ "commit_change_content_path": { "type": "string" }, "remove_wip_path": { "type": "string" }, "commits_count": { "type": "integer" }, - "remove_source_branch": { "type": ["boolean", "null"] } + "remove_source_branch": { "type": ["boolean", "null"] }, + "merge_ongoing": { "type": "boolean" } }, "additionalProperties": false } diff --git a/spec/fixtures/api/schemas/public_api/v4/comment.json b/spec/fixtures/api/schemas/public_api/v4/comment.json new file mode 100644 index 00000000000..52cfe86aeeb --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/comment.json @@ -0,0 +1,21 @@ +{ + "type": "object", + "required" : [ + "name", + "message", + "commit", + "release" + ], + "properties" : { + "name": { "type": "string" }, + "message": { "type": ["string", "null"] }, + "commit": { "$ref": "commit/basic.json" }, + "release": { + "oneOf": [ + { "type": "null" }, + { "$ref": "release.json" } + ] + } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/commit/detail.json b/spec/fixtures/api/schemas/public_api/v4/commit/detail.json new file mode 100644 index 00000000000..b7b2535c204 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commit/detail.json @@ -0,0 +1,16 @@ +{ + "type": "object", + "allOf": [ + { "$ref": "basic.json" }, + { + "required" : [ + "stats", + "status" + ], + "properties": { + "stats": { "$ref": "../commit_stats.json" }, + "status": { "type": ["string", "null"] } + } + } + ] +} diff --git a/spec/fixtures/api/schemas/public_api/v4/commit_note.json b/spec/fixtures/api/schemas/public_api/v4/commit_note.json new file mode 100644 index 00000000000..02081989271 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commit_note.json @@ -0,0 +1,19 @@ +{ + "type": "object", + "required" : [ + "note", + "path", + "line", + "line_type", + "author", + "created_at" + ], + "properties" : { + "note": { "type": ["string", "null"] }, + "path": { "type": ["string", "null"] }, + "line": { "type": ["integer", "null"] }, + "line_type": { "type": ["string", "null"] }, + "author": { "$ref": "user/basic.json" }, + "created_at": { "type": "date" } + } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/commit_notes.json b/spec/fixtures/api/schemas/public_api/v4/commit_notes.json new file mode 100644 index 00000000000..d65a7d677ea --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commit_notes.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "commit_note.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/commit_stats.json b/spec/fixtures/api/schemas/public_api/v4/commit_stats.json new file mode 100644 index 00000000000..779384c62e6 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commit_stats.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "required" : [ + "additions", + "deletions", + "total" + ], + "properties" : { + "additions": { "type": "integer" }, + "deletions": { "type": "integer" }, + "total": { "type": "integer" } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/commits.json b/spec/fixtures/api/schemas/public_api/v4/commits.json new file mode 100644 index 00000000000..98b17a96071 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commits.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "commit/basic.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/release.json b/spec/fixtures/api/schemas/public_api/v4/release.json new file mode 100644 index 00000000000..6612c2a9911 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/release.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "required" : [ + "tag_name", + "description" + ], + "properties" : { + "tag_name": { "type": ["string", "null"] }, + "description": { "type": "string" } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/tag.json b/spec/fixtures/api/schemas/public_api/v4/tag.json new file mode 100644 index 00000000000..52cfe86aeeb --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/tag.json @@ -0,0 +1,21 @@ +{ + "type": "object", + "required" : [ + "name", + "message", + "commit", + "release" + ], + "properties" : { + "name": { "type": "string" }, + "message": { "type": ["string", "null"] }, + "commit": { "$ref": "commit/basic.json" }, + "release": { + "oneOf": [ + { "type": "null" }, + { "$ref": "release.json" } + ] + } + }, + "additionalProperties": false +} diff --git a/spec/fixtures/api/schemas/public_api/v4/tags.json b/spec/fixtures/api/schemas/public_api/v4/tags.json new file mode 100644 index 00000000000..eae352e7f87 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/tags.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "tag.json" } +} diff --git a/spec/fixtures/api/schemas/public_api/v4/user/basic.json b/spec/fixtures/api/schemas/public_api/v4/user/basic.json new file mode 100644 index 00000000000..9f69d31971c --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/user/basic.json @@ -0,0 +1,15 @@ +{ + "type": "object", + "required": [ + "id", + "state", + "avatar_url", + "web_url" + ], + "properties": { + "id": { "type": "integer" }, + "state": { "type": "string" }, + "avatar_url": { "type": "string" }, + "web_url": { "type": "string" } + } +} diff --git a/spec/fixtures/encoding/Japanese.md b/spec/fixtures/encoding/Japanese.md new file mode 100644 index 00000000000..dd469c9f232 --- /dev/null +++ b/spec/fixtures/encoding/Japanese.md @@ -0,0 +1,42 @@ ++++ +date = "2017-05-21T13:05:07+09:00" +title = "レイヤ" +weight = 10 + ++++ + +## ã“ã®ãƒãƒ¥ãƒ¼ãƒˆãƒªã‚¢ãƒ«ã§æ‰±ã†å†…容 +1. Redactedã«ãŠã‘ã‚‹2D開発ã§ã®ãƒ¬ã‚¤ãƒ¤ã®åŸºæœ¬çš„ãªæ¦‚è¦ +2. スクリーン上ã®ã‚¹ãƒ—ライトã®é †åºä»˜ã‘方法 + +### Redactedã«ãŠã‘ã‚‹2D開発ã§ã®ãƒ¬ã‚¤ãƒ¤ã®åŸºæœ¬çš„ãªæ¦‚è¦ +2Dã«ãŠã„ã¦ã¯z軸ãŒå˜åœ¨ã—ãªã„ãŸã‚ã€ã‚·ãƒ¼ãƒ³å†…è¦ç´ ã®æç”»é †ã‚’åˆ¶å¾¡ã™ã‚‹ãŸã‚ã«ã¯ä»£æ›¿ã¨ãªã‚‹ä»•組ã¿ãŒå¿…è¦ã§ã™ã€‚ +Redactedã§ã¯**レイヤ**ã«ãŠã‘ã‚‹**zIndex**属性を制御å¯èƒ½ã«ã™ã‚‹ã“ã¨ã§ã€ã“ã®èª²é¡Œã‚’解決ã—ã¦ã„ã¾ã™ã€‚ +**デフォルトã§ã¯ã€zIndexã¯0ã¨ãªã‚Šã‚ªãƒ–ジェクトã¯ãƒ¬ã‚¤ãƒ¤ã«è¿½åŠ ã•れãŸé †ç•ªã«æç”»ã•れã¾ã™ã€‚** + +レイヤã«ã¯ã„ãã¤ã‹ã®é‡è¦ãªç‰¹æ€§ãŒã‚りã¾ã™ã€‚ + +* レイヤã«ã¯ãƒ¬ã‚¤ãƒ¤åŒ–ã•れãŸã‚ªãƒ–ジェクトã®ã¿ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚(**3Dモデルã¯çµ¶å¯¾ã«è¿½åŠ ã—ãªã„ã§ãã ã•ã„**) +* レイヤã¯ãƒ¬ã‚¤ãƒ¤åŒ–ã•れãŸã‚ªãƒ–ジェクトã§ã™ã€‚(ã—ãŸãŒã£ã¦ã€ãƒ¬ã‚¤ãƒ¤ã«ã¯ä»–ã®ãƒ¬ã‚¤ãƒ¤ã‚’å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™) +* レイヤ化ã•れãŸã‚ªãƒ–ジェクトã¯ã€æœ€å¤§ã§1ã¤ã®ãƒ¬ã‚¤ãƒ¤ã«å±žã™ã“ã¨ãŒã§ãã¾ã™ã€‚ + +ãƒ¬ã‚¤ãƒ¤ã‚’ç›´æŽ¥åˆæœŸåŒ–ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“ãŒã€ãã®æ´¾ç”Ÿã‚¯ãƒ©ã‚¹ã¯åˆæœŸåŒ–ã™ã‚‹ã“ã¨ãŒå¯èƒ½ã§ã™ã€‚**Scene2D**ã¨**コンテナ**ã¯ã€**レイヤ**ã‹ã‚‰æ´¾ç”Ÿã™ã‚‹2ã¤ã®ä¸»ãªã‚ªãƒ–ジェクトã§ã™ã€‚ã™ã¹ã¦ã®åˆæœŸåŒ–(createContainerã€instantiateã€...)ã¯ãƒ¬ã‚¤ãƒ¤ä¸Šã§è¡Œã‚れã¾ã™ã€‚ã¤ã¾ã‚Šã€2Dã§åˆæœŸåŒ–ã•れるã™ã¹ã¦ã®ã‚ªãƒ–ジェクトã¯ã€zIndexプãƒãƒ‘ティをæŒã¤ãƒ¬ã‚¤ãƒ¤åŒ–ã•れãŸã‚ªãƒ–ジェクトã§ã™ã€‚ + +**zIndexã¯ã‚°ãƒãƒ¼ãƒãƒ«ã§ã¯ã‚りã¾ã›ã‚“!** + +CSSã¨ã¯ç•°ãªã‚Šã€zIndexã¯ã™ã¹ã¦ã®ã‚ªãƒ–ジェクトã«å¯¾ã—ã¦ã‚°ãƒãƒ¼ãƒãƒ«ã§ã¯ã‚りã¾ã›ã‚“。zIndexプãƒãƒ‘ティã¯è¦ªãƒ¬ã‚¤ãƒ¤ã«å¯¾ã—ã¦ãƒãƒ¼ã‚«ãƒ«ã§ã™ã€‚詳細ã«ã¤ãã¾ã—ã¦ã¯ã€ã‚³ãƒ³ãƒ†ãƒŠãƒãƒ¥ãƒ¼ãƒˆãƒªã‚¢ãƒ«ã§èª¬æ˜Žã—ã¦ã„ã¾ã™ã€‚ [TODO: Link]。 + +### スクリーン上ã®ã‚¹ãƒ—ライトã®é †åºä»˜ã‘方法 +ã“れã¾ã§å¦ã‚“ã ã“ã¨ã‚’生ã‹ã—ã¦ã€ç”»é¢ã«ã‚¹ãƒ—ライトを表示ã—ã¦ã€zIndexã®è¨å®šã‚’ã—ã¦ã¿ã¾ã—ょã†ï¼ + +* ã¾ãšã€æœ€åˆã« (A,B,C) スプライトを生æˆã—ã¾ã™ã€‚ +* スプライトAをシーンã«è¿½åŠ ã—ã¾ã™ï¼ˆzIndex = 0ã€æ¨™æº–色) +* スプライトBをシーン2ã«è¿½åŠ ã™ã‚‹ã¨ã€**スプライトAã®ä¸Šã«**表示ã•れã¾ã™ï¼ˆzIndex = 0ã€èµ¤è‰²ï¼‰ +* 最後ã«ã‚¹ãƒ—ライトCをシーンã«è¿½åŠ ã—ã¾ã™ï¼ˆé’色)ãŒã€ã‚¹ãƒ—ライトã®zIndexã‚’-1ã«è¨å®šã™ã‚‹ã¨ã€ã‚¹ãƒ—ライトã¯Aã¨Bã®å¾Œå´ã«è¡¨ç¤ºã•れã¾ã™ã€‚ + +{{< code "static/tutorials/layers.html" >}} + +### ソースコード全体 +```js +{{< snippet "static/tutorials/layers.html" >}} +``` diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb index 58b43805705..4f46e40ce7a 100644 --- a/spec/fixtures/markdown.md.erb +++ b/spec/fixtures/markdown.md.erb @@ -227,8 +227,11 @@ References should be parseable even inside _<%= merge_request.to_reference %>_ e - Milestone in another project: <%= xmilestone.to_reference(project) %> - Ignored in code: `<%= simple_milestone.to_reference %>` - Ignored in links: [Link to <%= simple_milestone.to_reference %>](#milestone-link) -- Milestone by URL: <%= urls.project_milestone_url(milestone.project, milestone) %> +- Milestone by URL: <%= urls.milestone_url(milestone) %> - Link to milestone by URL: [Milestone](<%= milestone.to_reference %>) +- Group milestone by name: <%= Milestone.reference_prefix %><%= group_milestone.name %> +- Group milestone by name in quotes: <%= group_milestone.to_reference(format: :name) %> +- Group milestone by URL is ignore: <%= urls.milestone_url(group_milestone) %> ### Task Lists diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index ac5a58ac189..10bc5f2ecd2 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -58,7 +58,7 @@ describe ApplicationHelper do describe 'project_icon' do it 'returns an url for the avatar' do - project = create(:empty_project, avatar: File.open(uploaded_image_temp_path)) + project = create(:project, avatar: File.open(uploaded_image_temp_path)) avatar_url = "/uploads/-/system/project/avatar/#{project.id}/banana_sample.gif" expect(helper.project_icon(project.full_path).to_s) @@ -72,7 +72,7 @@ describe ApplicationHelper do end it 'gives uploaded icon when present' do - project = create(:empty_project) + project = create(:project) allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true) diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb index bd3a3d24b84..c654151564e 100644 --- a/spec/helpers/blob_helper_spec.rb +++ b/spec/helpers/blob_helper_spec.rb @@ -108,7 +108,7 @@ describe BlobHelper do context 'viewer related' do include FakeBlobHelpers - let(:project) { build(:empty_project, lfs_enabled: true) } + let(:project) { build(:project, lfs_enabled: true) } before do allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb index 7ecb75da8ce..250ba239033 100644 --- a/spec/helpers/button_helper_spec.rb +++ b/spec/helpers/button_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe ButtonHelper do describe 'http_clone_button' do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { build_stubbed(:project) } let(:has_tooltip_class) { 'has-tooltip' } def element diff --git a/spec/helpers/ci_status_helper_spec.rb b/spec/helpers/ci_status_helper_spec.rb index e6bb953e9d8..6a3945c0ebc 100644 --- a/spec/helpers/ci_status_helper_spec.rb +++ b/spec/helpers/ci_status_helper_spec.rb @@ -48,7 +48,7 @@ describe CiStatusHelper do describe "#pipeline_status_cache_key" do it "builds a cache key for pipeline status" do pipeline_status = Gitlab::Cache::Ci::ProjectPipelineStatus.new( - build(:project), + build_stubbed(:project), pipeline_info: { sha: "123abc", status: "success" diff --git a/spec/helpers/commits_helper_spec.rb b/spec/helpers/commits_helper_spec.rb index c245bb439db..7179185285c 100644 --- a/spec/helpers/commits_helper_spec.rb +++ b/spec/helpers/commits_helper_spec.rb @@ -28,7 +28,7 @@ describe CommitsHelper do end describe '#view_on_environment_button' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:environment) { create(:environment, external_url: 'http://example.com') } let(:path) { 'source/file.html' } let(:sha) { RepoHelpers.sample_commit.id } diff --git a/spec/helpers/defer_script_tag_helper_spec.rb b/spec/helpers/defer_script_tag_helper_spec.rb new file mode 100644 index 00000000000..d10b6f134e4 --- /dev/null +++ b/spec/helpers/defer_script_tag_helper_spec.rb @@ -0,0 +1,13 @@ +# coding: utf-8 +require 'spec_helper' + +describe DeferScriptTagHelper do + describe 'script tag' do + script_url = 'test.js' + + it 'returns an script tag with defer=true' do + expect(javascript_include_tag(script_url).to_s) + .to eq "<script src=\"/javascripts/#{script_url}\" defer=\"defer\"></script>" + end + end +end diff --git a/spec/helpers/diff_helper_spec.rb b/spec/helpers/diff_helper_spec.rb index 060c112e20d..f81a9b6492c 100644 --- a/spec/helpers/diff_helper_spec.rb +++ b/spec/helpers/diff_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe DiffHelper do include RepoHelpers - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:repository) { project.repository } let(:commit) { project.commit(sample_commit.id) } let(:diffs) { commit.raw_diffs } diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb index c3bd0cb3542..aa138f25bd3 100644 --- a/spec/helpers/events_helper_spec.rb +++ b/spec/helpers/events_helper_spec.rb @@ -72,13 +72,13 @@ describe EventsHelper do end it 'preserves style attribute for a label that can be accessed by current_user' do - project = create(:empty_project, :public) + project = create(:project, :public) expect(format_event_note(project)).to match(/span class=.*style=.*/) end it 'does not style a label that can not be accessed by current_user' do - project = create(:empty_project, :private) + project = create(:project, :private) expect(format_event_note(project)).to eq("<p>#{input}</p>") end diff --git a/spec/helpers/gitlab_routing_helper_spec.rb b/spec/helpers/gitlab_routing_helper_spec.rb index 717ac1962d1..a44b200c5da 100644 --- a/spec/helpers/gitlab_routing_helper_spec.rb +++ b/spec/helpers/gitlab_routing_helper_spec.rb @@ -1,6 +1,9 @@ require 'spec_helper' describe GitlabRoutingHelper do + let(:project) { build_stubbed(:project) } + let(:group) { build_stubbed(:group) } + describe 'Project URL helpers' do describe '#project_member_path' do let(:project_member) { create(:project_member) } @@ -9,14 +12,10 @@ describe GitlabRoutingHelper do end describe '#request_access_project_members_path' do - let(:project) { build_stubbed(:empty_project) } - it { expect(request_access_project_members_path(project)).to eq request_access_project_project_members_path(project) } end describe '#leave_project_members_path' do - let(:project) { build_stubbed(:empty_project) } - it { expect(leave_project_members_path(project)).to eq leave_project_project_members_path(project) } end @@ -35,8 +34,6 @@ describe GitlabRoutingHelper do describe 'Group URL helpers' do describe '#group_members_url' do - let(:group) { build_stubbed(:group) } - it { expect(group_members_url(group)).to eq group_group_members_url(group) } end @@ -47,14 +44,10 @@ describe GitlabRoutingHelper do end describe '#request_access_group_members_path' do - let(:group) { build_stubbed(:group) } - it { expect(request_access_group_members_path(group)).to eq request_access_group_group_members_path(group) } end describe '#leave_group_members_path' do - let(:group) { build_stubbed(:group) } - it { expect(leave_group_members_path(group)).to eq leave_group_group_members_path(group) } end diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index 3a246f10283..9d6e03e3868 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -23,7 +23,7 @@ describe GroupsHelper do describe 'group_lfs_status' do let(:group) { create(:group) } - let!(:project) { create(:empty_project, namespace_id: group.id) } + let!(:project) { create(:project, namespace_id: group.id) } before do allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) @@ -47,7 +47,7 @@ describe GroupsHelper do context 'more than one project in group' do before do - create(:empty_project, namespace_id: group.id) + create(:project, namespace_id: group.id) end context 'LFS enabled in group' do diff --git a/spec/helpers/hooks_helper_spec.rb b/spec/helpers/hooks_helper_spec.rb index 9f0004bf8cf..2e21f1134b1 100644 --- a/spec/helpers/hooks_helper_spec.rb +++ b/spec/helpers/hooks_helper_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe HooksHelper do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:project_hook) { create(:project_hook, project: project) } let(:system_hook) { create(:system_hook) } let(:trigger) { 'push_events' } diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb index 9524a101e74..dc3100311f8 100644 --- a/spec/helpers/issues_helper_spec.rb +++ b/spec/helpers/issues_helper_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" describe IssuesHelper do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create :issue, project: project } let(:ext_project) { create :redmine_project } diff --git a/spec/helpers/labels_helper_spec.rb b/spec/helpers/labels_helper_spec.rb index a8d6044fda7..36d6e495ed0 100644 --- a/spec/helpers/labels_helper_spec.rb +++ b/spec/helpers/labels_helper_spec.rb @@ -2,18 +2,18 @@ require 'spec_helper' describe LabelsHelper do describe 'link_to_label' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:label) { create(:label, project: project) } context 'without subject' do it "uses the label's project" do - expect(link_to_label(label)).to match %r{<a href="/#{label.project.path_with_namespace}/issues\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label)).to match %r{<a href="/#{label.project.full_path}/issues\?label_name%5B%5D=#{label.name}">.*</a>} end end context 'with a project as subject' do let(:namespace) { build(:namespace, name: 'foo3') } - let(:another_project) { build(:empty_project, namespace: namespace, name: 'bar3') } + let(:another_project) { build(:project, namespace: namespace, name: 'bar3') } it 'links to project issues page' do expect(link_to_label(label, subject: another_project)).to match %r{<a href="/foo3/bar3/issues\?label_name%5B%5D=#{label.name}">.*</a>} @@ -32,7 +32,7 @@ describe LabelsHelper do ['issue', :issue, 'merge_request', :merge_request].each do |type| context "set to #{type}" do it 'links to correct page' do - expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.path_with_namespace}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>} + expect(link_to_label(label, type: type)).to match %r{<a href="/#{label.project.full_path}/#{type.to_s.pluralize}\?label_name%5B%5D=#{label.name}">.*</a>} end end end diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index 4b6a351cf70..70eb01c9c44 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -210,11 +210,11 @@ describe MarkupHelper do describe '#cross_project_reference' do it 'shows the full MR reference' do - expect(helper.cross_project_reference(project, merge_request)).to include(project.path_with_namespace) + expect(helper.cross_project_reference(project, merge_request)).to include(project.full_path) end it 'shows the full issue reference' do - expect(helper.cross_project_reference(project, issue)).to include(project.path_with_namespace) + expect(helper.cross_project_reference(project, issue)).to include(project.full_path) end end end diff --git a/spec/helpers/members_helper_spec.rb b/spec/helpers/members_helper_spec.rb index 2b455571d52..33186cf50d5 100644 --- a/spec/helpers/members_helper_spec.rb +++ b/spec/helpers/members_helper_spec.rb @@ -11,7 +11,7 @@ describe MembersHelper do describe '#remove_member_message' do let(:requester) { create(:user) } - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:project_member) { build(:project_member, project: project) } let(:project_member_invite) { build(:project_member, project: project).tap { |m| m.generate_invite_token! } } let(:project_member_request) { project.request_access(requester) } @@ -32,7 +32,7 @@ describe MembersHelper do describe '#remove_member_title' do let(:requester) { create(:user) } - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:project_member) { build(:project_member, project: project) } let(:project_member_request) { project.request_access(requester) } let(:group) { create(:group, :access_requestable) } @@ -46,7 +46,7 @@ describe MembersHelper do end describe '#leave_confirmation_message' do - let(:project) { build_stubbed(:empty_project) } + let(:project) { build_stubbed(:project) } let(:group) { build_stubbed(:group) } let(:user) { build_stubbed(:user) } diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb index 493a4ff9a93..7d1c17909bf 100644 --- a/spec/helpers/merge_requests_helper_spec.rb +++ b/spec/helpers/merge_requests_helper_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe MergeRequestsHelper do describe 'ci_build_details_path' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:merge_request) { MergeRequest.new } let(:ci_service) { CiService.new } let(:last_commit) { Ci::Pipeline.new({}) } @@ -30,12 +30,12 @@ describe MergeRequestsHelper do end describe 'within different projects' do - let(:project) { create(:empty_project) } - let(:fork_project) { create(:empty_project, forked_from_project: project) } + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } let(:merge_request) { create(:merge_request, source_project: fork_project, target_project: project) } subject { format_mr_branch_names(merge_request) } - let(:source_title) { "#{fork_project.path_with_namespace}:#{merge_request.source_branch}" } - let(:target_title) { "#{project.path_with_namespace}:#{merge_request.target_branch}" } + let(:source_title) { "#{fork_project.full_path}:#{merge_request.source_branch}" } + let(:target_title) { "#{project.full_path}:#{merge_request.target_branch}" } it { is_expected.to eq([source_title, target_title]) } end diff --git a/spec/helpers/milestones_helper_spec.rb b/spec/helpers/milestones_helper_spec.rb index b8f9c02a486..70b4a89cb86 100644 --- a/spec/helpers/milestones_helper_spec.rb +++ b/spec/helpers/milestones_helper_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe MilestonesHelper do describe '#milestones_filter_dropdown_path' do - let(:project) { create(:empty_project) } - let(:project2) { create(:empty_project) } + let(:project) { create(:project) } + let(:project2) { create(:project) } let(:group) { create(:group) } context 'when @project present' do @@ -57,7 +57,7 @@ describe MilestonesHelper do end describe '#milestone_counts' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:counts) { helper.milestone_counts(project.milestones) } context 'when there are milestones' do diff --git a/spec/helpers/milestones_routing_helper_spec.rb b/spec/helpers/milestones_routing_helper_spec.rb new file mode 100644 index 00000000000..dc13a43c2ab --- /dev/null +++ b/spec/helpers/milestones_routing_helper_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe MilestonesRoutingHelper do + let(:project) { build_stubbed(:project) } + let(:group) { build_stubbed(:group) } + + describe '#milestone_path' do + context 'for a group milestone' do + let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) } + + it 'links to the group milestone page' do + expect(milestone_path(milestone)) + .to eq(group_milestone_path(group, milestone)) + end + end + + context 'for a project milestone' do + let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) } + + it 'links to the project milestone page' do + expect(milestone_path(milestone)) + .to eq(project_milestone_path(project, milestone)) + end + end + end + + describe '#milestone_url' do + context 'for a group milestone' do + let(:milestone) { build_stubbed(:milestone, group: group, iid: 1) } + + it 'links to the group milestone page' do + expect(milestone_url(milestone)) + .to eq(group_milestone_url(group, milestone)) + end + end + + context 'for a project milestone' do + let(:milestone) { build_stubbed(:milestone, project: project, iid: 1) } + + it 'links to the project milestone page' do + expect(milestone_url(milestone)) + .to eq(project_milestone_url(project, milestone)) + end + end + end +end diff --git a/spec/helpers/notes_helper_spec.rb b/spec/helpers/notes_helper_spec.rb index 56f252ba273..9921ca1af33 100644 --- a/spec/helpers/notes_helper_spec.rb +++ b/spec/helpers/notes_helper_spec.rb @@ -5,7 +5,7 @@ describe NotesHelper do let(:owner) { create(:owner) } let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } let(:master) { create(:user) } let(:reporter) { create(:user) } let(:guest) { create(:user) } @@ -30,7 +30,7 @@ describe NotesHelper do end it 'handles access in different projects' do - second_project = create(:empty_project) + second_project = create(:project) second_project.team << [master, :reporter] other_note = create(:note, author: master, project: second_project) @@ -40,7 +40,7 @@ describe NotesHelper do end describe '#discussion_path' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } context 'for a merge request discusion' do let(:merge_request) { create(:merge_request, source_project: project, target_project: project, importing: true) } @@ -191,7 +191,7 @@ describe NotesHelper do it 'return project notes path for project snippet' do namespace = create(:namespace, path: 'nm') - @project = create(:empty_project, path: 'test', namespace: namespace) + @project = create(:project, path: 'test', namespace: namespace) @snippet = create(:project_snippet, project: @project) @noteable = @snippet @@ -200,7 +200,7 @@ describe NotesHelper do it 'return project notes path for other noteables' do namespace = create(:namespace, path: 'nm') - @project = create(:empty_project, path: 'test', namespace: namespace) + @project = create(:project, path: 'test', namespace: namespace) @noteable = create(:issue, project: @project) expect(helper.notes_url).to eq("/nm/test/noteable/issue/#{@noteable.id}/notes") @@ -216,7 +216,7 @@ describe NotesHelper do it 'return project notes path for project snippet' do namespace = create(:namespace, path: 'nm') - @project = create(:empty_project, path: 'test', namespace: namespace) + @project = create(:project, path: 'test', namespace: namespace) note = create(:note_on_project_snippet, project: @project) expect(helper.note_url(note)).to eq("/nm/test/notes/#{note.id}") @@ -224,7 +224,7 @@ describe NotesHelper do it 'return project notes path for other noteables' do namespace = create(:namespace, path: 'nm') - @project = create(:empty_project, path: 'test', namespace: namespace) + @project = create(:project, path: 'test', namespace: namespace) note = create(:note_on_issue, project: @project) expect(helper.note_url(note)).to eq("/nm/test/notes/#{note.id}") @@ -241,7 +241,7 @@ describe NotesHelper do it 'returns namespace, project and note for project snippet' do namespace = create(:namespace, path: 'nm') - @project = create(:empty_project, path: 'test', namespace: namespace) + @project = create(:project, path: 'test', namespace: namespace) @snippet = create(:project_snippet, project: @project) @note = create(:note_on_personal_snippet) @@ -250,7 +250,7 @@ describe NotesHelper do it 'returns namespace, project and note path for other noteables' do namespace = create(:namespace, path: 'nm') - @project = create(:empty_project, path: 'test', namespace: namespace) + @project = create(:project, path: 'test', namespace: namespace) @note = create(:note_on_issue, project: @project) expect(helper.form_resources).to eq([@project.namespace, @project, @note]) @@ -258,7 +258,7 @@ describe NotesHelper do end describe '#noteable_note_url' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:note) { create(:note_on_issue, noteable: issue, project: project) } diff --git a/spec/helpers/pagination_helper_spec.rb b/spec/helpers/pagination_helper_spec.rb new file mode 100644 index 00000000000..e235475fb47 --- /dev/null +++ b/spec/helpers/pagination_helper_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe PaginationHelper do + describe '#paginate_collection' do + let(:collection) { User.all.page(1) } + + it 'paginates a collection without using a COUNT' do + without_count = collection.without_count + + expect(helper).to receive(:paginate_without_count) + .with(without_count) + .and_call_original + + helper.paginate_collection(without_count) + end + + it 'paginates a collection using a COUNT' do + expect(helper).to receive(:paginate_with_count).and_call_original + + helper.paginate_collection(collection) + end + end +end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 45066a60f50..d1efa318d14 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -46,25 +46,25 @@ describe ProjectsHelper do end describe "readme_cache_key" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do helper.instance_variable_set(:@project, project) end it "returns a valid cach key" do - expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-#{project.commit.id}-readme") + expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-#{project.commit.id}-readme") end it "returns a valid cache key if HEAD does not exist" do allow(project).to receive(:commit) { nil } - expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-nil-readme") + expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-nil-readme") end end describe "#project_list_cache_key", clean_gitlab_redis_shared_state: true do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it "includes the route" do expect(helper.project_list_cache_key(project)).to include(project.route.cache_key) @@ -105,7 +105,7 @@ describe ProjectsHelper do describe '#load_pipeline_status' do it 'loads the pipeline status in batch' do - project = build(:empty_project) + project = build(:project) helper.load_pipeline_status([project]) # Skip lazy loading of the `pipeline_status` attribute @@ -193,7 +193,7 @@ describe ProjectsHelper do describe 'link_to_member' do let(:group) { create(:group) } - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } let(:user) { create(:user) } describe 'using the default options' do @@ -225,7 +225,7 @@ describe ProjectsHelper do end describe '#license_short_name' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when project.repository has a license_key' do it 'returns the nickname of the license if present' do @@ -251,7 +251,7 @@ describe ProjectsHelper do end describe '#sanitized_import_error' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do allow(project).to receive(:repository_storage_path).and_return('/base/repo/path') @@ -312,7 +312,7 @@ describe ProjectsHelper do end describe "#project_feature_access_select" do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } context "when project is internal or public" do @@ -380,7 +380,7 @@ describe ProjectsHelper do end describe '#get_project_nav_tabs' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } before do @@ -411,4 +411,54 @@ describe ProjectsHelper do end end end + + describe '#has_projects_or_name?' do + let(:projects) do + create(:project) + Project.all + end + + it 'returns true when there are projects' do + expect(helper.has_projects_or_name?(projects, {})).to eq(true) + end + + it 'returns true when there are no projects but a name is given' do + expect(helper.has_projects_or_name?(Project.none, name: 'foo')).to eq(true) + end + + it 'returns false when there are no projects and there is no name' do + expect(helper.has_projects_or_name?(Project.none, {})).to eq(false) + end + end + + describe '#any_projects?' do + let!(:project) { create(:project) } + + it 'returns true when projects will be returned' do + expect(helper.any_projects?(Project.all)).to eq(true) + end + + it 'returns false when no projects will be returned' do + expect(helper.any_projects?(Project.none)).to eq(false) + end + + it 'returns true when using a non-empty Array' do + expect(helper.any_projects?([project])).to eq(true) + end + + it 'returns false when using an empty Array' do + expect(helper.any_projects?([])).to eq(false) + end + + it 'only executes a single query when a LIMIT is applied' do + relation = Project.limit(1) + recorder = ActiveRecord::QueryRecorder.new do + 2.times do + helper.any_projects?(relation) + end + end + + expect(recorder.count).to eq(1) + end + end end diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index b7e547dc1f5..463af15930d 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -47,7 +47,7 @@ describe SearchHelper do end it "includes the user's projects" do - project = create(:empty_project, namespace: create(:namespace, owner: user)) + project = create(:project, namespace: create(:namespace, owner: user)) expect(search_autocomplete_opts(project.name).size).to eq(1) end @@ -68,4 +68,38 @@ describe SearchHelper do end end end + + describe 'search_filter_input_options' do + context 'project' do + before do + @project = create(:project, :repository) + end + + it 'includes id with type' do + expect(search_filter_input_options('type')[:id]).to eq('filtered-search-type') + end + + it 'includes project-id' do + expect(search_filter_input_options('')[:data]['project-id']).to eq(@project.id) + end + + it 'includes project base-endpoint' do + expect(search_filter_input_options('')[:data]['base-endpoint']).to eq(project_path(@project)) + end + end + + context 'group' do + before do + @group = create(:group, name: 'group') + end + + it 'does not includes project-id' do + expect(search_filter_input_options('')[:data]['project-id']).to eq(nil) + end + + it 'includes group base-endpoint' do + expect(search_filter_input_options('')[:data]['base-endpoint']).to eq("/groups#{group_path(@group)}") + end + end + end end diff --git a/spec/helpers/storage_health_helper_spec.rb b/spec/helpers/storage_health_helper_spec.rb new file mode 100644 index 00000000000..874498e6338 --- /dev/null +++ b/spec/helpers/storage_health_helper_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe StorageHealthHelper do + describe '#failing_storage_health_message' do + let(:health) do + Gitlab::Git::Storage::Health.new( + "<script>alert('storage name');)</script>", + [] + ) + end + + it 'escapes storage names' do + escaped_storage_name = '<script>alert('storage name');)</script>' + + result = helper.failing_storage_health_message(health) + + expect(result).to include(escaped_storage_name) + end + end +end diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb index 9e561d0f191..c4f4e0d21dc 100644 --- a/spec/helpers/submodule_helper_spec.rb +++ b/spec/helpers/submodule_helper_spec.rb @@ -91,7 +91,7 @@ describe SubmoduleHelper do context 'in-repository submodule' do let(:group) { create(:group, name: "Master Project", path: "master-project") } - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } before do self.instance_variable_set(:@project, project) end @@ -158,7 +158,7 @@ describe SubmoduleHelper do context 'submodules with relative links' do let(:group) { create(:group, name: "Master Project", path: "master-project") } - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } let(:commit_id) { sample_commit[:id] } before do @@ -192,7 +192,7 @@ describe SubmoduleHelper do context 'personal project' do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } it 'one level down with personal project' do result = relative_self_links('../test.git', commit_id) diff --git a/spec/helpers/todos_helper_spec.rb b/spec/helpers/todos_helper_spec.rb index 18a41ca24e3..f55163c26e9 100644 --- a/spec/helpers/todos_helper_spec.rb +++ b/spec/helpers/todos_helper_spec.rb @@ -15,7 +15,7 @@ describe TodosHelper do end describe '#todo_projects_options' do - let(:projects) { create_list(:empty_project, 3) } + let(:projects) { create_list(:project, 3) } let(:user) { create(:user) } it 'returns users authorised projects in json format' do diff --git a/spec/helpers/visibility_level_helper_spec.rb b/spec/helpers/visibility_level_helper_spec.rb index ad19cf9263d..c3cccbb0d95 100644 --- a/spec/helpers/visibility_level_helper_spec.rb +++ b/spec/helpers/visibility_level_helper_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe VisibilityLevelHelper do - let(:project) { build(:empty_project) } + let(:project) { build(:project) } let(:group) { build(:group) } let(:personal_snippet) { build(:personal_snippet) } let(:project_snippet) { build(:project_snippet) } @@ -60,8 +60,8 @@ describe VisibilityLevelHelper do describe "skip_level?" do describe "forks" do - let(:project) { create(:empty_project, :internal) } - let(:fork_project) { create(:empty_project, forked_from_project: project) } + let(:project) { create(:project, :internal) } + let(:fork_project) { create(:project, forked_from_project: project) } it "skips levels" do expect(skip_level?(fork_project, Gitlab::VisibilityLevel::PUBLIC)).to be_truthy @@ -71,7 +71,7 @@ describe VisibilityLevelHelper do end describe "non-forked project" do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } it "skips levels" do expect(skip_level?(project, Gitlab::VisibilityLevel::PUBLIC)).to be_falsey diff --git a/spec/initializers/6_validations_spec.rb b/spec/initializers/6_validations_spec.rb index 0877770c167..83283f03940 100644 --- a/spec/initializers/6_validations_spec.rb +++ b/spec/initializers/6_validations_spec.rb @@ -23,6 +23,16 @@ describe '6_validations' do end end + context 'when one of the settings is incorrect' do + before do + mock_storages('foo' => { 'path' => 'tmp/tests/paths/a/b/c', 'failure_count_threshold' => 'not a number' }) + end + + it 'throws an error' do + expect { validate_storages_config }.to raise_error(/failure_count_threshold/) + end + end + context 'with invalid storage names' do before do mock_storages('name with spaces' => { 'path' => 'tmp/tests/paths/a/b/c' }) @@ -84,6 +94,17 @@ describe '6_validations' do expect { validate_storages_paths }.not_to raise_error end end + + describe 'inaccessible storage' do + before do + mock_storages('foo' => { 'path' => 'tmp/tests/a/path/that/does/not/exist' }) + end + + it 'passes through with a warning' do + expect(Rails.logger).to receive(:error) + expect { validate_storages_paths }.not_to raise_error + end + end end def mock_storages(storages) diff --git a/spec/initializers/settings_spec.rb b/spec/initializers/settings_spec.rb index ebdabcf93f1..e5ec90cb8f9 100644 --- a/spec/initializers/settings_spec.rb +++ b/spec/initializers/settings_spec.rb @@ -2,6 +2,17 @@ require 'spec_helper' require_relative '../../config/initializers/1_settings' describe Settings do + describe '#repositories' do + it 'assigns the default failure attributes' do + repository_settings = Gitlab.config.repositories.storages['broken'] + + expect(repository_settings['failure_count_threshold']).to eq(10) + expect(repository_settings['failure_wait_time']).to eq(30) + expect(repository_settings['failure_reset_time']).to eq(1800) + expect(repository_settings['storage_timeout']).to eq(5) + end + end + describe '#host_without_www' do context 'URL with protocol' do it 'returns the host' do diff --git a/spec/javascripts/abuse_reports_spec.js b/spec/javascripts/abuse_reports_spec.js index 069d857eab6..13cab81dd60 100644 --- a/spec/javascripts/abuse_reports_spec.js +++ b/spec/javascripts/abuse_reports_spec.js @@ -6,10 +6,10 @@ import '~/abuse_reports'; const FIXTURE = 'abuse_reports/abuse_reports_list.html.raw'; const MAX_MESSAGE_LENGTH = 500; - let messages; + let $messages; const assertMaxLength = $message => expect($message.text().length).toEqual(MAX_MESSAGE_LENGTH); - const findMessage = searchText => messages.filter( + const findMessage = searchText => $messages.filter( (index, element) => element.innerText.indexOf(searchText) > -1, ).first(); @@ -18,7 +18,7 @@ import '~/abuse_reports'; beforeEach(function () { loadFixtures(FIXTURE); this.abuseReports = new global.AbuseReports(); - messages = $('.abuse-reports .message'); + $messages = $('.abuse-reports .message'); }); it('should truncate long messages', () => { diff --git a/spec/javascripts/ajax_loading_spinner_spec.js b/spec/javascripts/ajax_loading_spinner_spec.js index 1518ae68b0d..46e072a8ebb 100644 --- a/spec/javascripts/ajax_loading_spinner_spec.js +++ b/spec/javascripts/ajax_loading_spinner_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import 'jquery'; import 'jquery-ujs'; import '~/ajax_loading_spinner'; diff --git a/spec/javascripts/blob/blob_file_dropzone_spec.js b/spec/javascripts/blob/blob_file_dropzone_spec.js new file mode 100644 index 00000000000..2c8183ff77b --- /dev/null +++ b/spec/javascripts/blob/blob_file_dropzone_spec.js @@ -0,0 +1,42 @@ +import 'dropzone'; +import BlobFileDropzone from '~/blob/blob_file_dropzone'; + +describe('BlobFileDropzone', () => { + preloadFixtures('blob/show.html.raw'); + + beforeEach(() => { + loadFixtures('blob/show.html.raw'); + const form = $('.js-upload-blob-form'); + this.blobFileDropzone = new BlobFileDropzone(form, 'POST'); + this.dropzone = $('.js-upload-blob-form .dropzone').get(0).dropzone; + this.replaceFileButton = $('#submit-all'); + }); + + describe('submit button', () => { + it('requires file', () => { + spyOn(window, 'alert'); + + this.replaceFileButton.click(); + + expect(window.alert).toHaveBeenCalled(); + }); + + it('is disabled while uploading', () => { + spyOn(window, 'alert'); + + const file = { + name: 'some-file.jpg', + type: 'jpg', + }; + const fakeEvent = jQuery.Event('drop', { + dataTransfer: { files: [file] }, + }); + + this.dropzone.listeners[0].events.drop(fakeEvent); + this.replaceFileButton.click(); + + expect(window.alert).not.toHaveBeenCalled(); + expect(this.replaceFileButton.is(':disabled')).toEqual(true); + }); + }); +}); diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js index af04e7c1e72..cfa6650d85f 100644 --- a/spec/javascripts/blob/viewer/index_spec.js +++ b/spec/javascripts/blob/viewer/index_spec.js @@ -3,10 +3,10 @@ import BlobViewer from '~/blob/viewer/index'; describe('Blob viewer', () => { let blob; - preloadFixtures('blob/show.html.raw'); + preloadFixtures('snippets/show.html.raw'); beforeEach(() => { - loadFixtures('blob/show.html.raw'); + loadFixtures('snippets/show.html.raw'); $('#modal-upload-blob').remove(); blob = new BlobViewer(); diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js index bd9b4fbfdd3..69cfcbbce5a 100644 --- a/spec/javascripts/boards/issue_card_spec.js +++ b/spec/javascripts/boards/issue_card_spec.js @@ -238,12 +238,6 @@ describe('Issue card component', () => { }); describe('labels', () => { - it('does not render any', () => { - expect( - component.$el.querySelector('.label'), - ).toBeNull(); - }); - describe('exists', () => { beforeEach((done) => { component.issue.addLabel(label1); @@ -251,16 +245,21 @@ describe('Issue card component', () => { Vue.nextTick(() => done()); }); - it('does not render list label', () => { + it('renders list label', () => { expect( component.$el.querySelectorAll('.label').length, - ).toBe(1); + ).toBe(2); }); it('renders label', () => { + const nodes = []; + component.$el.querySelectorAll('.label').forEach((label) => { + nodes.push(label.title); + }); + expect( - component.$el.querySelector('.label').textContent, - ).toContain(label1.title); + nodes.includes(label1.description), + ).toBe(true); }); it('sets label description as title', () => { @@ -270,9 +269,14 @@ describe('Issue card component', () => { }); it('sets background color of button', () => { + const nodes = []; + component.$el.querySelectorAll('.label').forEach((label) => { + nodes.push(label.style.backgroundColor); + }); + expect( - component.$el.querySelector('.label').style.backgroundColor, - ).toContain(label1.color); + nodes.includes(label1.color), + ).toBe(true); }); }); }); diff --git a/spec/javascripts/breakpoints_spec.js b/spec/javascripts/breakpoints_spec.js new file mode 100644 index 00000000000..b1b5d36c1fb --- /dev/null +++ b/spec/javascripts/breakpoints_spec.js @@ -0,0 +1,15 @@ +import bp, { + breakpoints, +} from '~/breakpoints'; + +describe('breakpoints', () => { + Object.keys(breakpoints).forEach((key) => { + const size = breakpoints[key]; + + it(`returns ${key} when larger than ${size}`, () => { + spyOn(bp, 'windowWidth').and.returnValue(size + 10); + + expect(bp.getBreakpointSize()).toBe(key); + }); + }); +}); diff --git a/spec/javascripts/build_spec.js b/spec/javascripts/build_spec.js index be90dbdd88a..35149611095 100644 --- a/spec/javascripts/build_spec.js +++ b/spec/javascripts/build_spec.js @@ -5,7 +5,6 @@ import '~/lib/utils/datetime_utility'; import '~/lib/utils/url_utility'; import '~/build'; import '~/breakpoints'; -import 'vendor/jquery.nicescroll'; describe('Build', () => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1`; diff --git a/spec/javascripts/droplab/plugins/ajax_spec.js b/spec/javascripts/droplab/plugins/ajax_spec.js new file mode 100644 index 00000000000..085f25764fe --- /dev/null +++ b/spec/javascripts/droplab/plugins/ajax_spec.js @@ -0,0 +1,36 @@ +import AjaxCache from '~/lib/utils/ajax_cache'; +import Ajax from '~/droplab/plugins/ajax'; + +describe('Ajax', () => { + describe('preprocessing', () => { + const config = {}; + + describe('is not configured', () => { + it('passes the data through', () => { + const data = ['data']; + expect(Ajax.preprocessing(config, data)).toEqual(data); + }); + }); + + describe('is configured', () => { + const processedArray = ['processed']; + + beforeEach(() => { + config.preprocessing = () => processedArray; + spyOn(config, 'preprocessing').and.callFake(() => processedArray); + }); + + it('calls preprocessing', () => { + Ajax.preprocessing(config, []); + expect(config.preprocessing.calls.count()).toBe(1); + }); + + it('overrides AjaxCache', () => { + spyOn(AjaxCache, 'override').and.callFake((endpoint, results) => expect(results).toEqual(processedArray)); + + Ajax.preprocessing(config, []); + expect(AjaxCache.override.calls.count()).toBe(1); + }); + }); + }); +}); diff --git a/spec/javascripts/extensions/array_spec.js b/spec/javascripts/extensions/array_spec.js deleted file mode 100644 index b1b81b4efc2..00000000000 --- a/spec/javascripts/extensions/array_spec.js +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable space-before-function-paren, no-var */ - -import '~/extensions/array'; - -(function() { - describe('Array extensions', function() { - describe('first', function() { - return it('returns the first item', function() { - var arr; - arr = [0, 1, 2, 3, 4, 5]; - return expect(arr.first()).toBe(0); - }); - }); - describe('last', function() { - return it('returns the last item', function() { - var arr; - arr = [0, 1, 2, 3, 4, 5]; - return expect(arr.last()).toBe(5); - }); - }); - }); -}).call(window); diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js b/spec/javascripts/filtered_search/dropdown_utils_spec.js index f55726379f3..b1b3d43f241 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/dropdown_utils'; import '~/filtered_search/filtered_search_tokenizer'; import '~/filtered_search/filtered_search_dropdown_manager'; @@ -191,6 +190,102 @@ describe('Dropdown Utils', () => { }); }); + describe('mergeDuplicateLabels', () => { + const dataMap = { + label: { + title: 'label', + color: '#FFFFFF', + }, + }; + + it('should add label to dataMap if it is not a duplicate', () => { + const newLabel = { + title: 'new-label', + color: '#000000', + }; + + const updated = gl.DropdownUtils.mergeDuplicateLabels(dataMap, newLabel); + expect(updated[newLabel.title]).toEqual(newLabel); + }); + + it('should merge colors if label is a duplicate', () => { + const duplicate = { + title: 'label', + color: '#000000', + }; + + const updated = gl.DropdownUtils.mergeDuplicateLabels(dataMap, duplicate); + expect(updated.label.multipleColors).toEqual([dataMap.label.color, duplicate.color]); + }); + }); + + describe('duplicateLabelColor', () => { + it('should linear-gradient 2 colors', () => { + const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000']); + expect(gradient).toEqual('linear-gradient(#FFFFFF 0%, #FFFFFF 50%, #000000 50%, #000000 100%)'); + }); + + it('should linear-gradient 3 colors', () => { + const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000', '#333333']); + expect(gradient).toEqual('linear-gradient(#FFFFFF 0%, #FFFFFF 33%, #000000 33%, #000000 66%, #333333 66%, #333333 100%)'); + }); + + it('should linear-gradient 4 colors', () => { + const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000', '#333333', '#DDDDDD']); + expect(gradient).toEqual('linear-gradient(#FFFFFF 0%, #FFFFFF 25%, #000000 25%, #000000 50%, #333333 50%, #333333 75%, #DDDDDD 75%, #DDDDDD 100%)'); + }); + + it('should not linear-gradient more than 4 colors', () => { + const gradient = gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000', '#333333', '#DDDDDD', '#EEEEEE']); + expect(gradient.indexOf('#EEEEEE') === -1).toEqual(true); + }); + }); + + describe('duplicateLabelPreprocessing', () => { + it('should set preprocessed to true', () => { + const results = gl.DropdownUtils.duplicateLabelPreprocessing([]); + expect(results.preprocessed).toEqual(true); + }); + + it('should not mutate existing data if there are no duplicates', () => { + const data = [{ + title: 'label1', + color: '#FFFFFF', + }, { + title: 'label2', + color: '#000000', + }]; + const results = gl.DropdownUtils.duplicateLabelPreprocessing(data); + + expect(results.length).toEqual(2); + expect(results[0]).toEqual(data[0]); + expect(results[1]).toEqual(data[1]); + }); + + describe('duplicate labels', () => { + const data = [{ + title: 'label', + color: '#FFFFFF', + }, { + title: 'label', + color: '#000000', + }]; + const results = gl.DropdownUtils.duplicateLabelPreprocessing(data); + + it('should merge duplicate labels', () => { + expect(results.length).toEqual(1); + }); + + it('should convert multiple colored labels into linear-gradient', () => { + expect(results[0].color).toEqual(gl.DropdownUtils.duplicateLabelColor(['#FFFFFF', '#000000'])); + }); + + it('should set multiple colored label text color to black', () => { + expect(results[0].text_color).toEqual('#000000'); + }); + }); + }); + describe('setDataValueIfSelected', () => { beforeEach(() => { spyOn(gl.FilteredSearchDropdownManager, 'addWordToInput') diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js index 9e2076dc383..5c7e9115aac 100644 --- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/filtered_search_visual_tokens'; import '~/filtered_search/filtered_search_tokenizer'; import '~/filtered_search/filtered_search_dropdown_manager'; diff --git a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js index 1a7631994b4..69b424c3af5 100644 --- a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/filtered_search_token_keys'; describe('Filtered Search Token Keys', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js index e4a15c83c23..585bea9b499 100644 --- a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js @@ -1,4 +1,3 @@ -import '~/extensions/array'; import '~/filtered_search/filtered_search_token_keys'; import '~/filtered_search/filtered_search_tokenizer'; diff --git a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js index fa4343ffbc8..67166802c70 100644 --- a/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js +++ b/spec/javascripts/filtered_search/filtered_search_visual_tokens_spec.js @@ -797,6 +797,69 @@ describe('Filtered Search Visual Tokens', () => { }); }); + describe('setTokenStyle', () => { + let originalTextColor; + + beforeEach(() => { + originalTextColor = bugLabelToken.style.color; + }); + + it('should set backgroundColor', () => { + const originalBackgroundColor = bugLabelToken.style.backgroundColor; + const token = subject.setTokenStyle(bugLabelToken, 'blue', 'white'); + expect(token.style.backgroundColor).toEqual('blue'); + expect(token.style.backgroundColor).not.toEqual(originalBackgroundColor); + }); + + it('should not set backgroundColor when it is a linear-gradient', () => { + const token = subject.setTokenStyle(bugLabelToken, 'linear-gradient(135deg, red, blue)', 'white'); + expect(token.style.backgroundColor).toEqual(bugLabelToken.style.backgroundColor); + }); + + it('should set textColor', () => { + const token = subject.setTokenStyle(bugLabelToken, 'white', 'black'); + expect(token.style.color).toEqual('black'); + expect(token.style.color).not.toEqual(originalTextColor); + }); + + it('should add inverted class when textColor is #FFFFFF', () => { + const token = subject.setTokenStyle(bugLabelToken, 'black', '#FFFFFF'); + expect(token.style.color).toEqual('rgb(255, 255, 255)'); + expect(token.style.color).not.toEqual(originalTextColor); + expect(token.querySelector('.remove-token').classList.contains('inverted')).toEqual(true); + }); + }); + + describe('preprocessLabel', () => { + const endpoint = 'endpoint'; + + it('does not preprocess more than once', () => { + let labels = []; + + spyOn(gl.DropdownUtils, 'duplicateLabelPreprocessing').and.callFake(() => []); + + labels = gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, labels); + gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, labels); + + expect(gl.DropdownUtils.duplicateLabelPreprocessing.calls.count()).toEqual(1); + }); + + describe('not preprocessed before', () => { + it('returns preprocessed labels', () => { + let labels = []; + expect(labels.preprocessed).not.toEqual(true); + labels = gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, labels); + expect(labels.preprocessed).toEqual(true); + }); + + it('overrides AjaxCache with preprocessed results', () => { + spyOn(AjaxCache, 'override').and.callFake(() => {}); + gl.FilteredSearchVisualTokens.preprocessLabel(endpoint, []); + expect(AjaxCache.override.calls.count()).toEqual(1); + }); + }); + }); + describe('updateLabelTokenColor', () => { const jsonFixtureName = 'labels/project_labels.json'; const dummyEndpoint = '/dummy/endpoint'; diff --git a/spec/javascripts/fixtures/abuse_reports.rb b/spec/javascripts/fixtures/abuse_reports.rb index de673f94d72..387858cba77 100644 --- a/spec/javascripts/fixtures/abuse_reports.rb +++ b/spec/javascripts/fixtures/abuse_reports.rb @@ -14,7 +14,7 @@ describe Admin::AbuseReportsController, '(JavaScript fixtures)', type: :controll clean_frontend_fixtures('abuse_reports/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/balsamiq.rb b/spec/javascripts/fixtures/balsamiq.rb index b5372821bf5..234e246119a 100644 --- a/spec/javascripts/fixtures/balsamiq.rb +++ b/spec/javascripts/fixtures/balsamiq.rb @@ -4,7 +4,7 @@ describe 'Balsamiq file', '(JavaScript fixtures)', type: :controller do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'balsamiq-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'balsamiq-project') } before(:all) do clean_frontend_fixtures('blob/balsamiq/') diff --git a/spec/javascripts/fixtures/blob.rb b/spec/javascripts/fixtures/blob.rb index 16490ad5039..2dffc42b0ef 100644 --- a/spec/javascripts/fixtures/blob.rb +++ b/spec/javascripts/fixtures/blob.rb @@ -13,7 +13,7 @@ describe Projects::BlobController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('blob/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/boards.rb b/spec/javascripts/fixtures/boards.rb index d7c3dc0a235..494c9cabdcc 100644 --- a/spec/javascripts/fixtures/boards.rb +++ b/spec/javascripts/fixtures/boards.rb @@ -13,7 +13,7 @@ describe Projects::BoardsController, '(JavaScript fixtures)', type: :controller clean_frontend_fixtures('boards/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/branches.rb b/spec/javascripts/fixtures/branches.rb index a059818145b..bb3bdf7c215 100644 --- a/spec/javascripts/fixtures/branches.rb +++ b/spec/javascripts/fixtures/branches.rb @@ -13,7 +13,7 @@ describe Projects::BranchesController, '(JavaScript fixtures)', type: :controlle clean_frontend_fixtures('branches/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/dashboard.rb b/spec/javascripts/fixtures/dashboard.rb index e83db8daaf2..793ffa7c220 100644 --- a/spec/javascripts/fixtures/dashboard.rb +++ b/spec/javascripts/fixtures/dashboard.rb @@ -13,7 +13,7 @@ describe Dashboard::ProjectsController, '(JavaScript fixtures)', type: :controll clean_frontend_fixtures('dashboard/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/deploy_keys.rb b/spec/javascripts/fixtures/deploy_keys.rb index 16e598a4b29..bea161c514f 100644 --- a/spec/javascripts/fixtures/deploy_keys.rb +++ b/spec/javascripts/fixtures/deploy_keys.rb @@ -6,13 +6,13 @@ describe Projects::DeployKeysController, '(JavaScript fixtures)', type: :control let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} let(:project) { create(:project_empty_repo, namespace: namespace, path: 'todos-project') } - let(:project2) { create(:empty_project, :internal)} + let(:project2) { create(:project, :internal)} before(:all) do clean_frontend_fixtures('deploy_keys/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/environments.rb b/spec/javascripts/fixtures/environments.rb index 3474f4696ef..d2457d75419 100644 --- a/spec/javascripts/fixtures/environments.rb +++ b/spec/javascripts/fixtures/environments.rb @@ -14,7 +14,7 @@ describe Projects::EnvironmentsController, '(JavaScript fixtures)', type: :contr clean_frontend_fixtures('environments/metrics') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/issues.rb b/spec/javascripts/fixtures/issues.rb index 1a30909977e..d3ad50af1b9 100644 --- a/spec/javascripts/fixtures/issues.rb +++ b/spec/javascripts/fixtures/issues.rb @@ -13,7 +13,7 @@ describe Projects::IssuesController, '(JavaScript fixtures)', type: :controller clean_frontend_fixtures('issues/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/jobs.rb b/spec/javascripts/fixtures/jobs.rb index dc7dde1138c..83a96797506 100644 --- a/spec/javascripts/fixtures/jobs.rb +++ b/spec/javascripts/fixtures/jobs.rb @@ -17,7 +17,7 @@ describe Projects::JobsController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('builds/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/labels.rb b/spec/javascripts/fixtures/labels.rb index 2e4811b64a4..814f065f3a4 100644 --- a/spec/javascripts/fixtures/labels.rb +++ b/spec/javascripts/fixtures/labels.rb @@ -22,7 +22,7 @@ describe 'Labels (JavaScript fixtures)' do describe Groups::LabelsController, '(JavaScript fixtures)', type: :controller do render_views - before(:each) do + before do sign_in(admin) end @@ -39,7 +39,7 @@ describe 'Labels (JavaScript fixtures)' do describe Projects::LabelsController, '(JavaScript fixtures)', type: :controller do render_views - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/merge_requests.rb b/spec/javascripts/fixtures/merge_requests.rb index 7e2f364ffa4..f97a5d2b5de 100644 --- a/spec/javascripts/fixtures/merge_requests.rb +++ b/spec/javascripts/fixtures/merge_requests.rb @@ -5,7 +5,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') } let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') } let(:merged_merge_request) { create(:merge_request, :merged, source_project: project, target_project: project) } let(:pipeline) do @@ -33,7 +33,7 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont clean_frontend_fixtures('merge_requests/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/merge_requests_diffs.rb b/spec/javascripts/fixtures/merge_requests_diffs.rb index ac5b06ace6d..6e0a97d2e3f 100644 --- a/spec/javascripts/fixtures/merge_requests_diffs.rb +++ b/spec/javascripts/fixtures/merge_requests_diffs.rb @@ -6,7 +6,7 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type let(:admin) { create(:admin) } let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'merge-requests-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'merge-requests-project') } let(:merge_request) { create(:merge_request, :with_diffs, source_project: project, target_project: project, description: '- [ ] Task List Item') } let(:path) { "files/ruby/popen.rb" } let(:position) do @@ -25,7 +25,7 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type clean_frontend_fixtures('merge_request_diffs/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/pdf.rb b/spec/javascripts/fixtures/pdf.rb index 6b2422a7986..ef9976b9fd3 100644 --- a/spec/javascripts/fixtures/pdf.rb +++ b/spec/javascripts/fixtures/pdf.rb @@ -4,7 +4,7 @@ describe 'PDF file', '(JavaScript fixtures)', type: :controller do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'pdf-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'pdf-project') } before(:all) do clean_frontend_fixtures('blob/pdf/') diff --git a/spec/javascripts/fixtures/pipelines.rb b/spec/javascripts/fixtures/pipelines.rb index daafbac86db..bb85da50f0f 100644 --- a/spec/javascripts/fixtures/pipelines.rb +++ b/spec/javascripts/fixtures/pipelines.rb @@ -19,7 +19,7 @@ describe Projects::PipelinesController, '(JavaScript fixtures)', type: :controll clean_frontend_fixtures('pipelines/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/project_select_combo_button.html.haml b/spec/javascripts/fixtures/project_select_combo_button.html.haml new file mode 100644 index 00000000000..54bc1a59279 --- /dev/null +++ b/spec/javascripts/fixtures/project_select_combo_button.html.haml @@ -0,0 +1,6 @@ +.project-item-select-holder + %input.project-item-select{ data: { group_id: '12345' , relative_path: 'issues/new' } } + %a.new-project-item-link{ data: { label: 'New issue' }, href: ''} + %i.fa.fa-spinner.spin + %a.new-project-item-select-button + %i.fa.fa-caret-down diff --git a/spec/javascripts/fixtures/projects.rb b/spec/javascripts/fixtures/projects.rb index 6c33b240e5c..f09d44a49d1 100644 --- a/spec/javascripts/fixtures/projects.rb +++ b/spec/javascripts/fixtures/projects.rb @@ -13,7 +13,7 @@ describe ProjectsController, '(JavaScript fixtures)', type: :controller do clean_frontend_fixtures('projects/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/prometheus_service.rb b/spec/javascripts/fixtures/prometheus_service.rb index 3200577b326..7a46e47bb15 100644 --- a/spec/javascripts/fixtures/prometheus_service.rb +++ b/spec/javascripts/fixtures/prometheus_service.rb @@ -14,7 +14,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle clean_frontend_fixtures('services/prometheus') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/raw.rb b/spec/javascripts/fixtures/raw.rb index 17533443d76..25f5a3b0bb3 100644 --- a/spec/javascripts/fixtures/raw.rb +++ b/spec/javascripts/fixtures/raw.rb @@ -4,7 +4,7 @@ describe 'Raw files', '(JavaScript fixtures)', type: :controller do include JavaScriptFixturesHelpers let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} - let(:project) { create(:project, namespace: namespace, path: 'raw-project') } + let(:project) { create(:project, :repository, namespace: namespace, path: 'raw-project') } before(:all) do clean_frontend_fixtures('blob/notebook/') diff --git a/spec/javascripts/fixtures/services.rb b/spec/javascripts/fixtures/services.rb index 554451d1bbf..0a3c64d5d31 100644 --- a/spec/javascripts/fixtures/services.rb +++ b/spec/javascripts/fixtures/services.rb @@ -15,7 +15,7 @@ describe Projects::ServicesController, '(JavaScript fixtures)', type: :controlle clean_frontend_fixtures('services/') end - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fixtures/snippet.rb b/spec/javascripts/fixtures/snippet.rb new file mode 100644 index 00000000000..01bfb87b0c1 --- /dev/null +++ b/spec/javascripts/fixtures/snippet.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe SnippetsController, '(JavaScript fixtures)', type: :controller do + include JavaScriptFixturesHelpers + + let(:admin) { create(:admin) } + let(:namespace) { create(:namespace, name: 'frontend-fixtures' )} + let(:project) { create(:project, :repository, namespace: namespace, path: 'branches-project') } + let(:snippet) { create(:personal_snippet, title: 'snippet.md', content: '# snippet', file_name: 'snippet.md', author: admin) } + + render_views + + before(:all) do + clean_frontend_fixtures('snippets/') + end + + before do + sign_in(admin) + end + + it 'snippets/show.html.raw' do |example| + get(:show, id: snippet.to_param) + + expect(response).to be_success + store_frontend_fixture(response, example.description) + end +end diff --git a/spec/javascripts/fixtures/todos.rb b/spec/javascripts/fixtures/todos.rb index a81ef8c5492..ba630365c18 100644 --- a/spec/javascripts/fixtures/todos.rb +++ b/spec/javascripts/fixtures/todos.rb @@ -18,7 +18,7 @@ describe 'Todos (JavaScript fixtures)' do describe Dashboard::TodosController, '(JavaScript fixtures)', type: :controller do render_views - before(:each) do + before do sign_in(admin) end @@ -33,7 +33,7 @@ describe 'Todos (JavaScript fixtures)' do describe Projects::TodosController, '(JavaScript fixtures)', type: :controller do render_views - before(:each) do + before do sign_in(admin) end diff --git a/spec/javascripts/fly_out_nav_spec.js b/spec/javascripts/fly_out_nav_spec.js new file mode 100644 index 00000000000..65a7459c5ed --- /dev/null +++ b/spec/javascripts/fly_out_nav_spec.js @@ -0,0 +1,329 @@ +import Cookies from 'js-cookie'; +import { + calculateTop, + showSubLevelItems, + canShowSubItems, + canShowActiveSubItems, + mouseEnterTopItems, + mouseLeaveTopItem, + setOpenMenu, + mousePos, + getHideSubItemsInterval, + documentMouseMove, +} from '~/fly_out_nav'; +import bp from '~/breakpoints'; + +describe('Fly out sidebar navigation', () => { + let el; + let breakpointSize = 'lg'; + + beforeEach(() => { + el = document.createElement('div'); + el.style.position = 'relative'; + document.body.appendChild(el); + + spyOn(bp, 'getBreakpointSize').and.callFake(() => breakpointSize); + + setOpenMenu(null); + }); + + afterEach(() => { + document.body.innerHTML = ''; + breakpointSize = 'lg'; + mousePos.length = 0; + }); + + describe('calculateTop', () => { + it('returns boundingRect top', () => { + const boundingRect = { + top: 100, + height: 100, + }; + + expect( + calculateTop(boundingRect, 100), + ).toBe(100); + }); + + it('returns boundingRect - bottomOverflow', () => { + const boundingRect = { + top: window.innerHeight - 50, + height: 100, + }; + + expect( + calculateTop(boundingRect, 100), + ).toBe(window.innerHeight - 50); + }); + }); + + describe('getHideSubItemsInterval', () => { + beforeEach(() => { + el.innerHTML = '<div class="sidebar-sub-level-items" style="position: fixed; top: 0; left: 100px; height: 50px;"></div>'; + }); + + it('returns 0 if currentOpenMenu is nil', () => { + expect( + getHideSubItemsInterval(), + ).toBe(0); + }); + + it('returns 0 when mouse above sub-items', () => { + showSubLevelItems(el); + documentMouseMove({ + clientX: el.getBoundingClientRect().left, + clientY: el.getBoundingClientRect().top, + }); + documentMouseMove({ + clientX: el.getBoundingClientRect().left, + clientY: el.getBoundingClientRect().top - 50, + }); + + expect( + getHideSubItemsInterval(), + ).toBe(0); + }); + + it('returns 0 when mouse is below sub-items', () => { + const subItems = el.querySelector('.sidebar-sub-level-items'); + + showSubLevelItems(el); + documentMouseMove({ + clientX: el.getBoundingClientRect().left, + clientY: el.getBoundingClientRect().top, + }); + documentMouseMove({ + clientX: el.getBoundingClientRect().left, + clientY: (el.getBoundingClientRect().top - subItems.getBoundingClientRect().height) + 50, + }); + + expect( + getHideSubItemsInterval(), + ).toBe(0); + }); + + it('returns 300 when mouse is moved towards sub-items', () => { + documentMouseMove({ + clientX: el.getBoundingClientRect().left, + clientY: el.getBoundingClientRect().top, + }); + showSubLevelItems(el); + documentMouseMove({ + clientX: el.getBoundingClientRect().left + 20, + clientY: el.getBoundingClientRect().top + 10, + }); + + expect( + getHideSubItemsInterval(), + ).toBe(300); + }); + }); + + describe('mouseLeaveTopItem', () => { + beforeEach(() => { + spyOn(el.classList, 'remove'); + }); + + it('removes is-over class if currentOpenMenu is null', () => { + mouseLeaveTopItem(el); + + expect( + el.classList.remove, + ).toHaveBeenCalledWith('is-over'); + }); + + it('removes is-over class if currentOpenMenu is null & there are sub-items', () => { + el.innerHTML = '<div class="sidebar-sub-level-items" style="position: absolute;"></div>'; + + mouseLeaveTopItem(el); + + expect( + el.classList.remove, + ).toHaveBeenCalledWith('is-over'); + }); + + it('does not remove is-over class if currentOpenMenu is the passed in sub-items', () => { + el.innerHTML = '<div class="sidebar-sub-level-items" style="position: absolute;"></div>'; + + setOpenMenu(el.querySelector('.sidebar-sub-level-items')); + mouseLeaveTopItem(el); + + expect( + el.classList.remove, + ).not.toHaveBeenCalled(); + }); + }); + + describe('mouseEnterTopItems', () => { + beforeEach(() => { + jasmine.clock().install(); + + el.innerHTML = '<div class="sidebar-sub-level-items" style="position: absolute; top: 0; left: 100px; height: 200px;"></div>'; + }); + + afterEach(() => { + jasmine.clock().uninstall(); + }); + + it('shows sub-items after 0ms if no menu is open', () => { + mouseEnterTopItems(el); + + expect( + getHideSubItemsInterval(), + ).toBe(0); + + jasmine.clock().tick(0); + + expect( + el.querySelector('.sidebar-sub-level-items').style.display, + ).toBe('block'); + }); + + it('shows sub-items after 300ms if a menu is currently open', () => { + documentMouseMove({ + clientX: el.getBoundingClientRect().left, + clientY: el.getBoundingClientRect().top, + }); + + setOpenMenu(el.querySelector('.sidebar-sub-level-items')); + + documentMouseMove({ + clientX: el.getBoundingClientRect().left + 20, + clientY: el.getBoundingClientRect().top + 10, + }); + + mouseEnterTopItems(el); + + expect( + getHideSubItemsInterval(), + ).toBe(300); + + jasmine.clock().tick(300); + + expect( + el.querySelector('.sidebar-sub-level-items').style.display, + ).toBe('block'); + }); + }); + + describe('showSubLevelItems', () => { + beforeEach(() => { + el.innerHTML = '<div class="sidebar-sub-level-items" style="position: absolute;"></div>'; + }); + + it('adds is-over class to el', () => { + spyOn(el.classList, 'add'); + + showSubLevelItems(el); + + expect( + el.classList.add, + ).toHaveBeenCalledWith('is-over'); + }); + + it('does not show sub-items on mobile', () => { + breakpointSize = 'xs'; + + showSubLevelItems(el); + + expect( + el.querySelector('.sidebar-sub-level-items').style.display, + ).not.toBe('block'); + }); + + it('shows sub-items', () => { + showSubLevelItems(el); + + expect( + el.querySelector('.sidebar-sub-level-items').style.display, + ).toBe('block'); + }); + + it('sets transform of sub-items', () => { + const subItems = el.querySelector('.sidebar-sub-level-items'); + showSubLevelItems(el); + + expect( + subItems.style.transform, + ).toBe(`translate3d(0px, ${Math.floor(el.getBoundingClientRect().top)}px, 0px)`); + }); + + it('sets is-above when element is above', () => { + const subItems = el.querySelector('.sidebar-sub-level-items'); + subItems.style.height = `${window.innerHeight + el.offsetHeight}px`; + el.style.top = `${window.innerHeight - el.offsetHeight}px`; + + spyOn(subItems.classList, 'add'); + + showSubLevelItems(el); + + expect( + subItems.classList.add, + ).toHaveBeenCalledWith('is-above'); + }); + }); + + describe('canShowSubItems', () => { + it('returns true if on desktop size', () => { + expect( + canShowSubItems(), + ).toBeTruthy(); + }); + + it('returns false if on mobile size', () => { + breakpointSize = 'xs'; + + expect( + canShowSubItems(), + ).toBeFalsy(); + }); + }); + + describe('canShowActiveSubItems', () => { + afterEach(() => { + Cookies.remove('sidebar_collapsed'); + }); + + it('returns true by default', () => { + expect( + canShowActiveSubItems(el), + ).toBeTruthy(); + }); + + it('returns false when cookie is false & element is active', () => { + Cookies.set('sidebar_collapsed', 'false'); + el.classList.add('active'); + + expect( + canShowActiveSubItems(el), + ).toBeFalsy(); + }); + + it('returns true when cookie is false & element is active', () => { + Cookies.set('sidebar_collapsed', 'true'); + el.classList.add('active'); + + expect( + canShowActiveSubItems(el), + ).toBeTruthy(); + }); + + it('returns true when element is active & breakpoint is sm', () => { + breakpointSize = 'sm'; + el.classList.add('active'); + + expect( + canShowActiveSubItems(el), + ).toBeTruthy(); + }); + + it('returns true when element is active & breakpoint is md', () => { + breakpointSize = 'md'; + el.classList.add('active'); + + expect( + canShowActiveSubItems(el), + ).toBeTruthy(); + }); + }); +}); diff --git a/spec/javascripts/gpg_badges_spec.js b/spec/javascripts/gpg_badges_spec.js new file mode 100644 index 00000000000..7a826487bf9 --- /dev/null +++ b/spec/javascripts/gpg_badges_spec.js @@ -0,0 +1,48 @@ +import GpgBadges from '~/gpg_badges'; + +describe('GpgBadges', () => { + const dummyCommitSha = 'n0m0rec0ffee'; + const dummyBadgeHtml = 'dummy html'; + const dummyResponse = { + signatures: [{ + commit_sha: dummyCommitSha, + html: dummyBadgeHtml, + }], + }; + + beforeEach(() => { + setFixtures(` + <div class="parent-container"> + <div class="js-loading-gpg-badge" data-commit-sha="${dummyCommitSha}"></div> + </div> + `); + }); + + it('displays a loading spinner', () => { + spyOn($, 'get').and.returnValue({ + done() { + // intentionally left blank + }, + }); + + GpgBadges.fetch(); + + expect(document.querySelector('.js-loading-gpg-badge:empty')).toBe(null); + const spinners = document.querySelectorAll('.js-loading-gpg-badge i.fa.fa-spinner.fa-spin'); + expect(spinners.length).toBe(1); + }); + + it('replaces the loading spinner', () => { + spyOn($, 'get').and.returnValue({ + done(callback) { + callback(dummyResponse); + }, + }); + + GpgBadges.fetch(); + + expect(document.querySelector('.js-loading-gpg-badge')).toBe(null); + const parentContainer = document.querySelector('.parent-container'); + expect(parentContainer.innerHTML.trim()).toEqual(dummyBadgeHtml); + }); +}); diff --git a/spec/javascripts/groups/group_identicon_spec.js b/spec/javascripts/groups/group_identicon_spec.js new file mode 100644 index 00000000000..66772327503 --- /dev/null +++ b/spec/javascripts/groups/group_identicon_spec.js @@ -0,0 +1,60 @@ +import Vue from 'vue'; +import groupIdenticonComponent from '~/groups/components/group_identicon.vue'; +import GroupsStore from '~/groups/stores/groups_store'; +import { group1 } from './mock_data'; + +const createComponent = () => { + const Component = Vue.extend(groupIdenticonComponent); + const store = new GroupsStore(); + const group = store.decorateGroup(group1); + + return new Component({ + propsData: { + entityId: group.id, + entityName: group.name, + }, + }).$mount(); +}; + +describe('GroupIdenticonComponent', () => { + let vm; + + beforeEach(() => { + vm = createComponent(); + }); + + describe('computed', () => { + describe('identiconStyles', () => { + it('should return styles attribute value with `background-color` property', () => { + vm.entityId = 4; + + expect(vm.identiconStyles).toBeDefined(); + expect(vm.identiconStyles.indexOf('background-color: #E0F2F1;') > -1).toBeTruthy(); + }); + + it('should return styles attribute value with `color` property', () => { + vm.entityId = 4; + + expect(vm.identiconStyles).toBeDefined(); + expect(vm.identiconStyles.indexOf('color: #555;') > -1).toBeTruthy(); + }); + }); + + describe('identiconTitle', () => { + it('should return first letter of entity title in uppercase', () => { + vm.entityName = 'dummy-group'; + + expect(vm.identiconTitle).toBeDefined(); + expect(vm.identiconTitle).toBe('D'); + }); + }); + }); + + describe('template', () => { + it('should render identicon', () => { + expect(vm.$el.nodeName).toBe('DIV'); + expect(vm.$el.classList.contains('identicon')).toBeTruthy(); + expect(vm.$el.getAttribute('style').indexOf('background-color') > -1).toBeTruthy(); + }); + }); +}); diff --git a/spec/javascripts/groups/groups_spec.js b/spec/javascripts/groups/groups_spec.js index aaffb56fa94..b14153dbbfa 100644 --- a/spec/javascripts/groups/groups_spec.js +++ b/spec/javascripts/groups/groups_spec.js @@ -64,6 +64,19 @@ describe('Groups Component', () => { expect(lists[2].querySelector('#group-1120').textContent).toContain(groups.id1119.subGroups.id1120.name); }); + it('should render group identicon when group avatar is not present', () => { + const avatar = component.$el.querySelector('#group-12 .avatar-container .avatar'); + expect(avatar.nodeName).toBe('DIV'); + expect(avatar.classList.contains('identicon')).toBeTruthy(); + expect(avatar.getAttribute('style').indexOf('background-color') > -1).toBeTruthy(); + }); + + it('should render group avatar when group avatar is present', () => { + const avatar = component.$el.querySelector('#group-1120 .avatar-container .avatar'); + expect(avatar.nodeName).toBe('IMG'); + expect(avatar.classList.contains('identicon')).toBeFalsy(); + }); + it('should remove prefix of parent group', () => { expect(component.$el.querySelector('#group-12 #group-1128 .title').textContent).toContain('level2 / level3 / level4'); }); diff --git a/spec/javascripts/groups/mock_data.js b/spec/javascripts/groups/mock_data.js index b3f5d791b89..5bb84b591f4 100644 --- a/spec/javascripts/groups/mock_data.js +++ b/spec/javascripts/groups/mock_data.js @@ -1,5 +1,5 @@ const group1 = { - id: '12', + id: 12, name: 'level1', path: 'level1', description: 'foo', @@ -71,7 +71,7 @@ const group21 = { path: 'chef', description: 'foo', visibility: 'public', - avatar_url: null, + avatar_url: '/uploads/-/system/group/avatar/2/GitLab.png', web_url: 'http://localhost:3000/groups/devops/chef', group_path: '/devops/chef', full_name: 'devops / chef', diff --git a/spec/javascripts/labels_issue_sidebar_spec.js b/spec/javascripts/labels_issue_sidebar_spec.js index c99f379b871..e47adc49224 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js +++ b/spec/javascripts/labels_issue_sidebar_spec.js @@ -4,7 +4,6 @@ import '~/gl_dropdown'; import 'select2'; -import 'vendor/jquery.nicescroll'; import '~/api'; import '~/create_label'; import '~/issuable_context'; diff --git a/spec/javascripts/lib/utils/ajax_cache_spec.js b/spec/javascripts/lib/utils/ajax_cache_spec.js index 2c946802dcd..49971bd91e2 100644 --- a/spec/javascripts/lib/utils/ajax_cache_spec.js +++ b/spec/javascripts/lib/utils/ajax_cache_spec.js @@ -77,6 +77,15 @@ describe('AjaxCache', () => { }); }); + describe('override', () => { + it('overrides existing cache', () => { + AjaxCache.internalStorage.endpoint = 'existing-endpoint'; + AjaxCache.override('endpoint', 'new-endpoint'); + + expect(AjaxCache.internalStorage.endpoint).toEqual('new-endpoint'); + }); + }); + describe('retrieve', () => { let ajaxSpy; diff --git a/spec/javascripts/lib/utils/sticky_spec.js b/spec/javascripts/lib/utils/sticky_spec.js new file mode 100644 index 00000000000..c3ee3ef9825 --- /dev/null +++ b/spec/javascripts/lib/utils/sticky_spec.js @@ -0,0 +1,52 @@ +import { isSticky } from '~/lib/utils/sticky'; + +describe('sticky', () => { + const el = { + offsetTop: 0, + classList: {}, + }; + + beforeEach(() => { + el.offsetTop = 0; + el.classList.add = jasmine.createSpy('spy'); + el.classList.remove = jasmine.createSpy('spy'); + }); + + describe('classList.remove', () => { + it('does not call classList.remove when stuck', () => { + isSticky(el, 0, 0); + + expect( + el.classList.remove, + ).not.toHaveBeenCalled(); + }); + + it('calls classList.remove when not stuck', () => { + el.offsetTop = 10; + isSticky(el, 0, 0); + + expect( + el.classList.remove, + ).toHaveBeenCalledWith('is-stuck'); + }); + }); + + describe('classList.add', () => { + it('calls classList.add when stuck', () => { + isSticky(el, 0, 0); + + expect( + el.classList.add, + ).toHaveBeenCalledWith('is-stuck'); + }); + + it('does not call classList.add when not stuck', () => { + el.offsetTop = 10; + isSticky(el, 0, 0); + + expect( + el.classList.add, + ).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/javascripts/pdf/index_spec.js b/spec/javascripts/pdf/index_spec.js index f661fae5fe2..bebed432f91 100644 --- a/spec/javascripts/pdf/index_spec.js +++ b/spec/javascripts/pdf/index_spec.js @@ -1,8 +1,8 @@ /* eslint-disable import/no-unresolved */ import Vue from 'vue'; -import { PDFJS } from 'pdfjs-dist'; -import workerSrc from 'vendor/pdf.worker'; +import { PDFJS } from 'vendor/pdf'; +import workerSrc from 'vendor/pdf.worker.min'; import PDFLab from '~/pdf/index.vue'; import pdf from '../fixtures/blob/pdf/test.pdf'; diff --git a/spec/javascripts/pdf/page_spec.js b/spec/javascripts/pdf/page_spec.js index ac76ebbfbe6..ac5b21e8f6c 100644 --- a/spec/javascripts/pdf/page_spec.js +++ b/spec/javascripts/pdf/page_spec.js @@ -1,8 +1,8 @@ /* eslint-disable import/no-unresolved */ import Vue from 'vue'; -import pdfjsLib from 'pdfjs-dist'; -import workerSrc from 'vendor/pdf.worker'; +import pdfjsLib from 'vendor/pdf'; +import workerSrc from 'vendor/pdf.worker.min'; import PageComponent from '~/pdf/page/index.vue'; import testPDF from '../fixtures/blob/pdf/test.pdf'; diff --git a/spec/javascripts/pipeline_schedules/pipeline_schedule_callout_spec.js b/spec/javascripts/pipeline_schedules/pipeline_schedule_callout_spec.js index 6120d224ac0..ed481cb60a1 100644 --- a/spec/javascripts/pipeline_schedules/pipeline_schedule_callout_spec.js +++ b/spec/javascripts/pipeline_schedules/pipeline_schedule_callout_spec.js @@ -1,6 +1,6 @@ import Vue from 'vue'; import Cookies from 'js-cookie'; -import PipelineSchedulesCallout from '~/pipeline_schedules/components/pipeline_schedules_callout'; +import PipelineSchedulesCallout from '~/pipeline_schedules/components/pipeline_schedules_callout.vue'; const PipelineSchedulesCalloutComponent = Vue.extend(PipelineSchedulesCallout); const cookieKey = 'pipeline_schedules_callout_dismissed'; diff --git a/spec/javascripts/project_select_combo_button_spec.js b/spec/javascripts/project_select_combo_button_spec.js new file mode 100644 index 00000000000..e10a5a3bef6 --- /dev/null +++ b/spec/javascripts/project_select_combo_button_spec.js @@ -0,0 +1,105 @@ +import ProjectSelectComboButton from '~/project_select_combo_button'; + +const fixturePath = 'static/project_select_combo_button.html.raw'; + +describe('Project Select Combo Button', function () { + preloadFixtures(fixturePath); + + beforeEach(function () { + this.defaults = { + label: 'Select project to create issue', + groupId: 12345, + projectMeta: { + name: 'My Cool Project', + url: 'http://mycoolproject.com', + }, + newProjectMeta: { + name: 'My Other Cool Project', + url: 'http://myothercoolproject.com', + }, + localStorageKey: 'group-12345-new-issue-recent-project', + relativePath: 'issues/new', + }; + + loadFixtures(fixturePath); + + this.newItemBtn = document.querySelector('.new-project-item-link'); + this.projectSelectInput = document.querySelector('.project-item-select'); + }); + + describe('on page load when localStorage is empty', function () { + beforeEach(function () { + this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); + }); + + it('newItemBtn is disabled', function () { + expect(this.newItemBtn.hasAttribute('disabled')).toBe(true); + expect(this.newItemBtn.classList.contains('disabled')).toBe(true); + }); + + it('newItemBtn href is null', function () { + expect(this.newItemBtn.getAttribute('href')).toBe(''); + }); + + it('newItemBtn text is the plain default label', function () { + expect(this.newItemBtn.textContent).toBe(this.defaults.label); + }); + }); + + describe('on page load when localStorage is filled', function () { + beforeEach(function () { + window.localStorage + .setItem(this.defaults.localStorageKey, JSON.stringify(this.defaults.projectMeta)); + this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); + }); + + it('newItemBtn is not disabled', function () { + expect(this.newItemBtn.hasAttribute('disabled')).toBe(false); + expect(this.newItemBtn.classList.contains('disabled')).toBe(false); + }); + + it('newItemBtn href is correctly set', function () { + expect(this.newItemBtn.getAttribute('href')).toBe(this.defaults.projectMeta.url); + }); + + it('newItemBtn text is the cached label', function () { + expect(this.newItemBtn.textContent) + .toBe(`New issue in ${this.defaults.projectMeta.name}`); + }); + + afterEach(function () { + window.localStorage.clear(); + }); + }); + + describe('after selecting a new project', function () { + beforeEach(function () { + this.comboButton = new ProjectSelectComboButton(this.projectSelectInput); + + // mock the effect of selecting an item from the projects dropdown (select2) + $('.project-item-select') + .val(JSON.stringify(this.defaults.newProjectMeta)) + .trigger('change'); + }); + + it('newItemBtn is not disabled', function () { + expect(this.newItemBtn.hasAttribute('disabled')).toBe(false); + expect(this.newItemBtn.classList.contains('disabled')).toBe(false); + }); + + it('newItemBtn href is correctly set', function () { + expect(this.newItemBtn.getAttribute('href')) + .toBe('http://myothercoolproject.com/issues/new'); + }); + + it('newItemBtn text is the selected project label', function () { + expect(this.newItemBtn.textContent) + .toBe(`New issue in ${this.defaults.newProjectMeta.name}`); + }); + + afterEach(function () { + window.localStorage.clear(); + }); + }); +}); + diff --git a/spec/javascripts/projects/project_import_gitlab_project_spec.js b/spec/javascripts/projects/project_import_gitlab_project_spec.js new file mode 100644 index 00000000000..2f1aae109e3 --- /dev/null +++ b/spec/javascripts/projects/project_import_gitlab_project_spec.js @@ -0,0 +1,25 @@ +import projectImportGitlab from '~/projects/project_import_gitlab_project'; + +describe('Import Gitlab project', () => { + let projectName; + beforeEach(() => { + projectName = 'project'; + window.history.pushState({}, null, `?path=${projectName}`); + + setFixtures(` + <input class="js-path-name" /> + `); + + projectImportGitlab.bindEvents(); + }); + + afterEach(() => { + window.history.pushState({}, null, ''); + }); + + describe('path name', () => { + it('should fill in the project name derived from the previously filled project name', () => { + expect(document.querySelector('.js-path-name').value).toEqual(projectName); + }); + }); +}); diff --git a/spec/javascripts/projects/project_new_spec.js b/spec/javascripts/projects/project_new_spec.js new file mode 100644 index 00000000000..850768f0e4f --- /dev/null +++ b/spec/javascripts/projects/project_new_spec.js @@ -0,0 +1,127 @@ +import projectNew from '~/projects/project_new'; + +describe('New Project', () => { + let $projectImportUrl; + let $projectPath; + + beforeEach(() => { + setFixtures(` + <input id="project_import_url" /> + <input id="project_path" /> + `); + + $projectImportUrl = $('#project_import_url'); + $projectPath = $('#project_path'); + }); + + describe('deriveProjectPathFromUrl', () => { + const dummyImportUrl = `${gl.TEST_HOST}/dummy/import/url.git`; + + beforeEach(() => { + projectNew.bindEvents(); + $projectPath.val('').keyup().val(dummyImportUrl); + }); + + it('does not change project path for disabled $projectImportUrl', () => { + $projectImportUrl.attr('disabled', true); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + describe('for enabled $projectImportUrl', () => { + beforeEach(() => { + $projectImportUrl.attr('disabled', false); + }); + + it('does not change project path if it is set by user', () => { + $projectPath.keyup(); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('does not change project path for empty $projectImportUrl', () => { + $projectImportUrl.val(''); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('does not change project path for whitespace $projectImportUrl', () => { + $projectImportUrl.val(' '); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('does not change project path for $projectImportUrl without slashes', () => { + $projectImportUrl.val('has-no-slash'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual(dummyImportUrl); + }); + + it('changes project path to last $projectImportUrl component', () => { + $projectImportUrl.val('/this/is/last'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('last'); + }); + + it('ignores trailing slashes in $projectImportUrl', () => { + $projectImportUrl.val('/has/trailing/slash/'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('slash'); + }); + + it('ignores fragment identifier in $projectImportUrl', () => { + $projectImportUrl.val('/this/has/a#fragment-identifier/'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('a'); + }); + + it('ignores query string in $projectImportUrl', () => { + $projectImportUrl.val('/url/with?query=string'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('with'); + }); + + it('ignores trailing .git in $projectImportUrl', () => { + $projectImportUrl.val('/repository.git'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('repository'); + }); + + it('changes project path for HTTPS URL in $projectImportUrl', () => { + $projectImportUrl.val('https://username:password@gitlab.company.com/group/project.git'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('project'); + }); + + it('changes project path for SSH URL in $projectImportUrl', () => { + $projectImportUrl.val('git@gitlab.com:gitlab-org/gitlab-ce.git'); + + projectNew.deriveProjectPathFromUrl($projectImportUrl, $projectPath); + + expect($projectPath.val()).toEqual('gitlab-ce'); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_commit_section_spec.js b/spec/javascripts/repo/components/repo_commit_section_spec.js new file mode 100644 index 00000000000..249a2f36fcd --- /dev/null +++ b/spec/javascripts/repo/components/repo_commit_section_spec.js @@ -0,0 +1,160 @@ +import Vue from 'vue'; +import repoCommitSection from '~/repo/components/repo_commit_section.vue'; +import RepoStore from '~/repo/stores/repo_store'; +import Api from '~/api'; + +describe('RepoCommitSection', () => { + const branch = 'master'; + const projectUrl = 'projectUrl'; + const changedFiles = [{ + id: 0, + changed: true, + url: `/namespace/${projectUrl}/blob/${branch}/dir/file0.ext`, + path: 'dir/file0.ext', + newContent: 'a', + }, { + id: 1, + changed: true, + url: `/namespace/${projectUrl}/blob/${branch}/dir/file1.ext`, + path: 'dir/file1.ext', + newContent: 'b', + }]; + const openedFiles = changedFiles.concat([{ + id: 2, + url: `/namespace/${projectUrl}/blob/${branch}/dir/file2.ext`, + path: 'dir/file2.ext', + changed: false, + }]); + + RepoStore.projectUrl = projectUrl; + + function createComponent(el) { + const RepoCommitSection = Vue.extend(repoCommitSection); + + return new RepoCommitSection().$mount(el); + } + + it('renders a commit section', () => { + RepoStore.isCommitable = true; + RepoStore.currentBranch = branch; + RepoStore.targetBranch = branch; + RepoStore.openedFiles = openedFiles; + + const vm = createComponent(); + const changedFileElements = [...vm.$el.querySelectorAll('.changed-files > li')]; + const commitMessage = vm.$el.querySelector('#commit-message'); + const submitCommit = vm.$refs.submitCommit; + const targetBranch = vm.$el.querySelector('.target-branch'); + + expect(vm.$el.querySelector(':scope > form')).toBeTruthy(); + expect(vm.$el.querySelector('.staged-files').textContent.trim()).toEqual('Staged files (2)'); + expect(changedFileElements.length).toEqual(2); + + changedFileElements.forEach((changedFile, i) => { + expect(changedFile.textContent.trim()).toEqual(changedFiles[i].path); + }); + + expect(commitMessage.tagName).toEqual('TEXTAREA'); + expect(commitMessage.name).toEqual('commit-message'); + expect(submitCommit.type).toEqual('submit'); + expect(submitCommit.disabled).toBeTruthy(); + expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeFalsy(); + expect(vm.$el.querySelector('.commit-summary').textContent.trim()).toEqual('Commit 2 files'); + expect(targetBranch.querySelector(':scope > label').textContent.trim()).toEqual('Target branch'); + expect(targetBranch.querySelector('.help-block').textContent.trim()).toEqual(branch); + }); + + it('does not render if not isCommitable', () => { + RepoStore.isCommitable = false; + RepoStore.openedFiles = [{ + id: 0, + changed: true, + }]; + + const vm = createComponent(); + + expect(vm.$el.innerHTML).toBeFalsy(); + }); + + it('does not render if no changedFiles', () => { + RepoStore.isCommitable = true; + RepoStore.openedFiles = []; + + const vm = createComponent(); + + expect(vm.$el.innerHTML).toBeFalsy(); + }); + + it('shows commit submit and summary if commitMessage and spinner if submitCommitsLoading', (done) => { + const projectId = 'projectId'; + const commitMessage = 'commitMessage'; + RepoStore.isCommitable = true; + RepoStore.currentBranch = branch; + RepoStore.targetBranch = branch; + RepoStore.openedFiles = openedFiles; + RepoStore.projectId = projectId; + + // We need to append to body to get form `submit` events working + // Otherwise we run into, "Form submission canceled because the form is not connected" + // See https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#form-submission-algorithm + const el = document.createElement('div'); + document.body.appendChild(el); + + const vm = createComponent(el); + const commitMessageEl = vm.$el.querySelector('#commit-message'); + const submitCommit = vm.$refs.submitCommit; + + vm.commitMessage = commitMessage; + + Vue.nextTick(() => { + expect(commitMessageEl.value).toBe(commitMessage); + expect(submitCommit.disabled).toBeFalsy(); + + spyOn(vm, 'makeCommit').and.callThrough(); + spyOn(Api, 'commitMultiple'); + + submitCommit.click(); + + Vue.nextTick(() => { + expect(vm.makeCommit).toHaveBeenCalled(); + expect(submitCommit.querySelector('.fa-spinner.fa-spin')).toBeTruthy(); + + const args = Api.commitMultiple.calls.allArgs()[0]; + const { commit_message, actions, branch: payloadBranch } = args[1]; + + expect(args[0]).toBe(projectId); + expect(commit_message).toBe(commitMessage); + expect(actions.length).toEqual(2); + expect(payloadBranch).toEqual(branch); + expect(actions[0].action).toEqual('update'); + expect(actions[1].action).toEqual('update'); + expect(actions[0].content).toEqual(openedFiles[0].newContent); + expect(actions[1].content).toEqual(openedFiles[1].newContent); + expect(actions[0].file_path).toEqual(openedFiles[0].path); + expect(actions[1].file_path).toEqual(openedFiles[1].path); + + done(); + }); + }); + }); + + describe('methods', () => { + describe('resetCommitState', () => { + it('should reset store vars and scroll to top', () => { + const vm = { + submitCommitsLoading: true, + changedFiles: new Array(10), + commitMessage: 'commitMessage', + editMode: true, + }; + + repoCommitSection.methods.resetCommitState.call(vm); + + expect(vm.submitCommitsLoading).toEqual(false); + expect(vm.changedFiles).toEqual([]); + expect(vm.commitMessage).toEqual(''); + expect(vm.editMode).toEqual(false); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_edit_button_spec.js b/spec/javascripts/repo/components/repo_edit_button_spec.js new file mode 100644 index 00000000000..29dc2d21e4b --- /dev/null +++ b/spec/javascripts/repo/components/repo_edit_button_spec.js @@ -0,0 +1,51 @@ +import Vue from 'vue'; +import repoEditButton from '~/repo/components/repo_edit_button.vue'; +import RepoStore from '~/repo/stores/repo_store'; + +describe('RepoEditButton', () => { + function createComponent() { + const RepoEditButton = Vue.extend(repoEditButton); + + return new RepoEditButton().$mount(); + } + + it('renders an edit button that toggles the view state', (done) => { + RepoStore.isCommitable = true; + RepoStore.changedFiles = []; + RepoStore.binary = false; + RepoStore.openedFiles = [{}, {}]; + + const vm = createComponent(); + + expect(vm.$el.tagName).toEqual('BUTTON'); + expect(vm.$el.textContent).toMatch('Edit'); + + spyOn(vm, 'editCancelClicked').and.callThrough(); + spyOn(vm, 'toggleProjectRefsForm'); + + vm.$el.click(); + + Vue.nextTick(() => { + expect(vm.editCancelClicked).toHaveBeenCalled(); + expect(vm.toggleProjectRefsForm).toHaveBeenCalled(); + expect(vm.$el.textContent).toMatch('Cancel edit'); + done(); + }); + }); + + it('does not render if not isCommitable', () => { + RepoStore.isCommitable = false; + + const vm = createComponent(); + + expect(vm.$el.innerHTML).toBeUndefined(); + }); + + describe('methods', () => { + describe('editCancelClicked', () => { + it('sets dialog to open when there are changedFiles'); + + it('toggles editMode and calls toggleBlobView'); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_editor_spec.js b/spec/javascripts/repo/components/repo_editor_spec.js new file mode 100644 index 00000000000..85d55d171f9 --- /dev/null +++ b/spec/javascripts/repo/components/repo_editor_spec.js @@ -0,0 +1,49 @@ +import Vue from 'vue'; +import repoEditor from '~/repo/components/repo_editor.vue'; + +describe('RepoEditor', () => { + beforeEach(() => { + const RepoEditor = Vue.extend(repoEditor); + + this.vm = new RepoEditor().$mount(); + }); + + it('renders an ide container', (done) => { + this.vm.openedFiles = ['idiidid']; + this.vm.binary = false; + + Vue.nextTick(() => { + expect(this.vm.shouldHideEditor).toBe(false); + expect(this.vm.$el.id).toEqual('ide'); + expect(this.vm.$el.tagName).toBe('DIV'); + done(); + }); + }); + + describe('when there are no open files', () => { + it('does not render the ide', (done) => { + this.vm.openedFiles = []; + + Vue.nextTick(() => { + expect(this.vm.shouldHideEditor).toBe(true); + expect(this.vm.$el.tagName).not.toBeDefined(); + done(); + }); + }); + }); + + describe('when open file is binary and not raw', () => { + it('does not render the IDE', (done) => { + this.vm.binary = true; + this.vm.activeFile = { + raw: false, + }; + + Vue.nextTick(() => { + expect(this.vm.shouldHideEditor).toBe(true); + expect(this.vm.$el.tagName).not.toBeDefined(); + done(); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_file_buttons_spec.js b/spec/javascripts/repo/components/repo_file_buttons_spec.js new file mode 100644 index 00000000000..dfab51710c3 --- /dev/null +++ b/spec/javascripts/repo/components/repo_file_buttons_spec.js @@ -0,0 +1,75 @@ +import Vue from 'vue'; +import repoFileButtons from '~/repo/components/repo_file_buttons.vue'; +import RepoStore from '~/repo/stores/repo_store'; + +describe('RepoFileButtons', () => { + function createComponent() { + const RepoFileButtons = Vue.extend(repoFileButtons); + + return new RepoFileButtons().$mount(); + } + + it('renders Raw, Blame, History, Permalink and Preview toggle', () => { + const activeFile = { + extension: 'md', + url: 'url', + raw_path: 'raw_path', + blame_path: 'blame_path', + commits_path: 'commits_path', + permalink: 'permalink', + }; + const activeFileLabel = 'activeFileLabel'; + RepoStore.openedFiles = new Array(1); + RepoStore.activeFile = activeFile; + RepoStore.activeFileLabel = activeFileLabel; + RepoStore.editMode = true; + RepoStore.binary = false; + + const vm = createComponent(); + const raw = vm.$el.querySelector('.raw'); + const blame = vm.$el.querySelector('.blame'); + const history = vm.$el.querySelector('.history'); + + expect(vm.$el.id).toEqual('repo-file-buttons'); + expect(raw.href).toMatch(`/${activeFile.raw_path}`); + expect(raw.textContent.trim()).toEqual('Raw'); + expect(blame.href).toMatch(`/${activeFile.blame_path}`); + expect(blame.textContent.trim()).toEqual('Blame'); + expect(history.href).toMatch(`/${activeFile.commits_path}`); + expect(history.textContent.trim()).toEqual('History'); + expect(vm.$el.querySelector('.permalink').textContent.trim()).toEqual('Permalink'); + expect(vm.$el.querySelector('.preview').textContent.trim()).toEqual(activeFileLabel); + }); + + it('triggers rawPreviewToggle on preview click', () => { + const activeFile = { + extension: 'md', + url: 'url', + }; + RepoStore.openedFiles = new Array(1); + RepoStore.activeFile = activeFile; + RepoStore.editMode = true; + + const vm = createComponent(); + const preview = vm.$el.querySelector('.preview'); + + spyOn(vm, 'rawPreviewToggle'); + + preview.click(); + + expect(vm.rawPreviewToggle).toHaveBeenCalled(); + }); + + it('does not render preview toggle if not canPreview', () => { + const activeFile = { + extension: 'abcd', + url: 'url', + }; + RepoStore.openedFiles = new Array(1); + RepoStore.activeFile = activeFile; + + const vm = createComponent(); + + expect(vm.$el.querySelector('.preview')).toBeFalsy(); + }); +}); diff --git a/spec/javascripts/repo/components/repo_file_options_spec.js b/spec/javascripts/repo/components/repo_file_options_spec.js new file mode 100644 index 00000000000..9759b4bf12d --- /dev/null +++ b/spec/javascripts/repo/components/repo_file_options_spec.js @@ -0,0 +1,33 @@ +import Vue from 'vue'; +import repoFileOptions from '~/repo/components/repo_file_options.vue'; + +describe('RepoFileOptions', () => { + const projectName = 'projectName'; + + function createComponent(propsData) { + const RepoFileOptions = Vue.extend(repoFileOptions); + + return new RepoFileOptions({ + propsData, + }).$mount(); + } + + it('renders the title and new file/folder buttons if isMini is true', () => { + const vm = createComponent({ + isMini: true, + projectName, + }); + + expect(vm.$el.classList.contains('repo-file-options')).toBeTruthy(); + expect(vm.$el.querySelector('.title').textContent).toEqual(projectName); + }); + + it('does not render if isMini is false', () => { + const vm = createComponent({ + isMini: false, + projectName, + }); + + expect(vm.$el.innerHTML).toBeFalsy(); + }); +}); diff --git a/spec/javascripts/repo/components/repo_file_spec.js b/spec/javascripts/repo/components/repo_file_spec.js new file mode 100644 index 00000000000..518a2d25ecf --- /dev/null +++ b/spec/javascripts/repo/components/repo_file_spec.js @@ -0,0 +1,136 @@ +import Vue from 'vue'; +import repoFile from '~/repo/components/repo_file.vue'; + +describe('RepoFile', () => { + const updated = 'updated'; + const file = { + icon: 'icon', + url: 'url', + name: 'name', + lastCommitMessage: 'message', + lastCommitUpdate: Date.now(), + level: 10, + }; + const activeFile = { + url: 'url', + }; + + function createComponent(propsData) { + const RepoFile = Vue.extend(repoFile); + + return new RepoFile({ + propsData, + }).$mount(); + } + + beforeEach(() => { + spyOn(repoFile.mixins[0].methods, 'timeFormated').and.returnValue(updated); + }); + + it('renders link, icon, name and last commit details', () => { + const vm = createComponent({ + file, + activeFile, + }); + const name = vm.$el.querySelector('.repo-file-name'); + const fileIcon = vm.$el.querySelector('.file-icon'); + + expect(vm.$el.classList.contains('active')).toBeTruthy(); + expect(vm.$el.querySelector(`.${file.icon}`).style.marginLeft).toEqual('100px'); + expect(name.title).toEqual(file.url); + expect(name.href).toMatch(`/${file.url}`); + expect(name.textContent.trim()).toEqual(file.name); + expect(vm.$el.querySelector('.commit-message').textContent.trim()).toBe(file.lastCommitMessage); + expect(vm.$el.querySelector('.commit-update').textContent.trim()).toBe(updated); + expect(fileIcon.classList.contains(file.icon)).toBeTruthy(); + expect(fileIcon.style.marginLeft).toEqual(`${file.level * 10}px`); + }); + + it('does render if hasFiles is true and is loading tree', () => { + const vm = createComponent({ + file, + activeFile, + loading: { + tree: true, + }, + hasFiles: true, + }); + + expect(vm.$el.innerHTML).toBeTruthy(); + expect(vm.$el.querySelector('.fa-spin.fa-spinner')).toBeFalsy(); + }); + + it('renders a spinner if the file is loading', () => { + file.loading = true; + const vm = createComponent({ + file, + activeFile, + loading: { + tree: true, + }, + hasFiles: true, + }); + + expect(vm.$el.innerHTML).toBeTruthy(); + expect(vm.$el.querySelector('.fa-spin.fa-spinner').style.marginLeft).toEqual(`${file.level * 10}px`); + }); + + it('does not render if loading tree', () => { + const vm = createComponent({ + file, + activeFile, + loading: { + tree: true, + }, + }); + + expect(vm.$el.innerHTML).toBeFalsy(); + }); + + it('does not render commit message and datetime if mini', () => { + const vm = createComponent({ + file, + activeFile, + isMini: true, + }); + + expect(vm.$el.querySelector('.commit-message')).toBeFalsy(); + expect(vm.$el.querySelector('.commit-update')).toBeFalsy(); + }); + + it('does not set active class if file is active file', () => { + const vm = createComponent({ + file, + activeFile: {}, + }); + + expect(vm.$el.classList.contains('active')).toBeFalsy(); + }); + + it('fires linkClicked when the link is clicked', () => { + const vm = createComponent({ + file, + activeFile, + }); + + spyOn(vm, 'linkClicked'); + + vm.$el.querySelector('.repo-file-name').click(); + + expect(vm.linkClicked).toHaveBeenCalledWith(file); + }); + + describe('methods', () => { + describe('linkClicked', () => { + const vm = jasmine.createSpyObj('vm', ['$emit']); + + it('$emits linkclicked with file obj', () => { + const theFile = {}; + + repoFile.methods.linkClicked.call(vm, theFile); + + expect(vm.$emit).toHaveBeenCalledWith('linkclicked', theFile); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_loading_file_spec.js b/spec/javascripts/repo/components/repo_loading_file_spec.js new file mode 100644 index 00000000000..a030314d749 --- /dev/null +++ b/spec/javascripts/repo/components/repo_loading_file_spec.js @@ -0,0 +1,79 @@ +import Vue from 'vue'; +import repoLoadingFile from '~/repo/components/repo_loading_file.vue'; + +describe('RepoLoadingFile', () => { + function createComponent(propsData) { + const RepoLoadingFile = Vue.extend(repoLoadingFile); + + return new RepoLoadingFile({ + propsData, + }).$mount(); + } + + function assertLines(lines) { + lines.forEach((line, n) => { + const index = n + 1; + expect(line.classList.contains(`skeleton-line-${index}`)).toBeTruthy(); + }); + } + + function assertColumns(columns) { + columns.forEach((column) => { + const container = column.querySelector('.animation-container'); + const lines = [...container.querySelectorAll(':scope > div')]; + + expect(container).toBeTruthy(); + expect(lines.length).toEqual(6); + assertLines(lines); + }); + } + + it('renders 3 columns of animated LoC', () => { + const vm = createComponent({ + loading: { + tree: true, + }, + hasFiles: false, + }); + const columns = [...vm.$el.querySelectorAll('td')]; + + expect(columns.length).toEqual(3); + assertColumns(columns); + }); + + it('renders 1 column of animated LoC if isMini', () => { + const vm = createComponent({ + loading: { + tree: true, + }, + hasFiles: false, + isMini: true, + }); + const columns = [...vm.$el.querySelectorAll('td')]; + + expect(columns.length).toEqual(1); + assertColumns(columns); + }); + + it('does not render if tree is not loading', () => { + const vm = createComponent({ + loading: { + tree: false, + }, + hasFiles: false, + }); + + expect(vm.$el.innerHTML).toBeFalsy(); + }); + + it('does not render if hasFiles is true', () => { + const vm = createComponent({ + loading: { + tree: true, + }, + hasFiles: true, + }); + + expect(vm.$el.innerHTML).toBeFalsy(); + }); +}); diff --git a/spec/javascripts/repo/components/repo_prev_directory_spec.js b/spec/javascripts/repo/components/repo_prev_directory_spec.js new file mode 100644 index 00000000000..34dde545e6a --- /dev/null +++ b/spec/javascripts/repo/components/repo_prev_directory_spec.js @@ -0,0 +1,43 @@ +import Vue from 'vue'; +import repoPrevDirectory from '~/repo/components/repo_prev_directory.vue'; + +describe('RepoPrevDirectory', () => { + function createComponent(propsData) { + const RepoPrevDirectory = Vue.extend(repoPrevDirectory); + + return new RepoPrevDirectory({ + propsData, + }).$mount(); + } + + it('renders a prev dir link', () => { + const prevUrl = 'prevUrl'; + const vm = createComponent({ + prevUrl, + }); + const link = vm.$el.querySelector('a'); + + spyOn(vm, 'linkClicked'); + + expect(link.href).toMatch(`/${prevUrl}`); + expect(link.textContent).toEqual('..'); + + link.click(); + + expect(vm.linkClicked).toHaveBeenCalledWith(prevUrl); + }); + + describe('methods', () => { + describe('linkClicked', () => { + const vm = jasmine.createSpyObj('vm', ['$emit']); + + it('$emits linkclicked with file obj', () => { + const file = {}; + + repoPrevDirectory.methods.linkClicked.call(vm, file); + + expect(vm.$emit).toHaveBeenCalledWith('linkclicked', file); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_preview_spec.js b/spec/javascripts/repo/components/repo_preview_spec.js new file mode 100644 index 00000000000..4920cf02083 --- /dev/null +++ b/spec/javascripts/repo/components/repo_preview_spec.js @@ -0,0 +1,23 @@ +import Vue from 'vue'; +import repoPreview from '~/repo/components/repo_preview.vue'; +import RepoStore from '~/repo/stores/repo_store'; + +describe('RepoPreview', () => { + function createComponent() { + const RepoPreview = Vue.extend(repoPreview); + + return new RepoPreview().$mount(); + } + + it('renders a div with the activeFile html', () => { + const activeFile = { + html: '<p class="file-content">html</p>', + }; + RepoStore.activeFile = activeFile; + + const vm = createComponent(); + + expect(vm.$el.tagName).toEqual('DIV'); + expect(vm.$el.innerHTML).toContain(activeFile.html); + }); +}); diff --git a/spec/javascripts/repo/components/repo_sidebar_spec.js b/spec/javascripts/repo/components/repo_sidebar_spec.js new file mode 100644 index 00000000000..abcff8e537e --- /dev/null +++ b/spec/javascripts/repo/components/repo_sidebar_spec.js @@ -0,0 +1,111 @@ +import Vue from 'vue'; +import Helper from '~/repo/helpers/repo_helper'; +import RepoService from '~/repo/services/repo_service'; +import RepoStore from '~/repo/stores/repo_store'; +import repoSidebar from '~/repo/components/repo_sidebar.vue'; + +describe('RepoSidebar', () => { + function createComponent() { + const RepoSidebar = Vue.extend(repoSidebar); + + return new RepoSidebar().$mount(); + } + + it('renders a sidebar', () => { + RepoStore.files = [{ + id: 0, + }]; + RepoStore.openedFiles = []; + const vm = createComponent(); + const thead = vm.$el.querySelector('thead'); + const tbody = vm.$el.querySelector('tbody'); + + expect(vm.$el.id).toEqual('sidebar'); + expect(vm.$el.classList.contains('sidebar-mini')).toBeFalsy(); + expect(thead.querySelector('.name').textContent).toEqual('Name'); + expect(thead.querySelector('.last-commit').textContent).toEqual('Last Commit'); + expect(thead.querySelector('.last-update').textContent).toEqual('Last Update'); + expect(tbody.querySelector('.repo-file-options')).toBeFalsy(); + expect(tbody.querySelector('.prev-directory')).toBeFalsy(); + expect(tbody.querySelector('.loading-file')).toBeFalsy(); + expect(tbody.querySelector('.file')).toBeTruthy(); + }); + + it('does not render a thead, renders repo-file-options and sets sidebar-mini class if isMini', () => { + RepoStore.openedFiles = [{ + id: 0, + }]; + const vm = createComponent(); + + expect(vm.$el.classList.contains('sidebar-mini')).toBeTruthy(); + expect(vm.$el.querySelector('thead')).toBeFalsy(); + expect(vm.$el.querySelector('tbody .repo-file-options')).toBeTruthy(); + }); + + it('renders 5 loading files if tree is loading and not hasFiles', () => { + RepoStore.loading = { + tree: true, + }; + RepoStore.files = []; + const vm = createComponent(); + + expect(vm.$el.querySelectorAll('tbody .loading-file').length).toEqual(5); + }); + + it('renders a prev directory if isRoot', () => { + RepoStore.files = [{ + id: 0, + }]; + RepoStore.isRoot = true; + const vm = createComponent(); + + expect(vm.$el.querySelector('tbody .prev-directory')).toBeTruthy(); + }); + + describe('methods', () => { + describe('fileClicked', () => { + it('should fetch data for new file', () => { + spyOn(Helper, 'getContent').and.callThrough(); + const file1 = { + id: 0, + url: '', + }; + RepoStore.files = [file1]; + RepoStore.isRoot = true; + const vm = createComponent(); + + vm.fileClicked(file1); + + expect(Helper.getContent).toHaveBeenCalledWith(file1); + }); + + it('should hide files in directory if already open', () => { + spyOn(RepoStore, 'removeChildFilesOfTree').and.callThrough(); + const file1 = { + id: 0, + type: 'tree', + url: '', + opened: true, + }; + RepoStore.files = [file1]; + RepoStore.isRoot = true; + const vm = createComponent(); + + vm.fileClicked(file1); + + expect(RepoStore.removeChildFilesOfTree).toHaveBeenCalledWith(file1); + }); + }); + + describe('goToPreviousDirectoryClicked', () => { + it('should hide files in directory if already open', () => { + const prevUrl = 'foo/bar'; + const vm = createComponent(); + + vm.goToPreviousDirectoryClicked(prevUrl); + + expect(RepoService.url).toEqual(prevUrl); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_tab_spec.js b/spec/javascripts/repo/components/repo_tab_spec.js new file mode 100644 index 00000000000..d2a790ad73a --- /dev/null +++ b/spec/javascripts/repo/components/repo_tab_spec.js @@ -0,0 +1,70 @@ +import Vue from 'vue'; +import repoTab from '~/repo/components/repo_tab.vue'; + +describe('RepoTab', () => { + function createComponent(propsData) { + const RepoTab = Vue.extend(repoTab); + + return new RepoTab({ + propsData, + }).$mount(); + } + + it('renders a close link and a name link', () => { + const tab = { + url: 'url', + name: 'name', + }; + const vm = createComponent({ + tab, + }); + const close = vm.$el.querySelector('.close'); + const name = vm.$el.querySelector(`a[title="${tab.url}"]`); + + spyOn(vm, 'closeTab'); + spyOn(vm, 'tabClicked'); + + expect(close.querySelector('.fa-times')).toBeTruthy(); + expect(name.textContent.trim()).toEqual(tab.name); + + close.click(); + name.click(); + + expect(vm.closeTab).toHaveBeenCalledWith(tab); + expect(vm.tabClicked).toHaveBeenCalledWith(tab); + }); + + it('renders an fa-circle icon if tab is changed', () => { + const tab = { + url: 'url', + name: 'name', + changed: true, + }; + const vm = createComponent({ + tab, + }); + + expect(vm.$el.querySelector('.close .fa-circle')).toBeTruthy(); + }); + + describe('methods', () => { + describe('closeTab', () => { + const vm = jasmine.createSpyObj('vm', ['$emit']); + + it('returns undefined and does not $emit if file is changed', () => { + const file = { changed: true }; + const returnVal = repoTab.methods.closeTab.call(vm, file); + + expect(returnVal).toBeUndefined(); + expect(vm.$emit).not.toHaveBeenCalled(); + }); + + it('$emits tabclosed event with file obj', () => { + const file = { changed: false }; + repoTab.methods.closeTab.call(vm, file); + + expect(vm.$emit).toHaveBeenCalledWith('tabclosed', file); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/components/repo_tabs_spec.js b/spec/javascripts/repo/components/repo_tabs_spec.js new file mode 100644 index 00000000000..a02b54efafc --- /dev/null +++ b/spec/javascripts/repo/components/repo_tabs_spec.js @@ -0,0 +1,45 @@ +import Vue from 'vue'; +import RepoStore from '~/repo/stores/repo_store'; +import repoTabs from '~/repo/components/repo_tabs.vue'; + +describe('RepoTabs', () => { + const openedFiles = [{ + id: 0, + active: true, + }, { + id: 1, + }]; + + function createComponent() { + const RepoTabs = Vue.extend(repoTabs); + + return new RepoTabs().$mount(); + } + + it('renders a list of tabs', () => { + RepoStore.openedFiles = openedFiles; + + const vm = createComponent(); + const tabs = [...vm.$el.querySelectorAll(':scope > li')]; + + expect(vm.$el.id).toEqual('tabs'); + expect(tabs.length).toEqual(3); + expect(tabs[0].classList.contains('active')).toBeTruthy(); + expect(tabs[1].classList.contains('active')).toBeFalsy(); + expect(tabs[2].classList.contains('tabs-divider')).toBeTruthy(); + }); + + describe('methods', () => { + describe('tabClosed', () => { + it('calls removeFromOpenedFiles with file obj', () => { + const file = {}; + + spyOn(RepoStore, 'removeFromOpenedFiles'); + + repoTabs.methods.tabClosed(file); + + expect(RepoStore.removeFromOpenedFiles).toHaveBeenCalledWith(file); + }); + }); + }); +}); diff --git a/spec/javascripts/repo/monaco_loader_spec.js b/spec/javascripts/repo/monaco_loader_spec.js new file mode 100644 index 00000000000..be6e779c50f --- /dev/null +++ b/spec/javascripts/repo/monaco_loader_spec.js @@ -0,0 +1,17 @@ +/* global __webpack_public_path__ */ +import monacoContext from 'monaco-editor/dev/vs/loader'; + +describe('MonacoLoader', () => { + it('calls require.config and exports require', () => { + spyOn(monacoContext.require, 'config'); + + const monacoLoader = require('~/repo/monaco_loader'); // eslint-disable-line global-require + + expect(monacoContext.require.config).toHaveBeenCalledWith({ + paths: { + vs: `${__webpack_public_path__}monaco-editor/vs`, // eslint-disable-line camelcase + }, + }); + expect(monacoLoader.default).toBe(monacoContext.require); + }); +}); diff --git a/spec/javascripts/repo/services/repo_service_spec.js b/spec/javascripts/repo/services/repo_service_spec.js new file mode 100644 index 00000000000..d74e6a67b1e --- /dev/null +++ b/spec/javascripts/repo/services/repo_service_spec.js @@ -0,0 +1,121 @@ +import axios from 'axios'; +import RepoService from '~/repo/services/repo_service'; + +describe('RepoService', () => { + it('has default json format param', () => { + expect(RepoService.options.params.format).toBe('json'); + }); + + describe('buildParams', () => { + let newParams; + const url = 'url'; + + beforeEach(() => { + newParams = {}; + + spyOn(Object, 'assign').and.returnValue(newParams); + }); + + it('clones params', () => { + const params = RepoService.buildParams(url); + + expect(Object.assign).toHaveBeenCalledWith({}, RepoService.options.params); + + expect(params).toBe(newParams); + }); + + it('sets and returns viewer params to richif urlIsRichBlob is true', () => { + spyOn(RepoService, 'urlIsRichBlob').and.returnValue(true); + + const params = RepoService.buildParams(url); + + expect(params.viewer).toEqual('rich'); + }); + + it('returns params urlIsRichBlob is false', () => { + spyOn(RepoService, 'urlIsRichBlob').and.returnValue(false); + + const params = RepoService.buildParams(url); + + expect(params.viewer).toBeUndefined(); + }); + + it('calls urlIsRichBlob with the objects url prop if no url arg is provided', () => { + spyOn(RepoService, 'urlIsRichBlob'); + RepoService.url = url; + + RepoService.buildParams(); + + expect(RepoService.urlIsRichBlob).toHaveBeenCalledWith(url); + }); + }); + + describe('urlIsRichBlob', () => { + it('returns true for md extension', () => { + const isRichBlob = RepoService.urlIsRichBlob('url.md'); + + expect(isRichBlob).toBeTruthy(); + }); + + it('returns false for js extension', () => { + const isRichBlob = RepoService.urlIsRichBlob('url.js'); + + expect(isRichBlob).toBeFalsy(); + }); + }); + + describe('getContent', () => { + const params = {}; + const url = 'url'; + const requestPromise = Promise.resolve(); + + beforeEach(() => { + spyOn(RepoService, 'buildParams').and.returnValue(params); + spyOn(axios, 'get').and.returnValue(requestPromise); + }); + + it('calls buildParams and axios.get', () => { + const request = RepoService.getContent(url); + + expect(RepoService.buildParams).toHaveBeenCalledWith(url); + expect(axios.get).toHaveBeenCalledWith(url, { + params, + }); + expect(request).toBe(requestPromise); + }); + + it('uses object url prop if no url arg is provided', () => { + RepoService.url = url; + + RepoService.getContent(); + + expect(axios.get).toHaveBeenCalledWith(url, { + params, + }); + }); + }); + + describe('getBase64Content', () => { + const url = 'url'; + const response = { data: 'data' }; + + beforeEach(() => { + spyOn(RepoService, 'bufferToBase64'); + spyOn(axios, 'get').and.returnValue(Promise.resolve(response)); + }); + + it('calls axios.get and bufferToBase64 on completion', (done) => { + const request = RepoService.getBase64Content(url); + + expect(axios.get).toHaveBeenCalledWith(url, { + responseType: 'arraybuffer', + }); + expect(request).toEqual(jasmine.any(Promise)); + + request.then(() => { + expect(RepoService.bufferToBase64).toHaveBeenCalledWith(response.data); + done(); + }).catch(done.fail); + }); + }); +}); diff --git a/spec/javascripts/sidebar/confidential_edit_buttons_spec.js b/spec/javascripts/sidebar/confidential_edit_buttons_spec.js new file mode 100644 index 00000000000..482be466aad --- /dev/null +++ b/spec/javascripts/sidebar/confidential_edit_buttons_spec.js @@ -0,0 +1,39 @@ +import Vue from 'vue'; +import editFormButtons from '~/sidebar/components/confidential/edit_form_buttons.vue'; + +describe('Edit Form Buttons', () => { + let vm1; + let vm2; + + beforeEach(() => { + const Component = Vue.extend(editFormButtons); + const toggleForm = () => { }; + const updateConfidentialAttribute = () => { }; + + vm1 = new Component({ + propsData: { + isConfidential: true, + toggleForm, + updateConfidentialAttribute, + }, + }).$mount(); + + vm2 = new Component({ + propsData: { + isConfidential: false, + toggleForm, + updateConfidentialAttribute, + }, + }).$mount(); + }); + + it('renders on or off text based on confidentiality', () => { + expect( + vm1.$el.innerHTML.includes('Turn Off'), + ).toBe(true); + + expect( + vm2.$el.innerHTML.includes('Turn On'), + ).toBe(true); + }); +}); diff --git a/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js b/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js new file mode 100644 index 00000000000..724f5126945 --- /dev/null +++ b/spec/javascripts/sidebar/confidential_edit_form_buttons_spec.js @@ -0,0 +1,39 @@ +import Vue from 'vue'; +import editForm from '~/sidebar/components/confidential/edit_form.vue'; + +describe('Edit Form Dropdown', () => { + let vm1; + let vm2; + + beforeEach(() => { + const Component = Vue.extend(editForm); + const toggleForm = () => { }; + const updateConfidentialAttribute = () => { }; + + vm1 = new Component({ + propsData: { + isConfidential: true, + toggleForm, + updateConfidentialAttribute, + }, + }).$mount(); + + vm2 = new Component({ + propsData: { + isConfidential: false, + toggleForm, + updateConfidentialAttribute, + }, + }).$mount(); + }); + + it('renders on the appropriate warning text', () => { + expect( + vm1.$el.innerHTML.includes('You are going to turn off the confidentiality.'), + ).toBe(true); + + expect( + vm2.$el.innerHTML.includes('You are going to turn on the confidentiality.'), + ).toBe(true); + }); +}); diff --git a/spec/javascripts/sidebar/confidential_issue_sidebar_spec.js b/spec/javascripts/sidebar/confidential_issue_sidebar_spec.js new file mode 100644 index 00000000000..2e16adffb5b --- /dev/null +++ b/spec/javascripts/sidebar/confidential_issue_sidebar_spec.js @@ -0,0 +1,65 @@ +import Vue from 'vue'; +import confidentialIssueSidebar from '~/sidebar/components/confidential/confidential_issue_sidebar.vue'; + +describe('Confidential Issue Sidebar Block', () => { + let vm1; + let vm2; + + beforeEach(() => { + const Component = Vue.extend(confidentialIssueSidebar); + const service = { + update: () => new Promise((resolve, reject) => { + resolve(true); + reject('failed!'); + }), + }; + + vm1 = new Component({ + propsData: { + isConfidential: true, + isEditable: true, + service, + }, + }).$mount(); + + vm2 = new Component({ + propsData: { + isConfidential: false, + isEditable: false, + service, + }, + }).$mount(); + }); + + it('shows if confidential and/or editable', () => { + expect( + vm1.$el.innerHTML.includes('Edit'), + ).toBe(true); + + expect( + vm1.$el.innerHTML.includes('This issue is confidential'), + ).toBe(true); + + expect( + vm2.$el.innerHTML.includes('This issue is not confidential'), + ).toBe(true); + }); + + it('displays the edit form when editable', (done) => { + expect(vm1.edit).toBe(false); + + vm1.$el.querySelector('.confidential-edit').click(); + + expect(vm1.edit).toBe(true); + + setTimeout(() => { + expect( + vm1.$el + .innerHTML + .includes('You are going to turn off the confidentiality.'), + ).toBe(true); + + done(); + }); + }); +}); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js index ab8a3f6c64c..7ee998c8fce 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_deployment_spec.js @@ -1,7 +1,6 @@ import Vue from 'vue'; import deploymentComponent from '~/vue_merge_request_widget/components/mr_widget_deployment'; import MRWidgetService from '~/vue_merge_request_widget/services/mr_widget_service'; -import { statusIconEntityMap } from '~/vue_shared/ci_status_icons'; const deploymentMockData = [ { @@ -43,15 +42,6 @@ describe('MRWidgetDeployment', () => { }); }); - describe('computed', () => { - describe('svg', () => { - it('should have the proper SVG icon', () => { - const vm = createComponent(deploymentMockData); - expect(vm.svg).toEqual(statusIconEntityMap.icon_status_success); - }); - }); - }); - describe('methods', () => { let vm = createComponent(); const deployment = deploymentMockData[0]; diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js index 6adcbc73ed7..2ae3adc1f93 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_memory_usage_spec.js @@ -52,10 +52,10 @@ const createComponent = () => { }; const messages = { - loadingMetrics: 'Loading deployment statistics.', + loadingMetrics: 'Loading deployment statistics', hasMetrics: 'Memory usage unchanged from 0MB to 0MB', - loadFailed: 'Failed to load deployment statistics.', - metricsUnavailable: 'Deployment statistics are not available currently.', + loadFailed: 'Failed to load deployment statistics', + metricsUnavailable: 'Deployment statistics are not available currently', }; describe('MemoryUsage', () => { diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js index 647b59520f8..c763487d12f 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_pipeline_spec.js @@ -81,13 +81,12 @@ describe('MRWidgetPipeline', () => { expect(el.querySelectorAll('.ci-status-icon.ci-status-icon-success').length).toEqual(1); expect(el.querySelector('.pipeline-id').textContent).toContain(`#${pipeline.id}`); expect(el.innerText).toContain('passed'); - expect(el.innerText).toContain('with stages'); expect(el.querySelector('.pipeline-id').getAttribute('href')).toEqual(pipeline.path); expect(el.querySelectorAll('.stage-container').length).toEqual(2); expect(el.querySelector('.js-ci-error')).toEqual(null); expect(el.querySelector('.js-commit-link').getAttribute('href')).toEqual(pipeline.commit.commit_path); expect(el.querySelector('.js-commit-link').textContent).toContain(pipeline.commit.short_id); - expect(el.querySelector('.js-mr-coverage').textContent).toContain(`Coverage ${pipeline.coverage}%.`); + expect(el.querySelector('.js-mr-coverage').textContent).toContain(`Coverage ${pipeline.coverage}%`); }); it('should list single stage', (done) => { @@ -95,7 +94,6 @@ describe('MRWidgetPipeline', () => { Vue.nextTick(() => { expect(el.querySelectorAll('.stage-container button').length).toEqual(1); - expect(el.innerText).toContain('with stage'); done(); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js index f6e0c3dfb74..f86fb6a0b4b 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js @@ -22,15 +22,16 @@ describe('MRWidgetRelatedLinks', () => { }); describe('computed', () => { + const data = { + relatedLinks: { + closing: '/foo', + mentioned: '/foo', + assignToMe: '/foo', + }, + }; + describe('hasLinks', () => { it('should return correct value when we have links reference', () => { - const data = { - relatedLinks: { - closing: '/foo', - mentioned: '/foo', - assignToMe: '/foo', - }, - }; const vm = createComponent(data); expect(vm.hasLinks).toBeTruthy(); @@ -44,44 +45,24 @@ describe('MRWidgetRelatedLinks', () => { expect(vm.hasLinks).toBeFalsy(); }); }); - }); - - describe('methods', () => { - const data = { - relatedLinks: { - closing: '<a href="#">#23</a> and <a>#42</a>', - mentioned: '<a href="#">#7</a>', - }, - }; - const vm = createComponent(data); - - describe('hasMultipleIssues', () => { - it('should return true if the given text has multiple issues', () => { - expect(vm.hasMultipleIssues(data.relatedLinks.closing)).toBeTruthy(); - }); - - it('should return false if the given text has one issue', () => { - expect(vm.hasMultipleIssues(data.relatedLinks.mentioned)).toBeFalsy(); - }); - }); - describe('issueLabel', () => { - it('should return true if the given text has multiple issues', () => { - expect(vm.issueLabel('closing')).toEqual('issues'); - }); - - it('should return false if the given text has one issue', () => { - expect(vm.issueLabel('mentioned')).toEqual('issue'); + describe('closesText', () => { + it('returns correct text for open merge request', () => { + data.state = 'open'; + const vm = createComponent(data); + expect(vm.closesText).toEqual('Closes'); }); - }); - describe('verbLabel', () => { - it('should return true if the given text has multiple issues', () => { - expect(vm.verbLabel('closing')).toEqual('are'); + it('returns correct text for closed merge request', () => { + data.state = 'closed'; + const vm = createComponent(data); + expect(vm.closesText).toEqual('Did not close'); }); - it('should return false if the given text has one issue', () => { - expect(vm.verbLabel('mentioned')).toEqual('is'); + it('returns correct tense for merged request', () => { + data.state = 'merged'; + const vm = createComponent(data); + expect(vm.closesText).toEqual('Closed'); }); }); }); @@ -95,8 +76,8 @@ describe('MRWidgetRelatedLinks', () => { }); const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); - expect(content).toContain('Closes issues #23 and #42'); - expect(content).not.toContain('mentioned'); + expect(content).toContain('Closes #23 and #42'); + expect(content).not.toContain('Mentions'); }); it('should have only have mentioned issues text', () => { @@ -106,8 +87,7 @@ describe('MRWidgetRelatedLinks', () => { }, }); - expect(vm.$el.innerText).toContain('issue #7'); - expect(vm.$el.innerText).toContain('is mentioned but will not be closed.'); + expect(vm.$el.innerText).toContain('Mentions #7'); expect(vm.$el.innerText).not.toContain('Closes'); }); @@ -120,9 +100,8 @@ describe('MRWidgetRelatedLinks', () => { }); const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); - expect(content).toContain('Closes issue #7.'); - expect(content).toContain('issues #23 and #42'); - expect(content).toContain('are mentioned but will not be closed.'); + expect(content).toContain('Closes #7'); + expect(content).toContain('Mentions #23 and #42'); }); it('should have assing issues link', () => { diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js index cac2f561a0b..4869fb17d96 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_archived_spec.js @@ -12,7 +12,7 @@ describe('MRWidgetArchived', () => { expect(el.classList.contains('mr-widget-body')).toBeTruthy(); expect(el.querySelector('button').classList.contains('btn-success')).toBeTruthy(); expect(el.querySelector('button').disabled).toBeTruthy(); - expect(el.innerText).toContain('This project is archived, write access has been disabled.'); + expect(el.innerText).toContain('This project is archived, write access has been disabled'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js index 47b4ba893e0..6042d7384d5 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_auto_merge_failed_spec.js @@ -24,8 +24,8 @@ describe('MRWidgetAutoMergeFailed', () => { it('should have correct elements', () => { expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(vm.$el.innerText).toContain('This merge request failed to be merged automatically.'); + expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeFalsy(); + expect(vm.$el.innerText).toContain('This merge request failed to be merged automatically'); expect(vm.$el.innerText).toContain(mergeError); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js index 3be11d47227..6b7aa935ad3 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_checking_spec.js @@ -12,7 +12,7 @@ describe('MRWidgetChecking', () => { expect(el.classList.contains('mr-widget-body')).toBeTruthy(); expect(el.querySelector('button').classList.contains('btn-success')).toBeTruthy(); expect(el.querySelector('button').disabled).toBeTruthy(); - expect(el.innerText).toContain('Checking ability to merge automatically.'); + expect(el.innerText).toContain('Checking ability to merge automatically'); expect(el.querySelector('i')).toBeDefined(); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js index e7ae85caec4..3b7b7d93662 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_conflicts_spec.js @@ -29,15 +29,16 @@ describe('MRWidgetConflicts', () => { describe('template', () => { it('should have correct elements', () => { const el = createComponent().$el; - const resolveButton = el.querySelectorAll('.btn-group .btn')[0]; - const mergeLocallyButton = el.querySelectorAll('.btn-group .btn')[1]; + const resolveButton = el.querySelector('.js-resolve-conflicts-button'); + const mergeButton = el.querySelector('.mr-widget-body .btn'); + const mergeLocallyButton = el.querySelector('.js-merge-locally-button'); - expect(el.textContent).toContain('There are merge conflicts.'); + expect(el.textContent).toContain('There are merge conflicts'); expect(el.textContent).not.toContain('ask someone with write access'); expect(el.querySelector('.btn-success').disabled).toBeTruthy(); - expect(el.querySelectorAll('.btn-group .btn').length).toBe(2); expect(resolveButton.textContent).toContain('Resolve conflicts'); expect(resolveButton.getAttribute('href')).toEqual(path); + expect(mergeButton.textContent).toContain('Merge'); expect(mergeLocallyButton.textContent).toContain('Merge locally'); }); @@ -59,8 +60,8 @@ describe('MRWidgetConflicts', () => { it('should not have action buttons', (done) => { Vue.nextTick(() => { expect(vm.$el.querySelectorAll('.btn').length).toBe(1); - expect(vm.$el.querySelector('a.js-resolve-conflicts-button')).toEqual(null); - expect(vm.$el.querySelector('a.js-merge-locally-button')).toEqual(null); + expect(vm.$el.querySelector('.js-resolve-conflicts-button')).toEqual(null); + expect(vm.$el.querySelector('.js-merge-locally-button')).toEqual(null); done(); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js index 587b83430d9..cef365eec8a 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js @@ -94,7 +94,7 @@ describe('MRWidgetFailedToMerge', () => { expect(el.querySelector('button').innerText).toContain('Merge'); expect(el.querySelector('.js-refresh-button').innerText).toContain('Refresh now'); expect(el.querySelector('.js-refresh-label')).toEqual(null); - expect(el.innerText).not.toContain('Refreshing now...'); + expect(el.innerText).not.toContain('Refreshing now'); setTimeout(() => { expect(el.innerText).toContain('Refreshing in 9 seconds'); done(); @@ -115,7 +115,7 @@ describe('MRWidgetFailedToMerge', () => { vm.refresh(); Vue.nextTick(() => { expect(el.innerText).not.toContain('Merge failed. Refreshing'); - expect(el.innerText).toContain('Refreshing now...'); + expect(el.innerText).toContain('Refreshing now'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js index fb2ef606604..237035648cf 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_locked_spec.js @@ -1,10 +1,10 @@ import Vue from 'vue'; -import lockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_locked'; +import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging'; -describe('MRWidgetLocked', () => { +describe('MRWidgetMerging', () => { describe('props', () => { it('should have props', () => { - const { mr } = lockedComponent.props; + const { mr } = mergingComponent.props; expect(mr.type instanceof Object).toBeTruthy(); expect(mr.required).toBeTruthy(); @@ -13,7 +13,7 @@ describe('MRWidgetLocked', () => { describe('template', () => { it('should have correct elements', () => { - const Component = Vue.extend(lockedComponent); + const Component = Vue.extend(mergingComponent); const mr = { targetBranchPath: '/branch-path', targetBranch: 'branch', @@ -24,7 +24,7 @@ describe('MRWidgetLocked', () => { }).$el; expect(el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(el.innerText).toContain('it is locked'); + expect(el.innerText).toContain('This merge request is in the process of being merged'); expect(el.innerText).toContain('changes will be merged into'); expect(el.querySelector('.label-branch a').getAttribute('href')).toEqual(mr.targetBranchPath); expect(el.querySelector('.label-branch a').textContent).toContain(mr.targetBranch); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js index 8d8b90cea16..9a71d0b47d7 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merge_when_pipeline_succeeds_spec.js @@ -162,10 +162,10 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => { it('should have correct elements', () => { expect(el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(el.innerText).toContain('to be merged automatically when the pipeline succeeds.'); + expect(el.innerText).toContain('to be merged automatically when the pipeline succeeds'); expect(el.innerText).toContain('The changes will be merged into'); expect(el.innerText).toContain(targetBranch); - expect(el.innerText).toContain('The source branch will not be removed.'); + expect(el.innerText).toContain('The source branch will not be removed'); expect(el.querySelector('.js-cancel-auto-merge').innerText).toContain('Cancel automatic merge'); expect(el.querySelector('.js-cancel-auto-merge').getAttribute('disabled')).toBeFalsy(); expect(el.querySelector('.js-remove-source-branch').innerText).toContain('Remove source branch'); @@ -186,8 +186,8 @@ describe('MRWidgetMergeWhenPipelineSucceeds', () => { Vue.nextTick(() => { const normalizedText = el.innerText.replace(/\s+/g, ' '); - expect(normalizedText).toContain('The source branch will be removed.'); - expect(normalizedText).not.toContain('The source branch will not be removed.'); + expect(normalizedText).toContain('The source branch will be removed'); + expect(normalizedText).not.toContain('The source branch will not be removed'); done(); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js index 6628010112d..afaa750199a 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js @@ -142,19 +142,19 @@ describe('MRWidgetMerged', () => { expect(el.querySelector('.js-mr-widget-author')).toBeDefined(); expect(el.innerText).toContain('The changes were merged into'); expect(el.innerText).toContain(targetBranch); - expect(el.innerText).toContain('The source branch has been removed.'); + expect(el.innerText).toContain('The source branch has been removed'); expect(el.innerText).toContain('Revert'); expect(el.innerText).toContain('Cherry-pick'); - expect(el.innerText).not.toContain('You can remove source branch now.'); - expect(el.innerText).not.toContain('The source branch is being removed.'); + expect(el.innerText).not.toContain('You can remove source branch now'); + expect(el.innerText).not.toContain('The source branch is being removed'); }); it('should not show source branch removed text', (done) => { vm.mr.sourceBranchRemoved = false; Vue.nextTick(() => { - expect(el.innerText).toContain('You can remove source branch now.'); - expect(el.innerText).not.toContain('The source branch has been removed.'); + expect(el.innerText).toContain('You can remove source branch now'); + expect(el.innerText).not.toContain('The source branch has been removed'); done(); }); }); @@ -164,9 +164,9 @@ describe('MRWidgetMerged', () => { vm.mr.sourceBranchRemoved = false; Vue.nextTick(() => { - expect(el.innerText).toContain('The source branch is being removed.'); - expect(el.innerText).not.toContain('You can remove source branch now.'); - expect(el.innerText).not.toContain('The source branch has been removed.'); + expect(el.innerText).toContain('The source branch is being removed'); + expect(el.innerText).not.toContain('You can remove source branch now'); + expect(el.innerText).not.toContain('The source branch has been removed'); done(); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js index 98674d12afb..720effb5c1c 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_missing_branch_spec.js @@ -49,7 +49,7 @@ describe('MRWidgetMissingBranch', () => { expect(el.classList.contains('mr-widget-body')).toBeTruthy(); expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy(); expect(content).toContain('source branch does not exist.'); - expect(content).toContain('Please restore the source branch or use a different source branch.'); + expect(content).toContain('Please restore it or use a different source branch'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js index 61e00f4cf79..33f20ab132d 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_not_allowed_spec.js @@ -11,7 +11,7 @@ describe('MRWidgetNotAllowed', () => { expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy(); expect(vm.$el.innerText).toContain('Ready to be merged automatically.'); - expect(vm.$el.innerText).toContain('Ask someone with write access to this repository to merge this request.'); + expect(vm.$el.innerText).toContain('Ask someone with write access to this repository to merge this request'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js index b293d118571..d0702f9f503 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_blocked_spec.js @@ -10,7 +10,7 @@ describe('MRWidgetPipelineBlocked', () => { it('should have correct elements', () => { expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(vm.$el.innerText).toContain('Pipeline blocked. The pipeline for this merge request requires a manual action to proceed.'); + expect(vm.$el.innerText).toContain('Pipeline blocked. The pipeline for this merge request requires a manual action to proceed'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js index 807fba705d4..78bac1c61a5 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_pipeline_failed_spec.js @@ -10,7 +10,7 @@ describe('MRWidgetPipelineFailed', () => { it('should have correct elements', () => { expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(vm.$el.innerText).toContain('The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure.'); + expect(vm.$el.innerText).toContain('The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js index 732b516badd..c607c9746a4 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_ready_to_merge_spec.js @@ -72,7 +72,7 @@ describe('MRWidgetReadyToMerge', () => { const withDesc = 'Include description in commit message'; const withoutDesc = "Don't include description in commit message"; - it('should return message wit description', () => { + it('should return message with description', () => { expect(vm.commitMessageLinkTitle).toEqual(withDesc); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js index 5fb1d69a8b3..4c67504b642 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_sha_mismatch_spec.js @@ -10,7 +10,7 @@ describe('MRWidgetSHAMismatch', () => { it('should have correct elements', () => { expect(vm.$el.classList.contains('mr-widget-body')).toBeTruthy(); expect(vm.$el.querySelector('button').getAttribute('disabled')).toBeTruthy(); - expect(vm.$el.innerText).toContain('The source branch HEAD has recently changed. Please reload the page and review the changes before merging.'); + expect(vm.$el.innerText).toContain('The source branch HEAD has recently changed. Please reload the page and review the changes before merging'); }); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js index 45bd1a69964..2cb3aaa6951 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_wip_spec.js @@ -78,7 +78,7 @@ describe('MRWidgetWIP', () => { it('should have correct elements', () => { expect(el.classList.contains('mr-widget-body')).toBeTruthy(); - expect(el.innerText).toContain('This merge request is currently Work In Progress and therefore unable to merge'); + expect(el.innerText).toContain('This is a Work in Progress'); expect(el.querySelector('button').getAttribute('disabled')).toBeTruthy(); expect(el.querySelector('button').innerText).toContain('Merge'); expect(el.querySelector('.js-remove-wip').innerText).toContain('Resolve WIP status'); diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js index e6f96d5588b..0795d0aaa82 100644 --- a/spec/javascripts/vue_mr_widget/mock_data.js +++ b/spec/javascripts/vue_mr_widget/mock_data.js @@ -20,7 +20,6 @@ export default { "human_time_estimate": null, "human_total_time_spent": null, "in_progress_merge_commit_sha": null, - "locked_at": null, "merge_commit_sha": "53027d060246c8f47e4a9310fb332aa52f221775", "merge_error": null, "merge_params": { @@ -30,6 +29,7 @@ export default { "merge_user_id": null, "merge_when_pipeline_succeeds": false, "source_branch": "daaaa", + "source_branch_link": "daaaa", "source_project_id": 19, "target_branch": "master", "target_project_id": 19, diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js index 3a0c50b750f..669ee248bf1 100644 --- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js @@ -342,7 +342,7 @@ describe('mrWidgetOptions', () => { expect(comps['mr-widget-related-links']).toBeDefined(); expect(comps['mr-widget-merged']).toBeDefined(); expect(comps['mr-widget-closed']).toBeDefined(); - expect(comps['mr-widget-locked']).toBeDefined(); + expect(comps['mr-widget-merging']).toBeDefined(); expect(comps['mr-widget-failed-to-merge']).toBeDefined(); expect(comps['mr-widget-wip']).toBeDefined(); expect(comps['mr-widget-archived']).toBeDefined(); diff --git a/spec/lib/api/helpers/pagination_spec.rb b/spec/lib/api/helpers/pagination_spec.rb index 267318faed4..fb3ef04b860 100644 --- a/spec/lib/api/helpers/pagination_spec.rb +++ b/spec/lib/api/helpers/pagination_spec.rb @@ -32,7 +32,7 @@ describe API::Helpers::Pagination do context 'when resource can be paginated' do before do - create_list(:empty_project, 3) + create_list(:project, 3) end describe 'first page' do diff --git a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb index 27532f96f56..7c0ba9ee67f 100644 --- a/spec/lib/banzai/filter/abstract_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/abstract_reference_filter_spec.rb @@ -1,11 +1,11 @@ require 'spec_helper' describe Banzai::Filter::AbstractReferenceFilter do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } describe '#references_per_project' do it 'returns a Hash containing references grouped per project paths' do - doc = Nokogiri::HTML.fragment("#1 #{project.path_with_namespace}#2") + doc = Nokogiri::HTML.fragment("#1 #{project.full_path}#2") filter = described_class.new(doc, project: project) expect(filter).to receive(:object_class).exactly(4).times.and_return(Issue) @@ -14,7 +14,7 @@ describe Banzai::Filter::AbstractReferenceFilter do refs = filter.references_per_project expect(refs).to be_an_instance_of(Hash) - expect(refs[project.path_with_namespace]).to eq(Set.new(%w[1 2])) + expect(refs[project.full_path]).to eq(Set.new(%w[1 2])) end end @@ -24,10 +24,10 @@ describe Banzai::Filter::AbstractReferenceFilter do filter = described_class.new(doc, project: project) expect(filter).to receive(:references_per_project) - .and_return({ project.path_with_namespace => Set.new(%w[1]) }) + .and_return({ project.full_path => Set.new(%w[1]) }) expect(filter.projects_per_reference) - .to eq({ project.path_with_namespace => project }) + .to eq({ project.full_path => project }) end end @@ -37,7 +37,7 @@ describe Banzai::Filter::AbstractReferenceFilter do context 'with RequestStore disabled' do it 'returns a list of Projects for a list of paths' do - expect(filter.find_projects_for_paths([project.path_with_namespace])) + expect(filter.find_projects_for_paths([project.full_path])) .to eq([project]) end @@ -49,7 +49,7 @@ describe Banzai::Filter::AbstractReferenceFilter do context 'with RequestStore enabled', :request_store do it 'returns a list of Projects for a list of paths' do - expect(filter.find_projects_for_paths([project.path_with_namespace])) + expect(filter.find_projects_for_paths([project.full_path])) .to eq([project]) end @@ -88,7 +88,7 @@ describe Banzai::Filter::AbstractReferenceFilter do doc = Nokogiri::HTML.fragment('') filter = described_class.new(doc, project: project) - expect(filter.current_project_path).to eq(project.path_with_namespace) + expect(filter.current_project_path).to eq(project.full_path) end end end diff --git a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb index 11d48387544..935146c17fc 100644 --- a/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_range_reference_filter_spec.rb @@ -100,7 +100,7 @@ describe Banzai::Filter::CommitRangeReferenceFilter do context 'cross-project / cross-namespace complete reference' do let(:project2) { create(:project, :public, :repository) } - let(:reference) { "#{project2.path_with_namespace}@#{commit1.id}...#{commit2.id}" } + let(:reference) { "#{project2.full_path}@#{commit1.id}...#{commit2.id}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -113,20 +113,20 @@ describe Banzai::Filter::CommitRangeReferenceFilter do doc = reference_filter("Fixed (#{reference}.)") expect(doc.css('a').first.text) - .to eql("#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}") + .to eql("#{project2.full_path}@#{commit1.short_id}...#{commit2.short_id}") end it 'has valid text' do doc = reference_filter("Fixed (#{reference}.)") - expect(doc.text).to eql("Fixed (#{project2.path_with_namespace}@#{commit1.short_id}...#{commit2.short_id}.)") + expect(doc.text).to eql("Fixed (#{project2.full_path}@#{commit1.short_id}...#{commit2.short_id}.)") end it 'ignores invalid commit IDs on the referenced project' do - exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id.reverse}...#{commit2.id}" + exp = act = "Fixed #{project2.full_path}@#{commit1.id.reverse}...#{commit2.id}" expect(reference_filter(act).to_html).to eq exp - exp = act = "Fixed #{project2.path_with_namespace}@#{commit1.id}...#{commit2.id.reverse}" + exp = act = "Fixed #{project2.full_path}@#{commit1.id}...#{commit2.id.reverse}" expect(reference_filter(act).to_html).to eq exp end end diff --git a/spec/lib/banzai/filter/commit_reference_filter_spec.rb b/spec/lib/banzai/filter/commit_reference_filter_spec.rb index fb2a36d1ba1..702fcac0c6f 100644 --- a/spec/lib/banzai/filter/commit_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/commit_reference_filter_spec.rb @@ -98,18 +98,18 @@ describe Banzai::Filter::CommitReferenceFilter do let(:namespace) { create(:namespace) } let(:project2) { create(:project, :public, :repository, namespace: namespace) } let(:commit) { project2.commit } - let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" } + let(:reference) { "#{project2.full_path}@#{commit.short_id}" } it 'link has valid text' do doc = reference_filter("See (#{reference}.)") - expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}@#{commit.short_id}") + expect(doc.css('a').first.text).to eql("#{project2.full_path}@#{commit.short_id}") end it 'has valid text' do doc = reference_filter("See (#{reference}.)") - expect(doc.text).to eql("See (#{project2.path_with_namespace}@#{commit.short_id}.)") + expect(doc.text).to eql("See (#{project2.full_path}@#{commit.short_id}.)") end it 'ignores invalid commit IDs on the referenced project' do @@ -121,10 +121,10 @@ describe Banzai::Filter::CommitReferenceFilter do context 'cross-project / same-namespace complete reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, namespace: namespace) } + let(:project) { create(:project, namespace: namespace) } let(:project2) { create(:project, :public, :repository, namespace: namespace) } let(:commit) { project2.commit } - let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" } + let(:reference) { "#{project2.full_path}@#{commit.short_id}" } it 'link has valid text' do doc = reference_filter("See (#{reference}.)") @@ -147,10 +147,10 @@ describe Banzai::Filter::CommitReferenceFilter do context 'cross-project shorthand reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, namespace: namespace) } + let(:project) { create(:project, namespace: namespace) } let(:project2) { create(:project, :public, :repository, namespace: namespace) } let(:commit) { project2.commit } - let(:reference) { "#{project2.path_with_namespace}@#{commit.short_id}" } + let(:reference) { "#{project2.full_path}@#{commit.short_id}" } it 'link has valid text' do doc = reference_filter("See (#{reference}.)") diff --git a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb index 663e3514436..97d612e6347 100644 --- a/spec/lib/banzai/filter/gollum_tags_filter_spec.rb +++ b/spec/lib/banzai/filter/gollum_tags_filter_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::Filter::GollumTagsFilter do include FilterSpecHelper - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { double } let(:project_wiki) { ProjectWiki.new(project, user) } diff --git a/spec/lib/banzai/filter/issuable_state_filter_spec.rb b/spec/lib/banzai/filter/issuable_state_filter_spec.rb index bc7cae1df8d..cacb33d3372 100644 --- a/spec/lib/banzai/filter/issuable_state_filter_spec.rb +++ b/spec/lib/banzai/filter/issuable_state_filter_spec.rb @@ -7,8 +7,8 @@ describe Banzai::Filter::IssuableStateFilter do let(:user) { create(:user) } let(:context) { { current_user: user, issuable_state_filter_enabled: true } } let(:closed_issue) { create_issue(:closed) } - let(:project) { create(:empty_project, :public) } - let(:other_project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } + let(:other_project) { create(:project, :public) } def create_link(text, data) link_to(text, '', class: 'gfm has-tooltip', data: data) diff --git a/spec/lib/banzai/filter/issue_reference_filter_spec.rb b/spec/lib/banzai/filter/issue_reference_filter_spec.rb index 045bf3e0cc9..9c74c9b8c99 100644 --- a/spec/lib/banzai/filter/issue_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/issue_reference_filter_spec.rb @@ -7,7 +7,7 @@ describe Banzai::Filter::IssueReferenceFilter do IssuesHelper end - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } it 'requires project context' do @@ -125,9 +125,9 @@ describe Banzai::Filter::IssueReferenceFilter do context 'cross-project / cross-namespace complete reference' do it_behaves_like 'a reference containing an element node' - let(:project2) { create(:empty_project, :public) } + let(:project2) { create(:project, :public) } let(:issue) { create(:issue, project: project2) } - let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" } + let(:reference) { "#{project2.full_path}##{issue.iid}" } it 'ignores valid references when cross-reference project uses external tracker' do expect_any_instance_of(described_class).to receive(:find_object) @@ -148,13 +148,13 @@ describe Banzai::Filter::IssueReferenceFilter do it 'link has valid text' do doc = reference_filter("Fixed (#{reference}.)") - expect(doc.css('a').first.text).to eql("#{project2.path_with_namespace}##{issue.iid}") + expect(doc.css('a').first.text).to eql("#{project2.full_path}##{issue.iid}") end it 'has valid text' do doc = reference_filter("Fixed (#{reference}.)") - expect(doc.text).to eq("Fixed (#{project2.path_with_namespace}##{issue.iid}.)") + expect(doc.text).to eq("Fixed (#{project2.full_path}##{issue.iid}.)") end it 'ignores invalid issue IDs on the referenced project' do @@ -168,10 +168,10 @@ describe Banzai::Filter::IssueReferenceFilter do it_behaves_like 'a reference containing an element node' let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } - let(:reference) { "#{project2.path_with_namespace}##{issue.iid}" } + let(:reference) { "#{project2.full_path}##{issue.iid}" } it 'ignores valid references when cross-reference project uses external tracker' do expect_any_instance_of(described_class).to receive(:find_object) @@ -212,8 +212,8 @@ describe Banzai::Filter::IssueReferenceFilter do it_behaves_like 'a reference containing an element node' let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } let(:reference) { "#{project2.path}##{issue.iid}" } @@ -256,7 +256,7 @@ describe Banzai::Filter::IssueReferenceFilter do it_behaves_like 'a reference containing an element node' let(:namespace) { create(:namespace, name: 'cross-reference') } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } let(:reference) { helper.url_for_issue(issue.iid, project2) + "#note_123" } @@ -277,7 +277,7 @@ describe Banzai::Filter::IssueReferenceFilter do it_behaves_like 'a reference containing an element node' let(:namespace) { create(:namespace, name: 'cross-reference') } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } let(:reference) { issue.to_reference(project) } let(:reference_link) { %{<a href="#{reference}">Reference</a>} } @@ -299,7 +299,7 @@ describe Banzai::Filter::IssueReferenceFilter do it_behaves_like 'a reference containing an element node' let(:namespace) { create(:namespace, name: 'cross-reference') } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let(:issue) { create(:issue, project: project2) } let(:reference) { "#{helper.url_for_issue(issue.iid, project2) + "#note_123"}" } let(:reference_link) { %{<a href="#{reference}">Reference</a>} } @@ -324,10 +324,10 @@ describe Banzai::Filter::IssueReferenceFilter do filter = described_class.new(doc, project: project) expect(filter).to receive(:projects_per_reference) - .and_return({ project.path_with_namespace => project }) + .and_return({ project.full_path => project }) expect(filter).to receive(:references_per_project) - .and_return({ project.path_with_namespace => Set.new([issue.iid]) }) + .and_return({ project.full_path => Set.new([issue.iid]) }) expect(filter.issues_per_project) .to eq({ project => { issue.iid => issue } }) diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 1daa6ac7f9e..2cd30a5e302 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -4,7 +4,7 @@ require 'html/pipeline' describe Banzai::Filter::LabelReferenceFilter do include FilterSpecHelper - let(:project) { create(:empty_project, :public, name: 'sample-project') } + let(:project) { create(:project, :public, name: 'sample-project') } let(:label) { create(:label, project: project) } let(:reference) { label.to_reference } @@ -315,7 +315,7 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'group label references' do let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:group_label) { create(:group_label, name: 'gfm references', group: group) } context 'without project reference' do @@ -366,9 +366,9 @@ describe Banzai::Filter::LabelReferenceFilter do end describe 'cross-project / cross-namespace complete reference' do - let(:project2) { create(:empty_project) } + let(:project2) { create(:project) } let(:label) { create(:label, project: project2, color: '#00ff00') } - let(:reference) { "#{project2.path_with_namespace}~#{label.name}" } + let(:reference) { "#{project2.full_path}~#{label.name}" } let!(:result) { reference_filter("See #{reference}") } it 'links to a valid reference' do @@ -397,10 +397,10 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'cross-project / same-namespace complete reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, namespace: namespace) } - let(:project2) { create(:empty_project, namespace: namespace) } + let(:project) { create(:project, namespace: namespace) } + let(:project2) { create(:project, namespace: namespace) } let(:label) { create(:label, project: project2, color: '#00ff00') } - let(:reference) { "#{project2.path_with_namespace}~#{label.name}" } + let(:reference) { "#{project2.full_path}~#{label.name}" } let!(:result) { reference_filter("See #{reference}") } it 'links to a valid reference' do @@ -429,8 +429,8 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'cross-project shorthand reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, namespace: namespace) } - let(:project2) { create(:empty_project, namespace: namespace) } + let(:project) { create(:project, namespace: namespace) } + let(:project2) { create(:project, namespace: namespace) } let(:label) { create(:label, project: project2, color: '#00ff00') } let(:reference) { "#{project2.path}~#{label.name}" } let!(:result) { reference_filter("See #{reference}") } @@ -462,11 +462,11 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'cross group label references' do let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:another_group) { create(:group) } - let(:another_project) { create(:empty_project, :public, namespace: another_group) } + let(:another_project) { create(:project, :public, namespace: another_group) } let(:group_label) { create(:group_label, group: another_group, color: '#00ff00') } - let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" } + let(:reference) { "#{another_project.full_path}~#{group_label.name}" } let!(:result) { reference_filter("See #{reference}", project: project) } it 'points to referenced project issues page' do @@ -498,10 +498,10 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'cross-project / same-group_label complete reference' do let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } - let(:another_project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } + let(:another_project) { create(:project, :public, namespace: group) } let(:group_label) { create(:group_label, group: group, color: '#00ff00') } - let(:reference) { "#{another_project.path_with_namespace}~#{group_label.name}" } + let(:reference) { "#{another_project.full_path}~#{group_label.name}" } let!(:result) { reference_filter("See #{reference}", project: project) } it 'points to referenced project issues page' do @@ -533,9 +533,9 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'same project / same group_label complete reference' do let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:group_label) { create(:group_label, group: group, color: '#00ff00') } - let(:reference) { "#{project.path_with_namespace}~#{group_label.name}" } + let(:reference) { "#{project.full_path}~#{group_label.name}" } let!(:result) { reference_filter("See #{reference}", project: project) } it 'points to referenced project issues page' do @@ -565,7 +565,7 @@ describe Banzai::Filter::LabelReferenceFilter do describe 'same project / same group_label shorthand reference' do let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:group_label) { create(:group_label, group: group, color: '#00ff00') } let(:reference) { "#{project.path}~#{group_label.name}" } let!(:result) { reference_filter("See #{reference}", project: project) } diff --git a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb index 683972a3112..ed2788f8a33 100644 --- a/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/merge_request_reference_filter_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::Filter::MergeRequestReferenceFilter do include FilterSpecHelper - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:merge) { create(:merge_request, source_project: project) } it 'requires project context' do @@ -100,9 +100,9 @@ describe Banzai::Filter::MergeRequestReferenceFilter do end context 'cross-project / cross-namespace complete reference' do - let(:project2) { create(:empty_project, :public) } + let(:project2) { create(:project, :public) } let(:merge) { create(:merge_request, source_project: project2) } - let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" } + let(:reference) { "#{project2.full_path}!#{merge.iid}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -132,10 +132,10 @@ describe Banzai::Filter::MergeRequestReferenceFilter do context 'cross-project / same-namespace complete reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let!(:merge) { create(:merge_request, source_project: project2) } - let(:reference) { "#{project2.path_with_namespace}!#{merge.iid}" } + let(:reference) { "#{project2.full_path}!#{merge.iid}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -165,8 +165,8 @@ describe Banzai::Filter::MergeRequestReferenceFilter do context 'cross-project shorthand reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let!(:merge) { create(:merge_request, source_project: project2) } let(:reference) { "#{project2.path}!#{merge.iid}" } @@ -198,7 +198,7 @@ describe Banzai::Filter::MergeRequestReferenceFilter do context 'cross-project URL reference' do let(:namespace) { create(:namespace, name: 'cross-reference') } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let(:merge) { create(:merge_request, source_project: project2, target_project: project2) } let(:reference) { urls.project_merge_request_url(project2, merge) + '/diffs#note_123' } diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb index 8fe05dc2e53..ebd6c79077e 100644 --- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -3,57 +3,57 @@ require 'spec_helper' describe Banzai::Filter::MilestoneReferenceFilter do include FilterSpecHelper - let(:project) { create(:empty_project, :public) } - let(:milestone) { create(:milestone, project: project) } - let(:reference) { milestone.to_reference } + let(:group) { create(:group, :public) } + let(:project) { create(:project, :public, group: group) } it 'requires project context' do expect { described_class.call('') }.to raise_error(ArgumentError, /:project/) end - %w(pre code a style).each do |elem| - it "ignores valid references contained inside '#{elem}' element" do - exp = act = "<#{elem}>milestone #{milestone.to_reference}</#{elem}>" - expect(reference_filter(act).to_html).to eq exp + shared_examples 'reference parsing' do + %w(pre code a style).each do |elem| + it "ignores valid references contained inside '#{elem}' element" do + exp = act = "<#{elem}>milestone #{reference}</#{elem}>" + expect(reference_filter(act).to_html).to eq exp + end end - end - it 'includes default classes' do - doc = reference_filter("Milestone #{reference}") - expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-milestone has-tooltip' - end + it 'includes default classes' do + doc = reference_filter("Milestone #{reference}") - it 'includes a data-project attribute' do - doc = reference_filter("Milestone #{reference}") - link = doc.css('a').first + expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-milestone has-tooltip' + end - expect(link).to have_attribute('data-project') - expect(link.attr('data-project')).to eq project.id.to_s - end + it 'includes a data-project attribute' do + doc = reference_filter("Milestone #{reference}") + link = doc.css('a').first - it 'includes a data-milestone attribute' do - doc = reference_filter("See #{reference}") - link = doc.css('a').first + expect(link).to have_attribute('data-project') + expect(link.attr('data-project')).to eq project.id.to_s + end - expect(link).to have_attribute('data-milestone') - expect(link.attr('data-milestone')).to eq milestone.id.to_s - end + it 'includes a data-milestone attribute' do + doc = reference_filter("See #{reference}") + link = doc.css('a').first - it 'supports an :only_path context' do - doc = reference_filter("Milestone #{reference}", only_path: true) - link = doc.css('a').first.attr('href') + expect(link).to have_attribute('data-milestone') + expect(link.attr('data-milestone')).to eq milestone.id.to_s + end + + it 'supports an :only_path context' do + doc = reference_filter("Milestone #{reference}", only_path: true) + link = doc.css('a').first.attr('href') - expect(link).not_to match %r(https?://) - expect(link).to eq urls - .project_milestone_path(project, milestone) + expect(link).not_to match %r(https?://) + expect(link).to eq urls.milestone_path(milestone) + end end - context 'Integer-based references' do + shared_examples 'Integer-based references' do it 'links to a valid reference' do doc = reference_filter("See #{reference}") - expect(doc.css('a').first.attr('href')).to eq urls - .project_milestone_url(project, milestone) + expect(doc.css('a').first.attr('href')).to eq urls.milestone_url(milestone) end it 'links with adjacent text' do @@ -68,15 +68,17 @@ describe Banzai::Filter::MilestoneReferenceFilter do end end - context 'String-based single-word references' do - let(:milestone) { create(:milestone, name: 'gfm', project: project) } + shared_examples 'String-based single-word references' do let(:reference) { "#{Milestone.reference_prefix}#{milestone.name}" } + before do + milestone.update!(name: 'gfm') + end + it 'links to a valid reference' do doc = reference_filter("See #{reference}") - expect(doc.css('a').first.attr('href')).to eq urls - .project_milestone_url(project, milestone) + expect(doc.css('a').first.attr('href')).to eq urls.milestone_url(milestone) expect(doc.text).to eq 'See gfm' end @@ -92,15 +94,17 @@ describe Banzai::Filter::MilestoneReferenceFilter do end end - context 'String-based multi-word references in quotes' do - let(:milestone) { create(:milestone, name: 'gfm references', project: project) } + shared_examples 'String-based multi-word references in quotes' do let(:reference) { milestone.to_reference(format: :name) } + before do + milestone.update!(name: 'gfm references') + end + it 'links to a valid reference' do doc = reference_filter("See #{reference}") - expect(doc.css('a').first.attr('href')).to eq urls - .project_milestone_url(project, milestone) + expect(doc.css('a').first.attr('href')).to eq urls.milestone_url(milestone) expect(doc.text).to eq 'See gfm references' end @@ -116,23 +120,27 @@ describe Banzai::Filter::MilestoneReferenceFilter do end end - describe 'referencing a milestone in a link href' do - let(:reference) { %Q{<a href="#{milestone.to_reference}">Milestone</a>} } + shared_examples 'referencing a milestone in a link href' do + let(:unquoted_reference) { "#{Milestone.reference_prefix}#{milestone.name}" } + let(:link_reference) { %Q{<a href="#{unquoted_reference}">Milestone</a>} } + + before do + milestone.update!(name: 'gfm') + end it 'links to a valid reference' do - doc = reference_filter("See #{reference}") + doc = reference_filter("See #{link_reference}") - expect(doc.css('a').first.attr('href')).to eq urls - .project_milestone_url(project, milestone) + expect(doc.css('a').first.attr('href')).to eq urls.milestone_url(milestone) end it 'links with adjacent text' do - doc = reference_filter("Milestone (#{reference}.)") + doc = reference_filter("Milestone (#{link_reference}.)") expect(doc.to_html).to match(%r(\(<a.+>Milestone</a>\.\))) end it 'includes a data-project attribute' do - doc = reference_filter("Milestone #{reference}") + doc = reference_filter("Milestone #{link_reference}") link = doc.css('a').first expect(link).to have_attribute('data-project') @@ -140,7 +148,35 @@ describe Banzai::Filter::MilestoneReferenceFilter do end it 'includes a data-milestone attribute' do - doc = reference_filter("See #{reference}") + doc = reference_filter("See #{link_reference}") + link = doc.css('a').first + + expect(link).to have_attribute('data-milestone') + expect(link.attr('data-milestone')).to eq milestone.id.to_s + end + end + + shared_examples 'linking to a milestone as the entire link' do + let(:unquoted_reference) { "#{Milestone.reference_prefix}#{milestone.name}" } + let(:link) { urls.milestone_url(milestone) } + let(:link_reference) { %Q{<a href="#{link}">#{link}</a>} } + + it 'replaces the link text with the milestone reference' do + doc = reference_filter("See #{link}") + + expect(doc.css('a').first.text).to eq(unquoted_reference) + end + + it 'includes a data-project attribute' do + doc = reference_filter("Milestone #{link_reference}") + link = doc.css('a').first + + expect(link).to have_attribute('data-project') + expect(link.attr('data-project')).to eq project.id.to_s + end + + it 'includes a data-milestone attribute' do + doc = reference_filter("See #{link_reference}") link = doc.css('a').first expect(link).to have_attribute('data-milestone') @@ -148,11 +184,11 @@ describe Banzai::Filter::MilestoneReferenceFilter do end end - describe 'cross-project / cross-namespace complete reference' do + shared_examples 'cross-project / cross-namespace complete reference' do let(:namespace) { create(:namespace) } - let(:another_project) { create(:empty_project, :public, namespace: namespace) } + let(:another_project) { create(:project, :public, namespace: namespace) } let(:milestone) { create(:milestone, project: another_project) } - let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" } + let(:reference) { "#{another_project.full_path}%#{milestone.iid}" } let!(:result) { reference_filter("See #{reference}") } it 'points to referenced project milestone page' do @@ -164,14 +200,14 @@ describe Banzai::Filter::MilestoneReferenceFilter do doc = reference_filter("See (#{reference}.)") expect(doc.css('a').first.text) - .to eq("#{milestone.name} in #{another_project.path_with_namespace}") + .to eq("#{milestone.name} in #{another_project.full_path}") end it 'has valid text' do doc = reference_filter("See (#{reference}.)") expect(doc.text) - .to eq("See (#{milestone.name} in #{another_project.path_with_namespace}.)") + .to eq("See (#{milestone.name} in #{another_project.full_path}.)") end it 'escapes the name attribute' do @@ -180,16 +216,16 @@ describe Banzai::Filter::MilestoneReferenceFilter do doc = reference_filter("See #{reference}") expect(doc.css('a').first.text) - .to eq "#{milestone.name} in #{another_project.path_with_namespace}" + .to eq "#{milestone.name} in #{another_project.full_path}" end end - describe 'cross-project / same-namespace complete reference' do + shared_examples 'cross-project / same-namespace complete reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:another_project) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:another_project) { create(:project, :public, namespace: namespace) } let(:milestone) { create(:milestone, project: another_project) } - let(:reference) { "#{another_project.path_with_namespace}%#{milestone.iid}" } + let(:reference) { "#{another_project.full_path}%#{milestone.iid}" } let!(:result) { reference_filter("See #{reference}") } it 'points to referenced project milestone page' do @@ -221,10 +257,10 @@ describe Banzai::Filter::MilestoneReferenceFilter do end end - describe 'cross project shorthand reference' do + shared_examples 'cross project shorthand reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:another_project) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:another_project) { create(:project, :public, namespace: namespace) } let(:milestone) { create(:milestone, project: another_project) } let(:reference) { "#{another_project.path}%#{milestone.iid}" } let!(:result) { reference_filter("See #{reference}") } @@ -257,4 +293,54 @@ describe Banzai::Filter::MilestoneReferenceFilter do .to eq "#{milestone.name} in #{another_project.path}" end end + + context 'project milestones' do + let(:milestone) { create(:milestone, project: project) } + let(:reference) { milestone.to_reference } + + include_examples 'reference parsing' + + it_behaves_like 'Integer-based references' + it_behaves_like 'String-based single-word references' + it_behaves_like 'String-based multi-word references in quotes' + it_behaves_like 'referencing a milestone in a link href' + it_behaves_like 'cross-project / cross-namespace complete reference' + it_behaves_like 'cross-project / same-namespace complete reference' + it_behaves_like 'cross project shorthand reference' + end + + context 'group milestones' do + let(:milestone) { create(:milestone, group: group) } + let(:reference) { milestone.to_reference(format: :name) } + + include_examples 'reference parsing' + + it_behaves_like 'String-based single-word references' + it_behaves_like 'String-based multi-word references in quotes' + it_behaves_like 'referencing a milestone in a link href' + + it 'does not support references by IID' do + doc = reference_filter("See #{Milestone.reference_prefix}#{milestone.iid}") + + expect(doc.css('a')).to be_empty + end + + it 'does not support references by link' do + doc = reference_filter("See #{urls.milestone_url(milestone)}") + + expect(doc.css('a').first.text).to eq(urls.milestone_url(milestone)) + end + + it 'does not support cross-project references' do + another_group = create(:group) + another_project = create(:project, :public, group: group) + project_reference = another_project.to_reference(project) + + milestone.update!(group: another_group) + + doc = reference_filter("See #{project_reference}#{reference}") + + expect(doc.css('a')).to be_empty + end + end end diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb index fb6b81d4f10..68643effb66 100644 --- a/spec/lib/banzai/filter/redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/redactor_filter_spec.rb @@ -17,7 +17,7 @@ describe Banzai::Filter::RedactorFilter do it 'skips when the skip_redaction flag is set' do user = create(:user) - project = create(:empty_project) + project = create(:project) link = reference_link(project: project.id, reference_type: 'test') doc = filter(link, current_user: user, skip_redaction: true) @@ -45,7 +45,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows permitted Project references' do user = create(:user) - project = create(:empty_project) + project = create(:project) project.team << [user, :master] link = reference_link(project: project.id, reference_type: 'test') @@ -62,7 +62,7 @@ describe Banzai::Filter::RedactorFilter do it 'removes unpermitted references' do user = create(:user) - project = create(:empty_project) + project = create(:project) link = reference_link(project: project.id, reference_type: 'test') doc = filter(link, current_user: user) @@ -82,7 +82,7 @@ describe Banzai::Filter::RedactorFilter do context 'for confidential issues' do it 'removes references for non project members' do non_member = create(:user) - project = create(:empty_project, :public) + project = create(:project, :public) issue = create(:issue, :confidential, project: project) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') @@ -93,7 +93,7 @@ describe Banzai::Filter::RedactorFilter do it 'removes references for project members with guest role' do member = create(:user) - project = create(:empty_project, :public) + project = create(:project, :public) project.team << [member, :guest] issue = create(:issue, :confidential, project: project) @@ -105,7 +105,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows references for author' do author = create(:user) - project = create(:empty_project, :public) + project = create(:project, :public) issue = create(:issue, :confidential, project: project, author: author) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') @@ -116,7 +116,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows references for assignee' do assignee = create(:user) - project = create(:empty_project, :public) + project = create(:project, :public) issue = create(:issue, :confidential, project: project, assignees: [assignee]) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') @@ -127,7 +127,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows references for project members' do member = create(:user) - project = create(:empty_project, :public) + project = create(:project, :public) project.team << [member, :developer] issue = create(:issue, :confidential, project: project) @@ -139,7 +139,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows references for admin' do admin = create(:admin) - project = create(:empty_project, :public) + project = create(:project, :public) issue = create(:issue, :confidential, project: project) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') @@ -151,7 +151,7 @@ describe Banzai::Filter::RedactorFilter do it 'allows references for non confidential issues' do user = create(:user) - project = create(:empty_project, :public) + project = create(:project, :public) issue = create(:issue, project: project) link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') diff --git a/spec/lib/banzai/filter/reference_filter_spec.rb b/spec/lib/banzai/filter/reference_filter_spec.rb index b9ca68e8935..f96b6c83b0a 100644 --- a/spec/lib/banzai/filter/reference_filter_spec.rb +++ b/spec/lib/banzai/filter/reference_filter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Banzai::Filter::ReferenceFilter do - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } describe '#each_node' do it 'iterates over the nodes in a document' do diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb index ddebf2264d9..08beede62db 100644 --- a/spec/lib/banzai/filter/relative_link_filter_spec.rb +++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb @@ -26,7 +26,7 @@ describe Banzai::Filter::RelativeLinkFilter do end let(:project) { create(:project, :repository) } - let(:project_path) { project.path_with_namespace } + let(:project_path) { project.full_path } let(:ref) { 'markdown' } let(:commit) { project.commit(ref) } let(:project_wiki) { nil } @@ -56,7 +56,7 @@ describe Banzai::Filter::RelativeLinkFilter do end context 'without a repository' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } include_examples :preserve_unchanged end diff --git a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb index 5f548888223..90ac4c7b238 100644 --- a/spec/lib/banzai/filter/snippet_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/snippet_reference_filter_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::Filter::SnippetReferenceFilter do include FilterSpecHelper - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:snippet) { create(:project_snippet, project: project) } let(:reference) { snippet.to_reference } @@ -81,9 +81,9 @@ describe Banzai::Filter::SnippetReferenceFilter do context 'cross-project / cross-namespace complete reference' do let(:namespace) { create(:namespace) } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let!(:snippet) { create(:project_snippet, project: project2) } - let(:reference) { "#{project2.path_with_namespace}$#{snippet.id}" } + let(:reference) { "#{project2.full_path}$#{snippet.id}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -113,10 +113,10 @@ describe Banzai::Filter::SnippetReferenceFilter do context 'cross-project / same-namespace complete reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let!(:snippet) { create(:project_snippet, project: project2) } - let(:reference) { "#{project2.path_with_namespace}$#{snippet.id}" } + let(:reference) { "#{project2.full_path}$#{snippet.id}" } it 'links to a valid reference' do doc = reference_filter("See #{reference}") @@ -146,8 +146,8 @@ describe Banzai::Filter::SnippetReferenceFilter do context 'cross-project shorthand reference' do let(:namespace) { create(:namespace) } - let(:project) { create(:empty_project, :public, namespace: namespace) } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project) { create(:project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let!(:snippet) { create(:project_snippet, project: project2) } let(:reference) { "#{project2.path}$#{snippet.id}" } @@ -179,7 +179,7 @@ describe Banzai::Filter::SnippetReferenceFilter do context 'cross-project URL reference' do let(:namespace) { create(:namespace, name: 'cross-reference') } - let(:project2) { create(:empty_project, :public, namespace: namespace) } + let(:project2) { create(:project, :public, namespace: namespace) } let(:snippet) { create(:project_snippet, project: project2) } let(:reference) { urls.project_snippet_url(project2, snippet) } diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb index 3bc9635b50e..60a88e903ef 100644 --- a/spec/lib/banzai/filter/upload_link_filter_spec.rb +++ b/spec/lib/banzai/filter/upload_link_filter_spec.rb @@ -29,7 +29,7 @@ describe Banzai::Filter::UploadLinkFilter do %(<div><a href="#{path}">#{path}</a></div>) end - let(:project) { create(:empty_project) } + let(:project) { create(:project) } shared_examples :preserve_unchanged do it 'does not modify any relative URL in anchor' do @@ -52,21 +52,21 @@ describe Banzai::Filter::UploadLinkFilter do it 'rebuilds relative URL for a link' do doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('a')['href']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" doc = filter(nested_link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('a')['href']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" end it 'rebuilds relative URL for an image' do doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('img')['src']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" doc = filter(nested_image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')) expect(doc.at_css('img')['src']) - .to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" + .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" end it 'does not modify absolute URL' do @@ -85,7 +85,7 @@ describe Banzai::Filter::UploadLinkFilter do .to receive(:image?).with(path).and_return(true) doc = filter(image(escaped)) - expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png" + expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png" end end diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb index 7ea9df5eda5..34dac1db69a 100644 --- a/spec/lib/banzai/filter/user_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::Filter::UserReferenceFilter do include FilterSpecHelper - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:reference) { user.to_reference } diff --git a/spec/lib/banzai/filter/wiki_link_filter_spec.rb b/spec/lib/banzai/filter/wiki_link_filter_spec.rb index ceafd12a68e..9596f004052 100644 --- a/spec/lib/banzai/filter/wiki_link_filter_spec.rb +++ b/spec/lib/banzai/filter/wiki_link_filter_spec.rb @@ -4,7 +4,7 @@ describe Banzai::Filter::WikiLinkFilter do include FilterSpecHelper let(:namespace) { build_stubbed(:namespace, name: "wiki_link_ns") } - let(:project) { build_stubbed(:empty_project, :public, name: "wiki_link_project", namespace: namespace) } + let(:project) { build_stubbed(:project, :public, name: "wiki_link_project", namespace: namespace) } let(:user) { double } let(:wiki) { ProjectWiki.new(project, user) } diff --git a/spec/lib/banzai/issuable_extractor_spec.rb b/spec/lib/banzai/issuable_extractor_spec.rb index 728271e757b..69763476dac 100644 --- a/spec/lib/banzai/issuable_extractor_spec.rb +++ b/spec/lib/banzai/issuable_extractor_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Banzai::IssuableExtractor do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:extractor) { described_class.new(project, user) } let(:issue) { create(:issue, project: project) } diff --git a/spec/lib/banzai/object_renderer_spec.rb b/spec/lib/banzai/object_renderer_spec.rb index dd2674f9f20..7f5d481c36c 100644 --- a/spec/lib/banzai/object_renderer_spec.rb +++ b/spec/lib/banzai/object_renderer_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Banzai::ObjectRenderer do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { project.owner } let(:renderer) { described_class.new(project, user, custom_value: 'value') } let(:object) { Note.new(note: 'hello', note_html: '<p dir="auto">hello</p>', cached_markdown_version: CacheMarkdownField::CACHE_VERSION) } @@ -28,7 +28,7 @@ describe Banzai::ObjectRenderer do it 'passes context to PostProcessPipeline' do another_user = create(:user) - another_project = create(:empty_project) + another_project = create(:project) object = Note.new( note: 'hello', note_html: 'hello', diff --git a/spec/lib/banzai/pipeline/full_pipeline_spec.rb b/spec/lib/banzai/pipeline/full_pipeline_spec.rb index 2501b638774..e9c7a2f352e 100644 --- a/spec/lib/banzai/pipeline/full_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/full_pipeline_spec.rb @@ -2,7 +2,7 @@ require 'rails_helper' describe Banzai::Pipeline::FullPipeline do describe 'References' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } it 'handles markdown inside a reference' do diff --git a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb index 601ffbb5456..75413596431 100644 --- a/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/gfm_pipeline_spec.rb @@ -36,7 +36,7 @@ describe Banzai::Pipeline::GfmPipeline do end it 'parses cross-project references to regular issues' do - other_project = create(:empty_project, :public) + other_project = create(:project, :public) issue = create(:issue, project: other_project) markdown = issue.to_reference(project, full: true) @@ -74,7 +74,7 @@ describe Banzai::Pipeline::GfmPipeline do end it 'parses cross-project references to regular issues' do - other_project = create(:empty_project, :public) + other_project = create(:project, :public) issue = create(:issue, project: other_project) markdown = issue.to_reference(project, full: true) diff --git a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb index ac9bde6baf1..88ae4c1e07a 100644 --- a/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb +++ b/spec/lib/banzai/pipeline/wiki_pipeline_spec.rb @@ -53,7 +53,7 @@ describe Banzai::Pipeline::WikiPipeline do describe "Links" do let(:namespace) { create(:namespace, name: "wiki_link_ns") } - let(:project) { create(:empty_project, :public, name: "wiki_link_project", namespace: namespace) } + let(:project) { create(:project, :public, name: "wiki_link_project", namespace: namespace) } let(:project_wiki) { ProjectWiki.new(project, double(:user)) } let(:page) { build(:wiki_page, wiki: project_wiki, page: OpenStruct.new(url_path: 'nested/twice/start-page')) } diff --git a/spec/lib/banzai/redactor_spec.rb b/spec/lib/banzai/redactor_spec.rb index 81ae5685b10..2424c3fdc66 100644 --- a/spec/lib/banzai/redactor_spec.rb +++ b/spec/lib/banzai/redactor_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Banzai::Redactor do let(:user) { build(:user) } - let(:project) { build(:empty_project) } + let(:project) { build(:project) } let(:redactor) { described_class.new(project, user) } describe '#redact' do diff --git a/spec/lib/banzai/reference_parser/base_parser_spec.rb b/spec/lib/banzai/reference_parser/base_parser_spec.rb index 0bf45329657..6175d4c4ca9 100644 --- a/spec/lib/banzai/reference_parser/base_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/base_parser_spec.rb @@ -4,7 +4,7 @@ describe Banzai::ReferenceParser::BaseParser do include ReferenceParserHelpers let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } subject do klass = Class.new(described_class) do diff --git a/spec/lib/banzai/reference_parser/commit_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_parser_spec.rb index 69bf28cdf85..3505659c2c3 100644 --- a/spec/lib/banzai/reference_parser/commit_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::ReferenceParser::CommitParser do include ReferenceParserHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } subject { described_class.new(project, user) } let(:link) { empty_html_link } diff --git a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb index b384a59bfb4..21813177deb 100644 --- a/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/commit_range_parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::ReferenceParser::CommitRangeParser do include ReferenceParserHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } subject { described_class.new(project, user) } let(:link) { empty_html_link } diff --git a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb index a3256afdbb1..25969b65168 100644 --- a/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/external_issue_parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::ReferenceParser::ExternalIssueParser do include ReferenceParserHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } subject { described_class.new(project, user) } let(:link) { empty_html_link } diff --git a/spec/lib/banzai/reference_parser/issue_parser_spec.rb b/spec/lib/banzai/reference_parser/issue_parser_spec.rb index 94b989fe91d..23dbe2b6238 100644 --- a/spec/lib/banzai/reference_parser/issue_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/issue_parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::ReferenceParser::IssueParser do include ReferenceParserHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:issue) { create(:issue, project: project) } let(:link) { empty_html_link } diff --git a/spec/lib/banzai/reference_parser/label_parser_spec.rb b/spec/lib/banzai/reference_parser/label_parser_spec.rb index cf1b2a92195..b700161d6c2 100644 --- a/spec/lib/banzai/reference_parser/label_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/label_parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::ReferenceParser::LabelParser do include ReferenceParserHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:label) { create(:label, project: project) } subject { described_class.new(project, user) } diff --git a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb index 2cfcafa8798..7dacdf8d629 100644 --- a/spec/lib/banzai/reference_parser/milestone_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/milestone_parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::ReferenceParser::MilestoneParser do include ReferenceParserHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:milestone) { create(:milestone, project: project) } subject { described_class.new(project, user) } diff --git a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb index c6d0b7be254..69ec3f66aa8 100644 --- a/spec/lib/banzai/reference_parser/snippet_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/snippet_parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Banzai::ReferenceParser::SnippetParser do include ReferenceParserHelpers - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:external_user) { create(:user, :external) } diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb index 64f2b607d7c..e49726aca6c 100644 --- a/spec/lib/banzai/reference_parser/user_parser_spec.rb +++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb @@ -5,7 +5,7 @@ describe Banzai::ReferenceParser::UserParser do let(:group) { create(:group) } let(:user) { create(:user) } - let(:project) { create(:empty_project, :public, group: group, creator: user) } + let(:project) { create(:project, :public, group: group, creator: user) } subject { described_class.new(project, user) } let(:link) { empty_html_link } @@ -125,7 +125,7 @@ describe Banzai::ReferenceParser::UserParser do end it 'returns the nodes if the user can read the project' do - other_project = create(:empty_project, :public) + other_project = create(:project, :public) link['data-project'] = other_project.id.to_s @@ -137,7 +137,7 @@ describe Banzai::ReferenceParser::UserParser do end it 'returns an empty Array if the user can not read the project' do - other_project = create(:empty_project, :public) + other_project = create(:project, :public) link['data-project'] = other_project.id.to_s @@ -161,7 +161,7 @@ describe Banzai::ReferenceParser::UserParser do describe '#nodes_user_can_reference' do context 'when the link has a data-author attribute' do it 'returns the nodes when the user is a member of the project' do - other_project = create(:empty_project) + other_project = create(:project) other_project.team << [user, :developer] link['data-project'] = other_project.id.to_s @@ -178,7 +178,7 @@ describe Banzai::ReferenceParser::UserParser do end it 'returns an empty Array when the user could not be found' do - other_project = create(:empty_project) + other_project = create(:project) link['data-project'] = other_project.id.to_s link['data-author'] = '' @@ -187,7 +187,7 @@ describe Banzai::ReferenceParser::UserParser do end it 'returns an empty Array when the user is not a team member' do - other_project = create(:empty_project) + other_project = create(:project) link['data-project'] = other_project.id.to_s link['data-author'] = user.id.to_s diff --git a/spec/lib/bitbucket/paginator_spec.rb b/spec/lib/bitbucket/paginator_spec.rb index 2c972da682e..bdf10a5e2a2 100644 --- a/spec/lib/bitbucket/paginator_spec.rb +++ b/spec/lib/bitbucket/paginator_spec.rb @@ -15,7 +15,7 @@ describe Bitbucket::Paginator do expect(paginator.items).to match(['item_2']) allow(paginator).to receive(:fetch_next_page).and_return(nil) - expect{ paginator.items }.to raise_error(StopIteration) + expect { paginator.items }.to raise_error(StopIteration) end end end diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb index 8e2d2724426..f0769deef21 100644 --- a/spec/lib/ci/charts_spec.rb +++ b/spec/lib/ci/charts_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::Charts do context "pipeline_times" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:chart) { Ci::Charts::PipelineTime.new(project) } subject { chart.pipeline_times } diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb index ed571a2ba05..ee28387cd48 100644 --- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -1323,11 +1323,11 @@ EOT describe "Error handling" do it "fails to parse YAML" do - expect{GitlabCiYamlProcessor.new("invalid: yaml: test")}.to raise_error(Psych::SyntaxError) + expect {GitlabCiYamlProcessor.new("invalid: yaml: test")}.to raise_error(Psych::SyntaxError) end it "indicates that object is invalid" do - expect{GitlabCiYamlProcessor.new("invalid_yaml")}.to raise_error(GitlabCiYamlProcessor::ValidationError) + expect {GitlabCiYamlProcessor.new("invalid_yaml")}.to raise_error(GitlabCiYamlProcessor::ValidationError) end it "returns errors if tags parameter is invalid" do diff --git a/spec/lib/constraints/project_url_constrainer_spec.rb b/spec/lib/constraints/project_url_constrainer_spec.rb index e4b5dfc574a..92331eb2e5d 100644 --- a/spec/lib/constraints/project_url_constrainer_spec.rb +++ b/spec/lib/constraints/project_url_constrainer_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProjectUrlConstrainer do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:namespace) { project.namespace } describe '#matches?' do diff --git a/spec/lib/container_registry/blob_spec.rb b/spec/lib/container_registry/blob_spec.rb index 175fd2e7e13..c73faa55513 100644 --- a/spec/lib/container_registry/blob_spec.rb +++ b/spec/lib/container_registry/blob_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ContainerRegistry::Blob do let(:group) { create(:group, name: 'group') } - let(:project) { create(:empty_project, path: 'test', group: group) } + let(:project) { create(:project, path: 'test', group: group) } let(:repository) do create(:container_repository, name: 'image', diff --git a/spec/lib/container_registry/path_spec.rb b/spec/lib/container_registry/path_spec.rb index c2bcb54210b..84cacdd3f0d 100644 --- a/spec/lib/container_registry/path_spec.rb +++ b/spec/lib/container_registry/path_spec.rb @@ -90,7 +90,7 @@ describe ContainerRegistry::Path do describe '#has_repository?' do context 'when project exists' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:path) { "#{project.full_path}/my/image" } context 'when path already has matching repository' do @@ -123,8 +123,8 @@ describe ContainerRegistry::Path do let(:path) { 'some_group/some_project' } before do - create(:empty_project, group: group, name: 'some_project') - create(:empty_project, name: 'some_project') + create(:project, group: group, name: 'some_project') + create(:project, name: 'some_project') end it 'returns a correct project' do @@ -142,7 +142,7 @@ describe ContainerRegistry::Path do context 'when matching multi-level path' do let(:project) do - create(:empty_project, group: group, name: 'some_project') + create(:project, group: group, name: 'some_project') end context 'when using the zero-level path' do @@ -192,7 +192,7 @@ describe ContainerRegistry::Path do let(:group) { create(:group, path: 'Some_Group') } before do - create(:empty_project, group: group, name: 'some_project') + create(:project, group: group, name: 'some_project') end context 'when project path equal repository path' do @@ -235,7 +235,7 @@ describe ContainerRegistry::Path do let(:group) { create(:group, path: 'SomeGroup') } before do - create(:empty_project, group: group, name: 'MyProject') + create(:project, group: group, name: 'MyProject') end it 'returns downcased project path' do diff --git a/spec/lib/container_registry/tag_spec.rb b/spec/lib/container_registry/tag_spec.rb index cb4ae3be525..e76463b5e7c 100644 --- a/spec/lib/container_registry/tag_spec.rb +++ b/spec/lib/container_registry/tag_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ContainerRegistry::Tag do let(:group) { create(:group, name: 'group') } - let(:project) { create(:project, path: 'test', group: group) } + let(:project) { create(:project, :repository, path: 'test', group: group) } let(:repository) do create(:container_repository, name: '', project: project) diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb index b1366e74802..87ae6b6cf01 100644 --- a/spec/lib/event_filter_spec.rb +++ b/spec/lib/event_filter_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe EventFilter do describe '#apply_filter' do let(:source_user) { create(:user) } - let!(:public_project) { create(:empty_project, :public) } + let!(:public_project) { create(:project, :public) } - let!(:push_event) { create(:event, :pushed, project: public_project, target: public_project, author: source_user) } + let!(:push_event) { create(:push_event, project: public_project, author: source_user) } let!(:merged_event) { create(:event, :merged, project: public_project, target: public_project, author: source_user) } let!(:created_event) { create(:event, :created, project: public_project, target: public_project, author: source_user) } let!(:updated_event) { create(:event, :updated, project: public_project, target: public_project, author: source_user) } diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index 9b89f47ae7e..e13406d1972 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -14,7 +14,7 @@ describe ExtractsPath do repo = double(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0', 'release/app', 'release/app/v1.0.0']) allow(project).to receive(:repository).and_return(repo) - allow(project).to receive(:path_with_namespace) + allow(project).to receive(:full_path) .and_return('gitlab/gitlab-ci') allow(request).to receive(:format=) end @@ -29,7 +29,7 @@ describe ExtractsPath do it "log tree path has no escape sequences" do assign_ref_vars - expect(@logs_path).to eq("/#{@project.path_with_namespace}/refs/#{ref}/logs_tree/files/ruby/popen.rb") + expect(@logs_path).to eq("/#{@project.full_path}/refs/#{ref}/logs_tree/files/ruby/popen.rb") end context 'ref contains %20' do @@ -56,7 +56,7 @@ describe ExtractsPath do context 'subclass overrides get_id' do it 'uses ref returned by get_id' do - allow_any_instance_of(self.class).to receive(:get_id){ '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e' } + allow_any_instance_of(self.class).to receive(:get_id) { '38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e' } assign_ref_vars diff --git a/spec/lib/gitlab/allowable_spec.rb b/spec/lib/gitlab/allowable_spec.rb index 87733d53e92..9d80d480b52 100644 --- a/spec/lib/gitlab/allowable_spec.rb +++ b/spec/lib/gitlab/allowable_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::Allowable do let(:user) { create(:user) } context 'when user is allowed to do something' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } it 'reports correct ability to perform action' do expect(subject.can?(user, :read_project, project)).to be true @@ -17,7 +17,7 @@ describe Gitlab::Allowable do end context 'when user is not allowed to do something' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } it 'reports correct ability to perform action' do expect(subject.can?(user, :read_project, project)).to be false diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index a9db0d5164d..4a498e79c87 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -65,7 +65,7 @@ describe Gitlab::Auth do end it 'recognizes other ci services' do - project = create(:empty_project) + project = create(:project) project.create_drone_ci_service(active: true) project.drone_ci_service.update(token: 'token') @@ -313,7 +313,8 @@ describe Gitlab::Auth do def full_authentication_abilities read_authentication_abilities + [ :push_code, - :create_container_image + :create_container_image, + :admin_container_image ] end end diff --git a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb new file mode 100644 index 00000000000..7cd2ce82eda --- /dev/null +++ b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb @@ -0,0 +1,199 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits do + describe '#perform' do + set(:merge_request) { create(:merge_request) } + set(:merge_request_diff) { merge_request.merge_request_diff } + let(:updated_merge_request_diff) { MergeRequestDiff.find(merge_request_diff.id) } + + def diffs_to_hashes(diffs) + diffs.as_json(only: Gitlab::Git::Diff::SERIALIZE_KEYS).map(&:with_indifferent_access) + end + + def quote_yaml(value) + MergeRequestDiff.connection.quote(YAML.dump(value)) + end + + def convert_to_yaml(merge_request_diff_id, commits, diffs) + MergeRequestDiff.where(id: merge_request_diff_id).update_all( + "st_commits = #{quote_yaml(commits)}, st_diffs = #{quote_yaml(diffs)}" + ) + end + + shared_examples 'updated MR diff' do + before do + convert_to_yaml(merge_request_diff.id, commits, diffs) + + MergeRequestDiffCommit.delete_all + MergeRequestDiffFile.delete_all + + subject.perform(merge_request_diff.id, merge_request_diff.id) + end + + it 'creates correct entries in the merge_request_diff_commits table' do + expect(updated_merge_request_diff.merge_request_diff_commits.count).to eq(commits.count) + expect(updated_merge_request_diff.commits.map(&:to_hash)).to eq(commits) + end + + it 'creates correct entries in the merge_request_diff_files table' do + expect(updated_merge_request_diff.merge_request_diff_files.count).to eq(expected_diffs.count) + expect(diffs_to_hashes(updated_merge_request_diff.raw_diffs)).to eq(expected_diffs) + end + + it 'sets the st_commits and st_diffs columns to nil' do + expect(updated_merge_request_diff.st_commits_before_type_cast).to be_nil + expect(updated_merge_request_diff.st_diffs_before_type_cast).to be_nil + end + end + + context 'when the diff IDs passed do not exist' do + it 'does not raise' do + expect { subject.perform(0, 0) }.not_to raise_exception + end + end + + context 'when the merge request diff has no serialised commits or diffs' do + before do + merge_request_diff.update(st_commits: nil, st_diffs: nil) + end + + it 'does not raise' do + expect { subject.perform(merge_request_diff.id, merge_request_diff.id) } + .not_to raise_exception + end + end + + context 'processing multiple merge request diffs' do + let(:start_id) { described_class::MergeRequestDiff.minimum(:id) } + let(:stop_id) { described_class::MergeRequestDiff.maximum(:id) } + + before do + merge_request.reload_diff(true) + + convert_to_yaml(start_id, merge_request_diff.commits, merge_request_diff.diffs) + convert_to_yaml(stop_id, updated_merge_request_diff.commits, updated_merge_request_diff.diffs) + + MergeRequestDiffCommit.delete_all + MergeRequestDiffFile.delete_all + end + + context 'when BUFFER_ROWS is exceeded' do + before do + stub_const("#{described_class}::BUFFER_ROWS", 1) + end + + it 'updates and continues' do + expect(described_class::MergeRequestDiff).to receive(:transaction).twice + + subject.perform(start_id, stop_id) + end + end + + context 'when BUFFER_ROWS is not exceeded' do + it 'only updates once' do + expect(described_class::MergeRequestDiff).to receive(:transaction).once + + subject.perform(start_id, stop_id) + end + end + end + + context 'when the merge request diff update fails' do + before do + allow(described_class::MergeRequestDiff) + .to receive(:update_all).and_raise(ActiveRecord::Rollback) + end + + it 'does not add any diff commits' do + expect { subject.perform(merge_request_diff.id, merge_request_diff.id) } + .not_to change { MergeRequestDiffCommit.count } + end + + it 'does not add any diff files' do + expect { subject.perform(merge_request_diff.id, merge_request_diff.id) } + .not_to change { MergeRequestDiffFile.count } + end + end + + context 'when the merge request diff has valid commits and diffs' do + let(:commits) { merge_request_diff.commits.map(&:to_hash) } + let(:diffs) { diffs_to_hashes(merge_request_diff.merge_request_diff_files) } + let(:expected_diffs) { diffs } + + include_examples 'updated MR diff' + end + + context 'when the merge request diffs do not have too_large set' do + let(:commits) { merge_request_diff.commits.map(&:to_hash) } + let(:expected_diffs) { diffs_to_hashes(merge_request_diff.merge_request_diff_files) } + + let(:diffs) do + expected_diffs.map { |diff| diff.except(:too_large) } + end + + include_examples 'updated MR diff' + end + + context 'when the merge request diffs have binary content' do + let(:commits) { merge_request_diff.commits.map(&:to_hash) } + let(:expected_diffs) { diffs } + + # The start of a PDF created by Illustrator + let(:binary_string) do + "\x25\x50\x44\x46\x2d\x31\x2e\x35\x0d\x25\xe2\xe3\xcf\xd3\x0d\x0a".force_encoding(Encoding::BINARY) + end + + let(:diffs) do + [ + { + 'diff' => binary_string, + 'new_path' => 'path', + 'old_path' => 'path', + 'a_mode' => '100644', + 'b_mode' => '100644', + 'new_file' => false, + 'renamed_file' => false, + 'deleted_file' => false, + 'too_large' => false + } + ] + end + + include_examples 'updated MR diff' + end + + context 'when the merge request diff has commits, but no diffs' do + let(:commits) { merge_request_diff.commits.map(&:to_hash) } + let(:diffs) { [] } + let(:expected_diffs) { diffs } + + include_examples 'updated MR diff' + end + + context 'when the merge request diffs have invalid content' do + let(:commits) { merge_request_diff.commits.map(&:to_hash) } + let(:diffs) { ['--broken-diff'] } + let(:expected_diffs) { [] } + + include_examples 'updated MR diff' + end + + context 'when the merge request diffs are Rugged::Patch instances' do + let(:commits) { merge_request_diff.commits.map(&:to_hash) } + let(:first_commit) { merge_request.project.repository.commit(merge_request_diff.head_commit_sha) } + let(:diffs) { first_commit.rugged_diff_from_parent.patches } + let(:expected_diffs) { [] } + + include_examples 'updated MR diff' + end + + context 'when the merge request diffs are Rugged::Diff::Delta instances' do + let(:commits) { merge_request_diff.commits.map(&:to_hash) } + let(:first_commit) { merge_request.project.repository.commit(merge_request_diff.head_commit_sha) } + let(:diffs) { first_commit.rugged_diff_from_parent.deltas } + let(:expected_diffs) { [] } + + include_examples 'updated MR diff' + end + end +end diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb new file mode 100644 index 00000000000..87f45619e7a --- /dev/null +++ b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb @@ -0,0 +1,423 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads::Event do + describe '#commit_title' do + it 'returns nil when there are no commits' do + expect(described_class.new.commit_title).to be_nil + end + + it 'returns nil when there are commits without commit messages' do + event = described_class.new + + allow(event).to receive(:commits).and_return([{ id: '123' }]) + + expect(event.commit_title).to be_nil + end + + it 'returns the commit message when it is less than 70 characters long' do + event = described_class.new + + allow(event).to receive(:commits).and_return([{ message: 'Hello world' }]) + + expect(event.commit_title).to eq('Hello world') + end + + it 'returns the first line of a commit message if multiple lines are present' do + event = described_class.new + + allow(event).to receive(:commits).and_return([{ message: "Hello\n\nworld" }]) + + expect(event.commit_title).to eq('Hello') + end + + it 'truncates the commit to 70 characters when it is too long' do + event = described_class.new + + allow(event).to receive(:commits).and_return([{ message: 'a' * 100 }]) + + expect(event.commit_title).to eq(('a' * 67) + '...') + end + end + + describe '#commit_from_sha' do + it 'returns nil when pushing to a new ref' do + event = described_class.new + + allow(event).to receive(:create?).and_return(true) + + expect(event.commit_from_sha).to be_nil + end + + it 'returns the ID of the first commit when pushing to an existing ref' do + event = described_class.new + + allow(event).to receive(:create?).and_return(false) + allow(event).to receive(:data).and_return(before: '123') + + expect(event.commit_from_sha).to eq('123') + end + end + + describe '#commit_to_sha' do + it 'returns nil when removing an existing ref' do + event = described_class.new + + allow(event).to receive(:remove?).and_return(true) + + expect(event.commit_to_sha).to be_nil + end + + it 'returns the ID of the last commit when pushing to an existing ref' do + event = described_class.new + + allow(event).to receive(:remove?).and_return(false) + allow(event).to receive(:data).and_return(after: '123') + + expect(event.commit_to_sha).to eq('123') + end + end + + describe '#data' do + it 'returns the deserialized data' do + event = described_class.new(data: { before: '123' }) + + expect(event.data).to eq(before: '123') + end + + it 'returns an empty hash when no data is present' do + event = described_class.new + + expect(event.data).to eq({}) + end + end + + describe '#commits' do + it 'returns an Array of commits' do + event = described_class.new(data: { commits: [{ id: '123' }] }) + + expect(event.commits).to eq([{ id: '123' }]) + end + + it 'returns an empty array when no data is present' do + event = described_class.new + + expect(event.commits).to eq([]) + end + end + + describe '#commit_count' do + it 'returns the number of commits' do + event = described_class.new(data: { total_commits_count: 2 }) + + expect(event.commit_count).to eq(2) + end + + it 'returns 0 when no data is present' do + event = described_class.new + + expect(event.commit_count).to eq(0) + end + end + + describe '#ref' do + it 'returns the name of the ref' do + event = described_class.new(data: { ref: 'refs/heads/master' }) + + expect(event.ref).to eq('refs/heads/master') + end + end + + describe '#trimmed_ref_name' do + it 'returns the trimmed ref name for a branch' do + event = described_class.new(data: { ref: 'refs/heads/master' }) + + expect(event.trimmed_ref_name).to eq('master') + end + + it 'returns the trimmed ref name for a tag' do + event = described_class.new(data: { ref: 'refs/tags/v1.2' }) + + expect(event.trimmed_ref_name).to eq('v1.2') + end + end + + describe '#create?' do + it 'returns true when creating a new ref' do + event = described_class.new(data: { before: described_class::BLANK_REF }) + + expect(event.create?).to eq(true) + end + + it 'returns false when pushing to an existing ref' do + event = described_class.new(data: { before: '123' }) + + expect(event.create?).to eq(false) + end + end + + describe '#remove?' do + it 'returns true when removing an existing ref' do + event = described_class.new(data: { after: described_class::BLANK_REF }) + + expect(event.remove?).to eq(true) + end + + it 'returns false when pushing to an existing ref' do + event = described_class.new(data: { after: '123' }) + + expect(event.remove?).to eq(false) + end + end + + describe '#push_action' do + let(:event) { described_class.new } + + it 'returns :created when creating a new ref' do + allow(event).to receive(:create?).and_return(true) + + expect(event.push_action).to eq(:created) + end + + it 'returns :removed when removing an existing ref' do + allow(event).to receive(:create?).and_return(false) + allow(event).to receive(:remove?).and_return(true) + + expect(event.push_action).to eq(:removed) + end + + it 'returns :pushed when pushing to an existing ref' do + allow(event).to receive(:create?).and_return(false) + allow(event).to receive(:remove?).and_return(false) + + expect(event.push_action).to eq(:pushed) + end + end + + describe '#ref_type' do + let(:event) { described_class.new } + + it 'returns :tag for a tag' do + allow(event).to receive(:ref).and_return('refs/tags/1.2') + + expect(event.ref_type).to eq(:tag) + end + + it 'returns :branch for a branch' do + allow(event).to receive(:ref).and_return('refs/heads/1.2') + + expect(event.ref_type).to eq(:branch) + end + end +end + +describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads do + let(:migration) { described_class.new } + let(:project) { create(:project_empty_repo) } + let(:author) { create(:user) } + + # We can not rely on FactoryGirl as the state of Event may change in ways that + # the background migration does not expect, hence we use the Event class of + # the migration itself. + def create_push_event(project, author, data = nil) + klass = Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads::Event + + klass.create!( + action: klass::PUSHED, + project_id: project.id, + author_id: author.id, + data: data + ) + end + + # The background migration relies on a temporary table, hence we're migrating + # to a specific version of the database where said table is still present. + before :all do + ActiveRecord::Migration.verbose = false + + ActiveRecord::Migrator + .migrate(ActiveRecord::Migrator.migrations_paths, 20170608152748) + end + + after :all do + ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths) + + ActiveRecord::Migration.verbose = true + end + + describe '#perform' do + it 'returns if data should not be migrated' do + allow(migration).to receive(:migrate?).and_return(false) + + expect(migration).not_to receive(:find_events) + + migration.perform(1, 10) + end + + it 'migrates the range of events if data is to be migrated' do + event1 = create_push_event(project, author, { commits: [] }) + event2 = create_push_event(project, author, { commits: [] }) + + allow(migration).to receive(:migrate?).and_return(true) + + expect(migration).to receive(:process_event).twice + + migration.perform(event1.id, event2.id) + end + end + + describe '#process_event' do + it 'processes a regular event' do + event = double(:event, push_event?: false) + + expect(migration).to receive(:replicate_event) + expect(migration).not_to receive(:create_push_event_payload) + + migration.process_event(event) + end + + it 'processes a push event' do + event = double(:event, push_event?: true) + + expect(migration).to receive(:replicate_event) + expect(migration).to receive(:create_push_event_payload) + + migration.process_event(event) + end + end + + describe '#replicate_event' do + it 'replicates the event to the "events_for_migration" table' do + event = create_push_event( + project, + author, + data: { commits: [] }, + title: 'bla' + ) + + attributes = event + .attributes.with_indifferent_access.except(:title, :data) + + expect(described_class::EventForMigration) + .to receive(:create!) + .with(attributes) + + migration.replicate_event(event) + end + end + + describe '#create_push_event_payload' do + let(:push_data) do + { + commits: [], + ref: 'refs/heads/master', + before: '156e0e9adc587a383a7eeb5b21ddecb9044768a8', + after: '0' * 40, + total_commits_count: 1 + } + end + + let(:event) do + create_push_event(project, author, push_data) + end + + before do + # The foreign key in push_event_payloads at this point points to the + # "events_for_migration" table so we need to make sure a row exists in + # said table. + migration.replicate_event(event) + end + + it 'creates a push event payload for an event' do + payload = migration.create_push_event_payload(event) + + expect(PushEventPayload.count).to eq(1) + expect(payload.valid?).to eq(true) + end + + it 'does not create push event payloads for removed events' do + allow(event).to receive(:id).and_return(-1) + + payload = migration.create_push_event_payload(event) + + expect(payload).to be_nil + expect(PushEventPayload.count).to eq(0) + end + + it 'encodes and decodes the commit IDs from and to binary data' do + payload = migration.create_push_event_payload(event) + packed = migration.pack(push_data[:before]) + + expect(payload.commit_from).to eq(packed) + expect(payload.commit_to).to be_nil + end + end + + describe '#find_events' do + it 'returns the events for the given ID range' do + event1 = create_push_event(project, author, { commits: [] }) + event2 = create_push_event(project, author, { commits: [] }) + event3 = create_push_event(project, author, { commits: [] }) + events = migration.find_events(event1.id, event2.id) + + expect(events.length).to eq(2) + expect(events.pluck(:id)).not_to include(event3.id) + end + end + + describe '#migrate?' do + it 'returns true when data should be migrated' do + allow(described_class::Event) + .to receive(:table_exists?).and_return(true) + + allow(described_class::PushEventPayload) + .to receive(:table_exists?).and_return(true) + + allow(described_class::EventForMigration) + .to receive(:table_exists?).and_return(true) + + expect(migration.migrate?).to eq(true) + end + + it 'returns false if the "events" table does not exist' do + allow(described_class::Event) + .to receive(:table_exists?).and_return(false) + + expect(migration.migrate?).to eq(false) + end + + it 'returns false if the "push_event_payloads" table does not exist' do + allow(described_class::Event) + .to receive(:table_exists?).and_return(true) + + allow(described_class::PushEventPayload) + .to receive(:table_exists?).and_return(false) + + expect(migration.migrate?).to eq(false) + end + + it 'returns false when the "events_for_migration" table does not exist' do + allow(described_class::Event) + .to receive(:table_exists?).and_return(true) + + allow(described_class::PushEventPayload) + .to receive(:table_exists?).and_return(true) + + allow(described_class::EventForMigration) + .to receive(:table_exists?).and_return(false) + + expect(migration.migrate?).to eq(false) + end + end + + describe '#pack' do + it 'packs a SHA1 into a 20 byte binary string' do + packed = migration.pack('156e0e9adc587a383a7eeb5b21ddecb9044768a8') + + expect(packed.bytesize).to eq(20) + end + + it 'returns nil if the input value is nil' do + expect(migration.pack(nil)).to be_nil + end + end +end diff --git a/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb index a910fb105a5..59f69d1e4b1 100644 --- a/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb +++ b/spec/lib/gitlab/background_migration/migrate_system_uploads_to_new_folder_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::BackgroundMigration::MigrateSystemUploadsToNewFolder do describe '#perform' do it 'renames the path of system-uploads', truncate: true do - upload = create(:upload, model: create(:empty_project), path: 'uploads/system/project/avatar.jpg') + upload = create(:upload, model: create(:project), path: 'uploads/system/project/avatar.jpg') migration.perform('uploads/system/', 'uploads/-/system/') diff --git a/spec/lib/gitlab/background_migration/move_personal_snippet_files_spec.rb b/spec/lib/gitlab/background_migration/move_personal_snippet_files_spec.rb new file mode 100644 index 00000000000..ee60e498b59 --- /dev/null +++ b/spec/lib/gitlab/background_migration/move_personal_snippet_files_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration::MovePersonalSnippetFiles do + let(:test_dir) { File.join(Rails.root, 'tmp', 'tests', 'move_snippet_files_test') } + let(:old_uploads_dir) { File.join('uploads', 'system', 'personal_snippet') } + let(:new_uploads_dir) { File.join('uploads', '-', 'system', 'personal_snippet') } + let(:snippet) do + snippet = create(:personal_snippet) + create_upload_for_snippet(snippet) + snippet.update_attributes!(description: markdown_linking_file(snippet)) + snippet + end + + let(:migration) { described_class.new } + + before do + allow(migration).to receive(:base_directory) { test_dir } + end + + describe '#perform' do + it 'moves the file on the disk' do + expected_path = File.join(test_dir, new_uploads_dir, snippet.id.to_s, "secret#{snippet.id}", 'upload.txt') + + migration.perform(old_uploads_dir, new_uploads_dir) + + expect(File.exist?(expected_path)).to be_truthy + end + + it 'updates the markdown of the snippet' do + expected_path = File.join(new_uploads_dir, snippet.id.to_s, "secret#{snippet.id}", 'upload.txt') + expected_markdown = "[an upload](#{expected_path})" + + migration.perform(old_uploads_dir, new_uploads_dir) + + expect(snippet.reload.description).to eq(expected_markdown) + end + + it 'updates the markdown of notes' do + expected_path = File.join(new_uploads_dir, snippet.id.to_s, "secret#{snippet.id}", 'upload.txt') + expected_markdown = "with [an upload](#{expected_path})" + + note = create(:note_on_personal_snippet, noteable: snippet, note: "with #{markdown_linking_file(snippet)}") + + migration.perform(old_uploads_dir, new_uploads_dir) + + expect(note.reload.note).to eq(expected_markdown) + end + end + + def create_upload_for_snippet(snippet) + snippet_path = path_for_file_in_snippet(snippet) + path = File.join(old_uploads_dir, snippet.id.to_s, snippet_path) + absolute_path = File.join(test_dir, path) + + FileUtils.mkdir_p(File.dirname(absolute_path)) + FileUtils.touch(absolute_path) + + create(:upload, model: snippet, path: snippet_path, uploader: PersonalFileUploader) + end + + def path_for_file_in_snippet(snippet) + secret = "secret#{snippet.id}" + filename = 'upload.txt' + + File.join(secret, filename) + end + + def markdown_linking_file(snippet) + path = File.join(old_uploads_dir, snippet.id.to_s, path_for_file_in_snippet(snippet)) + "[an upload](#{path})" + end +end diff --git a/spec/lib/gitlab/backup/repository_spec.rb b/spec/lib/gitlab/backup/repository_spec.rb index db860b01ba4..535cce12780 100644 --- a/spec/lib/gitlab/backup/repository_spec.rb +++ b/spec/lib/gitlab/backup/repository_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Backup::Repository do let(:progress) { StringIO.new } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } before do allow(progress).to receive(:puts) @@ -60,4 +60,58 @@ describe Backup::Repository do end end end + + describe '#empty_repo?' do + context 'for a wiki' do + let(:wiki) { create(:project_wiki) } + + context 'wiki repo has content' do + let!(:wiki_page) { create(:wiki_page, wiki: wiki) } + + before do + wiki.repository.exists? # initial cache + end + + context '`repository.exists?` is incorrectly cached as false' do + before do + repo = wiki.repository + repo.send(:cache).expire(:exists?) + repo.send(:cache).fetch(:exists?) { false } + repo.send(:instance_variable_set, :@exists, false) + end + + it 'returns false, regardless of bad cache value' do + expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey + end + end + + context '`repository.exists?` is correctly cached as true' do + it 'returns false' do + expect(described_class.new.send(:empty_repo?, wiki)).to be_falsey + end + end + end + + context 'wiki repo does not have content' do + context '`repository.exists?` is incorrectly cached as true' do + before do + repo = wiki.repository + repo.send(:cache).expire(:exists?) + repo.send(:cache).fetch(:exists?) { true } + repo.send(:instance_variable_set, :@exists, true) + end + + it 'returns true, regardless of bad cache value' do + expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy + end + end + + context '`repository.exists?` is correctly cached as false' do + it 'returns true' do + expect(described_class.new.send(:empty_repo?, wiki)).to be_truthy + end + end + end + end + end end diff --git a/spec/lib/gitlab/badge/coverage/metadata_spec.rb b/spec/lib/gitlab/badge/coverage/metadata_spec.rb index 5e93935ea37..74eaf7eaf8b 100644 --- a/spec/lib/gitlab/badge/coverage/metadata_spec.rb +++ b/spec/lib/gitlab/badge/coverage/metadata_spec.rb @@ -3,7 +3,7 @@ require 'lib/gitlab/badge/shared/metadata' describe Gitlab::Badge::Coverage::Metadata do let(:badge) do - double(project: create(:empty_project), ref: 'feature', job: 'test') + double(project: create(:project), ref: 'feature', job: 'test') end let(:metadata) { described_class.new(badge) } diff --git a/spec/lib/gitlab/badge/coverage/report_spec.rb b/spec/lib/gitlab/badge/coverage/report_spec.rb index 1547bd3228c..da789bf3705 100644 --- a/spec/lib/gitlab/badge/coverage/report_spec.rb +++ b/spec/lib/gitlab/badge/coverage/report_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::Badge::Coverage::Report do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:job_name) { nil } let(:badge) do diff --git a/spec/lib/gitlab/badge/pipeline/metadata_spec.rb b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb index d537ce8803c..9032a8e9016 100644 --- a/spec/lib/gitlab/badge/pipeline/metadata_spec.rb +++ b/spec/lib/gitlab/badge/pipeline/metadata_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' require 'lib/gitlab/badge/shared/metadata' describe Gitlab::Badge::Pipeline::Metadata do - let(:badge) { double(project: create(:empty_project), ref: 'feature') } + let(:badge) { double(project: create(:project), ref: 'feature') } let(:metadata) { described_class.new(badge) } it_behaves_like 'badge metadata' diff --git a/spec/lib/gitlab/bitbucket_import/importer_spec.rb b/spec/lib/gitlab/bitbucket_import/importer_spec.rb index df66a031fec..a66347ead76 100644 --- a/spec/lib/gitlab/bitbucket_import/importer_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/importer_spec.rb @@ -52,9 +52,9 @@ describe Gitlab::BitbucketImport::Importer do let(:project) do create( - :empty_project, + :project, import_source: project_identifier, - import_data: ProjectImportData.new(credentials: data) + import_data_attributes: { credentials: data } ) end diff --git a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb index d7f7b26740d..ae5b31dc12d 100644 --- a/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb +++ b/spec/lib/gitlab/bitbucket_import/project_creator_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::BitbucketImport::ProjectCreator do has_wiki?: false) end - let(:namespace){ create(:group, owner: user) } + let(:namespace) { create(:group, owner: user) } let(:token) { "asdasd12345" } let(:secret) { "sekrettt" } let(:access_params) { { bitbucket_access_token: token, bitbucket_access_token_secret: secret } } diff --git a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb index 0daf41a7c86..16704ff5e77 100644 --- a/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb +++ b/spec/lib/gitlab/cache/ci/project_pipeline_status_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let(:pipeline_status) { described_class.new(project) } let(:cache_key) { "projects/#{project.id}/pipeline_status" } @@ -18,7 +18,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do let(:sha) { '424d1b73bc0d3cb726eb7dc4ce17a4d48552f8c6' } let(:ref) { 'master' } let(:pipeline_info) { { sha: sha, status: status, ref: ref } } - let!(:project_without_status) { create(:project) } + let!(:project_without_status) { create(:project, :repository) } describe '.load_in_batch_for_projects' do it 'preloads pipeline_status on projects' do @@ -48,8 +48,9 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do described_class.load_in_batch_for_projects([project_without_status]) end - it 'only connects to redis_cache twice' do - # Once to load, once to store in the cache + it 'only connects to redis twice' do + # Stub circuitbreaker so it doesn't count the redis connections in there + stub_circuit_breaker(project_without_status) expect(Gitlab::Redis::Cache).to receive(:with).exactly(2).and_call_original described_class.load_in_batch_for_projects([project_without_status]) @@ -195,7 +196,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do end it "doesn't fail for an empty project" do - status_for_empty_commit = described_class.new(create(:empty_project)) + status_for_empty_commit = described_class.new(create(:project)) status_for_empty_commit.load_status @@ -243,7 +244,7 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do end it "deletes the cache if the repository doesn't have a head commit" do - empty_project = create(:empty_project) + empty_project = create(:project) Gitlab::Redis::Cache.with do |redis| redis.mapped_hmset(cache_key, { sha: 'sha', status: 'pending', ref: 'master' }) @@ -301,4 +302,13 @@ describe Gitlab::Cache::Ci::ProjectPipelineStatus, :clean_gitlab_redis_cache do end end end + + def stub_circuit_breaker(project) + fake_circuitbreaker = double + allow(fake_circuitbreaker).to receive(:perform).and_yield + allow(project.repository.raw_repository) + .to receive(:circuit_breaker).and_return(fake_circuitbreaker) + allow(project.repository) + .to receive(:circuit_breaker).and_return(fake_circuitbreaker) + end end diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb index 6c4cfa1203e..f8c8b83a3ac 100644 --- a/spec/lib/gitlab/checks/force_push_spec.rb +++ b/spec/lib/gitlab/checks/force_push_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::Checks::ForcePush do let(:project) { create(:project, :repository) } - context "exit code checking" do + context "exit code checking", skip_gitaly_mock: true do it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0]) diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb index f5fd31e8d03..4a5b45e7cae 100644 --- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb +++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::Ci::Status::Pipeline::Common do let(:user) { create(:user) } - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:pipeline) { create(:ci_pipeline, project: project) } subject do diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb index 8814a7614a0..f5f03ac0395 100644 --- a/spec/lib/gitlab/ci/status/stage/common_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::Ci::Status::Stage::Common do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:stage) do diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb index bbb40e2c1ab..432b07e4902 100644 --- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb +++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::Ci::Status::Stage::Factory do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, project: project) } let(:stage) do diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb index 8ff6125ada1..15012495247 100644 --- a/spec/lib/gitlab/closing_issue_extractor_spec.rb +++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe Gitlab::ClosingIssueExtractor do - let(:project) { create(:empty_project) } - let(:project2) { create(:empty_project) } + let(:project) { create(:project) } + let(:project2) { create(:project) } let(:forked_project) { Projects::ForkService.new(project, project.creator).execute } let(:issue) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project2) } diff --git a/spec/lib/gitlab/contributions_calendar_spec.rb b/spec/lib/gitlab/contributions_calendar_spec.rb index 79632e2b6a3..f1655854486 100644 --- a/spec/lib/gitlab/contributions_calendar_spec.rb +++ b/spec/lib/gitlab/contributions_calendar_spec.rb @@ -5,29 +5,31 @@ describe Gitlab::ContributionsCalendar do let(:user) { create(:user) } let(:private_project) do - create(:empty_project, :private) do |project| + create(:project, :private) do |project| create(:project_member, user: contributor, project: project) end end let(:public_project) do - create(:empty_project, :public) do |project| + create(:project, :public) do |project| create(:project_member, user: contributor, project: project) end end let(:feature_project) do - create(:empty_project, :public, :issues_private) do |project| + create(:project, :public, :issues_private) do |project| create(:project_member, user: contributor, project: project).project end end - let(:today) { Time.now.to_date } + let(:today) { Time.now.utc.to_date } + let(:yesterday) { today - 1.day } + let(:tomorrow) { today + 1.day } let(:last_week) { today - 7.days } let(:last_year) { today - 1.year } before do - travel_to today + travel_to Time.now.utc.end_of_day end after do @@ -38,7 +40,7 @@ describe Gitlab::ContributionsCalendar do described_class.new(contributor, current_user) end - def create_event(project, day) + def create_event(project, day, hour = 0) @targets ||= {} @targets[project] ||= create(:issue, project: project, author: contributor) @@ -47,7 +49,7 @@ describe Gitlab::ContributionsCalendar do action: Event::CREATED, target: @targets[project], author: contributor, - created_at: day + created_at: DateTime.new(day.year, day.month, day.day, hour) ) end @@ -68,6 +70,34 @@ describe Gitlab::ContributionsCalendar do expect(calendar(user).activity_dates[today]).to eq(0) expect(calendar(contributor).activity_dates[today]).to eq(2) end + + context "when events fall under different dates depending on the time zone" do + before do + create_event(public_project, today, 1) + create_event(public_project, today, 4) + create_event(public_project, today, 10) + create_event(public_project, today, 16) + create_event(public_project, today, 23) + end + + it "renders correct event counts within the UTC timezone" do + Time.use_zone('UTC') do + expect(calendar.activity_dates).to eq(today => 5) + end + end + + it "renders correct event counts within the Sydney timezone" do + Time.use_zone('Sydney') do + expect(calendar.activity_dates).to eq(today => 3, tomorrow => 2) + end + end + + it "renders correct event counts within the US Central timezone" do + Time.use_zone('Central Time (US & Canada)') do + expect(calendar.activity_dates).to eq(yesterday => 2, today => 3) + end + end + end end describe '#events_by_date' do diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb index d8757c601ab..854aaa34c73 100644 --- a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::CycleAnalytics::BaseEventFetcher do let(:max_events) { 2 } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user, :admin) } let(:start_time_attrs) { Issue.arel_table[:created_at] } let(:end_time_attrs) { [Issue::Metrics.arel_table[:first_associated_with_milestone_at]] } diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb index a1b3fe8509e..28ea7d4c303 100644 --- a/spec/lib/gitlab/cycle_analytics/events_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'cycle analytics events' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:from_date) { 10.days.ago } let(:user) { create(:user, :admin) } let!(:context) { create(:issue, project: project, created_at: 2.days.ago) } diff --git a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb index 2d85e712db0..2a0dd7be439 100644 --- a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::CycleAnalytics::Permissions do - let(:project) { create(:empty_project, public_builds: false) } + let(:project) { create(:project, public_builds: false) } let(:user) { create(:user) } subject { described_class.get(user: user, project: project) } diff --git a/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb index 9c5e57342e9..c22d27f60d6 100644 --- a/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' shared_examples 'default query config' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:event) { described_class.new(project: project, stage: stage_name, options: { from: 1.day.ago }) } it 'has the stage attribute' do diff --git a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb index 592448aef96..2e67c1c7f78 100644 --- a/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb +++ b/spec/lib/gitlab/cycle_analytics/stage_summary_spec.rb @@ -15,7 +15,7 @@ describe Gitlab::CycleAnalytics::StageSummary do end it "doesn't find issues from other projects" do - Timecop.freeze(5.days.from_now) { create(:issue, project: create(:empty_project)) } + Timecop.freeze(5.days.from_now) { create(:issue, project: create(:project)) } expect(subject.first[:value]).to eq(0) end diff --git a/spec/lib/gitlab/daemon_spec.rb b/spec/lib/gitlab/daemon_spec.rb new file mode 100644 index 00000000000..2bdb0dfc736 --- /dev/null +++ b/spec/lib/gitlab/daemon_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' + +describe Gitlab::Daemon do + subject { described_class.new } + + before do + allow(subject).to receive(:start_working) + allow(subject).to receive(:stop_working) + end + + describe '.instance' do + before do + allow(Kernel).to receive(:at_exit) + end + + after do + described_class.instance_variable_set(:@instance, nil) + end + + it 'provides instance of Daemon' do + expect(described_class.instance).to be_instance_of(described_class) + end + + it 'subsequent invocations provide the same instance' do + expect(described_class.instance).to eq(described_class.instance) + end + + it 'creates at_exit hook when instance is created' do + expect(described_class.instance).not_to be_nil + + expect(Kernel).to have_received(:at_exit) + end + end + + describe 'when Daemon is enabled' do + before do + allow(subject).to receive(:enabled?).and_return(true) + end + + describe 'when Daemon is stopped' do + describe '#start' do + it 'starts the Daemon' do + expect { subject.start.join }.to change { subject.thread? }.from(false).to(true) + + expect(subject).to have_received(:start_working) + end + end + + describe '#stop' do + it "doesn't shutdown stopped Daemon" do + expect { subject.stop }.not_to change { subject.thread? } + + expect(subject).not_to have_received(:start_working) + end + end + end + + describe 'when Daemon is running' do + before do + subject.start.join + end + + describe '#start' do + it "doesn't start running Daemon" do + expect { subject.start.join }.not_to change { subject.thread? } + + expect(subject).to have_received(:start_working).once + end + end + + describe '#stop' do + it 'shutdowns Daemon' do + expect { subject.stop }.to change { subject.thread? }.from(true).to(false) + + expect(subject).to have_received(:stop_working) + end + end + end + end + + describe 'when Daemon is disabled' do + before do + allow(subject).to receive(:enabled?).and_return(false) + end + + describe '#start' do + it "doesn't start working" do + expect(subject.start).to be_nil + expect { subject.start }.not_to change { subject.thread? } + + expect(subject).not_to have_received(:start_working) + end + end + + describe '#stop' do + it "doesn't stop working" do + expect { subject.stop }.not_to change { subject.thread? } + + expect(subject).not_to have_received(:stop_working) + end + end + end +end diff --git a/spec/lib/gitlab/data_builder/note_spec.rb b/spec/lib/gitlab/data_builder/note_spec.rb index 6415e4083d6..aaa42566a4d 100644 --- a/spec/lib/gitlab/data_builder/note_spec.rb +++ b/spec/lib/gitlab/data_builder/note_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::DataBuilder::Note do let(:data) { described_class.build(note, user) } let(:fixed_time) { Time.at(1425600000) } # Avoid time precision errors - before(:each) do + before do expect(data).to have_key(:object_attributes) expect(data[:object_attributes]).to have_key(:url) expect(data[:object_attributes][:url]) diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index d3dbd82e8ba..ec2274a70aa 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -276,7 +276,7 @@ describe Gitlab::Database::MigrationHelpers do before do expect(model).to receive(:transaction_open?).and_return(false) - create_list(:empty_project, 5) + create_list(:project, 5) end it 'updates all the rows in a table' do diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb index df7d1b5d27a..90aa4f63dd5 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb @@ -29,7 +29,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca end describe '#remove_cached_html_for_projects' do - let(:project) { create(:empty_project, description_html: 'Project description') } + let(:project) { create(:project, description_html: 'Project description') } it 'removes description_html from projects' do subject.remove_cached_html_for_projects([project.id]) @@ -94,7 +94,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca end it "renames the route for projects of the namespace" do - project = create(:project, path: "project-path", namespace: namespace) + project = create(:project, :repository, path: "project-path", namespace: namespace) subject.rename_path_for_routable(migration_namespace(namespace)) @@ -110,7 +110,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca it "doesn't rename routes that start with a similar name" do other_namespace = create(:namespace, path: 'the-path-but-not-really') - project = create(:empty_project, path: 'the-project', namespace: other_namespace) + project = create(:project, path: 'the-project', namespace: other_namespace) subject.rename_path_for_routable(migration_namespace(namespace)) @@ -120,7 +120,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca context "the-path namespace -> subgroup -> the-path0 project" do it "updates the route of the project correctly" do subgroup = create(:group, path: "subgroup", parent: namespace) - project = create(:project, path: "the-path0", namespace: subgroup) + project = create(:project, :repository, path: "the-path0", namespace: subgroup) subject.rename_path_for_routable(migration_namespace(namespace)) @@ -131,7 +131,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca context 'for projects' do let(:parent) { create(:namespace, path: 'the-parent') } - let(:project) { create(:empty_project, path: 'the-path', namespace: parent) } + let(:project) { create(:project, path: 'the-path', namespace: parent) } it 'renames the project called `the-path`' do subject.rename_path_for_routable(migration_project(project)) @@ -165,7 +165,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase, :trunca it 'renames all the routes for the namespace' do child = create(:group, path: 'child', parent: namespace) - project = create(:project, namespace: child, path: 'the-project') + project = create(:project, :repository, namespace: child, path: 'the-project') other_one = create(:namespace, path: 'the-path-is-similar') subject.perform_rename(migration_namespace(namespace), 'the-path', 'renamed') diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb index 803e923b4a5..32ac0b88a9b 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb @@ -94,7 +94,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : describe '#move_repositories' do let(:namespace) { create(:group, name: 'hello-group') } it 'moves a project for a namespace' do - create(:project, namespace: namespace, path: 'hello-project') + create(:project, :repository, namespace: namespace, path: 'hello-project') expected_path = File.join(TestEnv.repos_path, 'bye-group', 'hello-project.git') subject.move_repositories(namespace, 'hello-group', 'bye-group') @@ -104,7 +104,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : it 'moves a namespace in a subdirectory correctly' do child_namespace = create(:group, name: 'sub-group', parent: namespace) - create(:project, namespace: child_namespace, path: 'hello-project') + create(:project, :repository, namespace: child_namespace, path: 'hello-project') expected_path = File.join(TestEnv.repos_path, 'hello-group', 'renamed-sub-group', 'hello-project.git') @@ -115,7 +115,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : it 'moves a parent namespace with subdirectories' do child_namespace = create(:group, name: 'sub-group', parent: namespace) - create(:project, namespace: child_namespace, path: 'hello-project') + create(:project, :repository, namespace: child_namespace, path: 'hello-project') expected_path = File.join(TestEnv.repos_path, 'renamed-group', 'sub-group', 'hello-project.git') subject.move_repositories(child_namespace, 'hello-group', 'renamed-group') @@ -166,7 +166,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : describe '#rename_namespace_dependencies' do it "moves the the repository for a project in the namespace" do - create(:project, namespace: namespace, path: "the-path-project") + create(:project, :repository, namespace: namespace, path: "the-path-project") expected_repo = File.join(TestEnv.repos_path, "the-path0", "the-path-project.git") subject.rename_namespace_dependencies(namespace, 'the-path', 'the-path0') @@ -187,7 +187,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : end it 'invalidates the markdown cache of related projects' do - project = create(:empty_project, namespace: namespace, path: "the-path-project") + project = create(:project, namespace: namespace, path: "the-path-project") expect(subject).to receive(:remove_cached_html_for_projects).with([project.id]) @@ -243,7 +243,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : describe '#revert_renames', redis: true do it 'renames the routes back to the previous values' do - project = create(:project, path: 'a-project', namespace: namespace) + project = create(:project, :repository, path: 'a-project', namespace: namespace) subject.rename_namespace(namespace) expect(subject).to receive(:perform_rename) @@ -261,7 +261,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces, : end it 'moves the repositories back to their original place' do - project = create(:project, path: 'a-project', namespace: namespace) + project = create(:project, :repository, path: 'a-project', namespace: namespace) project.create_repository subject.rename_namespace(namespace) diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb index 0e240a5ccf1..595e06a9748 100644 --- a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb +++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr let(:migration) { FakeRenameReservedPathMigrationV1.new } let(:subject) { described_class.new(['the-path'], migration) } let(:project) do - create(:empty_project, + create(:project, path: 'the-path', namespace: create(:namespace, path: 'known-parent' )) end @@ -17,7 +17,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr describe '#projects_for_paths' do it 'searches using nested paths' do namespace = create(:namespace, path: 'hello') - project = create(:empty_project, path: 'THE-path', namespace: namespace) + project = create(:project, path: 'THE-path', namespace: namespace) result_ids = described_class.new(['Hello/the-path'], migration) .projects_for_paths.map(&:id) @@ -26,8 +26,8 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr end it 'includes the correct projects' do - project = create(:empty_project, path: 'THE-path') - _other_project = create(:empty_project) + project = create(:project, path: 'THE-path') + _other_project = create(:project) result_ids = subject.projects_for_paths.map(&:id) @@ -36,7 +36,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr end describe '#rename_projects' do - let!(:projects) { create_list(:empty_project, 2, path: 'the-path') } + let!(:projects) { create_list(:project, 2, path: 'the-path') } it 'renames each project' do expect(subject).to receive(:rename_project).twice @@ -104,7 +104,7 @@ describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects, :tr describe '#move_repository' do let(:known_parent) { create(:namespace, path: 'known-parent') } - let(:project) { create(:project, path: 'the-path', namespace: known_parent) } + let(:project) { create(:project, :repository, path: 'the-path', namespace: known_parent) } it 'moves the repository for a project' do expected_path = File.join(TestEnv.repos_path, 'known-parent', 'new-repo.git') diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index c5f9aecd867..5fa94999d25 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -51,6 +51,28 @@ describe Gitlab::Database do end end + describe '.join_lateral_supported?' do + it 'returns false when using MySQL' do + allow(described_class).to receive(:postgresql?).and_return(false) + + expect(described_class.join_lateral_supported?).to eq(false) + end + + it 'returns false when using PostgreSQL 9.2' do + allow(described_class).to receive(:postgresql?).and_return(true) + allow(described_class).to receive(:version).and_return('9.2.1') + + expect(described_class.join_lateral_supported?).to eq(false) + end + + it 'returns true when using PostgreSQL 9.3.0 or newer' do + allow(described_class).to receive(:postgresql?).and_return(true) + allow(described_class).to receive(:version).and_return('9.3.0') + + expect(described_class.join_lateral_supported?).to eq(true) + end + end + describe '.nulls_last_order' do context 'when using PostgreSQL' do before do diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index cd2fa98b14c..d3d841b0668 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -47,14 +47,6 @@ describe Gitlab::Diff::File do end end - describe '#old_content_commit' do - it 'returns base commit' do - old_content_commit = diff_file.old_content_commit - - expect(old_content_commit.id).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') - end - end - describe '#old_blob' do it 'returns blob of commit of base commit' do old_data = diff_file.old_blob.data diff --git a/spec/lib/gitlab/diff/parser_spec.rb b/spec/lib/gitlab/diff/parser_spec.rb index c71568e2a65..8af49ed50ff 100644 --- a/spec/lib/gitlab/diff/parser_spec.rb +++ b/spec/lib/gitlab/diff/parser_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::Diff::Parser do include RepoHelpers - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:commit) { project.commit(sample_commit.id) } let(:diff) { commit.raw_diffs.first } let(:parser) { described_class.new } diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb index 0127b012c91..d0fa16ce4d1 100644 --- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb @@ -36,15 +36,6 @@ describe Gitlab::Email::Handler::CreateNoteHandler do end end - context "when the email was auto generated" do - let!(:mail_key) { '636ca428858779856c226bb145ef4fad' } - let!(:email_raw) { fixture_file("emails/auto_reply.eml") } - - it "raises an AutoGeneratedEmailError" do - expect { receiver.execute }.to raise_error(Gitlab::Email::AutoGeneratedEmailError) - end - end - context "when the noteable could not be found" do before do noteable.destroy diff --git a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb index 66c38498e4e..21796694f26 100644 --- a/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/unsubscribe_handler_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::Email::Handler::UnsubscribeHandler do end let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "#{mail_key}+unsubscribe") } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:noteable) { create(:issue, project: project) } diff --git a/spec/lib/gitlab/email/message/repository_push_spec.rb b/spec/lib/gitlab/email/message/repository_push_spec.rb index 7b3291b8315..83c4d177cae 100644 --- a/spec/lib/gitlab/email/message/repository_push_spec.rb +++ b/spec/lib/gitlab/email/message/repository_push_spec.rb @@ -117,7 +117,7 @@ describe Gitlab::Email::Message::RepositoryPush do describe '#subject' do subject { message.subject } - it { is_expected.to include "[Git][#{project.path_with_namespace}]" } + it { is_expected.to include "[Git][#{project.full_path}]" } it { is_expected.to include "#{compare.commits.length} commits" } it { is_expected.to include compare.commits.first.message.split("\n").first } end diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb index 88565ea5311..59f43abf26d 100644 --- a/spec/lib/gitlab/email/receiver_spec.rb +++ b/spec/lib/gitlab/email/receiver_spec.rb @@ -28,14 +28,6 @@ describe Gitlab::Email::Receiver do it "raises an UnknownIncomingEmail error" do expect { receiver.execute }.to raise_error(Gitlab::Email::UnknownIncomingEmail) end - - context "and the email contains no references header" do - let(:email_raw) { fixture_file("emails/auto_reply.eml").gsub(mail_key, "!!!") } - - it "raises an UnknownIncomingEmail error" do - expect { receiver.execute }.to raise_error(Gitlab::Email::UnknownIncomingEmail) - end - end end context "when the email is blank" do @@ -45,4 +37,12 @@ describe Gitlab::Email::Receiver do expect { receiver.execute }.to raise_error(Gitlab::Email::EmptyEmailError) end end + + context "when the email was auto generated" do + let(:email_raw) { fixture_file("emails/auto_reply.eml") } + + it "raises an AutoGeneratedEmailError" do + expect { receiver.execute }.to raise_error(Gitlab::Email::AutoGeneratedEmailError) + end + end end diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb index 1482ef7132d..8b14b227e65 100644 --- a/spec/lib/gitlab/encoding_helper_spec.rb +++ b/spec/lib/gitlab/encoding_helper_spec.rb @@ -30,6 +30,53 @@ describe Gitlab::EncodingHelper do it 'leaves binary string as is' do expect(ext_class.encode!(binary_string)).to eq(binary_string) end + + context 'with corrupted diff' do + let(:corrupted_diff) do + with_empty_bare_repository do |repo| + content = File.read(Rails.root.join( + 'spec/fixtures/encoding/Japanese.md').to_s) + commit_a = commit(repo, 'Japanese.md', content) + commit_b = commit(repo, 'Japanese.md', + content.sub('[TODO: Link]', '[ç¾åœ¨ä½œæ¥ä¸ã§ã™: Link]')) + + repo.diff(commit_a, commit_b).each_line.map(&:content).join + end + end + + let(:cleaned_diff) do + corrupted_diff.dup.force_encoding('UTF-8') + .encode!('UTF-8', invalid: :replace, replace: '') + end + + let(:encoded_diff) do + described_class.encode!(corrupted_diff.dup) + end + + it 'does not corrupt data but remove invalid characters' do + expect(encoded_diff).to eq(cleaned_diff) + end + + def commit(repo, path, content) + oid = repo.write(content, :blob) + index = repo.index + + index.read_tree(repo.head.target.tree) unless repo.empty? + + index.add(path: path, oid: oid, mode: 0100644) + user = { name: 'Test', email: 'test@example.com' } + + Rugged::Commit.create( + repo, + tree: index.write_tree(repo), + author: user, + committer: user, + message: "Update #{path}", + parents: repo.empty? ? [] : [repo.head.target].compact, + update_ref: 'HEAD' + ) + end + end end describe '#encode_utf8' do diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index eaec699ad90..a3d323fe28a 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Gitlab::Gfm::ReferenceRewriter do let(:text) { 'some text' } - let(:old_project) { create(:empty_project, name: 'old-project') } - let(:new_project) { create(:empty_project, name: 'new-project') } + let(:old_project) { create(:project, name: 'old-project') } + let(:new_project) { create(:project, name: 'new-project') } let(:user) { create(:user) } before do diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb index c3016f63ebf..39e3b875c49 100644 --- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Gitlab::Gfm::UploadsRewriter do let(:user) { create(:user) } - let(:old_project) { create(:empty_project) } - let(:new_project) { create(:empty_project) } + let(:old_project) { create(:project) } + let(:new_project) { create(:project) } let(:rewriter) { described_class.new(text, old_project, user) } context 'text contains links to uploads' do @@ -39,8 +39,8 @@ describe Gitlab::Gfm::UploadsRewriter do it 'copies files' do expect(new_files).to all(exist) expect(old_paths).not_to match_array new_paths - expect(old_paths).to all(include(old_project.path_with_namespace)) - expect(new_paths).to all(include(new_project.path_with_namespace)) + expect(old_paths).to all(include(old_project.full_path)) + expect(new_paths).to all(include(new_project.full_path)) end it 'does not remove old files' do diff --git a/spec/lib/gitlab/git/blame_spec.rb b/spec/lib/gitlab/git/blame_spec.rb index 66c016d14b3..800c245b130 100644 --- a/spec/lib/gitlab/git/blame_spec.rb +++ b/spec/lib/gitlab/git/blame_spec.rb @@ -7,63 +7,73 @@ describe Gitlab::Git::Blame, seed_helper: true do Gitlab::Git::Blame.new(repository, SeedRepo::Commit::ID, "CONTRIBUTING.md") end - context "each count" do - it do - data = [] - blame.each do |commit, line| - data << { - commit: commit, - line: line - } - end - - expect(data.size).to eq(95) - expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit) - expect(data.first[:line]).to eq("# Contribute to GitLab") - expect(data.first[:line]).to be_utf8 - end - end + shared_examples 'blaming a file' do + context "each count" do + it do + data = [] + blame.each do |commit, line| + data << { + commit: commit, + line: line + } + end - context "ISO-8859 encoding" do - let(:blame) do - Gitlab::Git::Blame.new(repository, SeedRepo::EncodingCommit::ID, "encoding/iso8859.txt") + expect(data.size).to eq(95) + expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit) + expect(data.first[:line]).to eq("# Contribute to GitLab") + expect(data.first[:line]).to be_utf8 + end end - it 'converts to UTF-8' do - data = [] - blame.each do |commit, line| - data << { - commit: commit, - line: line - } + context "ISO-8859 encoding" do + let(:blame) do + Gitlab::Git::Blame.new(repository, SeedRepo::EncodingCommit::ID, "encoding/iso8859.txt") end - expect(data.size).to eq(1) - expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit) - expect(data.first[:line]).to eq("Ä ü") - expect(data.first[:line]).to be_utf8 - end - end + it 'converts to UTF-8' do + data = [] + blame.each do |commit, line| + data << { + commit: commit, + line: line + } + end - context "unknown encoding" do - let(:blame) do - Gitlab::Git::Blame.new(repository, SeedRepo::EncodingCommit::ID, "encoding/iso8859.txt") + expect(data.size).to eq(1) + expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit) + expect(data.first[:line]).to eq("Ä ü") + expect(data.first[:line]).to be_utf8 + end end - it 'converts to UTF-8' do - expect(CharlockHolmes::EncodingDetector).to receive(:detect).and_return(nil) - data = [] - blame.each do |commit, line| - data << { + context "unknown encoding" do + let(:blame) do + Gitlab::Git::Blame.new(repository, SeedRepo::EncodingCommit::ID, "encoding/iso8859.txt") + end + + it 'converts to UTF-8' do + expect(CharlockHolmes::EncodingDetector).to receive(:detect).and_return(nil) + data = [] + blame.each do |commit, line| + data << { commit: commit, line: line - } - end + } + end - expect(data.size).to eq(1) - expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit) - expect(data.first[:line]).to eq(" ") - expect(data.first[:line]).to be_utf8 + expect(data.size).to eq(1) + expect(data.first[:commit]).to be_kind_of(Gitlab::Git::Commit) + expect(data.first[:line]).to eq(" ") + expect(data.first[:line]).to be_utf8 + end end end + + context 'when Gitaly blame feature is enabled' do + it_behaves_like 'blaming a file' + end + + context 'when Gitaly blame feature is disabled', skip_gitaly_mock: true do + it_behaves_like 'blaming a file' + end end diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 3c784eda4f8..dfab0c2fe85 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -78,12 +78,18 @@ describe Gitlab::Git::Blob, seed_helper: true do context 'large file' do let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, 'files/images/6049019_460s.jpg') } let(:blob_size) { 111803 } + let(:stub_limit) { 1000 } + + before do + stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', stub_limit) + end it { expect(blob.size).to eq(blob_size) } - it { expect(blob.data.length).to eq(blob_size) } + it { expect(blob.data.length).to eq(stub_limit) } it 'check that this test is sane' do - expect(blob.size).to be <= Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE + # It only makes sense to test limiting if the blob is larger than the limit. + expect(blob.size).to be > Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE end it 'can load all data' do @@ -146,6 +152,77 @@ describe Gitlab::Git::Blob, seed_helper: true do end end + describe '.batch' do + let(:blob_references) do + [ + [SeedRepo::Commit::ID, "files/ruby/popen.rb"], + [SeedRepo::Commit::ID, 'six'] + ] + end + + subject { described_class.batch(repository, blob_references) } + + it { expect(subject.size).to eq(blob_references.size) } + + context 'first blob' do + let(:blob) { subject[0] } + + it { expect(blob.id).to eq(SeedRepo::RubyBlob::ID) } + it { expect(blob.name).to eq(SeedRepo::RubyBlob::NAME) } + it { expect(blob.path).to eq("files/ruby/popen.rb") } + it { expect(blob.commit_id).to eq(SeedRepo::Commit::ID) } + it { expect(blob.data[0..10]).to eq(SeedRepo::RubyBlob::CONTENT[0..10]) } + it { expect(blob.size).to eq(669) } + it { expect(blob.mode).to eq("100644") } + end + + context 'second blob' do + let(:blob) { subject[1] } + + it { expect(blob.id).to eq('409f37c4f05865e4fb208c771485f211a22c4c2d') } + it { expect(blob.data).to eq('') } + it 'does not mark the blob as binary' do + expect(blob).not_to be_binary + end + end + + context 'limiting' do + subject { described_class.batch(repository, blob_references, blob_size_limit: blob_size_limit) } + + context 'default' do + let(:blob_size_limit) { nil } + + it 'limits to MAX_DATA_DISPLAY_SIZE' do + stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', 100) + + expect(subject.first.data.size).to eq(100) + end + end + + context 'positive' do + let(:blob_size_limit) { 10 } + + it { expect(subject.first.data.size).to eq(10) } + end + + context 'zero' do + let(:blob_size_limit) { 0 } + + it { expect(subject.first.data).to eq('') } + end + + context 'negative' do + let(:blob_size_limit) { -1 } + + it 'ignores MAX_DATA_DISPLAY_SIZE' do + stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', 100) + + expect(subject.first.data.size).to eq(669) + end + end + end + end + describe 'encoding' do context 'file with russian text' do let(:blob) { Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "encoding/russian.rb") } diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 730fdb112d9..ac33cd8a2c9 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" describe Gitlab::Git::Commit, seed_helper: true do let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH) } - let(:commit) { Gitlab::Git::Commit.find(repository, SeedRepo::Commit::ID) } + let(:commit) { described_class.find(repository, SeedRepo::Commit::ID) } let(:rugged_commit) do repository.rugged.lookup(SeedRepo::Commit::ID) end @@ -24,7 +24,7 @@ describe Gitlab::Git::Commit, seed_helper: true do } @parents = [repo.head.target] - @gitlab_parents = @parents.map { |c| Gitlab::Git::Commit.decorate(c) } + @gitlab_parents = @parents.map { |c| described_class.decorate(repository, c) } @tree = @parents.first.tree sha = Rugged::Commit.create( @@ -38,7 +38,7 @@ describe Gitlab::Git::Commit, seed_helper: true do ) @raw_commit = repo.lookup(sha) - @commit = Gitlab::Git::Commit.new(@raw_commit) + @commit = described_class.new(repository, @raw_commit) end it { expect(@commit.short_id).to eq(@raw_commit.oid[0..10]) } @@ -66,6 +66,7 @@ describe Gitlab::Git::Commit, seed_helper: true do describe "Commit info from gitaly commit" do let(:id) { 'f00' } + let(:parent_ids) { %w(b45 b46) } let(:subject) { "My commit".force_encoding('ASCII-8BIT') } let(:body) { subject + "My body".force_encoding('ASCII-8BIT') } let(:committer) do @@ -88,10 +89,11 @@ describe Gitlab::Git::Commit, seed_helper: true do subject: subject, body: body, author: author, - committer: committer + committer: committer, + parent_ids: parent_ids ) end - let(:commit) { described_class.new(Gitlab::GitalyClient::Commit.new(repository, gitaly_commit)) } + let(:commit) { described_class.new(repository, gitaly_commit) } it { expect(commit.short_id).to eq(id[0..10]) } it { expect(commit.id).to eq(id) } @@ -102,6 +104,7 @@ describe Gitlab::Git::Commit, seed_helper: true do it { expect(commit.author_name).to eq(author.name) } it { expect(commit.committer_name).to eq(committer.name) } it { expect(commit.committer_email).to eq(committer.email) } + it { expect(commit.parent_ids).to eq(parent_ids) } context 'no body' do let(:body) { "".force_encoding('ASCII-8BIT') } @@ -113,45 +116,45 @@ describe Gitlab::Git::Commit, seed_helper: true do context 'Class methods' do describe '.find' do it "should return first head commit if without params" do - expect(Gitlab::Git::Commit.last(repository).id).to eq( - repository.raw.head.target.oid + expect(described_class.last(repository).id).to eq( + repository.rugged.head.target.oid ) end it "should return valid commit" do - expect(Gitlab::Git::Commit.find(repository, SeedRepo::Commit::ID)).to be_valid_commit + expect(described_class.find(repository, SeedRepo::Commit::ID)).to be_valid_commit end it "should return valid commit for tag" do - expect(Gitlab::Git::Commit.find(repository, 'v1.0.0').id).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') + expect(described_class.find(repository, 'v1.0.0').id).to eq('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') end it "should return nil for non-commit ids" do blob = Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "files/ruby/popen.rb") - expect(Gitlab::Git::Commit.find(repository, blob.id)).to be_nil + expect(described_class.find(repository, blob.id)).to be_nil end it "should return nil for parent of non-commit object" do blob = Gitlab::Git::Blob.find(repository, SeedRepo::Commit::ID, "files/ruby/popen.rb") - expect(Gitlab::Git::Commit.find(repository, "#{blob.id}^")).to be_nil + expect(described_class.find(repository, "#{blob.id}^")).to be_nil end it "should return nil for nonexisting ids" do - expect(Gitlab::Git::Commit.find(repository, "+123_4532530XYZ")).to be_nil + expect(described_class.find(repository, "+123_4532530XYZ")).to be_nil end context 'with broken repo' do let(:repository) { Gitlab::Git::Repository.new('default', TEST_BROKEN_REPO_PATH) } it 'returns nil' do - expect(Gitlab::Git::Commit.find(repository, SeedRepo::Commit::ID)).to be_nil + expect(described_class.find(repository, SeedRepo::Commit::ID)).to be_nil end end end describe '.last_for_path' do context 'no path' do - subject { Gitlab::Git::Commit.last_for_path(repository, 'master') } + subject { described_class.last_for_path(repository, 'master') } describe '#id' do subject { super().id } @@ -160,7 +163,7 @@ describe Gitlab::Git::Commit, seed_helper: true do end context 'path' do - subject { Gitlab::Git::Commit.last_for_path(repository, 'master', 'files/ruby') } + subject { described_class.last_for_path(repository, 'master', 'files/ruby') } describe '#id' do subject { super().id } @@ -169,7 +172,7 @@ describe Gitlab::Git::Commit, seed_helper: true do end context 'ref + path' do - subject { Gitlab::Git::Commit.last_for_path(repository, SeedRepo::Commit::ID, 'encoding') } + subject { described_class.last_for_path(repository, SeedRepo::Commit::ID, 'encoding') } describe '#id' do subject { super().id } @@ -181,7 +184,7 @@ describe Gitlab::Git::Commit, seed_helper: true do describe '.where' do context 'path is empty string' do subject do - commits = Gitlab::Git::Commit.where( + commits = described_class.where( repo: repository, ref: 'master', path: '', @@ -199,7 +202,7 @@ describe Gitlab::Git::Commit, seed_helper: true do context 'path is nil' do subject do - commits = Gitlab::Git::Commit.where( + commits = described_class.where( repo: repository, ref: 'master', path: nil, @@ -217,7 +220,7 @@ describe Gitlab::Git::Commit, seed_helper: true do context 'ref is branch name' do subject do - commits = Gitlab::Git::Commit.where( + commits = described_class.where( repo: repository, ref: 'master', path: 'files', @@ -237,7 +240,7 @@ describe Gitlab::Git::Commit, seed_helper: true do context 'ref is commit id' do subject do - commits = Gitlab::Git::Commit.where( + commits = described_class.where( repo: repository, ref: "874797c3a73b60d2187ed6e2fcabd289ff75171e", path: 'files', @@ -257,7 +260,7 @@ describe Gitlab::Git::Commit, seed_helper: true do context 'ref is tag' do subject do - commits = Gitlab::Git::Commit.where( + commits = described_class.where( repo: repository, ref: 'v1.0.0', path: 'files', @@ -278,7 +281,7 @@ describe Gitlab::Git::Commit, seed_helper: true do describe '.between' do subject do - commits = Gitlab::Git::Commit.between(repository, SeedRepo::Commit::PARENT_ID, SeedRepo::Commit::ID) + commits = described_class.between(repository, SeedRepo::Commit::PARENT_ID, SeedRepo::Commit::ID) commits.map { |c| c.id } end @@ -294,12 +297,12 @@ describe Gitlab::Git::Commit, seed_helper: true do it 'should return a return a collection of commits' do commits = described_class.find_all(repository) - expect(commits).to all( be_a_kind_of(Gitlab::Git::Commit) ) + expect(commits).to all( be_a_kind_of(described_class) ) end context 'max_count' do subject do - commits = Gitlab::Git::Commit.find_all( + commits = described_class.find_all( repository, max_count: 50 ) @@ -307,8 +310,8 @@ describe Gitlab::Git::Commit, seed_helper: true do commits.map(&:id) end - it 'has 33 elements' do - expect(subject.size).to eq(33) + it 'has 34 elements' do + expect(subject.size).to eq(34) end it 'includes the expected commits' do @@ -322,7 +325,7 @@ describe Gitlab::Git::Commit, seed_helper: true do context 'ref + max_count + skip' do subject do - commits = Gitlab::Git::Commit.find_all( + commits = described_class.find_all( repository, ref: 'master', max_count: 50, @@ -374,7 +377,7 @@ describe Gitlab::Git::Commit, seed_helper: true do end describe '#init_from_rugged' do - let(:gitlab_commit) { Gitlab::Git::Commit.new(rugged_commit) } + let(:gitlab_commit) { described_class.new(repository, rugged_commit) } subject { gitlab_commit } describe '#id' do @@ -384,7 +387,7 @@ describe Gitlab::Git::Commit, seed_helper: true do end describe '#init_from_hash' do - let(:commit) { Gitlab::Git::Commit.new(sample_commit_hash) } + let(:commit) { described_class.new(repository, sample_commit_hash) } subject { commit } describe '#id' do @@ -451,7 +454,7 @@ describe Gitlab::Git::Commit, seed_helper: true do end describe '#ref_names' do - let(:commit) { Gitlab::Git::Commit.find(repository, 'master') } + let(:commit) { described_class.find(repository, 'master') } subject { commit.ref_names(repository) } it 'has 1 element' do diff --git a/spec/lib/gitlab/git/diff_collection_spec.rb b/spec/lib/gitlab/git/diff_collection_spec.rb index 0cfb210e390..3494f0cc98d 100644 --- a/spec/lib/gitlab/git/diff_collection_spec.rb +++ b/spec/lib/gitlab/git/diff_collection_spec.rb @@ -384,7 +384,7 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do context 'when go over safe limits on files' do let(:iterator) { [fake_diff(1, 1)] * 4 } - before(:each) do + before do stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: 2, max_lines: max_lines }) end @@ -409,7 +409,7 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do ] end - before(:each) do + before do stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: max_files, max_lines: 80 }) end @@ -434,7 +434,7 @@ describe Gitlab::Git::DiffCollection, seed_helper: true do ] end - before(:each) do + before do stub_const('Gitlab::Git::DiffCollection::DEFAULT_LIMITS', { max_files: max_files, max_lines: 80 }) end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 50736d353ad..4ef5d9070a2 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -22,7 +22,6 @@ describe Gitlab::Git::Repository, seed_helper: true do describe "Respond to" do subject { repository } - it { is_expected.to respond_to(:raw) } it { is_expected.to respond_to(:rugged) } it { is_expected.to respond_to(:root_ref) } it { is_expected.to respond_to(:tags) } @@ -55,6 +54,20 @@ describe Gitlab::Git::Repository, seed_helper: true do end describe "#rugged" do + describe 'when storage is broken', broken_storage: true do + it 'raises a storage exception when storage is not available' do + broken_repo = described_class.new('broken', 'a/path.git') + + expect { broken_repo.rugged }.to raise_error(Gitlab::Git::Storage::Inaccessible) + end + end + + it 'raises a no repository exception when there is no repo' do + broken_repo = described_class.new('default', 'a/path.git') + + expect { broken_repo.rugged }.to raise_error(Gitlab::Git::Repository::NoRepository) + end + context 'with no Git env stored' do before do expect(Gitlab::Git::Env).to receive(:all).and_return({}) @@ -276,7 +289,13 @@ describe Gitlab::Git::Repository, seed_helper: true do it { expect(submodule_url('six')).to eq('git://github.com/randx/six.git') } end - context 'no submodules at commit' do + context 'no .gitmodules at commit' do + let(:ref) { '9596bc54a6f0c0c98248fe97077eb5ccf48a98d0' } + + it { expect(submodule_url('six')).to eq(nil) } + end + + context 'no gitlink entry' do let(:ref) { '6d39438' } it { expect(submodule_url('six')).to eq(nil) } @@ -361,20 +380,20 @@ describe Gitlab::Git::Repository, seed_helper: true do end describe '#commit_count' do - shared_examples 'counting commits' do + shared_examples 'simple commit counting' do it { expect(repository.commit_count("master")).to eq(25) } it { expect(repository.commit_count("feature")).to eq(9) } end context 'when Gitaly commit_count feature is enabled' do - it_behaves_like 'counting commits' + it_behaves_like 'simple commit counting' it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::CommitService, :commit_count do subject { repository.commit_count('master') } end end context 'when Gitaly commit_count feature is disabled', skip_gitaly_mock: true do - it_behaves_like 'counting commits' + it_behaves_like 'simple commit counting' end end @@ -409,11 +428,11 @@ describe Gitlab::Git::Repository, seed_helper: true do it "should fail if we create an existing branch" do @repo.create_branch('duplicated_branch', 'master') - expect{@repo.create_branch('duplicated_branch', 'master')}.to raise_error("Branch duplicated_branch already exists") + expect {@repo.create_branch('duplicated_branch', 'master')}.to raise_error("Branch duplicated_branch already exists") end it "should fail if we create a branch from a non existing ref" do - expect{@repo.create_branch('branch_based_in_wrong_ref', 'master_2_the_revenge')}.to raise_error("Invalid reference master_2_the_revenge") + expect {@repo.create_branch('branch_based_in_wrong_ref', 'master_2_the_revenge')}.to raise_error("Invalid reference master_2_the_revenge") end after(:all) do @@ -492,17 +511,22 @@ describe Gitlab::Git::Repository, seed_helper: true do end describe "#log" do - commit_with_old_name = nil - commit_with_new_name = nil - rename_commit = nil + let(:commit_with_old_name) do + Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id) + end + let(:commit_with_new_name) do + Gitlab::Git::Commit.decorate(repository, @commit_with_new_name_id) + end + let(:rename_commit) do + Gitlab::Git::Commit.decorate(repository, @rename_commit_id) + end before(:context) do # Add new commits so that there's a renamed file in the commit history repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH).rugged - - commit_with_old_name = Gitlab::Git::Commit.decorate(new_commit_edit_old_file(repo)) - rename_commit = Gitlab::Git::Commit.decorate(new_commit_move_file(repo)) - commit_with_new_name = Gitlab::Git::Commit.decorate(new_commit_edit_new_file(repo)) + @commit_with_old_name_id = new_commit_edit_old_file(repo) + @rename_commit_id = new_commit_move_file(repo) + @commit_with_new_name_id = new_commit_edit_new_file(repo) end after(:context) do @@ -741,7 +765,7 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } } def commit_files(commit) - commit.diff_from_parent.deltas.flat_map do |delta| + commit.rugged_diff_from_parent.deltas.flat_map do |delta| [delta.old_file[:path], delta.new_file[:path]].uniq.compact end end @@ -757,13 +781,13 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe "#commits_between" do + describe "#rugged_commits_between" do context 'two SHAs' do let(:first_sha) { 'b0e52af38d7ea43cf41d8a6f2471351ac036d6c9' } let(:second_sha) { '0e50ec4d3c7ce42ab74dda1d422cb2cbffe1e326' } it 'returns the number of commits between' do - expect(repository.commits_between(first_sha, second_sha).count).to eq(3) + expect(repository.rugged_commits_between(first_sha, second_sha).count).to eq(3) end end @@ -772,11 +796,11 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:branch) { 'master' } it 'returns the number of commits between a sha and a branch' do - expect(repository.commits_between(sha, branch).count).to eq(5) + expect(repository.rugged_commits_between(sha, branch).count).to eq(5) end it 'returns the number of commits between a branch and a sha' do - expect(repository.commits_between(branch, sha).count).to eq(0) # sha is before branch + expect(repository.rugged_commits_between(branch, sha).count).to eq(0) # sha is before branch end end @@ -785,7 +809,7 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:second_branch) { 'master' } it 'returns the number of commits between' do - expect(repository.commits_between(first_branch, second_branch).count).to eq(17) + expect(repository.rugged_commits_between(first_branch, second_branch).count).to eq(17) end end end @@ -797,28 +821,38 @@ describe Gitlab::Git::Repository, seed_helper: true do end describe '#count_commits' do - context 'with after timestamp' do - it 'returns the number of commits after timestamp' do - options = { ref: 'master', limit: nil, after: Time.iso8601('2013-03-03T20:15:01+00:00') } + shared_examples 'extended commit counting' do + context 'with after timestamp' do + it 'returns the number of commits after timestamp' do + options = { ref: 'master', limit: nil, after: Time.iso8601('2013-03-03T20:15:01+00:00') } - expect(repository.count_commits(options)).to eq(25) + expect(repository.count_commits(options)).to eq(25) + end end - end - context 'with before timestamp' do - it 'returns the number of commits after timestamp' do - options = { ref: 'feature', limit: nil, before: Time.iso8601('2015-03-03T20:15:01+00:00') } + context 'with before timestamp' do + it 'returns the number of commits before timestamp' do + options = { ref: 'feature', limit: nil, before: Time.iso8601('2015-03-03T20:15:01+00:00') } + + expect(repository.count_commits(options)).to eq(9) + end + end + + context 'with path' do + it 'returns the number of commits with path ' do + options = { ref: 'master', limit: nil, path: "encoding" } - expect(repository.count_commits(options)).to eq(9) + expect(repository.count_commits(options)).to eq(2) + end end end - context 'with path' do - it 'returns the number of commits with path ' do - options = { ref: 'master', limit: nil, path: "encoding" } + context 'when Gitaly count_commits feature is enabled' do + it_behaves_like 'extended commit counting' + end - expect(repository.count_commits(options)).to eq(2) - end + context 'when Gitaly count_commits feature is disabled', skip_gitaly_mock: true do + it_behaves_like 'extended commit counting' end end @@ -958,7 +992,7 @@ describe Gitlab::Git::Repository, seed_helper: true do describe '#branch_count' do it 'returns the number of branches' do - expect(repository.branch_count).to eq(9) + expect(repository.branch_count).to eq(10) end end @@ -974,7 +1008,7 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(master_file_paths).to include("files/html/500.html") end - it "dose not read submodule directory and empty directory of master branch" do + it "does not read submodule directory and empty directory of master branch" do expect(master_file_paths).not_to include("six") end @@ -995,7 +1029,7 @@ describe Gitlab::Git::Repository, seed_helper: true do end context "with no .gitattrbutes" do - before(:each) do + before do repository.copy_gitattributes("master") end @@ -1003,13 +1037,13 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(File.exist?(attributes_path)).to be_falsey end - after(:each) do + after do FileUtils.rm_rf(attributes_path) end end context "with .gitattrbutes" do - before(:each) do + before do repository.copy_gitattributes("gitattributes") end @@ -1022,13 +1056,13 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(contents).to eq("*.md binary\n") end - after(:each) do + after do FileUtils.rm_rf(attributes_path) end end context "with updated .gitattrbutes" do - before(:each) do + before do repository.copy_gitattributes("gitattributes") repository.copy_gitattributes("gitattributes-updated") end @@ -1042,13 +1076,13 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(contents).to eq("*.txt binary\n") end - after(:each) do + after do FileUtils.rm_rf(attributes_path) end end context "with no .gitattrbutes in HEAD but with previous info/attributes" do - before(:each) do + before do repository.copy_gitattributes("gitattributes") repository.copy_gitattributes("master") end @@ -1057,7 +1091,7 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(File.exist?(attributes_path)).to be_falsey end - after(:each) do + after do FileUtils.rm_rf(attributes_path) end end @@ -1127,6 +1161,45 @@ describe Gitlab::Git::Repository, seed_helper: true do end end + describe '#languages' do + shared_examples 'languages' do + it 'returns exactly the expected results' do + languages = repository.languages('4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6') + expected_languages = [ + { value: 66.63, label: "Ruby", color: "#701516", highlight: "#701516" }, + { value: 22.96, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" }, + { value: 7.9, label: "HTML", color: "#e44b23", highlight: "#e44b23" }, + { value: 2.51, label: "CoffeeScript", color: "#244776", highlight: "#244776" } + ] + + expect(languages.size).to eq(expected_languages.size) + + expected_languages.size.times do |i| + a = expected_languages[i] + b = languages[i] + + expect(a.keys.sort).to eq(b.keys.sort) + expect(a[:value]).to be_within(0.1).of(b[:value]) + + non_float_keys = a.keys - [:value] + expect(a.values_at(*non_float_keys)).to eq(b.values_at(*non_float_keys)) + end + end + + it "uses the repository's HEAD when no ref is passed" do + lang = repository.languages.first + + expect(lang[:label]).to eq('Ruby') + end + end + + it_behaves_like 'languages' + + context 'with rugged', skip_gitaly_mock: true do + it_behaves_like 'languages' + end + end + def create_remote_branch(repository, remote_name, branch_name, source_branch_name) source_branch = repository.branches.find { |branch| branch.name == source_branch_name } rugged = repository.rugged diff --git a/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb b/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb new file mode 100644 index 00000000000..9d1763b96ad --- /dev/null +++ b/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb @@ -0,0 +1,290 @@ +require 'spec_helper' + +describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state: true, broken_storage: true do + let(:circuit_breaker) { described_class.new('default') } + let(:hostname) { Gitlab::Environment.hostname } + let(:cache_key) { "storage_accessible:default:#{hostname}" } + + def value_from_redis(name) + Gitlab::Git::Storage.redis.with do |redis| + redis.hmget(cache_key, name) + end.first + end + + def set_in_redis(name, value) + Gitlab::Git::Storage.redis.with do |redis| + redis.hmset(cache_key, name, value) + end.first + end + + describe '.reset_all!' do + it 'clears all entries form redis' do + set_in_redis(:failure_count, 10) + + described_class.reset_all! + + key_exists = Gitlab::Git::Storage.redis.with { |redis| redis.exists(cache_key) } + + expect(key_exists).to be_falsey + end + end + + describe '.for_storage' do + it 'only builds a single circuitbreaker per storage' do + expect(described_class).to receive(:new).once.and_call_original + + breaker = described_class.for_storage('default') + + expect(breaker).to be_a(described_class) + expect(described_class.for_storage('default')).to eq(breaker) + end + end + + describe '#initialize' do + it 'assigns the settings' do + expect(circuit_breaker.hostname).to eq(hostname) + expect(circuit_breaker.storage).to eq('default') + expect(circuit_breaker.storage_path).to eq(TestEnv.repos_path) + expect(circuit_breaker.failure_count_threshold).to eq(10) + expect(circuit_breaker.failure_wait_time).to eq(30) + expect(circuit_breaker.failure_reset_time).to eq(1800) + expect(circuit_breaker.storage_timeout).to eq(5) + end + end + + describe '#perform' do + it 'raises an exception with retry time when the circuit is open' do + allow(circuit_breaker).to receive(:circuit_broken?).and_return(true) + + expect { |b| circuit_breaker.perform(&b) } + .to raise_error(Gitlab::Git::Storage::CircuitOpen) + end + + it 'yields the block' do + expect { |b| circuit_breaker.perform(&b) } + .to yield_control + end + + it 'checks if the storage is available' do + expect(circuit_breaker).to receive(:check_storage_accessible!) + + circuit_breaker.perform { 'hello world' } + end + + it 'returns the value of the block' do + result = circuit_breaker.perform { 'return value' } + + expect(result).to eq('return value') + end + + it 'raises possible errors' do + expect { circuit_breaker.perform { raise Rugged::OSError.new('Broken') } } + .to raise_error(Rugged::OSError) + end + + context 'with the feature disabled' do + it 'returns the block without checking accessibility' do + stub_feature_flags(git_storage_circuit_breaker: false) + + expect(circuit_breaker).not_to receive(:circuit_broken?) + + result = circuit_breaker.perform { 'hello' } + + expect(result).to eq('hello') + end + end + end + + describe '#circuit_broken?' do + it 'is closed when there is no last failure' do + set_in_redis(:last_failure, nil) + set_in_redis(:failure_count, 0) + + expect(circuit_breaker.circuit_broken?).to be_falsey + end + + it 'is open when there was a recent failure' do + Timecop.freeze do + set_in_redis(:last_failure, 1.second.ago.to_f) + set_in_redis(:failure_count, 1) + + expect(circuit_breaker.circuit_broken?).to be_truthy + end + end + + it 'is open when there are to many failures' do + set_in_redis(:last_failure, 1.day.ago.to_f) + set_in_redis(:failure_count, 200) + + expect(circuit_breaker.circuit_broken?).to be_truthy + end + end + + describe "storage_available?" do + context 'when the storage is available' do + it 'tracks that the storage was accessible an raises the error' do + expect(circuit_breaker).to receive(:track_storage_accessible) + + circuit_breaker.storage_available? + end + + it 'only performs the check once' do + expect(Gitlab::Git::Storage::ForkedStorageCheck) + .to receive(:storage_available?).once.and_call_original + + 2.times { circuit_breaker.storage_available? } + end + end + + context 'when storage is not available' do + let(:circuit_breaker) { described_class.new('broken') } + + it 'tracks that the storage was inaccessible' do + expect(circuit_breaker).to receive(:track_storage_inaccessible) + + circuit_breaker.storage_available? + end + end + end + + describe '#check_storage_accessible!' do + it 'raises an exception with retry time when the circuit is open' do + allow(circuit_breaker).to receive(:circuit_broken?).and_return(true) + + expect { circuit_breaker.check_storage_accessible! } + .to raise_error do |exception| + expect(exception).to be_kind_of(Gitlab::Git::Storage::CircuitOpen) + expect(exception.retry_after).to eq(30) + end + end + + context 'when the storage is not available' do + let(:circuit_breaker) { described_class.new('broken') } + + it 'raises an error' do + expect(circuit_breaker).to receive(:track_storage_inaccessible) + + expect { circuit_breaker.check_storage_accessible! } + .to raise_error do |exception| + expect(exception).to be_kind_of(Gitlab::Git::Storage::Inaccessible) + expect(exception.retry_after).to eq(30) + end + end + end + end + + describe '#track_storage_inaccessible' do + around do |example| + Timecop.freeze { example.run } + end + + it 'records the failure time in redis' do + circuit_breaker.track_storage_inaccessible + + failure_time = value_from_redis(:last_failure) + + expect(Time.at(failure_time.to_i)).to be_within(1.second).of(Time.now) + end + + it 'sets the failure time on the breaker without reloading' do + circuit_breaker.track_storage_inaccessible + + expect(circuit_breaker).not_to receive(:get_failure_info) + expect(circuit_breaker.last_failure).to eq(Time.now) + end + + it 'increments the failure count in redis' do + set_in_redis(:failure_count, 10) + + circuit_breaker.track_storage_inaccessible + + expect(value_from_redis(:failure_count).to_i).to be(11) + end + + it 'increments the failure count on the breaker without reloading' do + set_in_redis(:failure_count, 10) + + circuit_breaker.track_storage_inaccessible + + expect(circuit_breaker).not_to receive(:get_failure_info) + expect(circuit_breaker.failure_count).to eq(11) + end + end + + describe '#track_storage_accessible' do + it 'sets the failure count to zero in redis' do + set_in_redis(:failure_count, 10) + + circuit_breaker.track_storage_accessible + + expect(value_from_redis(:failure_count).to_i).to be(0) + end + + it 'sets the failure count to zero on the breaker without reloading' do + set_in_redis(:failure_count, 10) + + circuit_breaker.track_storage_accessible + + expect(circuit_breaker).not_to receive(:get_failure_info) + expect(circuit_breaker.failure_count).to eq(0) + end + + it 'removes the last failure time from redis' do + set_in_redis(:last_failure, Time.now.to_i) + + circuit_breaker.track_storage_accessible + + expect(circuit_breaker).not_to receive(:get_failure_info) + expect(circuit_breaker.last_failure).to be_nil + end + + it 'removes the last failure time from the breaker without reloading' do + set_in_redis(:last_failure, Time.now.to_i) + + circuit_breaker.track_storage_accessible + + expect(value_from_redis(:last_failure)).to be_empty + end + + it 'wont connect to redis when there are no failures' do + expect(Gitlab::Git::Storage.redis).to receive(:with).once + .and_call_original + expect(circuit_breaker).to receive(:track_storage_accessible) + .and_call_original + + circuit_breaker.track_storage_accessible + end + end + + describe '#no_failures?' do + it 'is false when a failure was tracked' do + set_in_redis(:last_failure, Time.now.to_i) + set_in_redis(:failure_count, 1) + + expect(circuit_breaker.no_failures?).to be_falsey + end + end + + describe '#last_failure' do + it 'returns the last failure time' do + time = Time.parse("2017-05-26 17:52:30") + set_in_redis(:last_failure, time.to_i) + + expect(circuit_breaker.last_failure).to eq(time) + end + end + + describe '#failure_count' do + it 'returns the failure count' do + set_in_redis(:failure_count, 7) + + expect(circuit_breaker.failure_count).to eq(7) + end + end + + describe '#cache_key' do + it 'includes storage and host' do + expect(circuit_breaker.cache_key).to eq(cache_key) + end + end +end diff --git a/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb b/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb new file mode 100644 index 00000000000..12366151f44 --- /dev/null +++ b/spec/lib/gitlab/git/storage/forked_storage_check_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe Gitlab::Git::Storage::ForkedStorageCheck, skip_database_cleaner: true do + let(:existing_path) do + existing_path = TestEnv.repos_path + FileUtils.mkdir_p(existing_path) + existing_path + end + + describe '.storage_accessible?' do + it 'detects when a storage is not available' do + expect(described_class.storage_available?('/non/existant/path')).to be_falsey + end + + it 'detects when a storage is available' do + expect(described_class.storage_available?(existing_path)).to be_truthy + end + + it 'returns false when the check takes to long' do + # We're forking a process here that takes too long + # It will be killed it's parent process will be killed by it's parent + # and waited for inside `Gitlab::Git::Storage::ForkedStorageCheck.timeout_check` + allow(described_class).to receive(:check_filesystem_in_process) do + Process.spawn("sleep 10") + end + result = true + + runtime = Benchmark.realtime do + result = described_class.storage_available?(existing_path, 0.5) + end + + expect(result).to be_falsey + expect(runtime).to be < 1.0 + end + + describe 'when using paths with spaces' do + let(:test_dir) { Rails.root.join('tmp', 'tests', 'storage_check') } + let(:path_with_spaces) { File.join(test_dir, 'path with spaces') } + + around do |example| + FileUtils.mkdir_p(path_with_spaces) + example.run + FileUtils.rm_r(test_dir) + end + + it 'works for paths with spaces' do + expect(described_class.storage_available?(path_with_spaces)).to be_truthy + end + + it 'works for a realpath with spaces' do + symlink_location = File.join(test_dir, 'a symlink') + FileUtils.ln_s(path_with_spaces, symlink_location) + + expect(described_class.storage_available?(symlink_location)).to be_truthy + end + end + end +end diff --git a/spec/lib/gitlab/git/storage/health_spec.rb b/spec/lib/gitlab/git/storage/health_spec.rb new file mode 100644 index 00000000000..2d3af387971 --- /dev/null +++ b/spec/lib/gitlab/git/storage/health_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' + +describe Gitlab::Git::Storage::Health, clean_gitlab_redis_shared_state: true, broken_storage: true do + let(:host1_key) { 'storage_accessible:broken:web01' } + let(:host2_key) { 'storage_accessible:default:kiq01' } + + def set_in_redis(cache_key, value) + Gitlab::Git::Storage.redis.with do |redis| + redis.hmset(cache_key, :failure_count, value) + end.first + end + + describe '.for_failing_storages' do + it 'only includes health status for failures' do + set_in_redis(host1_key, 10) + set_in_redis(host2_key, 0) + + expect(described_class.for_failing_storages.map(&:storage_name)) + .to contain_exactly('broken') + end + end + + describe '.load_for_keys' do + let(:subject) do + results = Gitlab::Git::Storage.redis.with do |redis| + fake_future = double + allow(fake_future).to receive(:value).and_return([host1_key]) + described_class.load_for_keys({ 'broken' => fake_future }, redis) + end + + # Make sure the `Redis#future is loaded + results.inject({}) do |result, (name, info)| + info.each { |i| i[:failure_count] = i[:failure_count].value.to_i } + + result[name] = info + + result + end + end + + it 'loads when there is no info in redis' do + expect(subject).to eq('broken' => [{ name: host1_key, failure_count: 0 }]) + end + + it 'reads the correct values for a storage from redis' do + set_in_redis(host1_key, 5) + set_in_redis(host2_key, 7) + + expect(subject).to eq('broken' => [{ name: host1_key, failure_count: 5 }]) + end + end + + describe '.for_all_storages' do + it 'loads health status for all configured storages' do + healths = described_class.for_all_storages + + expect(healths.map(&:storage_name)).to contain_exactly('default', 'broken') + end + end + + describe '#failing_info' do + it 'only contains storages that have failures' do + health = described_class.new('broken', [{ name: host1_key, failure_count: 0 }, + { name: host2_key, failure_count: 3 }]) + + expect(health.failing_info).to contain_exactly({ name: host2_key, failure_count: 3 }) + end + end + + describe '#total_failures' do + it 'sums up all the failures' do + health = described_class.new('broken', [{ name: host1_key, failure_count: 2 }, + { name: host2_key, failure_count: 3 }]) + + expect(health.total_failures).to eq(5) + end + end + + describe '#failing_on_hosts' do + it 'collects only the failing hostnames' do + health = described_class.new('broken', [{ name: host1_key, failure_count: 2 }, + { name: host2_key, failure_count: 0 }]) + + expect(health.failing_on_hosts).to contain_exactly('web01') + end + end +end diff --git a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb index 0868c793a33..7fe698fcb18 100644 --- a/spec/lib/gitlab/gitaly_client/commit_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/commit_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::GitalyClient::CommitService do let(:project) { create(:project, :repository) } let(:storage_name) { project.repository_storage } - let(:relative_path) { project.path_with_namespace + '.git' } + let(:relative_path) { project.disk_path + '.git' } let(:repository) { project.repository } let(:repository_message) { repository.gitaly_repository } let(:revision) { '913c66a37b4a45b9769037c55c2d238bd0942d2e' } @@ -30,7 +30,7 @@ describe Gitlab::GitalyClient::CommitService do context 'when a commit does not have a parent' do it 'sends an RPC request with empty tree ref as left commit' do - initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863') + initial_commit = project.commit('1a0b36b3cdad1d2ee32457c102a8c0b7056fa863').raw request = Gitaly::CommitDiffRequest.new( repository: repository_message, left_commit_id: '4b825dc642cb6eb9a060e54bf8d69288fbee4904', @@ -46,18 +46,10 @@ describe Gitlab::GitalyClient::CommitService do end end - it 'returns a Gitlab::Git::DiffCollection' do + it 'returns a Gitlab::GitalyClient::DiffStitcher' do ret = client.diff_from_parent(commit) - expect(ret).to be_kind_of(Gitlab::Git::DiffCollection) - end - - it 'passes options to Gitlab::Git::DiffCollection' do - options = { max_files: 31, max_lines: 13, from_gitaly: true } - - expect(Gitlab::Git::DiffCollection).to receive(:new).with(kind_of(Enumerable), options) - - client.diff_from_parent(commit, options) + expect(ret).to be_kind_of(Gitlab::GitalyClient::DiffStitcher) end end @@ -120,4 +112,18 @@ describe Gitlab::GitalyClient::CommitService do client.tree_entries(repository, revision, path) end end + + describe '#find_commit' do + let(:revision) { '4b825dc642cb6eb9a060e54bf8d69288fbee4904' } + it 'sends an RPC request' do + request = Gitaly::FindCommitRequest.new( + repository: repository_message, revision: revision + ) + + expect_any_instance_of(Gitaly::CommitService::Stub).to receive(:find_commit) + .with(request, kind_of(Hash)).and_return(double(commit: nil)) + + described_class.new(repository).find_commit(revision) + end + end end diff --git a/spec/lib/gitlab/gitaly_client/notification_service_spec.rb b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb index d9597c4aa78..ffc3a09be30 100644 --- a/spec/lib/gitlab/gitaly_client/notification_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/notification_service_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' describe Gitlab::GitalyClient::NotificationService do describe '#post_receive' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:storage_name) { project.repository_storage } - let(:relative_path) { project.path_with_namespace + '.git' } + let(:relative_path) { project.disk_path + '.git' } subject { described_class.new(project.repository) } it 'sends a post_receive message' do diff --git a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb index 0b1c890f956..46efc1b18f0 100644 --- a/spec/lib/gitlab/gitaly_client/ref_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/ref_service_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Gitlab::GitalyClient::RefService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:storage_name) { project.repository_storage } - let(:relative_path) { project.path_with_namespace + '.git' } + let(:relative_path) { project.disk_path + '.git' } let(:client) { described_class.new(project.repository) } describe '#branches' do diff --git a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb b/spec/lib/gitlab/gitaly_client/repository_service_spec.rb deleted file mode 100644 index 5a9f3fc130c..00000000000 --- a/spec/lib/gitlab/gitaly_client/repository_service_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'spec_helper' - -describe Gitlab::GitalyClient::RepositoryService do - set(:project) { create(:empty_project) } - let(:storage_name) { project.repository_storage } - let(:relative_path) { project.path_with_namespace + '.git' } - let(:client) { described_class.new(project.repository) } - - describe '#exists?' do - it 'sends an exists message' do - expect_any_instance_of(Gitaly::RepositoryService::Stub) - .to receive(:exists) - .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash)) - .and_call_original - - client.exists? - end - end -end diff --git a/spec/lib/gitlab/github_import/comment_formatter_spec.rb b/spec/lib/gitlab/github_import/comment_formatter_spec.rb index ef89634685a..035ac8c7c1f 100644 --- a/spec/lib/gitlab/github_import/comment_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/comment_formatter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::GithubImport::CommentFormatter do let(:client) { double } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') } let(:created_at) { DateTime.strptime('2013-04-10T20:09:31Z') } let(:updated_at) { DateTime.strptime('2014-03-03T18:58:10Z') } diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb index d00a2deaf7b..d570f34985b 100644 --- a/spec/lib/gitlab/github_import/importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -207,7 +207,7 @@ describe Gitlab::GithubImport::Importer do end end - let(:project) { create(:project, :wiki_disabled, import_url: "#{repo_root}/octocat/Hello-World.git") } + let(:project) { create(:project, :repository, :wiki_disabled, import_url: "#{repo_root}/octocat/Hello-World.git") } let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') } let(:credentials) { { user: 'joe' } } diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb index 39b15926193..0fc56d92aa6 100644 --- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::GithubImport::IssueFormatter do let(:client) { double } - let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) } + let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) } let(:octocat) { double(id: 123456, login: 'octocat', email: 'octocat@example.com') } let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } diff --git a/spec/lib/gitlab/github_import/label_formatter_spec.rb b/spec/lib/gitlab/github_import/label_formatter_spec.rb index 2cc7ac0b446..83fdd2cc415 100644 --- a/spec/lib/gitlab/github_import/label_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/label_formatter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::GithubImport::LabelFormatter do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:raw) { double(name: 'improvements', color: 'e6e6e6') } subject { described_class.new(project, raw) } diff --git a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb index 310e0536fd7..683fa51b78e 100644 --- a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::GithubImport::MilestoneFormatter do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } let(:base_data) do diff --git a/spec/lib/gitlab/github_import/release_formatter_spec.rb b/spec/lib/gitlab/github_import/release_formatter_spec.rb index 1357cb636ae..926bf725d6a 100644 --- a/spec/lib/gitlab/github_import/release_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/release_formatter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::GithubImport::ReleaseFormatter do - let!(:project) { create(:empty_project, namespace: create(:namespace, path: 'octocat')) } + let!(:project) { create(:project, namespace: create(:namespace, path: 'octocat')) } let(:octocat) { double(id: 123456, login: 'octocat') } let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } diff --git a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb index de50265bc14..fcd90fab547 100644 --- a/spec/lib/gitlab/github_import/wiki_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/wiki_formatter_spec.rb @@ -9,9 +9,9 @@ describe Gitlab::GithubImport::WikiFormatter do subject(:wiki) { described_class.new(project) } - describe '#path_with_namespace' do + describe '#disk_path' do it 'appends .wiki to project path' do - expect(wiki.path_with_namespace).to eq 'gitlabhq/gitlabhq.wiki' + expect(wiki.disk_path).to eq project.disk_path + '.wiki' end end diff --git a/spec/lib/gitlab/gitlab_import/importer_spec.rb b/spec/lib/gitlab/gitlab_import/importer_spec.rb index 16b14474b89..e1d935602b5 100644 --- a/spec/lib/gitlab/gitlab_import/importer_spec.rb +++ b/spec/lib/gitlab/gitlab_import/importer_spec.rb @@ -24,7 +24,7 @@ describe Gitlab::GitlabImport::Importer do end it 'persists issues' do - project = create(:empty_project, import_source: 'asd/vim') + project = create(:project, import_source: 'asd/vim') project.build_import_data(credentials: { password: 'password' }) subject = described_class.new(project) diff --git a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb index da48d8f0670..82548c7fd31 100644 --- a/spec/lib/gitlab/gitlab_import/project_creator_spec.rb +++ b/spec/lib/gitlab/gitlab_import/project_creator_spec.rb @@ -12,7 +12,7 @@ describe Gitlab::GitlabImport::ProjectCreator do owner: { name: "john" } }.with_indifferent_access end - let(:namespace){ create(:group, owner: user) } + let(:namespace) { create(:group, owner: user) } let(:token) { "asdffg" } let(:access_params) { { gitlab_access_token: token } } diff --git a/spec/lib/gitlab/gl_repository_spec.rb b/spec/lib/gitlab/gl_repository_spec.rb index ac3558ab386..4e09020471b 100644 --- a/spec/lib/gitlab/gl_repository_spec.rb +++ b/spec/lib/gitlab/gl_repository_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ::Gitlab::GlRepository do describe '.parse' do - set(:project) { create(:project) } + set(:project) { create(:project, :repository) } it 'parses a project gl_repository' do expect(described_class.parse("project-#{project.id}")).to eq([project, false]) diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb index 85f40825005..798ea0bac58 100644 --- a/spec/lib/gitlab/google_code_import/importer_spec.rb +++ b/spec/lib/gitlab/google_code_import/importer_spec.rb @@ -10,7 +10,7 @@ describe Gitlab::GoogleCodeImport::Importer do 'user_map' => { 'thilo...' => "@#{mapped_user.username}" } } end - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { described_class.new(project) } diff --git a/spec/lib/gitlab/google_code_import/project_creator_spec.rb b/spec/lib/gitlab/google_code_import/project_creator_spec.rb index aad53938d52..8d5b60d50de 100644 --- a/spec/lib/gitlab/google_code_import/project_creator_spec.rb +++ b/spec/lib/gitlab/google_code_import/project_creator_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::GoogleCodeImport::ProjectCreator do "repositoryUrls" => ["https://vim.googlecode.com/git/"] ) end - let(:namespace){ create(:group, owner: user) } + let(:namespace) { create(:group, owner: user) } before do namespace.add_owner(user) diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index 8041518117d..30ad033b204 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -43,6 +43,58 @@ describe Gitlab::Gpg do ).to eq [] end end + + describe '.current_home_dir' do + let(:default_home_dir) { GPGME::Engine.dirinfo('homedir') } + + it 'returns the default value when no explicit home dir has been set' do + expect(described_class.current_home_dir).to eq default_home_dir + end + + it 'returns the explicitely set home dir' do + GPGME::Engine.home_dir = '/tmp/gpg' + + expect(described_class.current_home_dir).to eq '/tmp/gpg' + + GPGME::Engine.home_dir = GPGME::Engine.dirinfo('homedir') + end + + it 'returns the default value when explicitely setting the home dir to nil' do + GPGME::Engine.home_dir = nil + + expect(described_class.current_home_dir).to eq default_home_dir + end + end + + describe '.using_tmp_keychain' do + it "the second thread does not change the first thread's directory" do + thread1 = Thread.new do + described_class.using_tmp_keychain do + dir = described_class.current_home_dir + sleep 0.1 + expect(described_class.current_home_dir).to eq dir + end + end + + thread2 = Thread.new do + described_class.using_tmp_keychain do + sleep 0.2 + end + end + + thread1.join + thread2.join + end + + it 'allows recursive execution in the same thread' do + expect do + described_class.using_tmp_keychain do + described_class.using_tmp_keychain do + end + end + end.not_to raise_error(ThreadError) + end + end end describe Gitlab::Gpg::CurrentKeyChain do diff --git a/spec/lib/gitlab/graphs/commits_spec.rb b/spec/lib/gitlab/graphs/commits_spec.rb index 3f9382a9143..b2084f56640 100644 --- a/spec/lib/gitlab/graphs/commits_spec.rb +++ b/spec/lib/gitlab/graphs/commits_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::Graphs::Commits do - let!(:project) { create(:empty_project, :public) } + let!(:project) { create(:project, :public) } let!(:commit1) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: Time.now) } let!(:commit1_yesterday) { create(:commit, git_commit: RepoHelpers.sample_commit, project: project, committed_date: 1.day.ago)} diff --git a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb index 8abc4320c59..f5c9680bf59 100644 --- a/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb +++ b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb @@ -44,6 +44,15 @@ describe Gitlab::HealthChecks::FsShardsCheck do describe '#readiness' do subject { described_class.readiness } + context 'storage has a tripped circuitbreaker', broken_storage: true do + let(:repository_storages) { ['broken'] } + let(:storages_paths) do + Gitlab.config.repositories.storages + end + + it { is_expected.to include(result_class.new(false, 'circuitbreaker tripped', shard: 'broken')) } + end + context 'storage points to not existing folder' do let(:storages_paths) do { @@ -51,6 +60,10 @@ describe Gitlab::HealthChecks::FsShardsCheck do }.with_indifferent_access end + before do + allow(described_class).to receive(:storage_circuitbreaker_test) { true } + end + it { is_expected.to include(result_class.new(false, 'cannot stat storage', shard: :default)) } end @@ -93,12 +106,6 @@ describe Gitlab::HealthChecks::FsShardsCheck do }.with_indifferent_access end - # Unsolved intermittent failure in CI https://gitlab.com/gitlab-org/gitlab-ce/issues/31128 - around(:each) do |example| # rubocop:disable RSpec/AroundBlock - times_to_try = ENV['CI'] ? 4 : 1 - example.run_with_retry retry: times_to_try - end - it 'provides metrics' do metrics = described_class.metrics @@ -109,6 +116,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_circuitbreaker_latency_seconds, value: be >= 0)) end end @@ -127,6 +135,7 @@ describe Gitlab::HealthChecks::FsShardsCheck do expect(metrics).to include(an_object_having_attributes(name: :filesystem_access_latency_seconds, value: be >= 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_read_latency_seconds, value: be >= 0)) expect(metrics).to include(an_object_having_attributes(name: :filesystem_write_latency_seconds, value: be >= 0)) + expect(metrics).to include(an_object_having_attributes(name: :filesystem_circuitbreaker_latency_seconds, value: be >= 0)) end it 'cleans up files used for metrics' do diff --git a/spec/lib/gitlab/identifier_spec.rb b/spec/lib/gitlab/identifier_spec.rb index 29912da2e25..cfaeb1f0d4f 100644 --- a/spec/lib/gitlab/identifier_spec.rb +++ b/spec/lib/gitlab/identifier_spec.rb @@ -5,7 +5,7 @@ describe Gitlab::Identifier do Class.new { include Gitlab::Identifier }.new end - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:key) { create(:key, user: user) } diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index e6c7f3bdf74..f323777b13a 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -22,6 +22,7 @@ events: - author - project - target +- push_event_payload notes: - award_emoji - project @@ -272,3 +273,5 @@ timelogs: - issue - merge_request - user +push_event_payload: +- event diff --git a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb index 574748756bd..cd5a1b2982b 100644 --- a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb +++ b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::ImportExport::AttributeCleaner do - let(:relation_class){ double('relation_class').as_null_object } + let(:relation_class) { double('relation_class').as_null_object } let(:unsafe_hash) do { 'id' => 101, diff --git a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb index a7b292c8558..a93a921e459 100644 --- a/spec/lib/gitlab/import_export/avatar_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_restorer_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::ImportExport::AvatarRestorer do include UploadHelpers let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do allow_any_instance_of(described_class).to receive(:avatar_export_file) diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb index 814f85de03b..3fb5ddde8b5 100644 --- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe Gitlab::ImportExport::AvatarSaver do let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: 'test') } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } - let(:project_with_avatar) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } - let(:project) { create(:empty_project) } + let(:project_with_avatar) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let(:project) { create(:project) } before do FileUtils.mkdir_p("#{shared.export_path}/avatar/") diff --git a/spec/lib/gitlab/import_export/file_importer_spec.rb b/spec/lib/gitlab/import_export/file_importer_spec.rb index 690c7625c52..162b776e107 100644 --- a/spec/lib/gitlab/import_export/file_importer_spec.rb +++ b/spec/lib/gitlab/import_export/file_importer_spec.rb @@ -5,6 +5,7 @@ describe Gitlab::ImportExport::FileImporter do let(:export_path) { "#{Dir.tmpdir}/file_importer_spec" } let(:valid_file) { "#{shared.export_path}/valid.json" } let(:symlink_file) { "#{shared.export_path}/invalid.json" } + let(:hidden_symlink_file) { "#{shared.export_path}/.hidden" } let(:subfolder_symlink_file) { "#{shared.export_path}/subfolder/invalid.json" } before do @@ -25,6 +26,10 @@ describe Gitlab::ImportExport::FileImporter do expect(File.exist?(symlink_file)).to be false end + it 'removes hidden symlinks in root folder' do + expect(File.exist?(hidden_symlink_file)).to be false + end + it 'removes symlinks in subfolders' do expect(File.exist?(subfolder_symlink_file)).to be false end diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb index 08588a76fe6..c7fbc2bc92f 100644 --- a/spec/lib/gitlab/import_export/fork_spec.rb +++ b/spec/lib/gitlab/import_export/fork_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' describe 'forked project import' do let(:user) { create(:user) } - let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } - let!(:project) { create(:empty_project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') } + let!(:project_with_repo) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project) { create(:project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } - let(:forked_from_project) { create(:project) } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) } + let(:forked_from_project) { create(:project, :repository) } let(:fork_link) { create(:forked_project_link, forked_from_project: project_with_repo) } let(:repo_saver) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) } let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) } diff --git a/spec/lib/gitlab/import_export/import_export_spec.rb b/spec/lib/gitlab/import_export/import_export_spec.rb index 07415d41f93..40a5f2294a2 100644 --- a/spec/lib/gitlab/import_export/import_export_spec.rb +++ b/spec/lib/gitlab/import_export/import_export_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ImportExport do describe 'export filename' do let(:group) { create(:group, :nested) } - let(:project) { create(:empty_project, :public, path: 'project-path', namespace: group) } + let(:project) { create(:project, :public, path: 'project-path', namespace: group) } it 'contains the project path' do expect(described_class.export_filename(project: project)).to include(project.path) diff --git a/spec/lib/gitlab/import_export/members_mapper_spec.rb b/spec/lib/gitlab/import_export/members_mapper_spec.rb index f66a2ab7dda..246f009ad27 100644 --- a/spec/lib/gitlab/import_export/members_mapper_spec.rb +++ b/spec/lib/gitlab/import_export/members_mapper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ImportExport::MembersMapper do describe 'map members' do let(:user) { create(:admin) } - let(:project) { create(:empty_project, :public, name: 'searchable_project') } + let(:project) { create(:project, :public, name: 'searchable_project') } let(:user2) { create(:user) } let(:exported_user_id) { 99 } let(:exported_members) do @@ -96,7 +96,7 @@ describe Gitlab::ImportExport::MembersMapper do context 'importer same as group member' do let(:user2) { create(:admin) } let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, name: 'searchable_project', namespace: group) } + let(:project) { create(:project, :public, name: 'searchable_project', namespace: group) } let(:members_mapper) do described_class.new( exported_members: exported_members, user: user2, project: project) @@ -119,7 +119,7 @@ describe Gitlab::ImportExport::MembersMapper do context 'importing group members' do let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } let(:members_mapper) do described_class.new( exported_members: exported_members, user: user, project: project) diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb index f2b66c4421c..4d87f27ce05 100644 --- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb +++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Gitlab::ImportExport::MergeRequestParser do let(:user) { create(:user) } - let!(:project) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } - let(:forked_from_project) { create(:project) } + let!(:project) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let(:forked_from_project) { create(:project, :repository) } let(:fork_link) { create(:forked_project_link, forked_from_project: project) } let!(:merge_request) do diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 469a014e4d2..4e631e13410 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -2534,7 +2534,6 @@ "iid": 9, "description": null, "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -2983,7 +2982,6 @@ "iid": 8, "description": null, "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -3267,7 +3265,6 @@ "iid": 7, "description": "Et commodi deserunt aspernatur vero rerum. Ut non dolorum alias in odit est libero. Voluptatibus eos in et vitae repudiandae facilis ex mollitia.", "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -3551,7 +3548,6 @@ "iid": 6, "description": "Dicta magnam non voluptates nam dignissimos nostrum deserunt. Dolorum et suscipit iure quae doloremque. Necessitatibus saepe aut labore sed.", "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -4241,7 +4237,6 @@ "iid": 5, "description": "Est eaque quasi qui qui. Similique voluptatem impedit iusto ratione reprehenderit. Itaque est illum ut nulla aut.", "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -4789,7 +4784,6 @@ "iid": 4, "description": "Nam magnam odit velit rerum. Sapiente dolore sunt saepe debitis. Culpa maiores ut ad dolores dolorem et.", "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -5288,7 +5282,6 @@ "iid": 3, "description": "Libero nesciunt mollitia quis odit eos vero quasi. Iure voluptatem ut sint pariatur voluptates ut aut. Laborum possimus unde illum ipsum eum.", "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -5548,7 +5541,6 @@ "iid": 2, "description": "Ut dolor quia aliquid dolore et nisi. Est minus suscipit enim quaerat sapiente consequatur rerum. Eveniet provident consequatur dolor accusantium reiciendis.", "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { @@ -6238,7 +6230,6 @@ "iid": 1, "description": "Eveniet nihil ratione veniam similique qui aut sapiente tempora. Sed praesentium iusto dignissimos possimus id repudiandae quo nihil. Qui doloremque autem et iure fugit.", "position": 0, - "locked_at": null, "updated_by_id": null, "merge_error": null, "merge_params": { diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb index d1ec0e45bbd..7ee0e22f28d 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -9,7 +9,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do RSpec::Mocks.with_temporary_scope do @shared = Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') allow(@shared).to receive(:export_path).and_return('spec/lib/gitlab/import_export/') - @project = create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') + @project = create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') project_tree_restorer = described_class.new(user: @user, shared: @shared, project: @project) @restored_project_json = project_tree_restorer.restore end @@ -178,7 +178,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do context 'Light JSON' do let(:user) { create(:user) } let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: "", project_path: 'path') } - let!(:project) { create(:empty_project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') } + let!(:project) { create(:project, :builds_disabled, :issues_disabled, name: 'project', path: 'project') } let(:project_tree_restorer) { described_class.new(user: user, shared: shared, project: project) } let(:restored_project_json) { project_tree_restorer.restore } @@ -210,7 +210,7 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do context 'with group' do let!(:project) do - create(:empty_project, + create(:project, :builds_disabled, :issues_disabled, name: 'project', diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index 0c7e733b01f..a278f89c1a1 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::ImportExport::ProjectTreeSaver do describe 'saves the project tree into a json object' do - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) } let(:project_tree_saver) { described_class.new(project: project, current_user: user, shared: shared) } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } let(:user) { create(:user) } diff --git a/spec/lib/gitlab/import_export/relation_factory_spec.rb b/spec/lib/gitlab/import_export/relation_factory_spec.rb index baa90af84f7..f1df44cea75 100644 --- a/spec/lib/gitlab/import_export/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/relation_factory_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::ImportExport::RelationFactory do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:members_mapper) { double('members_mapper').as_null_object } let(:user) { create(:admin) } let(:created_object) do diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb index d3be2965bf4..2786bc92fe5 100644 --- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb @@ -3,10 +3,10 @@ require 'spec_helper' describe Gitlab::ImportExport::RepoRestorer do describe 'bundle a project Git repo' do let(:user) { create(:user) } - let!(:project_with_repo) { create(:project, name: 'test-repo-restorer', path: 'test-repo-restorer') } - let!(:project) { create(:empty_project) } + let!(:project_with_repo) { create(:project, :repository, name: 'test-repo-restorer', path: 'test-repo-restorer') } + let!(:project) { create(:project) } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) } let(:bundler) { Gitlab::ImportExport::RepoSaver.new(project: project_with_repo, shared: shared) } let(:bundle_path) { File.join(shared.export_path, Gitlab::ImportExport.project_bundle_filename) } let(:restorer) do diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb index 87af13e0beb..e6ad516deef 100644 --- a/spec/lib/gitlab/import_export/repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe Gitlab::ImportExport::RepoSaver do describe 'bundle a project Git repo' do let(:user) { create(:user) } - let!(:project) { create(:empty_project, :public, name: 'searchable_project') } + let!(:project) { create(:project, :public, name: 'searchable_project') } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) } let(:bundler) { described_class.new(project: project, shared: shared) } before do diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 2d5a60fe6b8..a5e03e149a7 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -36,6 +36,14 @@ Event: - updated_at - action - author_id +PushEventPayload: +- commit_count +- action +- ref_type +- commit_from +- commit_to +- ref +- commit_title Note: - id - note @@ -145,7 +153,6 @@ MergeRequest: - iid - description - position -- locked_at - updated_by_id - merge_error - merge_params diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb index 78137aeff5e..0e55993c8ef 100644 --- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb +++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb @@ -3,9 +3,9 @@ require 'spec_helper' describe Gitlab::ImportExport::WikiRepoSaver do describe 'bundle a wiki Git repo' do let(:user) { create(:user) } - let!(:project) { create(:empty_project, :public, name: 'searchable_project') } + let!(:project) { create(:project, :public, name: 'searchable_project') } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } - let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) } + let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.full_path) } let(:wiki_bundler) { described_class.new(project: project, shared: shared) } let!(:project_wiki) { ProjectWiki.new(project, user) } diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb index b3b5e5e7e33..c5725f47453 100644 --- a/spec/lib/gitlab/import_sources_spec.rb +++ b/spec/lib/gitlab/import_sources_spec.rb @@ -56,7 +56,7 @@ describe Gitlab::ImportSources do describe '.importer' do import_sources = { - 'github' => Gitlab::GithubImport::Importer, + 'github' => Github::Import, 'bitbucket' => Gitlab::BitbucketImport::Importer, 'gitlab' => Gitlab::GitlabImport::Importer, 'google_code' => Gitlab::GoogleCodeImport::Importer, diff --git a/spec/lib/gitlab/issuable_sorter_spec.rb b/spec/lib/gitlab/issuable_sorter_spec.rb index aeb32ef96d6..642a6cb6caa 100644 --- a/spec/lib/gitlab/issuable_sorter_spec.rb +++ b/spec/lib/gitlab/issuable_sorter_spec.rb @@ -1,25 +1,25 @@ require 'spec_helper' describe Gitlab::IssuableSorter do - let(:namespace1) { build(:namespace, id: 1) } - let(:project1) { build(:project, id: 1, namespace: namespace1) } + let(:namespace1) { build_stubbed(:namespace, id: 1) } + let(:project1) { build_stubbed(:project, id: 1, namespace: namespace1) } - let(:project2) { build(:project, id: 2, path: "a", namespace: project1.namespace) } - let(:project3) { build(:project, id: 3, path: "b", namespace: project1.namespace) } + let(:project2) { build_stubbed(:project, id: 2, path: "a", namespace: project1.namespace) } + let(:project3) { build_stubbed(:project, id: 3, path: "b", namespace: project1.namespace) } - let(:namespace2) { build(:namespace, id: 2, path: "a") } - let(:namespace3) { build(:namespace, id: 3, path: "b") } - let(:project4) { build(:project, id: 4, path: "a", namespace: namespace2) } - let(:project5) { build(:project, id: 5, path: "b", namespace: namespace2) } - let(:project6) { build(:project, id: 6, path: "a", namespace: namespace3) } + let(:namespace2) { build_stubbed(:namespace, id: 2, path: "a") } + let(:namespace3) { build_stubbed(:namespace, id: 3, path: "b") } + let(:project4) { build_stubbed(:project, id: 4, path: "a", namespace: namespace2) } + let(:project5) { build_stubbed(:project, id: 5, path: "b", namespace: namespace2) } + let(:project6) { build_stubbed(:project, id: 6, path: "a", namespace: namespace3) } let(:unsorted) { [sorted[2], sorted[3], sorted[0], sorted[1]] } let(:sorted) do - [build(:issue, iid: 1, project: project1), - build(:issue, iid: 2, project: project1), - build(:issue, iid: 10, project: project1), - build(:issue, iid: 20, project: project1)] + [build_stubbed(:issue, iid: 1, project: project1), + build_stubbed(:issue, iid: 2, project: project1), + build_stubbed(:issue, iid: 10, project: project1), + build_stubbed(:issue, iid: 20, project: project1)] end it 'sorts references by a given key' do @@ -41,14 +41,14 @@ describe Gitlab::IssuableSorter do context 'for references from multiple projects and namespaces' do let(:sorted) do - [build(:issue, iid: 1, project: project1), - build(:issue, iid: 2, project: project1), - build(:issue, iid: 10, project: project1), - build(:issue, iid: 1, project: project2), - build(:issue, iid: 1, project: project3), - build(:issue, iid: 1, project: project4), - build(:issue, iid: 1, project: project5), - build(:issue, iid: 1, project: project6)] + [build_stubbed(:issue, iid: 1, project: project1), + build_stubbed(:issue, iid: 2, project: project1), + build_stubbed(:issue, iid: 10, project: project1), + build_stubbed(:issue, iid: 1, project: project2), + build_stubbed(:issue, iid: 1, project: project3), + build_stubbed(:issue, iid: 1, project: project4), + build_stubbed(:issue, iid: 1, project: project5), + build_stubbed(:issue, iid: 1, project: project6)] end let(:unsorted) do [sorted[3], sorted[1], sorted[4], sorted[2], diff --git a/spec/lib/gitlab/key_fingerprint_spec.rb b/spec/lib/gitlab/key_fingerprint_spec.rb index d7bebaca675..f5fd5a96bc9 100644 --- a/spec/lib/gitlab/key_fingerprint_spec.rb +++ b/spec/lib/gitlab/key_fingerprint_spec.rb @@ -1,12 +1,82 @@ -require "spec_helper" +require 'spec_helper' -describe Gitlab::KeyFingerprint do - let(:key) { "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=" } - let(:fingerprint) { "3f:a2:ee:de:b5:de:53:c3:aa:2f:9c:45:24:4c:47:7b" } +describe Gitlab::KeyFingerprint, lib: true do + KEYS = { + rsa: + 'example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC5z65PwQ1GE6foJgwk' \ + '9rmQi/glaXbUeVa5uvQpnZ3Z5+forcI7aTngh3aZ/H2UDP2L70TGy7kKNyp0J3a8/OdG' \ + 'Z08y5yi3JlbjFARO1NyoFEjw2H1SJxeJ43L6zmvTlu+hlK1jSAlidl7enS0ufTlzEEj4' \ + 'iJcuTPKdVzKRgZuTRVm9woWNVKqIrdRC0rJiTinERnfSAp/vNYERMuaoN4oJt8p/NEek' \ + 'rmFoDsQOsyDW5RAnCnjWUU+jFBKDpfkJQ1U2n6BjJewC9dl6ODK639l3yN4WOLZEk4tN' \ + 'UysfbGeF3rmMeflaD6O1Jplpv3YhwVGFNKa7fMq6k3Z0tszTJPYh', + ecdsa: + 'example.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAI' \ + 'bmlzdHAyNTYAAABBBKTJy43NZzJSfNxpv/e2E6Zy3qoHoTQbmOsU5FEfpWfWa1MdTeXQ' \ + 'YvKOi+qz/1AaNx6BK421jGu74JCDJtiZWT8=', + ed25519: + '@revoked example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAfuCHKVTjq' \ + 'uxvt6CM6tdG4SLp1Btn/nOeHHE5UOzRdf', + dss: + 'example.com ssh-dss AAAAB3NzaC1kc3MAAACBAP1/U4EddRIpUt9KnC7s5Of2EbdS' \ + 'PO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f' \ + '6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iID' \ + 'GZ3RSAHHAAAAFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QAAAIEA9+GghdabPd7LvKtcNrhX' \ + 'uXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwW' \ + 'eotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6A' \ + 'e1UlZAFMO/7PSSoAAACBAJcQ4JODqhuGbXIEpqxetm7PWbdbCcr3y/GzIZ066pRovpL6' \ + 'qm3qCVIym4cyChxWwb8qlyCIi+YRUUWm1z/wiBYT2Vf3S4FXBnyymCkKEaV/EY7+jd4X' \ + '1bXI58OD2u+bLCB/sInM4fGB8CZUIWT9nJH0Ve9jJUge2ms348/QOJ1+' + }.freeze - describe "#fingerprint" do - it "generates the key's fingerprint" do - expect(described_class.new(key).fingerprint).to eq(fingerprint) + MD5_FINGERPRINTS = { + rsa: '06:b2:8a:92:df:0e:11:2c:ca:7b:8f:a4:ba:6e:4b:fd', + ecdsa: '45:ff:5b:98:9a:b6:8a:41:13:c1:30:8b:09:5e:7b:4e', + ed25519: '2e:65:6a:c8:cf:bf:b2:8b:9a:bd:6d:9f:11:5c:12:16', + dss: '57:98:86:02:5f:9c:f4:9b:ad:5a:1e:51:92:0e:fd:2b' + }.freeze + + BIT_COUNTS = { + rsa: 2048, + ecdsa: 256, + ed25519: 256, + dss: 1024 + }.freeze + + describe '#type' do + KEYS.each do |type, key| + it "calculates the type of #{type} keys" do + calculated_type = described_class.new(key).type + + expect(calculated_type).to eq(type.to_s.upcase) + end + end + end + + describe '#fingerprint' do + KEYS.each do |type, key| + it "calculates the MD5 fingerprint for #{type} keys" do + fp = described_class.new(key).fingerprint + + expect(fp).to eq(MD5_FINGERPRINTS[type]) + end + end + end + + describe '#bits' do + KEYS.each do |type, key| + it "calculates the number of bits in #{type} keys" do + bits = described_class.new(key).bits + + expect(bits).to eq(BIT_COUNTS[type]) + end + end + end + + describe '#key' do + it 'carries the unmodified key data' do + key = described_class.new(KEYS[:rsa]).key + + expect(key).to eq(KEYS[:rsa]) end end end diff --git a/spec/lib/gitlab/ldap/config_spec.rb b/spec/lib/gitlab/ldap/config_spec.rb index 292ec064a67..ca2213cd112 100644 --- a/spec/lib/gitlab/ldap/config_spec.rb +++ b/spec/lib/gitlab/ldap/config_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::LDAP::Config do describe '#initialize' do it 'requires a provider' do - expect{ described_class.new }.to raise_error ArgumentError + expect { described_class.new }.to raise_error ArgumentError end it 'works' do @@ -15,7 +15,7 @@ describe Gitlab::LDAP::Config do end it 'raises an error if a unknown provider is used' do - expect{ described_class.new 'unknown' }.to raise_error(RuntimeError) + expect { described_class.new 'unknown' }.to raise_error(RuntimeError) end end diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb index 175ceec44d7..5100a5a609e 100644 --- a/spec/lib/gitlab/ldap/user_spec.rb +++ b/spec/lib/gitlab/ldap/user_spec.rb @@ -61,12 +61,12 @@ describe Gitlab::LDAP::User do it "finds the user if already existing" do create(:omniauth_user, extern_uid: 'my-uid', provider: 'ldapmain') - expect{ ldap_user.save }.not_to change{ User.count } + expect { ldap_user.save }.not_to change { User.count } end it "connects to existing non-ldap user if the email matches" do existing_user = create(:omniauth_user, email: 'john@example.com', provider: "twitter") - expect{ ldap_user.save }.not_to change{ User.count } + expect { ldap_user.save }.not_to change { User.count } existing_user.reload expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid' @@ -75,7 +75,7 @@ describe Gitlab::LDAP::User do it 'connects to existing ldap user if the extern_uid changes' do existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'old-uid', provider: 'ldapmain') - expect{ ldap_user.save }.not_to change{ User.count } + expect { ldap_user.save }.not_to change { User.count } existing_user.reload expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid' @@ -85,7 +85,7 @@ describe Gitlab::LDAP::User do it 'connects to existing ldap user if the extern_uid changes and email address has upper case characters' do existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'old-uid', provider: 'ldapmain') - expect{ ldap_user_upper_case.save }.not_to change{ User.count } + expect { ldap_user_upper_case.save }.not_to change { User.count } existing_user.reload expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid' @@ -106,7 +106,7 @@ describe Gitlab::LDAP::User do end it "creates a new user if not found" do - expect{ ldap_user.save }.to change{ User.count }.by(1) + expect { ldap_user.save }.to change { User.count }.by(1) end context 'when signup is disabled' do diff --git a/spec/lib/gitlab/metrics/influx_sampler_spec.rb b/spec/lib/gitlab/metrics/influx_sampler_spec.rb index 0bc68d64276..999a9536d82 100644 --- a/spec/lib/gitlab/metrics/influx_sampler_spec.rb +++ b/spec/lib/gitlab/metrics/influx_sampler_spec.rb @@ -11,7 +11,7 @@ describe Gitlab::Metrics::InfluxSampler do it 'runs once and gathers a sample at a given interval' do expect(sampler).to receive(:sleep).with(a_kind_of(Numeric)).twice expect(sampler).to receive(:sample).once - expect(sampler).to receive(:running).and_return(false, true, false) + expect(sampler).to receive(:running).and_return(true, false) sampler.start.join end diff --git a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb index 461b1e4182a..ebe66948a91 100644 --- a/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/requests_rack_middleware_spec.rb @@ -4,10 +4,6 @@ describe Gitlab::Metrics::RequestsRackMiddleware do let(:app) { double('app') } subject { described_class.new(app) } - around do |example| - Timecop.freeze { example.run } - end - describe '#call' do let(:status) { 100 } let(:env) { { 'REQUEST_METHOD' => 'GET' } } @@ -28,16 +24,14 @@ describe Gitlab::Metrics::RequestsRackMiddleware do subject.call(env) end - it 'measures execution time' do - execution_time = 10 - allow(app).to receive(:call) do |*args| - Timecop.freeze(execution_time.seconds) - [200, nil, nil] - end + RSpec::Matchers.define :a_positive_execution_time do + match { |actual| actual > 0 } + end - expect(described_class).to receive_message_chain(:http_request_duration_seconds, :observe).with({ status: 200, method: 'get' }, execution_time) + it 'measures execution time' do + expect(described_class).to receive_message_chain(:http_request_duration_seconds, :observe).with({ status: 200, method: 'get' }, a_positive_execution_time) - subject.call(env) + Timecop.scale(3600) { subject.call(env) } end end diff --git a/spec/lib/gitlab/metrics/sidekiq_metrics_exporter_spec.rb b/spec/lib/gitlab/metrics/sidekiq_metrics_exporter_spec.rb new file mode 100644 index 00000000000..6721e02fb85 --- /dev/null +++ b/spec/lib/gitlab/metrics/sidekiq_metrics_exporter_spec.rb @@ -0,0 +1,101 @@ +require 'spec_helper' + +describe Gitlab::Metrics::SidekiqMetricsExporter do + let(:exporter) { described_class.new } + let(:server) { double('server') } + + before do + allow(::WEBrick::HTTPServer).to receive(:new).and_return(server) + allow(server).to receive(:mount) + allow(server).to receive(:start) + allow(server).to receive(:shutdown) + end + + describe 'when exporter is enabled' do + before do + allow(Settings.monitoring.sidekiq_exporter).to receive(:enabled).and_return(true) + end + + describe 'when exporter is stopped' do + describe '#start' do + it 'starts the exporter' do + expect { exporter.start.join }.to change { exporter.thread? }.from(false).to(true) + + expect(server).to have_received(:start) + end + + describe 'with custom settings' do + let(:port) { 99999 } + let(:address) { 'sidekiq_exporter_address' } + + before do + allow(Settings.monitoring.sidekiq_exporter).to receive(:port).and_return(port) + allow(Settings.monitoring.sidekiq_exporter).to receive(:address).and_return(address) + end + + it 'starts server with port and address from settings' do + exporter.start.join + + expect(::WEBrick::HTTPServer).to have_received(:new).with( + Port: port, + BindAddress: address + ) + end + end + end + + describe '#stop' do + it "doesn't shutdown stopped server" do + expect { exporter.stop }.not_to change { exporter.thread? } + + expect(server).not_to have_received(:shutdown) + end + end + end + + describe 'when exporter is running' do + before do + exporter.start.join + end + + describe '#start' do + it "doesn't start running server" do + expect { exporter.start.join }.not_to change { exporter.thread? } + + expect(server).to have_received(:start).once + end + end + + describe '#stop' do + it 'shutdowns server' do + expect { exporter.stop }.to change { exporter.thread? }.from(true).to(false) + + expect(server).to have_received(:shutdown) + end + end + end + end + + describe 'when exporter is disabled' do + before do + allow(Settings.monitoring.sidekiq_exporter).to receive(:enabled).and_return(false) + end + + describe '#start' do + it "doesn't start" do + expect(exporter.start).to be_nil + expect { exporter.start }.not_to change { exporter.thread? } + + expect(server).not_to have_received(:start) + end + end + + describe '#stop' do + it "doesn't shutdown" do + expect { exporter.stop }.not_to change { exporter.thread? } + + expect(server).not_to have_received(:shutdown) + end + end + end +end diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb index 47aa19d5fd9..15edb820908 100644 --- a/spec/lib/gitlab/o_auth/user_spec.rb +++ b/spec/lib/gitlab/o_auth/user_spec.rb @@ -147,7 +147,7 @@ describe Gitlab::OAuth::User do end it 'throws an error' do - expect{ oauth_user.save }.to raise_error StandardError + expect { oauth_user.save }.to raise_error StandardError end end @@ -157,7 +157,7 @@ describe Gitlab::OAuth::User do end it 'throws an error' do - expect{ oauth_user.save }.to raise_error StandardError + expect { oauth_user.save }.to raise_error StandardError end end end @@ -457,4 +457,34 @@ describe Gitlab::OAuth::User do end end end + + describe 'generating username' do + context 'when no collision with existing user' do + it 'generates the username with no counter' do + expect(gl_user.username).to eq('johngitlab-ETC') + end + end + + context 'when collision with existing user' do + it 'generates the username with a counter' do + oauth_user.save + oauth_user2 = described_class.new(OmniAuth::AuthHash.new(uid: 'my-uid2', provider: provider, info: { nickname: 'johngitlab-ETC@othermail.com', email: 'john@othermail.com' })) + + expect(oauth_user2.gl_user.username).to eq('johngitlab-ETC1') + end + end + + context 'when username is a reserved word' do + let(:info_hash) do + { + nickname: 'admin@othermail.com', + email: 'admin@othermail.com' + } + end + + it 'generates the username with a counter' do + expect(gl_user.username).to eq('admin1') + end + end + end end diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb index 9ce33685697..953cfbb8b88 100644 --- a/spec/lib/gitlab/project_authorizations_spec.rb +++ b/spec/lib/gitlab/project_authorizations_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' describe Gitlab::ProjectAuthorizations do let(:group) { create(:group) } - let!(:owned_project) { create(:empty_project) } - let!(:other_project) { create(:empty_project) } - let!(:group_project) { create(:empty_project, namespace: group) } + let!(:owned_project) { create(:project) } + let!(:other_project) { create(:project) } + let!(:group_project) { create(:project, namespace: group) } let(:user) { owned_project.namespace.owner } @@ -49,7 +49,7 @@ describe Gitlab::ProjectAuthorizations do if Group.supports_nested_groups? context 'with nested groups' do let!(:nested_group) { create(:group, parent: group) } - let!(:nested_project) { create(:empty_project, namespace: nested_group) } + let!(:nested_project) { create(:project, namespace: nested_group) } it 'includes nested groups' do expect(authorizations.pluck(:project_id)).to include(nested_project.id) diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb index d17b436b910..9c3e7d7e9ba 100644 --- a/spec/lib/gitlab/project_search_results_spec.rb +++ b/spec/lib/gitlab/project_search_results_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::ProjectSearchResults do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:query) { 'hello world' } describe 'initialize with empty ref' do @@ -154,7 +154,7 @@ describe Gitlab::ProjectSearchResults do let(:non_member) { create(:user) } let(:member) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } 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, assignees: [assignee]) } @@ -226,7 +226,7 @@ describe Gitlab::ProjectSearchResults do describe 'notes search' do it 'lists notes' do - project = create(:empty_project, :public) + project = create(:project, :public) note = create(:note, project: project) results = described_class.new(user, project, note.note) @@ -235,7 +235,7 @@ describe Gitlab::ProjectSearchResults do end it "doesn't list issue notes when access is restricted" do - project = create(:empty_project, :public, :issues_private) + project = create(:project, :public, :issues_private) note = create(:note_on_issue, project: project) results = described_class.new(user, project, note.note) @@ -244,7 +244,7 @@ describe Gitlab::ProjectSearchResults do end it "doesn't list merge_request notes when access is restricted" do - project = create(:empty_project, :public, :merge_requests_private) + project = create(:project, :public, :merge_requests_private) note = create(:note_on_merge_request, project: project) results = described_class.new(user, project, note.note) diff --git a/spec/lib/gitlab/project_template_spec.rb b/spec/lib/gitlab/project_template_spec.rb new file mode 100644 index 00000000000..d19bd611919 --- /dev/null +++ b/spec/lib/gitlab/project_template_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe Gitlab::ProjectTemplate do + describe '.all' do + it 'returns a all templates' do + expected = [ + described_class.new('rails', 'Ruby on Rails'), + described_class.new('spring', 'Spring'), + described_class.new('express', 'NodeJS Express') + ] + + expect(described_class.all).to be_an(Array) + expect(described_class.all).to eq(expected) + end + end + + describe '.find' do + subject { described_class.find(query) } + + context 'when there is a match' do + let(:query) { :rails } + + it { is_expected.to be_a(described_class) } + end + + context 'when there is no match' do + let(:query) { 'no-match' } + + it { is_expected.to be(nil) } + end + end + + describe 'instance methods' do + subject { described_class.new('phoenix', 'Phoenix Framework') } + + it { is_expected.to respond_to(:logo, :file, :archive_path) } + end + + describe 'validate all templates' do + set(:admin) { create(:admin) } + + described_class.all.each do |template| + it "#{template.name} has a valid archive" do + archive = template.archive_path + + expect(File.exist?(archive)).to be(true) + end + + context 'with valid parameters' do + it 'can be imported' do + params = { + template_name: template.name, + namespace_id: admin.namespace.id, + path: template.name + } + + project = Projects::CreateFromTemplateService.new(admin, params).execute + + expect(project).to be_valid + expect(project).to be_persisted + end + end + end + end +end diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb index e42e034f4fb..c7169717fc1 100644 --- a/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_deployment_query_spec.rb @@ -1,19 +1,14 @@ require 'spec_helper' describe Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery do - include Prometheus::MetricBuilders - - let(:client) { double('prometheus_client') } - let(:environment) { create(:environment, slug: 'environment-slug') } - let(:deployment) { create(:deployment, environment: environment) } - - subject(:query_result) { described_class.new(client).query(deployment.id) } - around do |example| Timecop.freeze(Time.local(2008, 9, 1, 12, 0, 0)) { example.run } end include_examples 'additional metrics query' do + let(:deployment) { create(:deployment, environment: environment) } + let(:query_params) { [deployment.id] } + it 'queries using specific time' do expect(client).to receive(:query_range).with(anything, start: (deployment.created_at - 30.minutes).to_f, diff --git a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb index e9fd66d45fe..5a88b23aa82 100644 --- a/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb +++ b/spec/lib/gitlab/prometheus/queries/additional_metrics_environment_query_spec.rb @@ -1,20 +1,16 @@ require 'spec_helper' describe Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery do - include Prometheus::MetricBuilders - - let(:client) { double('prometheus_client') } - let(:environment) { create(:environment, slug: 'environment-slug') } - - subject(:query_result) { described_class.new(client).query(environment.id) } - around do |example| Timecop.freeze { example.run } end include_examples 'additional metrics query' do + let(:query_params) { [environment.id] } + it 'queries using specific time' do expect(client).to receive(:query_range).with(anything, start: 8.hours.ago.to_f, stop: Time.now.to_f) + expect(query_result).not_to be_nil end end diff --git a/spec/lib/gitlab/quick_actions/dsl_spec.rb b/spec/lib/gitlab/quick_actions/dsl_spec.rb index a4bb3f911d7..ff59dc48bcb 100644 --- a/spec/lib/gitlab/quick_actions/dsl_spec.rb +++ b/spec/lib/gitlab/quick_actions/dsl_spec.rb @@ -42,13 +42,18 @@ describe Gitlab::QuickActions::Dsl do command :with_params_parsing do |parsed| parsed end + + params '<Comment>' + substitution :something do |text| + "#{text} Some complicated thing you want in here" + end end end describe '.command_definitions' do it 'returns an array with commands definitions' do no_args_def, explanation_with_aliases_def, dynamic_description_def, - cc_def, cond_action_def, with_params_parsing_def = + cc_def, cond_action_def, with_params_parsing_def, substitution_def = DummyClass.command_definitions expect(no_args_def.name).to eq(:no_args) @@ -104,6 +109,15 @@ describe Gitlab::QuickActions::Dsl do expect(with_params_parsing_def.condition_block).to be_nil expect(with_params_parsing_def.action_block).to be_a_kind_of(Proc) expect(with_params_parsing_def.parse_params_block).to be_a_kind_of(Proc) + + expect(substitution_def.name).to eq(:something) + expect(substitution_def.aliases).to eq([]) + expect(substitution_def.description).to eq('') + expect(substitution_def.explanation).to eq('') + expect(substitution_def.params).to eq(['<Comment>']) + expect(substitution_def.condition_block).to be_nil + expect(substitution_def.action_block.call('text')).to eq('text Some complicated thing you want in here') + expect(substitution_def.parse_params_block).to be_nil end end end diff --git a/spec/lib/gitlab/quick_actions/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb index 9d32938e155..f7c288f2393 100644 --- a/spec/lib/gitlab/quick_actions/extractor_spec.rb +++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb @@ -9,6 +9,11 @@ describe Gitlab::QuickActions::Extractor do command(:assign) { } command(:labels) { } command(:power) { } + command(:noop_command) + substitution(:substitution) { 'foo' } + substitution :shrug do |comment| + "#{comment} SHRUG" + end end.command_definitions end @@ -177,6 +182,38 @@ describe Gitlab::QuickActions::Extractor do expect(msg).to eq "hello\nworld" end + it 'does not extract noop commands' do + msg = %(hello\nworld\n/reopen\n/noop_command) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen']] + expect(msg).to eq "hello\nworld\n/noop_command" + end + + it 'extracts and performs substitution commands' do + msg = %(hello\nworld\n/reopen\n/substitution) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen'], ['substitution']] + expect(msg).to eq "hello\nworld\nfoo" + end + + it 'extracts and performs substitution commands' do + msg = %(hello\nworld\n/reopen\n/shrug this is great?) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen'], ['shrug', 'this is great?']] + expect(msg).to eq "hello\nworld\nthis is great? SHRUG" + end + + it 'extracts and performs substitution commands with comments' do + msg = %(hello\nworld\n/reopen\n/substitution wow this is a thing.) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen'], ['substitution', 'wow this is a thing.']] + expect(msg).to eq "hello\nworld\nfoo" + end + it 'extracts multiple commands' do msg = %(hello\n/power @user.name %9.10 ~"bar baz.2" label\nworld\n/reopen) msg, commands = extractor.extract_commands(msg) diff --git a/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb new file mode 100644 index 00000000000..1bb8bc51c96 --- /dev/null +++ b/spec/lib/gitlab/quick_actions/substitution_definition_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Gitlab::QuickActions::SubstitutionDefinition do + let(:content) do + <<EOF +Hello! Let's do this! +/sub_name I like this stuff +EOF + end + subject do + described_class.new(:sub_name, action_block: proc { |text| "#{text} foo" }) + end + + describe '#perform_substitution!' do + it 'returns nil if content is nil' do + expect(subject.perform_substitution(self, nil)).to be_nil + end + + it 'performs the substitution by default' do + expect(subject.perform_substitution(self, content)).to eq <<EOF +Hello! Let's do this! +I like this stuff foo +EOF + end + end + + describe '#match' do + it 'checks the content for the command' do + expect(subject.match(content)).to be_truthy + end + + it 'returns the match data' do + data = subject.match(content) + expect(data).to be_a(MatchData) + expect(data[1]).to eq('I like this stuff') + end + + it 'is nil if content does not have the command' do + expect(subject.match('blah')).to be_falsey + end + end +end diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 1a0357534f2..476a3f1998d 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::ReferenceExtractor do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do project.team << [project.creator, :developer] @@ -215,7 +215,7 @@ describe Gitlab::ReferenceExtractor do end context 'with a project with an underscore' do - let(:other_project) { create(:empty_project, path: 'test_project') } + let(:other_project) { create(:project, path: 'test_project') } let(:issue) { create(:issue, project: other_project) } before do diff --git a/spec/lib/gitlab/repo_path_spec.rb b/spec/lib/gitlab/repo_path_spec.rb index efea4f429bf..1a925a15e0c 100644 --- a/spec/lib/gitlab/repo_path_spec.rb +++ b/spec/lib/gitlab/repo_path_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ::Gitlab::RepoPath do describe '.parse' do - set(:project) { create(:project) } + set(:project) { create(:project, :repository) } context 'a repository storage path' do it 'parses a full repository path' do @@ -65,7 +65,7 @@ describe ::Gitlab::RepoPath do end describe '.find_project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:redirect) { project.route.create_redirect('foo/bar/baz') } context 'when finding a project by its canonical path' do diff --git a/spec/lib/gitlab/request_context_spec.rb b/spec/lib/gitlab/request_context_spec.rb index e272bdb9284..8a28ad0e597 100644 --- a/spec/lib/gitlab/request_context_spec.rb +++ b/spec/lib/gitlab/request_context_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::RequestContext do let(:env) { Hash.new } context 'when RequestStore::Middleware is used' do - around(:each) do |example| + around do |example| RequestStore::Middleware.new(-> (env) { example.run }).call({}) end diff --git a/spec/lib/gitlab/saml/user_spec.rb b/spec/lib/gitlab/saml/user_spec.rb index 2827a18515e..19710029224 100644 --- a/spec/lib/gitlab/saml/user_spec.rb +++ b/spec/lib/gitlab/saml/user_spec.rb @@ -109,7 +109,7 @@ describe Gitlab::Saml::User do end it 'does not throw an error' do - expect{ saml_user.save }.not_to raise_error + expect { saml_user.save }.not_to raise_error end end @@ -119,7 +119,7 @@ describe Gitlab::Saml::User do end it 'throws an error' do - expect{ saml_user.save }.to raise_error StandardError + expect { saml_user.save }.to raise_error StandardError end end end diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb index 31c3cd4d53c..4c5efbde69a 100644 --- a/spec/lib/gitlab/search_results_spec.rb +++ b/spec/lib/gitlab/search_results_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::SearchResults do let(:user) { create(:user) } - let!(:project) { create(:empty_project, name: 'foo') } + let!(:project) { create(:project, name: 'foo') } let!(:issue) { create(:issue, project: project, title: 'foo') } let!(:merge_request) do @@ -42,7 +42,7 @@ describe Gitlab::SearchResults do end it 'includes merge requests from source and target projects' do - forked_project = create(:empty_project, forked_from_project: project) + forked_project = create(:project, forked_from_project: project) merge_request_2 = create(:merge_request, target_project: project, source_project: forked_project, title: 'foo') results = described_class.new(user, Project.where(id: forked_project.id), 'foo') @@ -52,17 +52,17 @@ describe Gitlab::SearchResults do end it 'does not list issues on private projects' do - private_project = create(:empty_project, :private) + private_project = create(:project, :private) issue = create(:issue, project: private_project, title: 'foo') expect(results.objects('issues')).not_to include issue end describe 'confidential issues' do - let(:project_1) { create(:empty_project, :internal) } - let(:project_2) { create(:empty_project, :internal) } - let(:project_3) { create(:empty_project, :internal) } - let(:project_4) { create(:empty_project, :internal) } + let(:project_1) { create(:project, :internal) } + let(:project_2) { create(:project, :internal) } + let(:project_3) { create(:project, :internal) } + let(:project_4) { create(:project, :internal) } let(:query) { 'issue' } let(:limit_projects) { Project.where(id: [project_1.id, project_2.id, project_3.id]) } let(:author) { create(:user) } diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index b90d8dede0f..2345874cf10 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -174,20 +174,94 @@ describe Gitlab::Shell do end describe '#fetch_remote' do + def fetch_remote(ssh_auth = nil) + gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage', ssh_auth: ssh_auth) + end + + def expect_popen(vars = {}) + popen_args = [ + projects_path, + 'fetch-remote', + 'current/storage', + 'project/path.git', + 'new/storage', + Gitlab.config.gitlab_shell.git_timeout.to_s + ] + + expect(Gitlab::Popen).to receive(:popen).with(popen_args, nil, popen_vars.merge(vars)) + end + + def build_ssh_auth(opts = {}) + defaults = { + ssh_import?: true, + ssh_key_auth?: false, + ssh_known_hosts: nil, + ssh_private_key: nil + } + + double(:ssh_auth, defaults.merge(opts)) + end + it 'returns true when the command succeeds' do - expect(Gitlab::Popen).to receive(:popen) - .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'], - nil, popen_vars).and_return([nil, 0]) + expect_popen.and_return([nil, 0]) - expect(gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage')).to be true + expect(fetch_remote).to be_truthy end it 'raises an exception when the command fails' do - expect(Gitlab::Popen).to receive(:popen) - .with([projects_path, 'fetch-remote', 'current/storage', 'project/path.git', 'new/storage', '800'], - nil, popen_vars).and_return(["error", 1]) + expect_popen.and_return(["error", 1]) + + expect { fetch_remote }.to raise_error(Gitlab::Shell::Error, "error") + end + + context 'SSH auth' do + it 'passes the SSH key if specified' do + expect_popen('GITLAB_SHELL_SSH_KEY' => 'foo').and_return([nil, 0]) + + ssh_auth = build_ssh_auth(ssh_key_auth?: true, ssh_private_key: 'foo') + + expect(fetch_remote(ssh_auth)).to be_truthy + end + + it 'does not pass an empty SSH key' do + expect_popen.and_return([nil, 0]) + + ssh_auth = build_ssh_auth(ssh_key_auth: true, ssh_private_key: '') + + expect(fetch_remote(ssh_auth)).to be_truthy + end + + it 'does not pass the key unless SSH key auth is to be used' do + expect_popen.and_return([nil, 0]) + + ssh_auth = build_ssh_auth(ssh_key_auth: false, ssh_private_key: 'foo') + + expect(fetch_remote(ssh_auth)).to be_truthy + end + + it 'passes the known_hosts data if specified' do + expect_popen('GITLAB_SHELL_KNOWN_HOSTS' => 'foo').and_return([nil, 0]) + + ssh_auth = build_ssh_auth(ssh_known_hosts: 'foo') + + expect(fetch_remote(ssh_auth)).to be_truthy + end + + it 'does not pass empty known_hosts data' do + expect_popen.and_return([nil, 0]) + + ssh_auth = build_ssh_auth(ssh_known_hosts: '') + + expect(fetch_remote(ssh_auth)).to be_truthy + end + + it 'does not pass known_hosts data unless SSH is to be used' do + expect_popen(popen_vars).and_return([nil, 0]) + + ssh_auth = build_ssh_auth(ssh_import?: false, ssh_known_hosts: 'foo') - expect { gitlab_shell.fetch_remote('current/storage', 'project/path', 'new/storage') }.to raise_error(Gitlab::Shell::Error, "error") + expect(fetch_remote(ssh_auth)).to be_truthy + end end end diff --git a/spec/lib/gitlab/slash_commands/command_spec.rb b/spec/lib/gitlab/slash_commands/command_spec.rb index f0ecf59406a..0173a45d480 100644 --- a/spec/lib/gitlab/slash_commands/command_spec.rb +++ b/spec/lib/gitlab/slash_commands/command_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::SlashCommands::Command do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } describe '#execute' do @@ -11,7 +11,7 @@ describe Gitlab::SlashCommands::Command do context 'when no command is available' do let(:params) { { text: 'issue show 1' } } - let(:project) { create(:empty_project, has_external_issue_tracker: true) } + let(:project) { create(:project, has_external_issue_tracker: true) } it 'displays 404 messages' do expect(subject[:response_type]).to be(:ephemeral) @@ -80,7 +80,7 @@ describe Gitlab::SlashCommands::Command do it 'returns error' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to include('Too many actions defined') + expect(subject[:text]).to include("Couldn't find a deployment manual action.") end end end diff --git a/spec/lib/gitlab/slash_commands/deploy_spec.rb b/spec/lib/gitlab/slash_commands/deploy_spec.rb index e52aaed7328..74b5ef4bb26 100644 --- a/spec/lib/gitlab/slash_commands/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/deploy_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::SlashCommands::Deploy do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:regex_match) { described_class.match('deploy staging to production') } @@ -22,7 +22,7 @@ describe Gitlab::SlashCommands::Deploy do context 'if no environment is defined' do it 'does not execute an action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("No action found to be executed") + expect(subject[:text]).to eq "Couldn't find a deployment manual action." end end @@ -35,12 +35,12 @@ describe Gitlab::SlashCommands::Deploy do context 'without actions' do it 'does not execute an action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("No action found to be executed") + expect(subject[:text]).to eq "Couldn't find a deployment manual action." end end - context 'with action' do - let!(:manual1) do + context 'when single action has been matched' do + before do create(:ci_build, :manual, pipeline: pipeline, name: 'first', environment: 'production') @@ -48,31 +48,61 @@ describe Gitlab::SlashCommands::Deploy do it 'returns success result' do expect(subject[:response_type]).to be(:in_channel) - expect(subject[:text]).to start_with('Deployment started from staging to production') + expect(subject[:text]) + .to start_with('Deployment started from staging to production') end + end + + context 'when more than one action has been matched' do + context 'when there is no specific actions with a environment name' do + before do + create(:ci_build, :manual, pipeline: pipeline, + name: 'first', + environment: 'production') - context 'when duplicate action exists' do - let!(:manual2) do create(:ci_build, :manual, pipeline: pipeline, name: 'second', environment: 'production') end - it 'returns error' do + it 'returns error about too many actions defined' do + expect(subject[:text]).to eq("Couldn't find a deployment manual action.") expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq('Too many actions defined') end end - context 'when teardown action exists' do - let!(:teardown) do + context 'when one of the actions is environement specific action' do + before do + create(:ci_build, :manual, pipeline: pipeline, + name: 'first', + environment: 'production') + + create(:ci_build, :manual, pipeline: pipeline, + name: 'production', + environment: 'production') + end + + it 'deploys to production' do + expect(subject[:text]) + .to start_with('Deployment started from staging to production') + expect(subject[:response_type]).to be(:in_channel) + end + end + + context 'when one of the actions is a teardown action' do + before do + create(:ci_build, :manual, pipeline: pipeline, + name: 'first', + environment: 'production') + create(:ci_build, :manual, :teardown_environment, pipeline: pipeline, name: 'teardown', environment: 'production') end - it 'returns the success message' do + it 'deploys to production' do + expect(subject[:text]) + .to start_with('Deployment started from staging to production') expect(subject[:response_type]).to be(:in_channel) - expect(subject[:text]).to start_with('Deployment started from staging to production') end end end diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb index 5dfb1b506bc..75ae58d0582 100644 --- a/spec/lib/gitlab/slash_commands/issue_new_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::SlashCommands::IssueNew do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:regex_match) { described_class.match("issue create bird is the word") } diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb index e5409fe2339..51f59216413 100644 --- a/spec/lib/gitlab/slash_commands/issue_search_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb @@ -4,7 +4,7 @@ describe Gitlab::SlashCommands::IssueSearch do describe '#execute' do let!(:issue) { create(:issue, project: project, title: 'find me') } let!(:confidential) { create(:issue, :confidential, project: project, title: 'mepmep find') } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { issue.author } let(:regex_match) { described_class.match("issue search find") } diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb index f67a17c7922..08c380ca8f1 100644 --- a/spec/lib/gitlab/slash_commands/issue_show_spec.rb +++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::SlashCommands::IssueShow do describe '#execute' do let(:issue) { create(:issue, project: project) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { issue.author } let(:regex_match) { described_class.match("issue show #{issue.iid}") } diff --git a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb index dee3c77db27..d16d122c64e 100644 --- a/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/deploy_spec.rb @@ -17,8 +17,8 @@ describe Gitlab::SlashCommands::Presenters::Deploy do end end - describe '#no_actions' do - subject { described_class.new(nil).no_actions } + describe '#action_not_found' do + subject { described_class.new(nil).action_not_found } it { is_expected.to have_key(:text) } it { is_expected.to have_key(:response_type) } @@ -27,21 +27,7 @@ describe Gitlab::SlashCommands::Presenters::Deploy do it 'tells the user there is no action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("No action found to be executed") - end - end - - describe '#too_many_actions' do - subject { described_class.new([]).too_many_actions } - - it { is_expected.to have_key(:text) } - it { is_expected.to have_key(:response_type) } - it { is_expected.to have_key(:status) } - it { is_expected.not_to have_key(:attachments) } - - it 'tells the user there is no action' do - expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to eq("Too many actions defined") + expect(subject[:text]).to eq "Couldn't find a deployment manual action." end end end diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb index 7f81ebb47db..76e4bad88fd 100644 --- a/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/issue_new_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::SlashCommands::Presenters::IssueNew do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:attachment) { subject[:attachments].first } diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb index 7e57a0addcb..5a7ec0685fe 100644 --- a/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/issue_search_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::SlashCommands::Presenters::IssueSearch do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:message) { subject[:text] } before do diff --git a/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb index 2a6ed860737..8f607d7a9c9 100644 --- a/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb +++ b/spec/lib/gitlab/slash_commands/presenters/issue_show_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Gitlab::SlashCommands::Presenters::IssueShow do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:attachment) { subject[:attachments].first } diff --git a/spec/lib/gitlab/sql/union_spec.rb b/spec/lib/gitlab/sql/union_spec.rb index 5346881444d..baf8f6644bf 100644 --- a/spec/lib/gitlab/sql/union_spec.rb +++ b/spec/lib/gitlab/sql/union_spec.rb @@ -19,7 +19,7 @@ describe Gitlab::SQL::Union do empty_relation = User.none union = described_class.new([empty_relation, relation_1, relation_2]) - expect{User.where("users.id IN (#{union.to_sql})").to_a}.not_to raise_error + expect {User.where("users.id IN (#{union.to_sql})").to_a}.not_to raise_error expect(union.to_sql).to eq("#{to_sql(relation_1)}\nUNION\n#{to_sql(relation_2)}") end end diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb index bf45c8d16d6..7098499f996 100644 --- a/spec/lib/gitlab/template/issue_template_spec.rb +++ b/spec/lib/gitlab/template/issue_template_spec.rb @@ -1,41 +1,28 @@ require 'spec_helper' describe Gitlab::Template::IssueTemplate do - subject { described_class } - - let(:user) { create(:user) } - - let(:project) do - create(:project, - :repository, - create_template: { - user: user, - access: Gitlab::Access::MASTER, - path: 'issue_templates' - }) - end + let(:project) { create(:project, :repository, create_templates: :issue) } describe '.all' do it 'strips the md suffix' do - expect(subject.all(project).first.name).not_to end_with('.issue_template') + expect(described_class.all(project).first.name).not_to end_with('.issue_template') end it 'combines the globals and rest' do - all = subject.all(project).map(&:name) + all = described_class.all(project).map(&:name) expect(all).to include('bug') expect(all).to include('feature_proposal') - expect(all).to include('template_test') end end describe '.find' do it 'returns nil if the file does not exist' do - expect { subject.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) + expect { described_class.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) end it 'returns the issue object of a valid file' do - ruby = subject.find('bug', project) + ruby = described_class.find('bug', project) expect(ruby).to be_a described_class expect(ruby.name).to eq('bug') @@ -44,21 +31,17 @@ describe Gitlab::Template::IssueTemplate do describe '.by_category' do it 'return array of templates' do - all = subject.by_category('', project).map(&:name) + all = described_class.by_category('', project).map(&:name) expect(all).to include('bug') expect(all).to include('feature_proposal') - expect(all).to include('template_test') end context 'when repo is bare or empty' do - let(:empty_project) { create(:empty_project) } - - before do - empty_project.add_user(user, Gitlab::Access::MASTER) - end + let(:empty_project) { create(:project) } it "returns empty array" do - templates = subject.by_category('', empty_project) + templates = described_class.by_category('', empty_project) + expect(templates).to be_empty end end @@ -66,26 +49,23 @@ describe Gitlab::Template::IssueTemplate do describe '#content' do it 'loads the full file' do - issue_template = subject.new('.gitlab/issue_templates/bug.md', project) + issue_template = described_class.new('.gitlab/issue_templates/bug.md', project) expect(issue_template.name).to eq 'bug' expect(issue_template.content).to eq('something valid') end it 'raises error when file is not found' do - issue_template = subject.new('.gitlab/issue_templates/bugnot.md', project) + issue_template = described_class.new('.gitlab/issue_templates/bugnot.md', project) expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) end context "when repo is empty" do - let(:empty_project) { create(:empty_project) } - - before do - empty_project.add_user(user, Gitlab::Access::MASTER) - end + let(:empty_project) { create(:project) } it "raises file not found" do - issue_template = subject.new('.gitlab/issue_templates/not_existent.md', empty_project) + issue_template = described_class.new('.gitlab/issue_templates/not_existent.md', empty_project) + expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) end end diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb index 8479f92c8df..bd7ff64aa8a 100644 --- a/spec/lib/gitlab/template/merge_request_template_spec.rb +++ b/spec/lib/gitlab/template/merge_request_template_spec.rb @@ -1,41 +1,28 @@ require 'spec_helper' describe Gitlab::Template::MergeRequestTemplate do - subject { described_class } - - let(:user) { create(:user) } - - let(:project) do - create(:project, - :repository, - create_template: { - user: user, - access: Gitlab::Access::MASTER, - path: 'merge_request_templates' - }) - end + let(:project) { create(:project, :repository, create_templates: :merge_request) } describe '.all' do it 'strips the md suffix' do - expect(subject.all(project).first.name).not_to end_with('.issue_template') + expect(described_class.all(project).first.name).not_to end_with('.issue_template') end it 'combines the globals and rest' do - all = subject.all(project).map(&:name) + all = described_class.all(project).map(&:name) expect(all).to include('bug') expect(all).to include('feature_proposal') - expect(all).to include('template_test') end end describe '.find' do it 'returns nil if the file does not exist' do - expect { subject.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) + expect { described_class.find('mepmep-yadida', project) }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) end it 'returns the merge request object of a valid file' do - ruby = subject.find('bug', project) + ruby = described_class.find('bug', project) expect(ruby).to be_a described_class expect(ruby.name).to eq('bug') @@ -44,21 +31,17 @@ describe Gitlab::Template::MergeRequestTemplate do describe '.by_category' do it 'return array of templates' do - all = subject.by_category('', project).map(&:name) + all = described_class.by_category('', project).map(&:name) expect(all).to include('bug') expect(all).to include('feature_proposal') - expect(all).to include('template_test') end context 'when repo is bare or empty' do - let(:empty_project) { create(:empty_project) } - - before do - empty_project.add_user(user, Gitlab::Access::MASTER) - end + let(:empty_project) { create(:project) } it "returns empty array" do - templates = subject.by_category('', empty_project) + templates = described_class.by_category('', empty_project) + expect(templates).to be_empty end end @@ -66,26 +49,23 @@ describe Gitlab::Template::MergeRequestTemplate do describe '#content' do it 'loads the full file' do - issue_template = subject.new('.gitlab/merge_request_templates/bug.md', project) + issue_template = described_class.new('.gitlab/merge_request_templates/bug.md', project) expect(issue_template.name).to eq 'bug' expect(issue_template.content).to eq('something valid') end it 'raises error when file is not found' do - issue_template = subject.new('.gitlab/merge_request_templates/bugnot.md', project) + issue_template = described_class.new('.gitlab/merge_request_templates/bugnot.md', project) expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) end context "when repo is empty" do - let(:empty_project) { create(:empty_project) } - - before do - empty_project.add_user(user, Gitlab::Access::MASTER) - end + let(:empty_project) { create(:project) } it "raises file not found" do - issue_template = subject.new('.gitlab/merge_request_templates/not_existent.md', empty_project) + issue_template = described_class.new('.gitlab/merge_request_templates/not_existent.md', empty_project) + expect { issue_template.content }.to raise_error(Gitlab::Template::Finders::RepoTemplateFinder::FileNotFoundError) end end diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/uploads_transfer_spec.rb index 109559bb01c..4275e7b015b 100644 --- a/spec/lib/gitlab/uploads_transfer_spec.rb +++ b/spec/lib/gitlab/uploads_transfer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::UploadsTransfer do it 'leaves avatar uploads where they are' do - project_with_avatar = create(:empty_project, :with_avatar) + project_with_avatar = create(:project, :with_avatar) described_class.new.rename_namespace('project', 'project-renamed') diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb index f5b4882815f..f18823b61ef 100644 --- a/spec/lib/gitlab/url_blocker_spec.rb +++ b/spec/lib/gitlab/url_blocker_spec.rb @@ -20,6 +20,34 @@ describe Gitlab::UrlBlocker do expect(described_class.blocked_url?('https://gitlab.com:25/foo/foo.git')).to be true end + it 'returns true for a non-alphanumeric hostname' do + stub_resolv + + aggregate_failures do + expect(described_class).to be_blocked_url('ssh://-oProxyCommand=whoami/a') + + # The leading character here is a Unicode "soft hyphen" + expect(described_class).to be_blocked_url('ssh://ÂoProxyCommand=whoami/a') + + # Unicode alphanumerics are allowed + expect(described_class).not_to be_blocked_url('ssh://ÄŸitlab.com/a') + end + end + + it 'returns true for a non-alphanumeric username' do + stub_resolv + + aggregate_failures do + expect(described_class).to be_blocked_url('ssh://-oProxyCommand=whoami@example.com/a') + + # The leading character here is a Unicode "soft hyphen" + expect(described_class).to be_blocked_url('ssh://ÂoProxyCommand=whoami@example.com/a') + + # Unicode alphanumerics are allowed + expect(described_class).not_to be_blocked_url('ssh://ÄŸitlab@example.com/a') + end + end + it 'returns true for invalid URL' do expect(described_class.blocked_url?('http://:8080')).to be true end @@ -28,4 +56,10 @@ describe Gitlab::UrlBlocker do expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git')).to be false end end + + # Resolv does not support resolving UTF-8 domain names + # See https://bugs.ruby-lang.org/issues/4270 + def stub_resolv + allow(Resolv).to receive(:getaddresses).and_return([]) + end end diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index 50422020823..b81749cf428 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -8,7 +8,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(commit) - expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.path_with_namespace}/commit/#{commit.id}" + expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.full_path}/commit/#{commit.id}" end end @@ -18,7 +18,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(issue) - expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}" + expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.full_path}/issues/#{issue.iid}" end end @@ -28,7 +28,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(merge_request) - expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}" + expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.full_path}/merge_requests/#{merge_request.iid}" end end @@ -39,7 +39,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(note) - expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}" + expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.full_path}/commit/#{note.commit_id}#note_#{note.id}" end end @@ -49,7 +49,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(note) - expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}" + expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.full_path}/commit/#{note.commit_id}#note_#{note.id}" end end @@ -60,7 +60,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(note) - expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}" + expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.full_path}/issues/#{issue.iid}#note_#{note.id}" end end @@ -71,7 +71,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(note) - expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}" + expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.full_path}/merge_requests/#{merge_request.iid}#note_#{note.id}" end end @@ -82,7 +82,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(note) - expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}" + expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.full_path}/merge_requests/#{merge_request.iid}#note_#{note.id}" end end @@ -93,7 +93,7 @@ describe Gitlab::UrlBuilder do url = described_class.build(note) - expect(url).to eq "#{Settings.gitlab['url']}/#{project_snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}" + expect(url).to eq "#{Settings.gitlab['url']}/#{project_snippet.project.full_path}/snippets/#{note.noteable_id}#note_#{note.id}" end end @@ -110,7 +110,7 @@ describe Gitlab::UrlBuilder do context 'on another object' do it 'returns a proper URL' do - project = build_stubbed(:empty_project) + project = build_stubbed(:project) expect { described_class.build(project) } .to raise_error(NotImplementedError, 'No URL builder defined for Project') diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index 5ebaf6c1507..cd97416bcc9 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Gitlab::UserAccess do let(:access) { described_class.new(user, project: project) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:user) { create(:user) } describe '#can_push_to_branch?' do diff --git a/spec/lib/gitlab/version_info_spec.rb b/spec/lib/gitlab/version_info_spec.rb index e7e1a92ae54..c8a1e433d59 100644 --- a/spec/lib/gitlab/version_info_spec.rb +++ b/spec/lib/gitlab/version_info_spec.rb @@ -50,8 +50,8 @@ describe 'Gitlab::VersionInfo' do context 'unknown' do it { expect(@unknown).not_to be @v0_0_1 } it { expect(@unknown).not_to be Gitlab::VersionInfo.new } - it { expect{@unknown > @v0_0_1}.to raise_error(ArgumentError) } - it { expect{@unknown < @v0_0_1}.to raise_error(ArgumentError) } + it { expect {@unknown > @v0_0_1}.to raise_error(ArgumentError) } + it { expect {@unknown < @v0_0_1}.to raise_error(ArgumentError) } end context 'parse' do diff --git a/spec/lib/gitlab/view/presenter/base_spec.rb b/spec/lib/gitlab/view/presenter/base_spec.rb index f2c152cdcd4..32a946ca034 100644 --- a/spec/lib/gitlab/view/presenter/base_spec.rb +++ b/spec/lib/gitlab/view/presenter/base_spec.rb @@ -26,7 +26,7 @@ describe Gitlab::View::Presenter::Base do describe '#can?' do context 'user is not allowed' do it 'returns false' do - presenter = presenter_class.new(build_stubbed(:empty_project)) + presenter = presenter_class.new(build_stubbed(:project)) expect(presenter.can?(nil, :read_project)).to be_falsy end @@ -34,7 +34,7 @@ describe Gitlab::View::Presenter::Base do context 'user is allowed' do it 'returns true' do - presenter = presenter_class.new(build_stubbed(:empty_project, :public)) + presenter = presenter_class.new(build_stubbed(:project, :public)) expect(presenter.can?(nil, :read_project)).to be_truthy end @@ -42,9 +42,9 @@ describe Gitlab::View::Presenter::Base do context 'subject is overriden' do it 'returns true' do - presenter = presenter_class.new(build_stubbed(:empty_project, :public)) + presenter = presenter_class.new(build_stubbed(:project, :public)) - expect(presenter.can?(nil, :read_project, build_stubbed(:empty_project))).to be_falsy + expect(presenter.can?(nil, :read_project, build_stubbed(:project))).to be_falsy end end end diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 654397ccffb..b66afafa174 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -202,7 +202,6 @@ describe Gitlab::Workhorse do context 'when Gitaly is enabled' do let(:gitaly_params) do { - GitalyAddress: Gitlab::GitalyClient.address('default'), GitalyServer: { address: Gitlab::GitalyClient.address('default'), token: Gitlab::GitalyClient.token('default') @@ -217,7 +216,9 @@ describe Gitlab::Workhorse do it 'includes a Repository param' do repo_param = { Repository: { storage_name: 'default', - relative_path: project.full_path + '.git' + relative_path: project.full_path + '.git', + git_object_directory: '', + git_alternate_object_directories: [] } } expect(subject).to include(repo_param) diff --git a/spec/lib/json_web_token/rsa_token_spec.rb b/spec/lib/json_web_token/rsa_token_spec.rb index e7022bd06f8..d6edc964844 100644 --- a/spec/lib/json_web_token/rsa_token_spec.rb +++ b/spec/lib/json_web_token/rsa_token_spec.rb @@ -27,7 +27,7 @@ describe JSONWebToken::RSAToken do subject { JWT.decode(rsa_encoded, rsa_key) } - it { expect{subject}.not_to raise_error } + it { expect {subject}.not_to raise_error } it { expect(subject.first).to include('key' => 'value') } it do expect(subject.second).to eq( @@ -41,7 +41,7 @@ describe JSONWebToken::RSAToken do let(:new_key) { OpenSSL::PKey::RSA.generate(512) } subject { JWT.decode(rsa_encoded, new_key) } - it { expect{subject}.to raise_error(JWT::DecodeError) } + it { expect {subject}.to raise_error(JWT::DecodeError) } end end end diff --git a/spec/lib/mattermost/session_spec.rb b/spec/lib/mattermost/session_spec.rb index be3908e8f6a..3db19d06305 100644 --- a/spec/lib/mattermost/session_spec.rb +++ b/spec/lib/mattermost/session_spec.rb @@ -20,9 +20,10 @@ describe Mattermost::Session, type: :request do describe '#with session' do let(:location) { 'http://location.tld' } + let(:cookie_header) {'MMOAUTH=taskik8az7rq8k6rkpuas7htia; Path=/;'} let!(:stub) do WebMock.stub_request(:get, "#{mattermost_url}/api/v3/oauth/gitlab/login") - .to_return(headers: { 'location' => location }, status: 307) + .to_return(headers: { 'location' => location, 'Set-Cookie' => cookie_header }, status: 307) end context 'without oauth uri' do @@ -34,9 +35,9 @@ describe Mattermost::Session, type: :request do context 'with oauth_uri' do let!(:doorkeeper) do Doorkeeper::Application.create( - name: "GitLab Mattermost", + name: 'GitLab Mattermost', redirect_uri: "#{mattermost_url}/signup/gitlab/complete\n#{mattermost_url}/login/gitlab/complete", - scopes: "") + scopes: '') end context 'without token_uri' do diff --git a/spec/lib/repository_cache_spec.rb b/spec/lib/repository_cache_spec.rb index 0c15ba22bf2..8b0c7254b5e 100644 --- a/spec/lib/repository_cache_spec.rb +++ b/spec/lib/repository_cache_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe RepositoryCache do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:backend) { double('backend').as_null_object } let(:cache) { described_class.new('example', project.id, backend) } diff --git a/spec/lib/rspec_flaky/example_spec.rb b/spec/lib/rspec_flaky/example_spec.rb new file mode 100644 index 00000000000..5b4fd5ddf3e --- /dev/null +++ b/spec/lib/rspec_flaky/example_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe RspecFlaky::Example do + let(:example_attrs) do + { + id: 'spec/foo/bar_spec.rb:2', + metadata: { + file_path: 'spec/foo/bar_spec.rb', + line_number: 2, + full_description: 'hello world' + }, + execution_result: double(status: 'passed', exception: 'BOOM!'), + attempts: 1 + } + end + let(:rspec_example) { double(example_attrs) } + + describe '#initialize' do + shared_examples 'a valid Example instance' do + it 'returns valid attributes' do + example = described_class.new(args) + + expect(example.example_id).to eq(example_attrs[:id]) + end + end + + context 'when given an Rspec::Core::Example that responds to #example' do + let(:args) { double(example: rspec_example) } + + it_behaves_like 'a valid Example instance' + end + + context 'when given an Rspec::Core::Example that does not respond to #example' do + let(:args) { rspec_example } + + it_behaves_like 'a valid Example instance' + end + end + + subject { described_class.new(rspec_example) } + + describe '#uid' do + it 'returns a hash of the full description' do + expect(subject.uid).to eq(Digest::MD5.hexdigest("#{subject.description}-#{subject.file}")) + end + end + + describe '#example_id' do + it 'returns the ID of the RSpec::Core::Example' do + expect(subject.example_id).to eq(rspec_example.id) + end + end + + describe '#attempts' do + it 'returns the attempts of the RSpec::Core::Example' do + expect(subject.attempts).to eq(rspec_example.attempts) + end + end + + describe '#file' do + it 'returns the metadata[:file_path] of the RSpec::Core::Example' do + expect(subject.file).to eq(rspec_example.metadata[:file_path]) + end + end + + describe '#line' do + it 'returns the metadata[:line_number] of the RSpec::Core::Example' do + expect(subject.line).to eq(rspec_example.metadata[:line_number]) + end + end + + describe '#description' do + it 'returns the metadata[:full_description] of the RSpec::Core::Example' do + expect(subject.description).to eq(rspec_example.metadata[:full_description]) + end + end + + describe '#status' do + it 'returns the execution_result.status of the RSpec::Core::Example' do + expect(subject.status).to eq(rspec_example.execution_result.status) + end + end + + describe '#exception' do + it 'returns the execution_result.exception of the RSpec::Core::Example' do + expect(subject.exception).to eq(rspec_example.execution_result.exception) + end + end +end diff --git a/spec/lib/rspec_flaky/flaky_example_spec.rb b/spec/lib/rspec_flaky/flaky_example_spec.rb new file mode 100644 index 00000000000..cbfc1e538ab --- /dev/null +++ b/spec/lib/rspec_flaky/flaky_example_spec.rb @@ -0,0 +1,104 @@ +require 'spec_helper' + +describe RspecFlaky::FlakyExample do + let(:flaky_example_attrs) do + { + example_id: 'spec/foo/bar_spec.rb:2', + file: 'spec/foo/bar_spec.rb', + line: 2, + description: 'hello world', + first_flaky_at: 1234, + last_flaky_at: 2345, + last_attempts_count: 2, + flaky_reports: 1 + } + end + let(:example_attrs) do + { + uid: 'abc123', + example_id: flaky_example_attrs[:example_id], + file: flaky_example_attrs[:file], + line: flaky_example_attrs[:line], + description: flaky_example_attrs[:description], + status: 'passed', + exception: 'BOOM!', + attempts: flaky_example_attrs[:last_attempts_count] + } + end + let(:example) { double(example_attrs) } + + describe '#initialize' do + shared_examples 'a valid FlakyExample instance' do + it 'returns valid attributes' do + flaky_example = described_class.new(args) + + expect(flaky_example.uid).to eq(flaky_example_attrs[:uid]) + expect(flaky_example.example_id).to eq(flaky_example_attrs[:example_id]) + end + end + + context 'when given an Rspec::Example' do + let(:args) { example } + + it_behaves_like 'a valid FlakyExample instance' + end + + context 'when given a hash' do + let(:args) { flaky_example_attrs } + + it_behaves_like 'a valid FlakyExample instance' + end + end + + describe '#to_h' do + before do + # Stub these env variables otherwise specs don't behave the same on the CI + stub_env('CI_PROJECT_URL', nil) + stub_env('CI_JOB_ID', nil) + end + + shared_examples 'a valid FlakyExample hash' do + let(:additional_attrs) { {} } + + it 'returns a valid hash' do + flaky_example = described_class.new(args) + final_hash = flaky_example_attrs + .merge(last_flaky_at: instance_of(Time), last_flaky_job: nil) + .merge(additional_attrs) + + expect(flaky_example.to_h).to match(hash_including(final_hash)) + end + end + + context 'when given an Rspec::Example' do + let(:args) { example } + + context 'when run locally' do + it_behaves_like 'a valid FlakyExample hash' do + let(:additional_attrs) do + { first_flaky_at: instance_of(Time) } + end + end + end + + context 'when run on the CI' do + before do + stub_env('CI_PROJECT_URL', 'https://gitlab.com/gitlab-org/gitlab-ce') + stub_env('CI_JOB_ID', 42) + end + + it_behaves_like 'a valid FlakyExample hash' do + let(:additional_attrs) do + { first_flaky_at: instance_of(Time), last_flaky_job: "https://gitlab.com/gitlab-org/gitlab-ce/-/jobs/42" } + end + end + end + end + + context 'when given a hash' do + let(:args) { flaky_example_attrs } + + it_behaves_like 'a valid FlakyExample hash' + end + end +end diff --git a/spec/lib/rspec_flaky/listener_spec.rb b/spec/lib/rspec_flaky/listener_spec.rb new file mode 100644 index 00000000000..0e193bf408b --- /dev/null +++ b/spec/lib/rspec_flaky/listener_spec.rb @@ -0,0 +1,178 @@ +require 'spec_helper' + +describe RspecFlaky::Listener do + let(:flaky_example_report) do + { + 'abc123' => { + example_id: 'spec/foo/bar_spec.rb:2', + file: 'spec/foo/bar_spec.rb', + line: 2, + description: 'hello world', + first_flaky_at: 1234, + last_flaky_at: instance_of(Time), + last_attempts_count: 2, + flaky_reports: 1, + last_flaky_job: nil + } + } + end + let(:example_attrs) do + { + id: 'spec/foo/baz_spec.rb:3', + metadata: { + file_path: 'spec/foo/baz_spec.rb', + line_number: 3, + full_description: 'hello GitLab' + }, + execution_result: double(status: 'passed', exception: nil) + } + end + + before do + # Stub these env variables otherwise specs don't behave the same on the CI + stub_env('CI_PROJECT_URL', nil) + stub_env('CI_JOB_ID', nil) + end + + describe '#initialize' do + shared_examples 'a valid Listener instance' do + let(:expected_all_flaky_examples) { {} } + + it 'returns a valid Listener instance' do + listener = described_class.new + + expect(listener.to_report(listener.all_flaky_examples)) + .to match(hash_including(expected_all_flaky_examples)) + expect(listener.new_flaky_examples).to eq({}) + end + end + + context 'when no report file exists' do + it_behaves_like 'a valid Listener instance' + end + + context 'when a report file exists and set by ALL_FLAKY_RSPEC_REPORT_PATH' do + let(:report_file) do + Tempfile.new(%w[rspec_flaky_report .json]).tap do |f| + f.write(JSON.pretty_generate(flaky_example_report)) + f.rewind + end + end + + before do + stub_env('ALL_FLAKY_RSPEC_REPORT_PATH', report_file.path) + end + + after do + report_file.close + report_file.unlink + end + + it_behaves_like 'a valid Listener instance' do + let(:expected_all_flaky_examples) { flaky_example_report } + end + end + end + + describe '#example_passed' do + let(:rspec_example) { double(example_attrs) } + let(:notification) { double(example: rspec_example) } + + shared_examples 'a non-flaky example' do + it 'does not change the flaky examples hash' do + expect { subject.example_passed(notification) } + .not_to change { subject.all_flaky_examples } + end + end + + describe 'when the RSpec example does not respond to attempts' do + it_behaves_like 'a non-flaky example' + end + + describe 'when the RSpec example has 1 attempt' do + let(:rspec_example) { double(example_attrs.merge(attempts: 1)) } + + it_behaves_like 'a non-flaky example' + end + + describe 'when the RSpec example has 2 attempts' do + let(:rspec_example) { double(example_attrs.merge(attempts: 2)) } + let(:expected_new_flaky_example) do + { + example_id: 'spec/foo/baz_spec.rb:3', + file: 'spec/foo/baz_spec.rb', + line: 3, + description: 'hello GitLab', + first_flaky_at: instance_of(Time), + last_flaky_at: instance_of(Time), + last_attempts_count: 2, + flaky_reports: 1, + last_flaky_job: nil + } + end + + it 'does not change the flaky examples hash' do + expect { subject.example_passed(notification) } + .to change { subject.all_flaky_examples } + + new_example = RspecFlaky::Example.new(rspec_example) + + expect(subject.all_flaky_examples[new_example.uid].to_h) + .to match(hash_including(expected_new_flaky_example)) + end + end + end + + describe '#dump_summary' do + let(:rspec_example) { double(example_attrs) } + let(:notification) { double(example: rspec_example) } + + context 'when a report file path is set by ALL_FLAKY_RSPEC_REPORT_PATH' do + let(:report_file_path) { Rails.root.join('tmp', 'rspec_flaky_report.json') } + + before do + stub_env('ALL_FLAKY_RSPEC_REPORT_PATH', report_file_path) + FileUtils.rm(report_file_path) if File.exist?(report_file_path) + end + + after do + FileUtils.rm(report_file_path) if File.exist?(report_file_path) + end + + context 'when FLAKY_RSPEC_GENERATE_REPORT == "false"' do + before do + stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'false') + end + + it 'does not write the report file' do + subject.example_passed(notification) + + subject.dump_summary(nil) + + expect(File.exist?(report_file_path)).to be(false) + end + end + + context 'when FLAKY_RSPEC_GENERATE_REPORT == "true"' do + before do + stub_env('FLAKY_RSPEC_GENERATE_REPORT', 'true') + end + + it 'writes the report file' do + subject.example_passed(notification) + + subject.dump_summary(nil) + + expect(File.exist?(report_file_path)).to be(true) + end + end + end + end + + describe '#to_report' do + it 'transforms the internal hash to a JSON-ready hash' do + expect(subject.to_report('abc123' => RspecFlaky::FlakyExample.new(flaky_example_report['abc123']))) + .to match(hash_including(flaky_example_report)) + end + end +end diff --git a/spec/lib/system_check/simple_executor_spec.rb b/spec/lib/system_check/simple_executor_spec.rb index 025ea2673b4..4de5da984ba 100644 --- a/spec/lib/system_check/simple_executor_spec.rb +++ b/spec/lib/system_check/simple_executor_spec.rb @@ -240,7 +240,7 @@ describe SystemCheck::SimpleExecutor do context 'when there is an exception' do it 'rescues the exception' do - expect{ subject.run_check(BugousCheck) }.not_to raise_exception + expect { subject.run_check(BugousCheck) }.not_to raise_exception end end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 683e893968b..1fa59ebd22b 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -348,7 +348,7 @@ describe Notify do end describe 'project was moved' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } subject { described_class.project_was_moved_email(project.id, user.id, "gitlab/gitlab") } @@ -366,7 +366,7 @@ describe Notify do describe 'project access requested' do context 'for a project in a user namespace' do let(:project) do - create(:empty_project, :public, :access_requestable) do |project| + create(:project, :public, :access_requestable) do |project| project.team << [project.owner, :master, project.owner] end end @@ -397,7 +397,7 @@ describe Notify do context 'for a project in a group' do let(:group_owner) { create(:user) } let(:group) { create(:group).tap { |g| g.add_owner(group_owner) } } - let(:project) { create(:empty_project, :public, :access_requestable, namespace: group) } + let(:project) { create(:project, :public, :access_requestable, namespace: group) } let(:user) { create(:user) } let(:project_member) do project.request_access(user) @@ -423,7 +423,7 @@ describe Notify do end describe 'project access denied' do - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:user) { create(:user) } let(:project_member) do project.request_access(user) @@ -444,7 +444,7 @@ describe Notify do describe 'project access changed' do let(:owner) { create(:user, name: "Chang O'Keefe") } - let(:project) { create(:empty_project, :public, :access_requestable, namespace: owner.namespace) } + let(:project) { create(:project, :public, :access_requestable, namespace: owner.namespace) } let(:user) { create(:user) } let(:project_member) { create(:project_member, project: project, user: user) } subject { described_class.member_access_granted_email('project', project_member.id) } @@ -474,7 +474,7 @@ describe Notify do end describe 'project invitation' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:master) { create(:user).tap { |u| project.team << [u, :master] } } let(:project_member) { invite_to_project(project, inviter: master) } @@ -494,7 +494,7 @@ describe Notify do end describe 'project invitation accepted' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:invited_user) { create(:user, name: 'invited user') } let(:master) { create(:user).tap { |u| project.team << [u, :master] } } let(:project_member) do @@ -519,7 +519,7 @@ describe Notify do end describe 'project invitation declined' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:master) { create(:user).tap { |u| project.team << [u, :master] } } let(:project_member) do invitee = invite_to_project(project, inviter: master) @@ -545,7 +545,7 @@ describe Notify do let(:note_author) { create(:user, name: 'author_name') } let(:note) { create(:note, project: project, author: note_author) } - before :each do + before do allow(Note).to receive(:find).with(note.id).and_return(note) end @@ -661,7 +661,7 @@ describe Notify do let(:project) { create(:project, :repository) } let(:note_author) { create(:user, name: 'author_name') } - before :each do + before do allow(Note).to receive(:find).with(note.id).and_return(note) end @@ -779,7 +779,7 @@ describe Notify do context 'items that are noteable, the email for a diff discussion note' do let(:note_author) { create(:user, name: 'author_name') } - before :each do + before do allow(Note).to receive(:find).with(note.id).and_return(note) end @@ -1242,7 +1242,7 @@ describe Notify do end describe 'HTML emails setting' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:multipart_mail) { described_class.project_was_moved_email(project.id, user.id, "gitlab/gitlab") } diff --git a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb b/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb index 65bea662b02..862907c5d01 100644 --- a/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb +++ b/spec/migrations/add_head_pipeline_for_each_merge_request_spec.rb @@ -4,7 +4,7 @@ require Rails.root.join('db', 'post_migrate', '20170508170547_add_head_pipeline_ describe AddHeadPipelineForEachMergeRequest, :truncate do let(:migration) { described_class.new } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let!(:forked_project_link) { create(:forked_project_link, forked_from_project: project) } let!(:other_project) { forked_project_link.forked_to_project } diff --git a/spec/migrations/calculate_conv_dev_index_percentages_spec.rb b/spec/migrations/calculate_conv_dev_index_percentages_spec.rb new file mode 100644 index 00000000000..597d8eab51c --- /dev/null +++ b/spec/migrations/calculate_conv_dev_index_percentages_spec.rb @@ -0,0 +1,41 @@ +# encoding: utf-8 + +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170803090603_calculate_conv_dev_index_percentages.rb') + +describe CalculateConvDevIndexPercentages, truncate: true do + let(:migration) { described_class.new } + let!(:conv_dev_index) do + create(:conversational_development_index_metric, + leader_notes: 0, + instance_milestones: 0, + percentage_issues: 0, + percentage_notes: 0, + percentage_milestones: 0, + percentage_boards: 0, + percentage_merge_requests: 0, + percentage_ci_pipelines: 0, + percentage_environments: 0, + percentage_deployments: 0, + percentage_projects_prometheus_active: 0, + percentage_service_desk_issues: 0) + end + + describe '#up' do + it 'calculates percentages correctly' do + migration.up + conv_dev_index.reload + + expect(conv_dev_index.percentage_issues).to be_within(0.1).of(13.3) + expect(conv_dev_index.percentage_notes).to be_zero # leader 0 + expect(conv_dev_index.percentage_milestones).to be_zero # instance 0 + expect(conv_dev_index.percentage_boards).to be_within(0.1).of(62.4) + expect(conv_dev_index.percentage_merge_requests).to eq(50.0) + expect(conv_dev_index.percentage_ci_pipelines).to be_within(0.1).of(19.3) + expect(conv_dev_index.percentage_environments).to be_within(0.1).of(66.7) + expect(conv_dev_index.percentage_deployments).to be_within(0.1).of(64.2) + expect(conv_dev_index.percentage_projects_prometheus_active).to be_within(0.1).of(98.2) + expect(conv_dev_index.percentage_service_desk_issues).to be_within(0.1).of(84.0) + end + end +end diff --git a/spec/migrations/clean_upload_symlinks_spec.rb b/spec/migrations/clean_upload_symlinks_spec.rb index cecb3ddac53..26653b9c008 100644 --- a/spec/migrations/clean_upload_symlinks_spec.rb +++ b/spec/migrations/clean_upload_symlinks_spec.rb @@ -5,7 +5,7 @@ describe CleanUploadSymlinks do let(:migration) { described_class.new } let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_uploads_test") } let(:uploads_dir) { File.join(test_dir, "public", "uploads") } - let(:new_uploads_dir) { File.join(uploads_dir, "system") } + let(:new_uploads_dir) { File.join(uploads_dir, "-", "system") } let(:original_path) { File.join(new_uploads_dir, 'user') } let(:symlink_path) { File.join(uploads_dir, 'user') } diff --git a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb index 49e750a3f4d..12cac1d033d 100644 --- a/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb +++ b/spec/migrations/cleanup_namespaceless_pending_delete_projects_spec.rb @@ -4,15 +4,15 @@ require Rails.root.join('db', 'post_migrate', '20170502101023_cleanup_namespacel describe CleanupNamespacelessPendingDeleteProjects do before do # Stub after_save callbacks that will fail when Project has no namespace - allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(nil) + allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil) allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil) end describe '#up' do it 'only cleans up pending delete projects' do - create(:empty_project) - create(:empty_project, pending_delete: true) - project = build(:empty_project, pending_delete: true, namespace_id: nil) + create(:project) + create(:project, pending_delete: true) + project = build(:project, pending_delete: true, namespace_id: nil) project.save(validate: false) expect(NamespacelessProjectDestroyWorker).to receive(:bulk_perform_async).with([[project.id]]) @@ -21,8 +21,8 @@ describe CleanupNamespacelessPendingDeleteProjects do end it 'does nothing when no pending delete projects without namespace found' do - create(:empty_project) - create(:empty_project, pending_delete: true) + create(:project) + create(:project, pending_delete: true) expect(NamespacelessProjectDestroyWorker).not_to receive(:bulk_perform_async) diff --git a/spec/migrations/fix_wrongly_renamed_routes_spec.rb b/spec/migrations/fix_wrongly_renamed_routes_spec.rb index 148290b0e7d..5ef10b92a3a 100644 --- a/spec/migrations/fix_wrongly_renamed_routes_spec.rb +++ b/spec/migrations/fix_wrongly_renamed_routes_spec.rb @@ -37,7 +37,7 @@ describe FixWronglyRenamedRoutes, truncate: true do describe '#routes_in_namespace_query' do it 'includes only the required routes' do namespace = create(:group, path: 'hello') - project = create(:empty_project, namespace: namespace) + project = create(:project, namespace: namespace) _other_namespace = create(:group, path: 'hello0') result = Route.where(subject.routes_in_namespace_query('hello')) @@ -48,7 +48,7 @@ describe FixWronglyRenamedRoutes, truncate: true do describe '#up' do let(:broken_project) do - project = create(:empty_project, namespace: broken_namespace, path: 'broken-project') + project = create(:project, namespace: broken_namespace, path: 'broken-project') project.route.update_attribute(:path, 'api0is/broken-project') project end diff --git a/spec/migrations/migrate_old_artifacts_spec.rb b/spec/migrations/migrate_old_artifacts_spec.rb index 50f4bbda001..cfe1ca481b2 100644 --- a/spec/migrations/migrate_old_artifacts_spec.rb +++ b/spec/migrations/migrate_old_artifacts_spec.rb @@ -16,9 +16,9 @@ describe MigrateOldArtifacts do end context 'with migratable data' do - let(:project1) { create(:empty_project, ci_id: 2) } - let(:project2) { create(:empty_project, ci_id: 3) } - let(:project3) { create(:empty_project) } + let(:project1) { create(:project, ci_id: 2) } + let(:project2) { create(:project, ci_id: 3) } + let(:project3) { create(:project) } let(:pipeline1) { create(:ci_empty_pipeline, project: project1) } let(:pipeline2) { create(:ci_empty_pipeline, project: project2) } diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb index 5b633dd349b..e5793a3c0ee 100644 --- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb +++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb @@ -6,7 +6,7 @@ require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_ describe MigrateProcessCommitWorkerJobs do let(:project) { create(:project, :repository) } let(:user) { create(:user) } - let(:commit) { project.commit.raw.raw_commit } + let(:commit) { project.commit.raw.rugged_commit } describe 'Project' do describe 'find_including_path' do @@ -20,7 +20,7 @@ describe MigrateProcessCommitWorkerJobs do .find_including_path(project.id) expect(migration_project[:path_with_namespace]) - .to eq(project.path_with_namespace) + .to eq(project.full_path) end end diff --git a/spec/migrations/move_personal_snippets_files_spec.rb b/spec/migrations/move_personal_snippets_files_spec.rb index 8505c7bf3e3..1a319eccc0d 100644 --- a/spec/migrations/move_personal_snippets_files_spec.rb +++ b/spec/migrations/move_personal_snippets_files_spec.rb @@ -5,7 +5,7 @@ describe MovePersonalSnippetsFiles do let(:migration) { described_class.new } let(:test_dir) { File.join(Rails.root, "tmp", "tests", "move_snippet_files_test") } let(:uploads_dir) { File.join(test_dir, 'uploads') } - let(:new_uploads_dir) { File.join(uploads_dir, 'system') } + let(:new_uploads_dir) { File.join(uploads_dir, '-', 'system') } before do allow(CarrierWave).to receive(:root).and_return(test_dir) @@ -42,7 +42,7 @@ describe MovePersonalSnippetsFiles do describe 'updating the markdown' do it 'includes the new path when the file exists' do secret = "secret#{snippet.id}" - file_location = "/uploads/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg" + file_location = "/uploads/-/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg" migration.up @@ -60,7 +60,7 @@ describe MovePersonalSnippetsFiles do it 'updates the note markdown' do secret = "secret#{snippet.id}" - file_location = "/uploads/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg" + file_location = "/uploads/-/system/personal_snippet/#{snippet.id}/#{secret}/picture.jpg" markdown = markdown_linking_file('picture.jpg', snippet) note = create(:note_on_personal_snippet, noteable: snippet, note: "with #{markdown}") @@ -108,7 +108,7 @@ describe MovePersonalSnippetsFiles do it 'keeps the markdown as is when the file is missing' do secret = "secret#{snippet_with_missing_file.id}" - file_location = "/uploads/system/personal_snippet/#{snippet_with_missing_file.id}/#{secret}/picture.jpg" + file_location = "/uploads/-/system/personal_snippet/#{snippet_with_missing_file.id}/#{secret}/picture.jpg" migration.down @@ -167,7 +167,7 @@ describe MovePersonalSnippetsFiles do def markdown_linking_file(filename, snippet, in_new_path: false) markdown = "![#{filename.split('.')[0]}]" markdown += '(/uploads' - markdown += '/system' if in_new_path + markdown += '/-/system' if in_new_path markdown += "/#{model_file_path(filename, snippet)})" markdown end diff --git a/spec/migrations/move_system_upload_folder_spec.rb b/spec/migrations/move_system_upload_folder_spec.rb index b622b4e9536..d3180477db3 100644 --- a/spec/migrations/move_system_upload_folder_spec.rb +++ b/spec/migrations/move_system_upload_folder_spec.rb @@ -33,6 +33,15 @@ describe MoveSystemUploadFolder do expect(File.symlink?(File.join(test_base, 'system'))).to be_truthy expect(File.exist?(File.join(test_base, 'system', 'file'))).to be_truthy end + + it 'does not move if the target directory already exists' do + FileUtils.mkdir_p(File.join(test_base, '-', 'system')) + + expect(FileUtils).not_to receive(:mv) + expect(migration).to receive(:say).with(/already exists. No need to redo the move/) + + migration.up + end end describe '#down' do @@ -58,5 +67,14 @@ describe MoveSystemUploadFolder do expect(File.directory?(File.join(test_base, 'system'))).to be_truthy expect(File.symlink?(File.join(test_base, 'system'))).to be_falsey end + + it 'does not move if the old directory already exists' do + FileUtils.mkdir_p(File.join(test_base, 'system')) + + expect(FileUtils).not_to receive(:mv) + expect(migration).to receive(:say).with(/already exists and is not a symlink, no need to revert/) + + migration.down + end end end diff --git a/spec/migrations/move_uploads_to_system_dir_spec.rb b/spec/migrations/move_uploads_to_system_dir_spec.rb index 37d66452447..ca11a2004c5 100644 --- a/spec/migrations/move_uploads_to_system_dir_spec.rb +++ b/spec/migrations/move_uploads_to_system_dir_spec.rb @@ -5,7 +5,7 @@ describe MoveUploadsToSystemDir do let(:migration) { described_class.new } let(:test_dir) { File.join(Rails.root, "tmp", "move_uploads_test") } let(:uploads_dir) { File.join(test_dir, "public", "uploads") } - let(:new_uploads_dir) { File.join(uploads_dir, "system") } + let(:new_uploads_dir) { File.join(uploads_dir, "-", "system") } before do FileUtils.remove_dir(test_dir) if File.directory?(test_dir) diff --git a/spec/migrations/rename_more_reserved_project_names_spec.rb b/spec/migrations/rename_more_reserved_project_names_spec.rb index 4bd8d4ac0d1..ae3a4cb9b29 100644 --- a/spec/migrations/rename_more_reserved_project_names_spec.rb +++ b/spec/migrations/rename_more_reserved_project_names_spec.rb @@ -8,7 +8,7 @@ require Rails.root.join('db', 'post_migrate', '20170313133418_rename_more_reserv # around this we use the TRUNCATE cleaning strategy. describe RenameMoreReservedProjectNames, truncate: true do let(:migration) { described_class.new } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } before do project.path = 'artifacts' diff --git a/spec/migrations/rename_reserved_project_names_spec.rb b/spec/migrations/rename_reserved_project_names_spec.rb index 05e021c2e32..462f4c08d63 100644 --- a/spec/migrations/rename_reserved_project_names_spec.rb +++ b/spec/migrations/rename_reserved_project_names_spec.rb @@ -8,7 +8,7 @@ require Rails.root.join('db', 'post_migrate', '20161221153951_rename_reserved_pr # around this we use the TRUNCATE cleaning strategy. describe RenameReservedProjectNames, truncate: true do let(:migration) { described_class.new } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } before do project.path = 'projects' diff --git a/spec/migrations/rename_system_namespaces_spec.rb b/spec/migrations/rename_system_namespaces_spec.rb deleted file mode 100644 index 626a6005838..00000000000 --- a/spec/migrations/rename_system_namespaces_spec.rb +++ /dev/null @@ -1,254 +0,0 @@ -require "spec_helper" -require Rails.root.join("db", "migrate", "20170316163800_rename_system_namespaces.rb") - -describe RenameSystemNamespaces, truncate: true do - let(:migration) { described_class.new } - let(:test_dir) { File.join(Rails.root, "tmp", "tests", "rename_namespaces_test") } - let(:uploads_dir) { File.join(test_dir, "public", "uploads") } - let(:system_namespace) do - namespace = build(:namespace, path: "system") - namespace.save(validate: false) - namespace - end - - def save_invalid_routable(routable) - routable.__send__(:prepare_route) - routable.save(validate: false) - end - - before do - FileUtils.remove_dir(test_dir) if File.directory?(test_dir) - FileUtils.mkdir_p(uploads_dir) - FileUtils.remove_dir(TestEnv.repos_path) if File.directory?(TestEnv.repos_path) - allow(migration).to receive(:say) - allow(migration).to receive(:uploads_dir).and_return(uploads_dir) - end - - describe "#system_namespace" do - it "only root namespaces called with path `system`" do - system_namespace - system_namespace_with_parent = build(:namespace, path: 'system', parent: create(:namespace)) - system_namespace_with_parent.save(validate: false) - - expect(migration.system_namespace.id).to eq(system_namespace.id) - end - end - - describe "#up" do - before do - system_namespace - end - - it "doesn't break if there are no namespaces called system" do - Namespace.delete_all - - migration.up - end - - it "renames namespaces called system" do - migration.up - - expect(system_namespace.reload.path).to eq("system0") - end - - it "renames the route to the namespace" do - migration.up - - expect(system_namespace.reload.full_path).to eq("system0") - end - - it "renames the route for projects of the namespace" do - project = build(:project, path: "project-path", namespace: system_namespace) - save_invalid_routable(project) - - migration.up - - expect(project.route.reload.path).to eq("system0/project-path") - end - - it "doesn't touch routes of namespaces that look like system" do - namespace = create(:group, path: 'systemlookalike') - project = create(:project, namespace: namespace, path: 'the-project') - - migration.up - - expect(project.route.reload.path).to eq('systemlookalike/the-project') - expect(namespace.route.reload.path).to eq('systemlookalike') - end - - it "moves the the repository for a project in the namespace" do - project = build(:project, namespace: system_namespace, path: "system-project") - save_invalid_routable(project) - TestEnv.copy_repo(project, - bare_repo: TestEnv.factory_repo_path_bare, - refs: TestEnv::BRANCH_SHA) - expected_repo = File.join(TestEnv.repos_path, "system0", "system-project.git") - - migration.up - - expect(File.directory?(expected_repo)).to be(true) - end - - it "moves the uploads for the namespace" do - allow(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0") - expect(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0") - - migration.up - end - - it "moves the pages for the namespace" do - allow(migration).to receive(:move_namespace_folders).with(uploads_dir, "system", "system0") - expect(migration).to receive(:move_namespace_folders).with(Settings.pages.path, "system", "system0") - - migration.up - end - - describe "clears the markdown cache for projects in the system namespace" do - let!(:project) do - project = build(:project, namespace: system_namespace) - save_invalid_routable(project) - project - end - - it 'removes description_html from projects' do - migration.up - - expect(project.reload.description_html).to be_nil - end - - it 'removes issue descriptions' do - issue = create(:issue, project: project, description_html: 'Issue description') - - migration.up - - expect(issue.reload.description_html).to be_nil - end - - it 'removes merge request descriptions' do - merge_request = create(:merge_request, - source_project: project, - target_project: project, - description_html: 'MergeRequest description') - - migration.up - - expect(merge_request.reload.description_html).to be_nil - end - - it 'removes note html' do - note = create(:note, - project: project, - noteable: create(:issue, project: project), - note_html: 'note description') - - migration.up - - expect(note.reload.note_html).to be_nil - end - - it 'removes milestone description' do - milestone = create(:milestone, - project: project, - description_html: 'milestone description') - - migration.up - - expect(milestone.reload.description_html).to be_nil - end - end - - context "system namespace -> subgroup -> system0 project" do - it "updates the route of the project correctly" do - subgroup = build(:group, path: "subgroup", parent: system_namespace) - save_invalid_routable(subgroup) - project = build(:project, path: "system0", namespace: subgroup) - save_invalid_routable(project) - - migration.up - - expect(project.route.reload.path).to eq("system0/subgroup/system0") - end - end - end - - describe "#move_repositories" do - let(:namespace) { create(:group, name: "hello-group") } - it "moves a project for a namespace" do - create(:project, namespace: namespace, path: "hello-project") - expected_path = File.join(TestEnv.repos_path, "bye-group", "hello-project.git") - - migration.move_repositories(namespace, "hello-group", "bye-group") - - expect(File.directory?(expected_path)).to be(true) - end - - it "moves a namespace in a subdirectory correctly" do - child_namespace = create(:group, name: "sub-group", parent: namespace) - create(:project, namespace: child_namespace, path: "hello-project") - - expected_path = File.join(TestEnv.repos_path, "hello-group", "renamed-sub-group", "hello-project.git") - - migration.move_repositories(child_namespace, "hello-group/sub-group", "hello-group/renamed-sub-group") - - expect(File.directory?(expected_path)).to be(true) - end - - it "moves a parent namespace with subdirectories" do - child_namespace = create(:group, name: "sub-group", parent: namespace) - create(:project, namespace: child_namespace, path: "hello-project") - expected_path = File.join(TestEnv.repos_path, "renamed-group", "sub-group", "hello-project.git") - - migration.move_repositories(child_namespace, "hello-group", "renamed-group") - - expect(File.directory?(expected_path)).to be(true) - end - end - - describe "#move_namespace_folders" do - it "moves a namespace with files" do - source = File.join(uploads_dir, "parent-group", "sub-group") - FileUtils.mkdir_p(source) - destination = File.join(uploads_dir, "parent-group", "moved-group") - FileUtils.touch(File.join(source, "test.txt")) - expected_file = File.join(destination, "test.txt") - - migration.move_namespace_folders(uploads_dir, File.join("parent-group", "sub-group"), File.join("parent-group", "moved-group")) - - expect(File.exist?(expected_file)).to be(true) - end - - it "moves a parent namespace uploads" do - source = File.join(uploads_dir, "parent-group", "sub-group") - FileUtils.mkdir_p(source) - destination = File.join(uploads_dir, "moved-parent", "sub-group") - FileUtils.touch(File.join(source, "test.txt")) - expected_file = File.join(destination, "test.txt") - - migration.move_namespace_folders(uploads_dir, "parent-group", "moved-parent") - - expect(File.exist?(expected_file)).to be(true) - end - end - - describe "#child_ids_for_parent" do - it "collects child ids for all levels" do - parent = create(:group) - first_child = create(:group, parent: parent) - second_child = create(:group, parent: parent) - third_child = create(:group, parent: second_child) - all_ids = [parent.id, first_child.id, second_child.id, third_child.id] - - collected_ids = migration.child_ids_for_parent(parent, ids: [parent.id]) - - expect(collected_ids).to contain_exactly(*all_ids) - end - end - - describe "#remove_last_ocurrence" do - it "removes only the last occurance of a string" do - input = "this/is/system/namespace/with/system" - - expect(migration.remove_last_occurrence(input, "system")).to eq("this/is/system/namespace/with/") - end - end -end diff --git a/spec/migrations/schedule_merge_request_diff_migrations_spec.rb b/spec/migrations/schedule_merge_request_diff_migrations_spec.rb new file mode 100644 index 00000000000..f95bd6e3511 --- /dev/null +++ b/spec/migrations/schedule_merge_request_diff_migrations_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20170703130158_schedule_merge_request_diff_migrations') + +describe ScheduleMergeRequestDiffMigrations, :migration, :sidekiq do + matcher :be_scheduled_migration do |time, *expected| + match do |migration| + BackgroundMigrationWorker.jobs.any? do |job| + job['args'] == [migration, expected] && + job['at'].to_i == time.to_i + end + end + + failure_message do |migration| + "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!" + end + end + + let(:merge_request_diffs) { table(:merge_request_diffs) } + let(:merge_requests) { table(:merge_requests) } + let(:projects) { table(:projects) } + + before do + stub_const("#{described_class.name}::BATCH_SIZE", 1) + + projects.create!(id: 1, name: 'gitlab', path: 'gitlab') + + merge_requests.create!(id: 1, target_project_id: 1, source_project_id: 1, target_branch: 'feature', source_branch: 'master') + + merge_request_diffs.create!(id: 1, merge_request_id: 1, st_commits: YAML.dump([]), st_diffs: nil) + merge_request_diffs.create!(id: 2, merge_request_id: 1, st_commits: nil, st_diffs: YAML.dump([])) + merge_request_diffs.create!(id: 3, merge_request_id: 1, st_commits: nil, st_diffs: nil) + merge_request_diffs.create!(id: 4, merge_request_id: 1, st_commits: YAML.dump([]), st_diffs: YAML.dump([])) + end + + it 'correctly schedules background migrations' do + Sidekiq::Testing.fake! do + Timecop.freeze do + migrate! + + expect(described_class::MIGRATION).to be_scheduled_migration(5.minutes.from_now, 1, 1) + expect(described_class::MIGRATION).to be_scheduled_migration(10.minutes.from_now, 2, 2) + expect(described_class::MIGRATION).to be_scheduled_migration(15.minutes.from_now, 4, 4) + expect(BackgroundMigrationWorker.jobs.size).to eq 3 + end + end + end + + it 'schedules background migrations' do + Sidekiq::Testing.inline! do + non_empty = 'st_commits IS NOT NULL OR st_diffs IS NOT NULL' + + expect(merge_request_diffs.where(non_empty).count).to eq 3 + + migrate! + + expect(merge_request_diffs.where(non_empty).count).to eq 0 + end + end +end diff --git a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb index 42109fd0743..6f7a730edff 100644 --- a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb +++ b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb @@ -44,7 +44,7 @@ describe TurnNestedGroupsIntoRegularGroupsForMysql do end it 'renames projects of the nested group' do - expect(updated_project.path_with_namespace) + expect(updated_project.full_path) .to eq("#{parent_group.name}-#{child_group.name}/#{updated_project.path}") end diff --git a/spec/migrations/update_upload_paths_to_system_spec.rb b/spec/migrations/update_upload_paths_to_system_spec.rb index 7df44515424..0a45c5ea32d 100644 --- a/spec/migrations/update_upload_paths_to_system_spec.rb +++ b/spec/migrations/update_upload_paths_to_system_spec.rb @@ -11,9 +11,9 @@ describe UpdateUploadPathsToSystem do describe "#uploads_to_switch_to_new_path" do it "contains only uploads with the old path for the correct models" do _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") - _upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") - _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg") - old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + _upload_with_system_path = create(:upload, model: create(:project), path: "uploads/-/system/project/avatar.jpg") + _upload_with_other_path = create(:upload, model: create(:project), path: "thelongsecretforafileupload/avatar.jpg") + old_upload = create(:upload, model: create(:project), path: "uploads/project/avatar.jpg") group_upload = create(:upload, model: create(:group), path: "uploads/group/avatar.jpg") expect(Upload.where(migration.uploads_to_switch_to_new_path)).to contain_exactly(old_upload, group_upload) @@ -23,9 +23,9 @@ describe UpdateUploadPathsToSystem do describe "#uploads_to_switch_to_old_path" do it "contains only uploads with the new path for the correct models" do _upload_for_other_type = create(:upload, model: create(:ci_pipeline), path: "uploads/ci_pipeline/avatar.jpg") - upload_with_system_path = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") - _upload_with_other_path = create(:upload, model: create(:empty_project), path: "thelongsecretforafileupload/avatar.jpg") - _old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + upload_with_system_path = create(:upload, model: create(:project), path: "uploads/-/system/project/avatar.jpg") + _upload_with_other_path = create(:upload, model: create(:project), path: "thelongsecretforafileupload/avatar.jpg") + _old_upload = create(:upload, model: create(:project), path: "uploads/project/avatar.jpg") expect(Upload.where(migration.uploads_to_switch_to_old_path)).to contain_exactly(upload_with_system_path) end @@ -33,17 +33,17 @@ describe UpdateUploadPathsToSystem do describe "#up", truncate: true do it "updates old upload records to the new path" do - old_upload = create(:upload, model: create(:empty_project), path: "uploads/project/avatar.jpg") + old_upload = create(:upload, model: create(:project), path: "uploads/project/avatar.jpg") migration.up - expect(old_upload.reload.path).to eq("uploads/system/project/avatar.jpg") + expect(old_upload.reload.path).to eq("uploads/-/system/project/avatar.jpg") end end describe "#down", truncate: true do it "updates the new system patsh to the old paths" do - new_upload = create(:upload, model: create(:empty_project), path: "uploads/system/project/avatar.jpg") + new_upload = create(:upload, model: create(:project), path: "uploads/-/system/project/avatar.jpg") migration.down diff --git a/spec/models/ability_spec.rb b/spec/models/ability_spec.rb index aa019288700..71aa51e1857 100644 --- a/spec/models/ability_spec.rb +++ b/spec/models/ability_spec.rb @@ -8,7 +8,7 @@ describe Ability do end describe '.can_edit_note?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:note) { create(:note_on_issue, project: project) } context 'using an anonymous user' do @@ -66,7 +66,7 @@ describe Ability do describe '.users_that_can_read_project' do context 'using a public project' do it 'returns all the users' do - project = create(:empty_project, :public) + project = create(:project, :public) user = build(:user) expect(described_class.users_that_can_read_project([user], project)) @@ -75,7 +75,7 @@ describe Ability do end context 'using an internal project' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } it 'returns users that are administrators' do user = build(:user, admin: true) @@ -126,7 +126,7 @@ describe Ability do end context 'using a private project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } it 'returns users that are administrators' do user = build(:user, admin: true) @@ -253,7 +253,7 @@ describe Ability do end describe '.project_disabled_features_rules' do - let(:project) { create(:empty_project, :wiki_disabled) } + let(:project) { create(:project, :wiki_disabled) } subject { described_class.policy_for(project.owner, project) } diff --git a/spec/models/appearance_spec.rb b/spec/models/appearance_spec.rb index 7cd3a84d592..b5d5d58697b 100644 --- a/spec/models/appearance_spec.rb +++ b/spec/models/appearance_spec.rb @@ -9,4 +9,39 @@ RSpec.describe Appearance do it { is_expected.to validate_presence_of(:description) } it { is_expected.to have_many(:uploads).dependent(:destroy) } + + describe '.current', :use_clean_rails_memory_store_caching do + let!(:appearance) { create(:appearance) } + + it 'returns the current appearance row' do + expect(described_class.current).to eq(appearance) + end + + it 'caches the result' do + expect(described_class).to receive(:first).once + + 2.times { described_class.current } + end + end + + describe '#flush_redis_cache' do + it 'flushes the cache in Redis' do + appearance = create(:appearance) + + expect(Rails.cache).to receive(:delete).with(described_class::CACHE_KEY) + + appearance.flush_redis_cache + end + end + + describe '#single_appearance_row' do + it 'adds an error when more than 1 row exists' do + create(:appearance) + + new_row = build(:appearance) + new_row.save + + expect(new_row.valid?).to eq(false) + end + end end diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb index e1193e0d19a..47342f98283 100644 --- a/spec/models/blob_spec.rb +++ b/spec/models/blob_spec.rb @@ -4,7 +4,7 @@ require 'rails_helper' describe Blob do include FakeBlobHelpers - let(:project) { build(:empty_project, lfs_enabled: true) } + let(:project) { build(:project, lfs_enabled: true) } before do allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) diff --git a/spec/models/blob_viewer/base_spec.rb b/spec/models/blob_viewer/base_spec.rb index e3640097dff..7ba28f72215 100644 --- a/spec/models/blob_viewer/base_spec.rb +++ b/spec/models/blob_viewer/base_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::Base do include FakeBlobHelpers - let(:project) { build(:empty_project) } + let(:project) { build(:project) } let(:viewer_class) do Class.new(described_class) do diff --git a/spec/models/blob_viewer/composer_json_spec.rb b/spec/models/blob_viewer/composer_json_spec.rb index 82f6f7e5046..85b0d9668a0 100644 --- a/spec/models/blob_viewer/composer_json_spec.rb +++ b/spec/models/blob_viewer/composer_json_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::ComposerJson do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } let(:data) do <<-SPEC.strip_heredoc { diff --git a/spec/models/blob_viewer/gemspec_spec.rb b/spec/models/blob_viewer/gemspec_spec.rb index 14cc5f3c0fd..d8c4490637f 100644 --- a/spec/models/blob_viewer/gemspec_spec.rb +++ b/spec/models/blob_viewer/gemspec_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::Gemspec do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } let(:data) do <<-SPEC.strip_heredoc Gem::Specification.new do |s| diff --git a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb index 7a4f9866375..bed364a8c14 100644 --- a/spec/models/blob_viewer/gitlab_ci_yml_spec.rb +++ b/spec/models/blob_viewer/gitlab_ci_yml_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::GitlabCiYml do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } let(:data) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) } let(:blob) { fake_blob(path: '.gitlab-ci.yml', data: data) } subject { described_class.new(blob) } diff --git a/spec/models/blob_viewer/package_json_spec.rb b/spec/models/blob_viewer/package_json_spec.rb index 96fb1b08c99..0f8330e91c1 100644 --- a/spec/models/blob_viewer/package_json_spec.rb +++ b/spec/models/blob_viewer/package_json_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::PackageJson do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } let(:data) do <<-SPEC.strip_heredoc { diff --git a/spec/models/blob_viewer/podspec_json_spec.rb b/spec/models/blob_viewer/podspec_json_spec.rb index f510077a87b..9a23877b23f 100644 --- a/spec/models/blob_viewer/podspec_json_spec.rb +++ b/spec/models/blob_viewer/podspec_json_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::PodspecJson do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } let(:data) do <<-SPEC.strip_heredoc { diff --git a/spec/models/blob_viewer/podspec_spec.rb b/spec/models/blob_viewer/podspec_spec.rb index 7c38083550c..02d06ea24d6 100644 --- a/spec/models/blob_viewer/podspec_spec.rb +++ b/spec/models/blob_viewer/podspec_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::Podspec do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } let(:data) do <<-SPEC.strip_heredoc Pod::Spec.new do |spec| diff --git a/spec/models/blob_viewer/route_map_spec.rb b/spec/models/blob_viewer/route_map_spec.rb index 115731b4970..c13662427b0 100644 --- a/spec/models/blob_viewer/route_map_spec.rb +++ b/spec/models/blob_viewer/route_map_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::RouteMap do include FakeBlobHelpers - let(:project) { build(:project) } + let(:project) { build_stubbed(:project) } let(:data) do <<-MAP.strip_heredoc # Team data diff --git a/spec/models/blob_viewer/server_side_spec.rb b/spec/models/blob_viewer/server_side_spec.rb index 2639eec9e84..63790486200 100644 --- a/spec/models/blob_viewer/server_side_spec.rb +++ b/spec/models/blob_viewer/server_side_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BlobViewer::ServerSide do include FakeBlobHelpers - let(:project) { build(:empty_project) } + let(:project) { build(:project) } let(:viewer_class) do Class.new(BlobViewer::Base) do @@ -25,7 +25,7 @@ describe BlobViewer::ServerSide do describe '#render_error' do context 'when the blob is stored externally' do - let(:project) { build(:empty_project, lfs_enabled: true) } + let(:project) { build(:project, lfs_enabled: true) } let(:blob) { fake_blob(path: 'file.pdf', lfs: true) } diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb index a8ca1d110e4..3369aef1d3e 100644 --- a/spec/models/broadcast_message_spec.rb +++ b/spec/models/broadcast_message_spec.rb @@ -20,7 +20,7 @@ describe BroadcastMessage do it { is_expected.not_to allow_value('000').for(:font) } end - describe '.current' do + describe '.current', :use_clean_rails_memory_store_caching do it 'returns message if time match' do message = create(:broadcast_message) @@ -45,6 +45,14 @@ describe BroadcastMessage do expect(described_class.current).to be_empty end + + it 'caches the output of the query' do + create(:broadcast_message) + + expect(described_class).to receive(:where).and_call_original.once + + 2.times { described_class.current } + end end describe '#active?' do @@ -102,4 +110,14 @@ describe BroadcastMessage do end end end + + describe '#flush_redis_cache' do + it 'flushes the Redis cache' do + message = create(:broadcast_message) + + expect(Rails.cache).to receive(:delete).with(described_class::CACHE_KEY) + + message.flush_redis_cache + end + end end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index b0efa689a07..ac75c6501ee 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1,10 +1,8 @@ require 'spec_helper' -describe Ci::Pipeline do - include EmailHelpers - +describe Ci::Pipeline, :mailer do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) do create(:ci_empty_pipeline, status: :created, project: project) @@ -93,7 +91,7 @@ describe Ci::Pipeline do end describe "coverage" do - let(:project) { create(:empty_project, build_coverage_regex: "/.*/") } + let(:project) { create(:project, build_coverage_regex: "/.*/") } let(:pipeline) { create(:ci_empty_pipeline, project: project) } it "calculates average when there are two builds with coverage" do @@ -1147,7 +1145,7 @@ describe Ci::Pipeline do end describe "#merge_requests" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master', sha: 'a288a022a53a5a944fae87bcec6efc87b7061808') } it "returns merge requests whose `diff_head_sha` matches the pipeline's SHA" do @@ -1172,7 +1170,7 @@ describe Ci::Pipeline do end describe "#all_merge_requests" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, status: 'created', project: project, ref: 'master') } it "returns all merge requests having the same source branch" do @@ -1248,8 +1246,6 @@ describe Ci::Pipeline do pipeline.user.global_notification_setting .update(level: 'custom', failed_pipeline: true, success_pipeline: true) - reset_delivered_emails! - perform_enqueued_jobs do pipeline.enqueue pipeline.run diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 8d12a9c09ca..48f878bbee6 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -37,7 +37,7 @@ describe Ci::Runner do end describe '#assign_to' do - let!(:project) { FactoryGirl.create :empty_project } + let!(:project) { FactoryGirl.create :project } let!(:shared_runner) { FactoryGirl.create(:ci_runner, :shared) } before do @@ -339,8 +339,8 @@ describe Ci::Runner do describe '.assignable_for' do let(:runner) { create(:ci_runner) } - let(:project) { create(:empty_project) } - let(:another_project) { create(:empty_project) } + let(:project) { create(:project) } + let(:another_project) { create(:project) } before do project.runners << runner @@ -400,8 +400,8 @@ describe Ci::Runner do describe "belongs_to_one_project?" do it "returns false if there are two projects runner assigned to" do runner = FactoryGirl.create(:ci_runner) - project = FactoryGirl.create(:empty_project) - project1 = FactoryGirl.create(:empty_project) + project = FactoryGirl.create(:project) + project1 = FactoryGirl.create(:project) project.runners << runner project1.runners << runner @@ -410,7 +410,7 @@ describe Ci::Runner do it "returns true" do runner = FactoryGirl.create(:ci_runner) - project = FactoryGirl.create(:empty_project) + project = FactoryGirl.create(:project) project.runners << runner expect(runner.belongs_to_one_project?).to be_truthy diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb index de51f4879fd..bd9c837402f 100644 --- a/spec/models/ci/trigger_spec.rb +++ b/spec/models/ci/trigger_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::Trigger do - let(:project) { create :empty_project } + let(:project) { create :project } describe 'associations' do it { is_expected.to belong_to(:project) } diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb index 07e10b44938..38829773599 100644 --- a/spec/models/commit_range_spec.rb +++ b/spec/models/commit_range_spec.rb @@ -45,7 +45,7 @@ describe CommitRange do end describe '#to_reference' do - let(:cross) { create(:empty_project, namespace: project.namespace) } + let(:cross) { create(:project, namespace: project.namespace) } it 'returns a String reference to the object' do expect(range.to_reference).to eq "#{full_sha_from}...#{full_sha_to}" @@ -61,7 +61,7 @@ describe CommitRange do end describe '#reference_link_text' do - let(:cross) { create(:empty_project, namespace: project.namespace) } + let(:cross) { create(:project, namespace: project.namespace) } it 'returns a String reference to the object' do expect(range.reference_link_text).to eq "#{sha_from}...#{sha_to}" diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 2285c338599..c18c635d811 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -33,7 +33,6 @@ describe Commit do describe '#to_reference' do let(:project) { create(:project, :repository, path: 'sample-project') } - let(:commit) { project.commit } it 'returns a String reference to the object' do expect(commit.to_reference).to eq commit.id @@ -47,7 +46,6 @@ describe Commit do describe '#reference_link_text' do let(:project) { create(:project, :repository, path: 'sample-project') } - let(:commit) { project.commit } it 'returns a String reference to the object' do expect(commit.reference_link_text).to eq commit.short_id @@ -151,7 +149,7 @@ eos describe '#closes_issues' do let(:issue) { create :issue, project: project } - let(:other_project) { create(:empty_project, :public) } + let(:other_project) { create(:project, :public) } let(:other_issue) { create :issue, project: other_project } let(:commiter) { create :user } @@ -161,7 +159,7 @@ eos end it 'detects issues that this commit is marked as closing' do - ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}" + ext_ref = "#{other_project.full_path}##{other_issue.iid}" allow(commit).to receive_messages( safe_message: "Fixes ##{issue.iid} and #{ext_ref}", @@ -191,7 +189,7 @@ eos it { expect(data).to be_a(Hash) } it { expect(data[:message]).to include('adds bar folder and branch-test text file to check Repository merged_to_root_ref method') } - it { expect(data[:timestamp]).to eq('2016-09-27T14:37:46+00:00') } + it { expect(data[:timestamp]).to eq('2016-09-27T14:37:46Z') } it { expect(data[:added]).to eq(["bar/branch-test.txt"]) } it { expect(data[:modified]).to eq([]) } it { expect(data[:removed]).to eq([]) } diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb index 4e915d73ced..f7583645e69 100644 --- a/spec/models/commit_status_spec.rb +++ b/spec/models/commit_status_spec.rb @@ -425,7 +425,7 @@ describe CommitStatus do end it "raise exception when trying to update" do - expect{ commit_status.save }.to raise_error(ActiveRecord::StaleObjectError) + expect { commit_status.save }.to raise_error(ActiveRecord::StaleObjectError) end end diff --git a/spec/models/concerns/access_requestable_spec.rb b/spec/models/concerns/access_requestable_spec.rb index 97b7e48bb3c..04d6cfa2c02 100644 --- a/spec/models/concerns/access_requestable_spec.rb +++ b/spec/models/concerns/access_requestable_spec.rb @@ -24,14 +24,14 @@ describe AccessRequestable do describe 'Project' do describe '#request_access' do - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:user) { create(:user) } it { expect(project.request_access(user)).to be_a(ProjectMember) } end describe '#access_requested?' do - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:user) { create(:user) } before do diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 505039c9d88..dfbe1a7c192 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -155,7 +155,7 @@ describe Issuable do end describe "#sort" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context "by milestone due date" do # Correct order is: @@ -296,11 +296,11 @@ describe Issuable do end describe '#labels_array' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:bug) { create(:label, project: project, title: 'bug') } let(:issue) { create(:issue, project: project) } - before(:each) do + before do issue.labels << bug end @@ -310,7 +310,7 @@ describe Issuable do end describe '#user_notes_count' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue1) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) } @@ -340,7 +340,7 @@ describe Issuable do end describe '.order_due_date_and_labels_priority' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } def create_issue(milestone, labels) create(:labeled_issue, milestone: milestone, labels: labels, project: project) @@ -394,7 +394,7 @@ describe Issuable do end describe ".with_label" do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:bug) { create(:label, project: project, title: 'bug') } let(:feature) { create(:label, project: project, title: 'feature') } let(:enhancement) { create(:label, project: project, title: 'enhancement') } @@ -402,7 +402,7 @@ describe Issuable do let(:issue2) { create(:issue, title: "Bugfix2", project: project) } let(:issue3) { create(:issue, title: "Feature1", project: project) } - before(:each) do + before do issue1.labels << bug issue1.labels << feature issue2.labels << bug diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb index 1ad811736af..8b545aec7f5 100644 --- a/spec/models/concerns/mentionable_spec.rb +++ b/spec/models/concerns/mentionable_spec.rb @@ -13,7 +13,7 @@ describe Mentionable do end describe 'references' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:mentionable) { Example.new } it 'excludes JIRA references' do @@ -48,10 +48,10 @@ describe Issue, "Mentionable" do describe '#referenced_mentionables' do context 'with an issue on a private project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } let(:public_issue) { create(:issue, project: project) } - let(:private_project) { create(:empty_project, :private) } + let(:private_project) { create(:project, :private) } let(:private_issue) { create(:issue, project: private_project) } let(:user) { create(:user) } @@ -102,7 +102,7 @@ describe Issue, "Mentionable" do end describe '#create_new_cross_references!' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:author) { create(:author) } let(:issues) { create_list(:issue, 2, project: project, author: author) } @@ -204,7 +204,7 @@ describe Commit, 'Mentionable' do end context 'with external issue tracker' do - let(:project) { create(:jira_project) } + let(:project) { create(:jira_project, :repository) } it 'is true if external issues referenced' do allow(commit.raw).to receive(:message).and_return 'JIRA-123' diff --git a/spec/models/concerns/milestoneish_spec.rb b/spec/models/concerns/milestoneish_spec.rb index cefe7fb6fea..66353935427 100644 --- a/spec/models/concerns/milestoneish_spec.rb +++ b/spec/models/concerns/milestoneish_spec.rb @@ -7,7 +7,7 @@ describe Milestone, 'Milestoneish' do let(:member) { create(:user) } let(:guest) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, :public) } + 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) } diff --git a/spec/models/concerns/project_features_compatibility_spec.rb b/spec/models/concerns/project_features_compatibility_spec.rb index 6cf5877424d..9041690023f 100644 --- a/spec/models/concerns/project_features_compatibility_spec.rb +++ b/spec/models/concerns/project_features_compatibility_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProjectFeaturesCompatibility do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:features) { %w(issues wiki builds merge_requests snippets) } # We had issues_enabled, snippets_enabled, builds_enabled, merge_requests_enabled and issues_enabled fields on projects table diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb index 5f9b7e0a367..a5d505af001 100644 --- a/spec/models/concerns/reactive_caching_spec.rb +++ b/spec/models/concerns/reactive_caching_spec.rb @@ -31,7 +31,7 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do let(:now) { Time.now.utc } - around(:each) do |example| + around do |example| Timecop.freeze(now) { example.run } end diff --git a/spec/models/concerns/relative_positioning_spec.rb b/spec/models/concerns/relative_positioning_spec.rb index 494e6f1b6f6..729056b6abc 100644 --- a/spec/models/concerns/relative_positioning_spec.rb +++ b/spec/models/concerns/relative_positioning_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe RelativePositioning do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:issue1) { create(:issue, project: project) } let(:new_issue) { create(:issue, project: project) } diff --git a/spec/models/concerns/resolvable_note_spec.rb b/spec/models/concerns/resolvable_note_spec.rb index 53eaa6f8461..d00faa4f8be 100644 --- a/spec/models/concerns/resolvable_note_spec.rb +++ b/spec/models/concerns/resolvable_note_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Note, ResolvableNote do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project) } subject { create(:discussion_note_on_merge_request, noteable: merge_request, project: project) } diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index 36aedd2f701..b463d12e448 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -156,13 +156,13 @@ end describe Project, 'Routable' do describe '#full_path' do - let(:project) { build_stubbed(:empty_project) } + let(:project) { build_stubbed(:project) } it { expect(project.full_path).to eq "#{project.namespace.full_path}/#{project.path}" } end describe '#full_name' do - let(:project) { build_stubbed(:empty_project) } + let(:project) { build_stubbed(:project) } it { expect(project.full_name).to eq "#{project.namespace.human_name} / #{project.name}" } end diff --git a/spec/models/concerns/subscribable_spec.rb b/spec/models/concerns/subscribable_spec.rb index 58f5c164116..28ff8158e0e 100644 --- a/spec/models/concerns/subscribable_spec.rb +++ b/spec/models/concerns/subscribable_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Subscribable, 'Subscribable' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:resource) { create(:issue, project: project) } let(:user_1) { create(:user) } diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb index eff41d85972..bae88cb1d24 100644 --- a/spec/models/container_repository_spec.rb +++ b/spec/models/container_repository_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ContainerRepository do let(:group) { create(:group, name: 'group') } - let(:project) { create(:project, path: 'test', group: group) } + let(:project) { create(:project, :repository, path: 'test', group: group) } let(:repository) do create(:container_repository, name: 'my_image', project: project) @@ -41,7 +41,7 @@ describe ContainerRepository do end context 'when path contains uppercase letters' do - let(:project) { create(:project, path: 'MY_PROJECT', group: group) } + let(:project) { create(:project, :repository, path: 'MY_PROJECT', group: group) } it 'returns a full path without capital letters' do expect(repository.path).to eq('group/my_project/my_image') diff --git a/spec/models/conversational_development_index/metric_spec.rb b/spec/models/conversational_development_index/metric_spec.rb new file mode 100644 index 00000000000..b3193619503 --- /dev/null +++ b/spec/models/conversational_development_index/metric_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +describe ConversationalDevelopmentIndex::Metric do + let(:conv_dev_index) { create(:conversational_development_index_metric) } + + describe '#percentage_score' do + it 'returns stored percentage score' do + expect(conv_dev_index.percentage_score('issues')).to eq(13.331) + end + end +end diff --git a/spec/models/deploy_key_spec.rb b/spec/models/deploy_key_spec.rb index 2aece75b817..3d7283e2164 100644 --- a/spec/models/deploy_key_spec.rb +++ b/spec/models/deploy_key_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe DeployKey do - include EmailHelpers - +describe DeployKey, :mailer do describe "Associations" do it { is_expected.to have_many(:deploy_keys_projects) } it { is_expected.to have_many(:projects) } diff --git a/spec/models/deploy_keys_project_spec.rb b/spec/models/deploy_keys_project_spec.rb index f10b65ba9d8..0345fefb254 100644 --- a/spec/models/deploy_keys_project_spec.rb +++ b/spec/models/deploy_keys_project_spec.rb @@ -12,7 +12,7 @@ describe DeployKeysProject do end describe "Destroying" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { create(:deploy_keys_project, project: project) } let(:deploy_key) { subject.deploy_key } @@ -39,7 +39,7 @@ describe DeployKeysProject do end context "when the deploy key is used by more than one project" do - let!(:other_project) { create(:empty_project) } + let!(:other_project) { create(:project) } before do other_project.deploy_keys << deploy_key diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb index 6447095078b..c5708e70ef9 100644 --- a/spec/models/deployment_spec.rb +++ b/spec/models/deployment_spec.rb @@ -91,7 +91,7 @@ describe Deployment do end describe '#additional_metrics' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:deployment) { create(:deployment, project: project) } subject { deployment.additional_metrics } diff --git a/spec/models/diff_discussion_spec.rb b/spec/models/diff_discussion_spec.rb index 2704698f6c9..fa02434b0fd 100644 --- a/spec/models/diff_discussion_spec.rb +++ b/spec/models/diff_discussion_spec.rb @@ -5,7 +5,7 @@ describe DiffDiscussion do subject { described_class.new([diff_note]) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:diff_note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index ebf2c070116..ea8512a5eae 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Environment do - set(:project) { create(:empty_project) } + set(:project) { create(:project) } subject(:environment) { create(:environment, project: project) } it { is_expected.to belong_to(:project) } @@ -21,7 +21,7 @@ describe Environment do it { is_expected.to validate_uniqueness_of(:external_url).scoped_to(:project_id) } describe '.order_by_last_deployed_at' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let!(:environment1) { create(:environment, project: project) } let!(:environment2) { create(:environment, project: project) } let!(:environment3) { create(:environment, project: project) } diff --git a/spec/models/event_collection_spec.rb b/spec/models/event_collection_spec.rb new file mode 100644 index 00000000000..e0a87c18cc7 --- /dev/null +++ b/spec/models/event_collection_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe EventCollection do + describe '#to_a' do + let(:project) { create(:project_empty_repo) } + let(:projects) { Project.where(id: project.id) } + let(:user) { create(:user) } + + before do + 20.times do + event = create(:push_event, project: project, author: user) + + create(:push_event_payload, event: event) + end + + create(:closed_issue_event, project: project, author: user) + end + + it 'returns an Array of events' do + events = described_class.new(projects).to_a + + expect(events).to be_an_instance_of(Array) + end + + it 'applies a limit to the number of events' do + events = described_class.new(projects).to_a + + expect(events.length).to eq(20) + end + + it 'can paginate through events' do + events = described_class.new(projects, offset: 20).to_a + + expect(events.length).to eq(1) + end + + it 'returns an empty Array when crossing the maximum page number' do + events = described_class.new(projects, limit: 1, offset: 15).to_a + + expect(events).to be_empty + end + + it 'allows filtering of events using an EventFilter' do + filter = EventFilter.new(EventFilter.issue) + events = described_class.new(projects, filter: filter).to_a + + expect(events.length).to eq(1) + expect(events[0].action).to eq(Event::CLOSED) + end + end +end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 4a4b84c9566..ff3224dd298 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -15,7 +15,7 @@ describe Event do end describe 'Callbacks' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } describe 'after_create :reset_project_activity' do it 'calls the reset_project_activity method' do @@ -53,7 +53,7 @@ describe Event do end describe "Push event" do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:user) { project.owner } let(:event) { create_push_event(project, user) } @@ -111,7 +111,7 @@ describe Event do end describe '#visible_to_user?' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:non_member) { create(:user) } let(:member) { create(:user) } let(:guest) { create(:user) } @@ -143,7 +143,7 @@ describe Event do end context 'private project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } it do aggregate_failures do @@ -213,7 +213,7 @@ describe Event do end context 'merge request diff note event' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:merge_request) { create(:merge_request, source_project: project, author: author, assignee: assignee) } let(:note_on_merge_request) { create(:legacy_diff_note_on_merge_request, noteable: merge_request, project: project) } let(:target) { note_on_merge_request } @@ -228,7 +228,7 @@ describe Event do end context 'private project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } it do expect(event.visible_to_user?(non_member)).to eq false @@ -260,7 +260,7 @@ describe Event do end describe '#reset_project_activity' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when a project was updated less than 1 hour ago' do it 'does not update the project' do @@ -304,27 +304,15 @@ describe Event do end end - def create_push_event(project, user, attrs = {}) - data = { - before: Gitlab::Git::BLANK_SHA, - after: "0220c11b9a3e6c69dc8fd35321254ca9a7b98f7e", - ref: "refs/heads/master", - user_id: user.id, - user_name: user.name, - repository: { - name: project.name, - url: "localhost/rubinius", - description: "", - homepage: "localhost/rubinius", - private: true - } - } - - described_class.create({ - project: project, - action: described_class::PUSHED, - data: data, - author_id: user.id - }.merge!(attrs)) + def create_push_event(project, user) + event = create(:push_event, project: project, author: user) + + create(:push_event_payload, + event: event, + commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + commit_count: 0, + ref: 'master') + + event end end diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 38fbdd2536a..7dbeb4d2e74 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -41,7 +41,7 @@ describe ForkedProjectLink, "add link on fork" do end describe '#forked?' do - let(:project_to) { create(:project, forked_project_link: forked_project_link) } + let(:project_to) { create(:project, :repository, forked_project_link: forked_project_link) } let(:forked_project_link) { create(:forked_project_link) } before do diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb index aedc74deb78..7f1909710d8 100644 --- a/spec/models/generic_commit_status_spec.rb +++ b/spec/models/generic_commit_status_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe GenericCommitStatus do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:external_url) { 'http://example.gitlab.com/status' } diff --git a/spec/models/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb index 5584a1a5a31..ab58f5c5021 100644 --- a/spec/models/global_milestone_spec.rb +++ b/spec/models/global_milestone_spec.rb @@ -4,9 +4,9 @@ describe GlobalMilestone do let(:user) { create(:user) } let(:user2) { create(:user) } let(:group) { create(:group) } - let(:project1) { create(:empty_project, group: group) } - let(:project2) { create(:empty_project, path: 'gitlab-ci', group: group) } - let(:project3) { create(:empty_project, path: 'cookbook-gitlab', group: group) } + let(:project1) { create(:project, group: group) } + let(:project2) { create(:project, path: 'gitlab-ci', group: group) } + let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) } describe '.build_collection' do let(:milestone1_due_date) { 2.weeks.from_now.to_date } diff --git a/spec/models/gpg_key_spec.rb b/spec/models/gpg_key_spec.rb index 59c074199db..e48f20bf53b 100644 --- a/spec/models/gpg_key_spec.rb +++ b/spec/models/gpg_key_spec.rb @@ -114,9 +114,7 @@ describe GpgKey do end end - describe 'notification' do - include EmailHelpers - + describe 'notification', :mailer do let(:user) { create(:user) } it 'sends a notification' do diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb index 9a9b1900aa5..c58fd46762a 100644 --- a/spec/models/gpg_signature_spec.rb +++ b/spec/models/gpg_signature_spec.rb @@ -16,7 +16,7 @@ RSpec.describe GpgSignature do describe '#commit' do it 'fetches the commit through the project' do commit_sha = '0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33' - project = create :project + project = create :project, :repository commit = create :commit, project: project gpg_signature = create :gpg_signature, commit_sha: commit_sha diff --git a/spec/models/group_label_spec.rb b/spec/models/group_label_spec.rb index f7828059295..d0fc1eaa3ec 100644 --- a/spec/models/group_label_spec.rb +++ b/spec/models/group_label_spec.rb @@ -39,8 +39,8 @@ describe GroupLabel do context 'cross-project' do let(:namespace) { build_stubbed(:namespace) } - let(:source_project) { build_stubbed(:empty_project, name: 'project-1', namespace: namespace) } - let(:target_project) { build_stubbed(:empty_project, name: 'project-2', namespace: namespace) } + let(:source_project) { build_stubbed(:project, name: 'project-1', namespace: namespace) } + let(:target_project) { build_stubbed(:project, name: 'project-2', namespace: namespace) } it 'returns a String reference to the object' do expect(label.to_reference(source_project, target_project: target_project)).to eq %(project-1~#{label.id}) diff --git a/spec/models/group_milestone_spec.rb b/spec/models/group_milestone_spec.rb index ac76c927c39..b60676afc91 100644 --- a/spec/models/group_milestone_spec.rb +++ b/spec/models/group_milestone_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GroupMilestone do let(:group) { create(:group) } - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } let(:project_milestone) do create(:milestone, title: "Milestone v1.2", project: project) end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 112bd605a64..c5bfae47606 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -425,7 +425,7 @@ describe Group do end describe '#secret_variables_for' do - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } let!(:secret_variable) do create(:ci_group_variable, value: 'secret', group: group) diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb index 0e9b94aac97..2afdd6751a4 100644 --- a/spec/models/guest_spec.rb +++ b/spec/models/guest_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Guest do - let(:public_project) { build_stubbed(:empty_project, :public) } - let(:private_project) { build_stubbed(:empty_project, :private) } - let(:internal_project) { build_stubbed(:empty_project, :internal) } + let(:public_project) { build_stubbed(:project, :public) } + let(:private_project) { build_stubbed(:project, :private) } + let(:internal_project) { build_stubbed(:project, :internal) } describe '.can_pull?' do context 'when project is private' do diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index eadc232a989..431e3db9f00 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -16,7 +16,7 @@ describe SystemHook do describe "execute" do let(:system_hook) { create(:system_hook) } let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let(:group) { create(:group) } let(:params) do { name: 'John Doe', username: 'jduser', email: 'jg@example.com', password: 'mydummypass' } diff --git a/spec/models/issue/metrics_spec.rb b/spec/models/issue/metrics_spec.rb index 6ceff7d24d4..1bf0ecb98ad 100644 --- a/spec/models/issue/metrics_spec.rb +++ b/spec/models/issue/metrics_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Issue::Metrics do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { create(:issue, project: project) } diff --git a/spec/models/issue_collection_spec.rb b/spec/models/issue_collection_spec.rb index 04d23d4c4fd..34d98a3c975 100644 --- a/spec/models/issue_collection_spec.rb +++ b/spec/models/issue_collection_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe IssueCollection do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue1) { create(:issue, project: project) } let(:issue2) { create(:issue, project: project) } let(:collection) { described_class.new([issue1, issue2]) } diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb index d72790eefe5..9203f6562f2 100644 --- a/spec/models/issue_spec.rb +++ b/spec/models/issue_spec.rb @@ -24,7 +24,7 @@ describe Issue do end describe '#order_by_position_and_priority' do - let(:project) { create :empty_project } + let(:project) { create :project } let(:p1) { create(:label, title: 'P1', project: project, priority: 1) } let(:p2) { create(:label, title: 'P2', project: project, priority: 2) } let!(:issue1) { create(:labeled_issue, project: project, labels: [p1]) } @@ -57,24 +57,20 @@ describe Issue do end describe '#closed_at' do - after do - Timecop.return - end - - let!(:now) { Timecop.freeze(Time.now) } - it 'sets closed_at to Time.now when issue is closed' do issue = create(:issue, state: 'opened') + expect(issue.closed_at).to be_nil + issue.close - expect(issue.closed_at).to eq(now) + expect(issue.closed_at).to be_present end end describe '#to_reference' do let(:namespace) { build(:namespace, path: 'sample-namespace') } - let(:project) { build(:empty_project, name: 'sample-project', namespace: namespace) } + let(:project) { build(:project, name: 'sample-project', namespace: namespace) } let(:issue) { build(:issue, iid: 1, project: project) } let(:group) { create(:group, name: 'Group', path: 'sample-group') } @@ -99,7 +95,7 @@ describe Issue do end context 'when cross namespace project argument' do - let(:another_namespace_project) { create(:empty_project, name: 'another-project') } + let(:another_namespace_project) { create(:project, name: 'another-project') } it 'returns complete path to the issue' do expect(issue.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project#1' @@ -107,12 +103,12 @@ describe Issue do end it 'supports a cross-project reference' do - another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) + another_project = build(:project, name: 'another-project', namespace: project.namespace) expect(issue.to_reference(another_project)).to eq "sample-project#1" end context 'when same namespace / cross-project argument' do - let(:another_project) { create(:empty_project, namespace: namespace) } + let(:another_project) { create(:project, namespace: namespace) } it 'returns path to the issue with the project name' do expect(issue.to_reference(another_project)).to eq 'sample-project#1' @@ -121,7 +117,7 @@ describe Issue do context 'when different namespace / cross-project argument' do let(:another_namespace) { create(:namespace, path: 'another-namespace') } - let(:another_project) { create(:empty_project, path: 'another-project', namespace: another_namespace) } + let(:another_project) { create(:project, path: 'another-project', namespace: another_namespace) } it 'returns full path to the issue' do expect(issue.to_reference(another_project)).to eq 'sample-namespace/sample-project#1' @@ -191,14 +187,10 @@ describe Issue do end it 'returns the merge request to close this issue' do - mr - expect(issue.closed_by_merge_requests(mr.author)).to eq([mr]) end it "returns an empty array when the merge request is closed already" do - closed_mr - expect(issue.closed_by_merge_requests(closed_mr.author)).to eq([]) end @@ -209,7 +201,7 @@ describe Issue do describe '#referenced_merge_requests' do it 'returns the referenced merge requests' do - project = create(:empty_project, :public) + project = create(:project, :public) mr1 = create(:merge_request, source_project: project, @@ -242,7 +234,7 @@ describe Issue do end context 'user is reporter in project issue belongs to' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } before do @@ -258,7 +250,7 @@ describe Issue do context 'checking destination project also' do subject { issue.can_move?(user, to_project) } - let(:to_project) { create(:empty_project) } + let(:to_project) { create(:project) } context 'destination project allowed' do before do @@ -354,7 +346,7 @@ describe Issue do subject { create(:issue, project: create(:project, :repository)) } let(:backref_text) { "issue #{subject.to_reference}" } - let(:set_mentionable_text) { ->(txt){ subject.description = txt } } + let(:set_mentionable_text) { ->(txt) { subject.description = txt } } end it_behaves_like 'a Taskable' do @@ -380,7 +372,7 @@ describe Issue do describe '#participants' do context 'using a public project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } let!(:note1) do @@ -402,7 +394,7 @@ describe Issue do context 'using a private project' do it 'does not include mentioned users that do not have access to the project' do - project = create(:empty_project) + project = create(:project) user = create(:user) issue = create(:issue, project: project) @@ -420,7 +412,7 @@ describe Issue do it 'updates when assignees change' do user1 = create(:user) user2 = create(:user) - project = create(:empty_project) + project = create(:project) issue = create(:issue, assignees: [user1], project: project) project.add_developer(user1) project.add_developer(user2) @@ -490,7 +482,7 @@ describe Issue do let(:user) { create(:user) } context 'using a public project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } it 'returns true for a regular issue' do issue = build(:issue, project: project) @@ -506,7 +498,7 @@ describe Issue do end context 'using an internal project' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } context 'using an internal user' do it 'returns true for a regular issue' do @@ -542,7 +534,7 @@ describe Issue do end context 'using a private project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } it 'returns false for a regular issue' do issue = build(:issue, project: project) @@ -578,7 +570,7 @@ describe Issue do context 'with a regular user that is a team member' do let(:user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } context 'using a public project' do before do @@ -599,7 +591,7 @@ describe Issue do end context 'using an internal project' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } before do project.team << [user, Gitlab::Access::DEVELOPER] @@ -619,7 +611,7 @@ describe Issue do end context 'using a private project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } before do project.team << [user, Gitlab::Access::DEVELOPER] @@ -640,7 +632,7 @@ describe Issue do end context 'with an admin user' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:admin) } it 'returns true for a regular issue' do @@ -659,7 +651,7 @@ describe Issue do describe '#publicly_visible?' do context 'using a public project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } it 'returns true for a regular issue' do issue = build(:issue, project: project) @@ -675,7 +667,7 @@ describe Issue do end context 'using an internal project' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } it 'returns false for a regular issue' do issue = build(:issue, project: project) @@ -691,7 +683,7 @@ describe Issue do end context 'using a private project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } it 'returns false for a regular issue' do issue = build(:issue, project: project) diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb index d41717d0223..3508391c721 100644 --- a/spec/models/key_spec.rb +++ b/spec/models/key_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe Key do - include EmailHelpers - +describe Key, :mailer do describe "Associations" do it { is_expected.to belong_to(:user) } end @@ -85,24 +83,16 @@ describe Key do expect(build(:key)).to be_valid end - it 'rejects an unfingerprintable key that contains a space' do + it 'accepts a key with newline charecters after stripping them' do key = build(:key) - - # Not always the middle, but close enough - key.key = key.key[0..100] + ' ' + key.key[101..-1] - - expect(key).not_to be_valid + key.key = key.key.insert(100, "\n") + key.key = key.key.insert(40, "\r\n") + expect(key).to be_valid end it 'rejects the unfingerprintable key (not a key)' do expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid end - - it 'rejects the multiple line key' do - key = build(:key) - key.key.tr!(' ', "\n") - expect(key).not_to be_valid - end end context 'callbacks' do diff --git a/spec/models/lfs_objects_project_spec.rb b/spec/models/lfs_objects_project_spec.rb index 8c74f1f9e86..d24d4cf7695 100644 --- a/spec/models/lfs_objects_project_spec.rb +++ b/spec/models/lfs_objects_project_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe LfsObjectsProject do subject { create(:lfs_objects_project, project: project) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } describe 'associations' do it { is_expected.to belong_to(:project) } diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb index 8bfd70b8d46..87513e18b25 100644 --- a/spec/models/member_spec.rb +++ b/spec/models/member_spec.rb @@ -57,7 +57,7 @@ describe Member do describe 'Scopes & finders' do before do - project = create(:empty_project, :public, :access_requestable) + project = create(:project, :public, :access_requestable) group = create(:group) @owner_user = create(:user).tap { |u| group.add_owner(u) } @owner = group.members.find_by(user_id: @owner_user.id) @@ -516,7 +516,7 @@ describe Member do describe "destroying a record", truncate: true do it "refreshes user's authorized projects" do - project = create(:empty_project, :private) + project = create(:project, :private) user = create(:user) member = project.team << [user, :reporter] diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 025fb2bf441..fa3e80ba062 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -24,7 +24,7 @@ describe ProjectMember do describe '.add_user' do it 'adds the user as a member' do user = create(:user) - project = create(:empty_project) + project = create(:project) expect(project.users).not_to include(user) @@ -82,8 +82,8 @@ describe ProjectMember do describe '.import_team' do before do - @project_1 = create(:empty_project) - @project_2 = create(:empty_project) + @project_1 = create(:project) + @project_2 = create(:project) @user_1 = create :user @user_2 = create :user @@ -112,7 +112,7 @@ describe ProjectMember do describe '.add_users_to_projects' do it 'adds the given users to the given projects' do - projects = create_list(:empty_project, 2) + projects = create_list(:project, 2) users = create_list(:user, 2) described_class.add_users_to_projects( @@ -130,8 +130,8 @@ describe ProjectMember do describe '.truncate_teams' do before do - @project_1 = create(:empty_project) - @project_2 = create(:empty_project) + @project_1 = create(:project) + @project_2 = create(:project) @user_1 = create :user @user_2 = create :user @@ -149,7 +149,7 @@ describe ProjectMember do describe 'notifications' do describe '#after_accept_request' do it 'calls NotificationService.new_project_member' do - member = create(:project_member, user: build_stubbed(:user), requested_at: Time.now) + member = create(:project_member, user: create(:user), requested_at: Time.now) expect_any_instance_of(NotificationService).to receive(:new_project_member) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index b2dd02553c1..026bdbd26d1 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -237,7 +237,7 @@ describe MergeRequest do end describe '#to_reference' do - let(:project) { build(:empty_project, name: 'sample-project') } + let(:project) { build(:project, name: 'sample-project') } let(:merge_request) { build(:merge_request, target_project: project, iid: 1) } it 'returns a String reference to the object' do @@ -245,12 +245,12 @@ describe MergeRequest do end it 'supports a cross-project reference' do - another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) + another_project = build(:project, name: 'another-project', namespace: project.namespace) expect(merge_request.to_reference(another_project)).to eq "sample-project!1" end it 'returns a String reference with the full path' do - expect(merge_request.to_reference(full: true)).to eq(project.path_with_namespace + '!1') + expect(merge_request.to_reference(full: true)).to eq(project.full_path + '!1') end end @@ -392,8 +392,8 @@ describe MergeRequest do describe '#for_fork?' do it 'returns true if the merge request is for a fork' do - subject.source_project = build_stubbed(:empty_project, namespace: create(:group)) - subject.target_project = build_stubbed(:empty_project, namespace: create(:group)) + subject.source_project = build_stubbed(:project, namespace: create(:group)) + subject.target_project = build_stubbed(:project, namespace: create(:group)) expect(subject.for_fork?).to be_truthy end @@ -681,7 +681,7 @@ describe MergeRequest do end it 'does not crash' do - expect{ subject.diverged_commits_count }.not_to raise_error + expect { subject.diverged_commits_count }.not_to raise_error end it 'returns 0' do @@ -714,7 +714,7 @@ describe MergeRequest do end describe 'caching' do - before(:example) do + before do allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new) end @@ -753,7 +753,7 @@ describe MergeRequest do subject { create(:merge_request, :simple) } let(:backref_text) { "merge request #{subject.to_reference}" } - let(:set_mentionable_text) { ->(txt){ subject.description = txt } } + let(:set_mentionable_text) { ->(txt) { subject.description = txt } } end it_behaves_like 'a Taskable' do @@ -889,7 +889,7 @@ describe MergeRequest do end describe '#participants' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:mr) do create(:merge_request, source_project: project, target_project: project) @@ -932,7 +932,7 @@ describe MergeRequest do end describe '#check_if_can_be_merged' do - let(:project) { create(:empty_project, only_allow_merge_if_pipeline_succeeds: true) } + let(:project) { create(:project, only_allow_merge_if_pipeline_succeeds: true) } subject { create(:merge_request, source_project: project, merge_status: :unchecked) } @@ -970,7 +970,7 @@ describe MergeRequest do end describe '#mergeable?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { create(:merge_request, source_project: project) } @@ -1055,7 +1055,7 @@ describe MergeRequest do end describe '#mergeable_ci_state?' do - let(:project) { create(:empty_project, only_allow_merge_if_pipeline_succeeds: true) } + let(:project) { create(:project, only_allow_merge_if_pipeline_succeeds: true) } let(:pipeline) { create(:ci_empty_pipeline) } subject { build(:merge_request, target_project: project) } @@ -1098,7 +1098,7 @@ describe MergeRequest do end context 'when merges are not restricted to green builds' do - subject { build(:merge_request, target_project: build(:empty_project, only_allow_merge_if_pipeline_succeeds: false)) } + subject { build(:merge_request, target_project: build(:project, only_allow_merge_if_pipeline_succeeds: false)) } context 'and a failed pipeline is associated' do before do @@ -1332,8 +1332,8 @@ describe MergeRequest do end describe "#source_project_missing?" do - let(:project) { create(:empty_project) } - let(:fork_project) { create(:empty_project, forked_from_project: project) } + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } let(:user) { create(:user) } let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } @@ -1369,9 +1369,35 @@ describe MergeRequest do end end + describe '#merge_ongoing?' do + it 'returns true when merge process is ongoing for merge_jid' do + merge_request = create(:merge_request, merge_jid: 'foo') + + allow(Gitlab::SidekiqStatus).to receive(:num_running).with(['foo']).and_return(1) + + expect(merge_request.merge_ongoing?).to be(true) + end + + it 'returns false when no merge process running for merge_jid' do + merge_request = build(:merge_request, merge_jid: 'foo') + + allow(Gitlab::SidekiqStatus).to receive(:num_running).with(['foo']).and_return(0) + + expect(merge_request.merge_ongoing?).to be(false) + end + + it 'returns false when merge_jid is nil' do + merge_request = build(:merge_request, merge_jid: nil) + + expect(Gitlab::SidekiqStatus).not_to receive(:num_running) + + expect(merge_request.merge_ongoing?).to be(false) + end + end + describe "#closed_without_fork?" do - let(:project) { create(:empty_project) } - let(:fork_project) { create(:empty_project, forked_from_project: project) } + let(:project) { create(:project) } + let(:fork_project) { create(:project, forked_from_project: project) } let(:user) { create(:user) } let(:unlink_project) { Projects::UnlinkForkService.new(fork_project, user) } @@ -1416,9 +1442,9 @@ describe MergeRequest do end context 'forked project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } - let(:fork_project) { create(:empty_project, forked_from_project: project, namespace: user.namespace) } + let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) } let!(:merge_request) do create(:closed_merge_request, diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index aa376e242e8..d3da0107d5c 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -21,7 +21,7 @@ describe Milestone do it { is_expected.to have_many(:issues) } end - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:milestone) { create(:milestone, project: project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } @@ -42,7 +42,7 @@ describe Milestone do end it "accepts the same title in another project" do - project = create(:empty_project) + project = create(:project) new_milestone = described_class.new(project: project, title: milestone.title) expect(new_milestone).to be_valid @@ -197,9 +197,9 @@ describe Milestone do end describe '.upcoming_ids_by_projects' do - let(:project_1) { create(:empty_project) } - let(:project_2) { create(:empty_project) } - let(:project_3) { create(:empty_project) } + let(:project_1) { create(:project) } + let(:project_2) { create(:project) } + let(:project_3) { create(:project) } let(:projects) { [project_1, project_2, project_3] } let!(:past_milestone_project_1) { create(:milestone, project: project_1, due_date: Time.now - 1.day) } @@ -230,21 +230,45 @@ describe Milestone do end describe '#to_reference' do - let(:project) { build(:empty_project, name: 'sample-project') } - let(:milestone) { build(:milestone, iid: 1, project: project) } + let(:group) { build_stubbed(:group) } + let(:project) { build_stubbed(:project, name: 'sample-project') } + let(:another_project) { build_stubbed(:project, name: 'another-project', namespace: project.namespace) } + + context 'for a project milestone' do + let(:milestone) { build_stubbed(:milestone, iid: 1, project: project, name: 'milestone') } + + it 'returns a String reference to the object' do + expect(milestone.to_reference).to eq '%1' + end - it 'returns a String reference to the object' do - expect(milestone.to_reference).to eq "%1" + it 'returns a reference by name when the format is set to :name' do + expect(milestone.to_reference(format: :name)).to eq '%"milestone"' + end + + it 'supports a cross-project reference' do + expect(milestone.to_reference(another_project)).to eq 'sample-project%1' + end end - it 'supports a cross-project reference' do - another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) - expect(milestone.to_reference(another_project)).to eq "sample-project%1" + context 'for a group milestone' do + let(:milestone) { build_stubbed(:milestone, iid: 1, group: group, name: 'milestone') } + + it 'returns nil with the default format' do + expect(milestone.to_reference).to be_nil + end + + it 'returns a reference by name when the format is set to :name' do + expect(milestone.to_reference(format: :name)).to eq '%"milestone"' + end + + it 'does not supports cross-project references' do + expect(milestone.to_reference(another_project, format: :name)).to eq '%"milestone"' + end end end describe '#participants' do - let(:project) { build(:empty_project, name: 'sample-project') } + let(:project) { build(:project, name: 'sample-project') } let(:milestone) { build(:milestone, iid: 1, project: project) } it 'returns participants without duplicates' do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index f12fe226e6b..69286eff984 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -111,7 +111,7 @@ describe Namespace do let(:namespace) { create :namespace } let(:project1) do - create(:empty_project, + create(:project, namespace: namespace, statistics: build(:project_statistics, storage_size: 606, @@ -121,7 +121,7 @@ describe Namespace do end let(:project2) do - create(:empty_project, + create(:project, namespace: namespace, statistics: build(:project_statistics, storage_size: 60, @@ -177,7 +177,7 @@ describe Namespace do stub_container_registry_config(enabled: true) stub_container_registry_tags(repository: :any, tags: ['tag']) - create(:empty_project, namespace: @namespace, container_repositories: [container_repository]) + create(:project, namespace: @namespace, container_repositories: [container_repository]) allow(@namespace).to receive(:path_was).and_return(@namespace.path) allow(@namespace).to receive(:path).and_return('new_path') @@ -315,6 +315,20 @@ describe Namespace do end end + describe '#self_and_ancestors', :nested_groups do + let(:group) { create(:group) } + let(:nested_group) { create(:group, parent: group) } + let(:deep_nested_group) { create(:group, parent: nested_group) } + let(:very_deep_nested_group) { create(:group, parent: deep_nested_group) } + + it 'returns the correct ancestors' do + expect(very_deep_nested_group.self_and_ancestors).to contain_exactly(group, nested_group, deep_nested_group, very_deep_nested_group) + expect(deep_nested_group.self_and_ancestors).to contain_exactly(group, nested_group, deep_nested_group) + expect(nested_group.self_and_ancestors).to contain_exactly(group, nested_group) + expect(group.self_and_ancestors).to contain_exactly(group) + end + end + describe '#descendants', :nested_groups do let!(:group) { create(:group, path: 'git_lab') } let!(:nested_group) { create(:group, parent: group) } @@ -331,6 +345,22 @@ describe Namespace do end end + describe '#self_and_descendants', :nested_groups do + let!(:group) { create(:group, path: 'git_lab') } + let!(:nested_group) { create(:group, parent: group) } + let!(:deep_nested_group) { create(:group, parent: nested_group) } + let!(:very_deep_nested_group) { create(:group, parent: deep_nested_group) } + let!(:another_group) { create(:group, path: 'gitllab') } + let!(:another_group_nested) { create(:group, path: 'foo', parent: another_group) } + + it 'returns the correct descendants' do + expect(very_deep_nested_group.self_and_descendants).to contain_exactly(very_deep_nested_group) + expect(deep_nested_group.self_and_descendants).to contain_exactly(deep_nested_group, very_deep_nested_group) + expect(nested_group.self_and_descendants).to contain_exactly(nested_group, deep_nested_group, very_deep_nested_group) + expect(group.self_and_descendants).to contain_exactly(group, nested_group, deep_nested_group, very_deep_nested_group) + end + end + describe '#users_with_descendants', :nested_groups do let(:user_a) { create(:user) } let(:user_b) { create(:user) } diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index cbe6d42ef53..b214074fdce 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -46,7 +46,7 @@ describe Note do context 'when noteable and note project differ' do subject do build(:note, noteable: build_stubbed(:issue), - project: build_stubbed(:empty_project)) + project: build_stubbed(:project)) end it { is_expected.to be_invalid } @@ -97,8 +97,8 @@ describe Note do describe 'authorization' do before do - @p1 = create(:empty_project) - @p2 = create(:empty_project) + @p1 = create(:project) + @p2 = create(:project) @u1 = create(:user) @u2 = create(:user) @u3 = create(:user) @@ -195,10 +195,10 @@ describe Note do describe "cross_reference_not_visible_for?" do let(:private_user) { create(:user) } - let(:private_project) { create(:empty_project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } } + let(:private_project) { create(:project, namespace: private_user.namespace) { |p| p.team << [private_user, :master] } } let(:private_issue) { create(:issue, project: private_project) } - let(:ext_proj) { create(:empty_project, :public) } + let(:ext_proj) { create(:project, :public) } let(:ext_issue) { create(:issue, project: ext_proj) } let(:note) do @@ -241,7 +241,7 @@ describe Note do describe '#participants' do it 'includes the note author' do - project = create(:empty_project, :public) + project = create(:project, :public) issue = create(:issue, project: project) note = create(:note_on_issue, noteable: issue, project: project) diff --git a/spec/models/notification_setting_spec.rb b/spec/models/notification_setting_spec.rb index 07e296424ca..2a0d102d3fe 100644 --- a/spec/models/notification_setting_spec.rb +++ b/spec/models/notification_setting_spec.rb @@ -63,24 +63,20 @@ RSpec.describe NotificationSetting do end end - describe 'event_enabled?' do + describe '#event_enabled?' do before do subject.update!(user: create(:user)) end context 'for an event with a matching column name' do - before do - subject.update!(events: { new_note: true }.to_json) - end - it 'returns the value of the column' do - subject.update!(new_note: false) + subject.update!(new_note: true) - expect(subject.event_enabled?(:new_note)).to be(false) + expect(subject.event_enabled?(:new_note)).to be(true) end context 'when the column has a nil value' do - it 'returns the value from the events hash' do + it 'returns false' do expect(subject.event_enabled?(:new_note)).to be(false) end end diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb index ee6bdc39c8c..9e7e525b2c0 100644 --- a/spec/models/project_authorization_spec.rb +++ b/spec/models/project_authorization_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe ProjectAuthorization do let(:user) { create(:user) } - let(:project1) { create(:empty_project) } - let(:project2) { create(:empty_project) } + let(:project1) { create(:project) } + let(:project2) { create(:project) } describe '.insert_authorizations' do it 'inserts the authorizations' do diff --git a/spec/models/project_feature_spec.rb b/spec/models/project_feature_spec.rb index 580c83c12c0..de3e86b627f 100644 --- a/spec/models/project_feature_spec.rb +++ b/spec/models/project_feature_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProjectFeature do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } describe '.quoted_access_level_column' do @@ -47,7 +47,7 @@ describe ProjectFeature do it "returns true when user is a member of project group" do group = create(:group) - project = create(:empty_project, namespace: group) + project = create(:project, namespace: group) group.add_developer(user) features.each do |feature| diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index d68d8b719cd..b3513c80150 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -32,7 +32,7 @@ describe ProjectGroupLink do describe "destroying a record", truncate: true do it "refreshes group users' authorized projects" do - project = create(:empty_project, :private) + project = create(:project, :private) group = create(:group) reporter = create(:user) group_users = group.users diff --git a/spec/models/project_label_spec.rb b/spec/models/project_label_spec.rb index add7e85f388..689d4e505e5 100644 --- a/spec/models/project_label_spec.rb +++ b/spec/models/project_label_spec.rb @@ -10,7 +10,7 @@ describe ProjectLabel do context 'validates if title must not exist at group level' do let(:group) { create(:group, name: 'gitlab-org') } - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } before do create(:group_label, group: group, title: 'Bug') @@ -33,7 +33,7 @@ describe ProjectLabel do end it 'does not returns error if project does not belong to group' do - another_project = create(:empty_project) + another_project = create(:project) label = described_class.new(project: another_project, title: 'Bug') label.valid? @@ -66,7 +66,7 @@ describe ProjectLabel do describe '#subject' do it 'aliases project to subject' do - subject = described_class.new(project: build(:empty_project)) + subject = described_class.new(project: build(:project)) expect(subject.subject).to be(subject.project) end @@ -100,19 +100,19 @@ describe ProjectLabel do end context 'cross project reference' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'using name' do it 'returns cross reference with label name' do expect(label.to_reference(project, format: :name)) - .to eq %Q(#{label.project.path_with_namespace}~"#{label.name}") + .to eq %Q(#{label.project.full_path}~"#{label.name}") end end context 'using id' do it 'returns cross reference with label id' do expect(label.to_reference(project, format: :id)) - .to eq %Q(#{label.project.path_with_namespace}~#{label.id}) + .to eq %Q(#{label.project.full_path}~#{label.id}) end end end diff --git a/spec/models/project_services/asana_service_spec.rb b/spec/models/project_services/asana_service_spec.rb index 4684c970885..04440d890aa 100644 --- a/spec/models/project_services/asana_service_spec.rb +++ b/spec/models/project_services/asana_service_spec.rb @@ -18,7 +18,7 @@ describe AsanaService do describe 'Execute' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } def create_data_for_commits(*messages) { diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index 82f02126de1..85baaccf035 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -7,7 +7,7 @@ describe BambooService, :use_clean_rails_memory_store_caching do subject(:service) do described_class.create( - project: create(:empty_project), + project: create(:project), properties: { bamboo_url: bamboo_url, username: 'mic', diff --git a/spec/models/project_services/buildkite_service_spec.rb b/spec/models/project_services/buildkite_service_spec.rb index 3f7eb33e08a..1615a93a4ca 100644 --- a/spec/models/project_services/buildkite_service_spec.rb +++ b/spec/models/project_services/buildkite_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe BuildkiteService, :use_clean_rails_memory_store_caching do include ReactiveCachingHelpers - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject(:service) do described_class.create( diff --git a/spec/models/project_services/chat_notification_service_spec.rb b/spec/models/project_services/chat_notification_service_spec.rb index 413ceed73bf..3aa1039d8bf 100644 --- a/spec/models/project_services/chat_notification_service_spec.rb +++ b/spec/models/project_services/chat_notification_service_spec.rb @@ -12,7 +12,7 @@ describe ChatNotificationService do describe '#can_test?' do context 'with empty repository' do it 'returns true' do - subject.project = create(:empty_project, :empty_repo) + subject.project = create(:project, :empty_repo) expect(subject.can_test?).to be true end @@ -20,7 +20,7 @@ describe ChatNotificationService do context 'with repository' do it 'returns true' do - subject.project = create(:project) + subject.project = create(:project, :repository) expect(subject.can_test?).to be true end diff --git a/spec/models/project_services/drone_ci_service_spec.rb b/spec/models/project_services/drone_ci_service_spec.rb index 5b0f24ce306..d8972aff407 100644 --- a/spec/models/project_services/drone_ci_service_spec.rb +++ b/spec/models/project_services/drone_ci_service_spec.rb @@ -43,7 +43,7 @@ describe DroneCiService, :use_clean_rails_memory_store_caching do let(:build_page) { "#{drone_url}/gitlab/#{path}/redirect/commits/#{sha}?branch=#{branch}" } let(:commit_status_path) { "#{drone_url}/gitlab/#{path}/commits/#{sha}?branch=#{branch}&access_token=#{token}" } - before(:each) do + before do allow(drone).to receive_messages( project_id: project.id, project: project, diff --git a/spec/models/project_services/external_wiki_service_spec.rb b/spec/models/project_services/external_wiki_service_spec.rb index 22cd9d5e31e..25e6ce7e804 100644 --- a/spec/models/project_services/external_wiki_service_spec.rb +++ b/spec/models/project_services/external_wiki_service_spec.rb @@ -27,7 +27,7 @@ describe ExternalWikiService do end describe 'External wiki' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when it is active' do before do diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb index d19dab8fd39..3237b660a16 100644 --- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb +++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb @@ -8,21 +8,21 @@ describe GitlabIssueTrackerService do describe 'Validations' do context 'when service is active' do - subject { described_class.new(project: create(:empty_project), active: true) } + subject { described_class.new(project: create(:project), active: true) } it { is_expected.to validate_presence_of(:issues_url) } it_behaves_like 'issue tracker service URL attribute', :issues_url end context 'when service is inactive' do - subject { described_class.new(project: create(:empty_project), active: false) } + subject { described_class.new(project: create(:project), active: false) } it { is_expected.not_to validate_presence_of(:issues_url) } end end describe 'project and issue urls' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:service) { project.create_gitlab_issue_tracker_service(active: true) } context 'with absolute urls' do @@ -31,9 +31,9 @@ describe GitlabIssueTrackerService do end it 'gives the correct path' do - expect(service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues") - expect(service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/new") - expect(service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/432") + expect(service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.full_path}/issues") + expect(service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.full_path}/issues/new") + expect(service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.full_path}/issues/432") end end @@ -43,9 +43,9 @@ describe GitlabIssueTrackerService do end it 'gives the correct path' do - expect(service.issue_tracker_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues") - expect(service.new_issue_path).to eq("/gitlab/root/#{project.path_with_namespace}/issues/new") - expect(service.issue_path(432)).to eq("/gitlab/root/#{project.path_with_namespace}/issues/432") + expect(service.issue_tracker_path).to eq("/gitlab/root/#{project.full_path}/issues") + expect(service.new_issue_path).to eq("/gitlab/root/#{project.full_path}/issues/new") + expect(service.issue_path(432)).to eq("/gitlab/root/#{project.full_path}/issues/432") end end end diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 7614bb897e8..23db29cb541 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -36,7 +36,7 @@ describe HipchatService do Gitlab::DataBuilder::Push.build_sample(project, user) end - before(:each) do + before do allow(hipchat).to receive_messages( project_id: project.id, project: project, diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 8f34b44930e..63bf131cfc5 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -29,7 +29,7 @@ describe JiraService do context 'validating urls' do let(:service) do described_class.new( - project: create(:empty_project), + project: create(:project), active: true, username: 'username', password: 'test', @@ -74,7 +74,7 @@ describe JiraService do describe '#close_issue' do let(:custom_base_url) { 'http://custom_url' } let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:merge_request) { create(:merge_request) } before do @@ -135,7 +135,7 @@ describe JiraService do body: hash_including( GlobalID: "GitLab", object: { - url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{merge_request.diff_head_sha}", + url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/#{merge_request.diff_head_sha}", title: "GitLab: Solved by commit #{merge_request.diff_head_sha}.", icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" }, status: { resolved: true } @@ -153,13 +153,22 @@ describe JiraService do expect(WebMock).not_to have_requested(:post, @remote_link_url) end + it "does not send comment or remote links to issues with unknown resolution" do + allow_any_instance_of(JIRA::Resource::Issue).to receive(:respond_to?).with(:resolution).and_return(false) + + @jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project)) + + expect(WebMock).not_to have_requested(:post, @comment_url) + expect(WebMock).not_to have_requested(:post, @remote_link_url) + end + it "references the GitLab commit/merge request" do stub_config_setting(base_url: custom_base_url) @jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project)) expect(WebMock).to have_requested(:post, @comment_url).with( - body: /#{custom_base_url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/ + body: /#{custom_base_url}\/#{project.full_path}\/commit\/#{merge_request.diff_head_sha}/ ).once end @@ -174,7 +183,7 @@ describe JiraService do @jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project)) expect(WebMock).to have_requested(:post, @comment_url).with( - body: /#{Gitlab.config.gitlab.url}\/#{project.path_with_namespace}\/commit\/#{merge_request.diff_head_sha}/ + body: /#{Gitlab.config.gitlab.url}\/#{project.full_path}\/commit\/#{merge_request.diff_head_sha}/ ).once end @@ -233,7 +242,7 @@ describe JiraService do end describe "Stored password invalidation" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context "when a password was previously set" do before do @@ -338,7 +347,7 @@ describe JiraService do end describe 'description and title' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when it is not set' do before do @@ -373,7 +382,7 @@ describe JiraService do end describe 'project and issue urls' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when gitlab.yml was initialized' do before do diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 4c21c8b88bd..522cf15f3ba 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -4,7 +4,7 @@ describe MattermostSlashCommandsService do it_behaves_like "chat slash commands service" context 'Mattermost API' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:service) { project.build_mattermost_slash_commands_service } let(:user) { create(:user) } diff --git a/spec/models/project_services/pipelines_email_service_spec.rb b/spec/models/project_services/pipelines_email_service_spec.rb index 03932895b0e..5faab9ba38b 100644 --- a/spec/models/project_services/pipelines_email_service_spec.rb +++ b/spec/models/project_services/pipelines_email_service_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe PipelinesEmailService do - include EmailHelpers - +describe PipelinesEmailService, :mailer do let(:pipeline) do create(:ci_pipeline, project: project, sha: project.commit('master').sha) end @@ -14,10 +12,6 @@ describe PipelinesEmailService do Gitlab::DataBuilder::Pipeline.build(pipeline) end - before do - reset_delivered_emails! - end - describe 'Validations' do context 'when service is active' do before do diff --git a/spec/models/project_services/slack_slash_commands_service_spec.rb b/spec/models/project_services/slack_slash_commands_service_spec.rb index aea674c4f6b..0d95f454819 100644 --- a/spec/models/project_services/slack_slash_commands_service_spec.rb +++ b/spec/models/project_services/slack_slash_commands_service_spec.rb @@ -5,7 +5,7 @@ describe SlackSlashCommandsService do describe '#trigger' do context 'when an auth url is generated' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:params) do { team_domain: 'http://domain.tld', diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb index 47fd0c79e0b..43a0ed99296 100644 --- a/spec/models/project_services/teamcity_service_spec.rb +++ b/spec/models/project_services/teamcity_service_spec.rb @@ -7,7 +7,7 @@ describe TeamcityService, :use_clean_rails_memory_store_caching do subject(:service) do described_class.create( - project: create(:empty_project), + project: create(:project), properties: { teamcity_url: teamcity_url, username: 'mic', diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 473b7a88d61..eba71ba2f72 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -82,7 +82,7 @@ describe Project do end describe '#members & #requesters' do - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:requester) { create(:user) } let(:developer) { create(:user) } before do @@ -131,7 +131,7 @@ describe Project do end describe 'validation' do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_uniqueness_of(:name).scoped_to(:namespace_id) } @@ -154,7 +154,7 @@ describe Project do it { is_expected.to validate_presence_of(:repository_storage) } it 'does not allow new projects beyond user limits' do - project2 = build(:empty_project) + project2 = build(:project) allow(project2).to receive(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object) expect(project2).not_to be_valid expect(project2.errors[:limit_reached].first).to match(/Personal project creation is not allowed/) @@ -163,7 +163,7 @@ describe Project do describe 'wiki path conflict' do context "when the new path has been used by the wiki of other Project" do it 'has an error on the name attribute' do - new_project = build_stubbed(:empty_project, namespace_id: project.namespace_id, path: "#{project.path}.wiki") + new_project = build_stubbed(:project, namespace_id: project.namespace_id, path: "#{project.path}.wiki") expect(new_project).not_to be_valid expect(new_project.errors[:name].first).to eq('has already been taken') @@ -172,8 +172,8 @@ describe Project do context "when the new wiki path has been used by the path of other Project" do it 'has an error on the name attribute' do - project_with_wiki_suffix = create(:empty_project, path: 'foo.wiki') - new_project = build_stubbed(:empty_project, namespace_id: project_with_wiki_suffix.namespace_id, path: 'foo') + project_with_wiki_suffix = create(:project, path: 'foo.wiki') + new_project = build_stubbed(:project, namespace_id: project_with_wiki_suffix.namespace_id, path: 'foo') expect(new_project).not_to be_valid expect(new_project.errors[:name].first).to eq('has already been taken') @@ -182,7 +182,7 @@ describe Project do end context 'repository storages inclussion' do - let(:project2) { build(:empty_project, repository_storage: 'missing') } + let(:project2) { build(:project, repository_storage: 'missing') } before do storages = { 'custom' => { 'path' => 'tmp/tests/custom_repositories' } } @@ -196,44 +196,44 @@ describe Project do end it 'does not allow an invalid URI as import_url' do - project2 = build(:empty_project, import_url: 'invalid://') + project2 = build(:project, import_url: 'invalid://') expect(project2).not_to be_valid end it 'does allow a valid URI as import_url' do - project2 = build(:empty_project, import_url: 'ssh://test@gitlab.com/project.git') + project2 = build(:project, import_url: 'ssh://test@gitlab.com/project.git') expect(project2).to be_valid end it 'allows an empty URI' do - project2 = build(:empty_project, import_url: '') + project2 = build(:project, import_url: '') expect(project2).to be_valid end it 'does not produce import data on an empty URI' do - project2 = build(:empty_project, import_url: '') + project2 = build(:project, import_url: '') expect(project2.import_data).to be_nil end it 'does not produce import data on an invalid URI' do - project2 = build(:empty_project, import_url: 'test://') + project2 = build(:project, import_url: 'test://') expect(project2.import_data).to be_nil end it "does not allow blocked import_url localhost" do - project2 = build(:empty_project, import_url: 'http://localhost:9000/t.git') + project2 = build(:project, import_url: 'http://localhost:9000/t.git') expect(project2).to be_invalid expect(project2.errors[:import_url]).to include('imports are not allowed from that URL') end it "does not allow blocked import_url port" do - project2 = build(:empty_project, import_url: 'http://github.com:25/t.git') + project2 = build(:project, import_url: 'http://github.com:25/t.git') expect(project2).to be_invalid expect(project2.errors[:import_url]).to include('imports are not allowed from that URL') @@ -241,11 +241,11 @@ describe Project do describe 'project pending deletion' do let!(:project_pending_deletion) do - create(:empty_project, + create(:project, pending_delete: true) end let(:new_project) do - build(:empty_project, + build(:project, name: project_pending_deletion.name, namespace: project_pending_deletion.namespace) end @@ -290,12 +290,12 @@ describe Project do describe 'project token' do it 'sets an random token if none provided' do - project = FactoryGirl.create :empty_project, runners_token: '' + project = FactoryGirl.create :project, runners_token: '' expect(project.runners_token).not_to eq('') end it 'does not set an random token if one provided' do - project = FactoryGirl.create :empty_project, runners_token: 'my-token' + project = FactoryGirl.create :project, runners_token: 'my-token' expect(project.runners_token).to eq('my-token') end end @@ -306,6 +306,7 @@ describe Project do it { is_expected.to respond_to(:execute_hooks) } it { is_expected.to respond_to(:owner) } it { is_expected.to respond_to(:path_with_namespace) } + it { is_expected.to respond_to(:full_path) } end describe 'delegation' do @@ -322,7 +323,7 @@ describe Project do describe '#to_reference' do let(:owner) { create(:user, name: 'Gitlab') } let(:namespace) { create(:namespace, path: 'sample-namespace', owner: owner) } - let(:project) { create(:empty_project, path: 'sample-project', namespace: namespace) } + let(:project) { create(:project, path: 'sample-project', namespace: namespace) } let(:group) { create(:group, name: 'Group', path: 'sample-group', owner: owner) } context 'when nil argument' do @@ -346,7 +347,7 @@ describe Project do end context 'when cross namespace project argument' do - let(:another_namespace_project) { create(:empty_project, name: 'another-project') } + let(:another_namespace_project) { create(:project, name: 'another-project') } it 'returns complete path to the project' do expect(project.to_reference(another_namespace_project)).to eq 'sample-namespace/sample-project' @@ -354,7 +355,7 @@ describe Project do end context 'when same namespace / cross-project argument' do - let(:another_project) { create(:empty_project, namespace: namespace) } + let(:another_project) { create(:project, namespace: namespace) } it 'returns path to the project' do expect(project.to_reference(another_project)).to eq 'sample-project' @@ -363,7 +364,7 @@ describe Project do context 'when different namespace / cross-project argument' do let(:another_namespace) { create(:namespace, path: 'another-namespace', owner: owner) } - let(:another_project) { create(:empty_project, path: 'another-project', namespace: another_namespace) } + let(:another_project) { create(:project, path: 'another-project', namespace: another_namespace) } it 'returns full path to the project' do expect(project.to_reference(another_project)).to eq 'sample-namespace/sample-project' @@ -388,7 +389,7 @@ describe Project do describe '#to_human_reference' do let(:owner) { create(:user, name: 'Gitlab') } let(:namespace) { create(:namespace, name: 'Sample namespace', owner: owner) } - let(:project) { create(:empty_project, name: 'Sample project', namespace: namespace) } + let(:project) { create(:project, name: 'Sample project', namespace: namespace) } context 'when nil argument' do it 'returns nil' do @@ -403,7 +404,7 @@ describe Project do end context 'when cross namespace project argument' do - let(:another_namespace_project) { create(:empty_project, name: 'another-project') } + let(:another_namespace_project) { create(:project, name: 'another-project') } it 'returns complete name with namespace of the project' do expect(project.to_human_reference(another_namespace_project)).to eq 'Gitlab / Sample project' @@ -411,7 +412,7 @@ describe Project do end context 'when same namespace / cross-project argument' do - let(:another_project) { create(:empty_project, namespace: namespace) } + let(:another_project) { create(:project, namespace: namespace) } it 'returns name of the project' do expect(project.to_human_reference(another_project)).to eq 'Sample project' @@ -420,7 +421,7 @@ describe Project do end describe '#repository_storage_path' do - let(:project) { create(:empty_project, repository_storage: 'custom') } + let(:project) { create(:project, repository_storage: 'custom') } before do FileUtils.mkdir('tmp/tests/custom_repositories') @@ -443,7 +444,7 @@ describe Project do end describe "#web_url" do - let(:project) { create(:empty_project, path: "somewhere") } + let(:project) { create(:project, path: "somewhere") } it 'returns the full web URL for this repo' do expect(project.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.namespace.full_path}/somewhere") @@ -451,7 +452,7 @@ describe Project do end describe "#new_issue_address" do - let(:project) { create(:empty_project, path: "somewhere") } + let(:project) { create(:project, path: "somewhere") } let(:user) { create(:user) } context 'incoming email enabled' do @@ -460,7 +461,7 @@ describe Project do end it 'returns the address to create a new issue' do - address = "p+#{project.path_with_namespace}+#{user.incoming_email_token}@gl.ab" + address = "p+#{project.full_path}+#{user.incoming_email_token}@gl.ab" expect(project.new_issue_address(user)).to eq(address) end @@ -480,11 +481,11 @@ describe Project do describe 'last_activity methods' do let(:timestamp) { 2.hours.ago } # last_activity_at gets set to created_at upon creation - let(:project) { create(:empty_project, created_at: timestamp, updated_at: timestamp) } + let(:project) { create(:project, created_at: timestamp, updated_at: timestamp) } describe 'last_activity' do it 'alias last_activity to last_event' do - last_event = create(:event, project: project) + last_event = create(:event, :closed, project: project) expect(project.last_activity).to eq(last_event) end @@ -492,7 +493,7 @@ describe Project do describe 'last_activity_date' do it 'returns the creation date of the project\'s last event if present' do - new_event = create(:event, project: project, created_at: Time.now) + new_event = create(:event, :closed, project: project, created_at: Time.now) project.reload expect(project.last_activity_at.to_i).to eq(new_event.created_at.to_i) @@ -505,7 +506,7 @@ describe Project do end describe '#get_issue' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:issue) { create(:issue, project: project) } let(:user) { create(:user) } @@ -580,7 +581,7 @@ describe Project do end describe '#issue_exists?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'is truthy when issue exists' do expect(project).to receive(:get_issue).and_return(double) @@ -597,7 +598,7 @@ describe Project do context 'with namespace' do before do @group = create :group, name: 'gitlab' - @project = create(:empty_project, name: 'gitlabhq', namespace: @group) + @project = create(:project, name: 'gitlabhq', namespace: @group) end it { expect(@project.to_param).to eq('gitlabhq') } @@ -605,7 +606,7 @@ describe Project do context 'with invalid path' do it 'returns previous path to keep project suitable for use in URLs when persisted' do - project = create(:empty_project, path: 'gitlab') + project = create(:project, path: 'gitlab') project.path = 'foo&bar' expect(project).not_to be_valid @@ -613,7 +614,7 @@ describe Project do end it 'returns current path when new record' do - project = build(:empty_project, path: 'gitlab') + project = build(:project, path: 'gitlab') project.path = 'foo&bar' expect(project).not_to be_valid @@ -632,7 +633,7 @@ describe Project do describe '#default_issues_tracker?' do it "is true if used internal tracker" do - project = build(:empty_project) + project = build(:project) expect(project.default_issues_tracker?).to be_truthy end @@ -646,11 +647,11 @@ describe Project do end describe '#external_issue_tracker' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:ext_project) { create(:redmine_project) } context 'on existing projects with no value for has_external_issue_tracker' do - before(:each) do + before do project.update_column(:has_external_issue_tracker, nil) ext_project.update_column(:has_external_issue_tracker, nil) end @@ -681,7 +682,7 @@ describe Project do end describe '#cache_has_external_issue_tracker' do - let(:project) { create(:empty_project, has_external_issue_tracker: nil) } + let(:project) { create(:project, has_external_issue_tracker: nil) } it 'stores true if there is any external_issue_tracker' do services = double(:service, external_issue_trackers: [RedmineService.new]) @@ -703,9 +704,9 @@ describe Project do end describe '#has_wiki?' do - let(:no_wiki_project) { create(:empty_project, :wiki_disabled, has_external_wiki: false) } - let(:wiki_enabled_project) { create(:empty_project) } - let(:external_wiki_project) { create(:empty_project, has_external_wiki: true) } + let(:no_wiki_project) { create(:project, :wiki_disabled, has_external_wiki: false) } + let(:wiki_enabled_project) { create(:project) } + let(:external_wiki_project) { create(:project, has_external_wiki: true) } it 'returns true if project is wiki enabled or has external wiki' do expect(wiki_enabled_project).to have_wiki @@ -715,7 +716,7 @@ describe Project do end describe '#external_wiki' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'with an active external wiki' do before do @@ -769,7 +770,7 @@ describe Project do it 'counts stars from multiple users' do user1 = create :user user2 = create :user - project = create(:empty_project, :public) + project = create(:project, :public) expect(project.star_count).to eq(0) @@ -791,8 +792,8 @@ describe Project do it 'counts stars on the right project' do user = create :user - project1 = create(:empty_project, :public) - project2 = create(:empty_project, :public) + project1 = create(:project, :public) + project2 = create(:project, :public) expect(project1.star_count).to eq(0) expect(project2.star_count).to eq(0) @@ -824,7 +825,7 @@ describe Project do end describe '#avatar_type' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'is true if avatar is image' do project.update_attribute(:avatar, 'uploads/avatar.png') @@ -840,10 +841,10 @@ describe Project do describe '#avatar_url' do subject { project.avatar_url } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when avatar file is uploaded' do - let(:project) { create(:empty_project, :with_avatar) } + let(:project) { create(:project, :with_avatar) } let(:avatar_path) { "/uploads/-/system/project/avatar/#{project.id}/dk.png" } let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" } @@ -868,7 +869,7 @@ describe Project do end context 'when git repo is empty' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it { is_expected.to eq nil } end @@ -909,7 +910,7 @@ describe Project do end describe '#builds_enabled' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { project.builds_enabled } @@ -920,7 +921,7 @@ describe Project do subject { described_class.with_shared_runners } context 'when shared runners are enabled for project' do - let!(:project) { create(:empty_project, shared_runners_enabled: true) } + let!(:project) { create(:project, shared_runners_enabled: true) } it "returns a project" do is_expected.to eq([project]) @@ -928,7 +929,7 @@ describe Project do end context 'when shared runners are disabled for project' do - let!(:project) { create(:empty_project, shared_runners_enabled: false) } + let!(:project) { create(:project, shared_runners_enabled: false) } it "returns an empty array" do is_expected.to be_empty @@ -938,8 +939,8 @@ describe Project do describe '.cached_count', :use_clean_rails_memory_store_caching do let(:group) { create(:group, :public) } - let!(:project1) { create(:empty_project, :public, group: group) } - let!(:project2) { create(:empty_project, :public, group: group) } + let!(:project1) { create(:project, :public, group: group) } + let!(:project2) { create(:project, :public, group: group) } it 'returns total project count' do expect(described_class).to receive(:count).once.and_call_original @@ -952,8 +953,8 @@ describe Project do describe '.trending' do let(:group) { create(:group, :public) } - let(:project1) { create(:empty_project, :public, group: group) } - let(:project2) { create(:empty_project, :public, group: group) } + let(:project1) { create(:project, :public, group: group) } + let(:project2) { create(:project, :public, group: group) } before do 2.times do @@ -984,9 +985,9 @@ describe Project do it 'returns only projects starred by the given user' do user1 = create(:user) user2 = create(:user) - project1 = create(:empty_project) - project2 = create(:empty_project) - create(:empty_project) + project1 = create(:project) + project2 = create(:project) + create(:project) user1.toggle_star(project1) user2.toggle_star(project2) @@ -995,7 +996,7 @@ describe Project do end describe '.visible_to_user' do - let!(:project) { create(:empty_project, :private) } + let!(:project) { create(:project, :private) } let!(:user) { create(:user) } subject { described_class.visible_to_user(user) } @@ -1014,7 +1015,7 @@ describe Project do end context 'repository storage by default' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do storages = { @@ -1032,7 +1033,7 @@ describe Project do end context 'shared runners by default' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { project.shared_runners_enabled } @@ -1054,7 +1055,7 @@ describe Project do end describe '#any_runners' do - let(:project) { create(:empty_project, shared_runners_enabled: shared_runners_enabled) } + let(:project) { create(:project, shared_runners_enabled: shared_runners_enabled) } let(:specific_runner) { create(:ci_runner) } let(:shared_runner) { create(:ci_runner, :shared) } @@ -1102,7 +1103,7 @@ describe Project do subject { project.shared_runners } context 'when shared runners are enabled for project' do - let!(:project) { create(:empty_project, shared_runners_enabled: true) } + let!(:project) { create(:project, shared_runners_enabled: true) } it "returns a list of shared runners" do is_expected.to eq([runner]) @@ -1110,7 +1111,7 @@ describe Project do end context 'when shared runners are disabled for project' do - let!(:project) { create(:empty_project, shared_runners_enabled: false) } + let!(:project) { create(:project, shared_runners_enabled: false) } it "returns a empty list" do is_expected.to be_empty @@ -1119,7 +1120,7 @@ describe Project do end describe '#visibility_level_allowed?' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } context 'when checking on non-forked project' do it { expect(project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy } @@ -1128,8 +1129,8 @@ describe Project do end context 'when checking on forked project' do - let(:project) { create(:empty_project, :internal) } - let(:forked_project) { create(:empty_project, forked_from_project: project) } + let(:project) { create(:project, :internal) } + let(:forked_project) { create(:project, forked_from_project: project) } it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::PRIVATE)).to be_truthy } it { expect(forked_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_truthy } @@ -1138,7 +1139,7 @@ describe Project do end describe '#pages_deployed?' do - let(:project) { create :empty_project } + let(:project) { create :project } subject { project.pages_deployed? } @@ -1155,8 +1156,35 @@ describe Project do end end + describe '#pages_url' do + let(:group) { create :group, name: group_name } + let(:project) { create :project, namespace: group, name: project_name } + let(:domain) { 'Example.com' } + + subject { project.pages_url } + + before do + allow(Settings.pages).to receive(:host).and_return(domain) + allow(Gitlab.config.pages).to receive(:url).and_return('http://example.com') + end + + context 'group page' do + let(:group_name) { 'Group' } + let(:project_name) { 'group.example.com' } + + it { is_expected.to eq("http://group.example.com") } + end + + context 'project page' do + let(:group_name) { 'Group' } + let(:project_name) { 'Project' } + + it { is_expected.to eq("http://group.example.com/project") } + end + end + describe '.search' do - let(:project) { create(:empty_project, description: 'kitten mittens') } + let(:project) { create(:project, description: 'kitten mittens') } it 'returns projects with a matching name' do expect(described_class.search(project.name)).to eq([project]) @@ -1213,7 +1241,7 @@ describe Project do end describe 'with pending_delete project' do - let(:pending_delete_project) { create(:empty_project, pending_delete: true) } + let(:pending_delete_project) { create(:project, pending_delete: true) } it 'shows pending deletion project' do search_result = described_class.search(pending_delete_project.name) @@ -1273,7 +1301,7 @@ describe Project do subject { project.rename_repo } - it { expect{subject}.to raise_error(StandardError) } + it { expect {subject}.to raise_error(StandardError) } end end @@ -1299,7 +1327,7 @@ describe Project do end describe '.search_by_title' do - let(:project) { create(:empty_project, name: 'kittens') } + let(:project) { create(:project, name: 'kittens') } it 'returns projects with a matching name' do expect(described_class.search_by_title(project.name)).to eq([project]) @@ -1318,8 +1346,8 @@ describe Project do let(:private_group) { create(:group, visibility_level: 0) } let(:internal_group) { create(:group, visibility_level: 10) } - let(:private_project) { create :empty_project, :private, group: private_group } - let(:internal_project) { create :empty_project, :internal, group: internal_group } + let(:private_project) { create :project, :private, group: private_group } + let(:internal_project) { create :project, :internal, group: internal_group } context 'when group is private project can not be internal' do it { expect(private_project.visibility_level_allowed?(Gitlab::VisibilityLevel::INTERNAL)).to be_falsey } @@ -1341,7 +1369,7 @@ describe Project do context 'using a regular repository' do it 'creates the repository' do expect(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(true) expect(project.repository).to receive(:after_create) @@ -1351,7 +1379,7 @@ describe Project do it 'adds an error if the repository could not be created' do expect(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(false) expect(project.repository).not_to receive(:after_create) @@ -1384,7 +1412,7 @@ describe Project do .and_return(false) allow(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(true) expect(project).to receive(:create_repository).with(force: true) @@ -1408,7 +1436,7 @@ describe Project do .and_return(false) expect(shell).to receive(:add_repository) - .with(project.repository_storage_path, project.path_with_namespace) + .with(project.repository_storage_path, project.disk_path) .and_return(true) project.ensure_repository @@ -1416,7 +1444,7 @@ describe Project do end describe '#user_can_push_to_empty_repo?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } it 'returns false when default_branch_protection is in full protection and user is developer' do @@ -1455,7 +1483,7 @@ describe Project do end describe '#container_registry_url' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { project.container_registry_url } @@ -1482,7 +1510,7 @@ describe Project do end describe '#has_container_registry_tags?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'when container registry is enabled' do before do @@ -1546,7 +1574,7 @@ describe Project do end describe '#ci_config_path=' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'sets nil' do project.update!(ci_config_path: nil) @@ -1568,11 +1596,11 @@ describe Project do end describe 'Project import job' do - let(:project) { create(:empty_project, import_url: generate(:url)) } + let(:project) { create(:project, import_url: generate(:url)) } before do allow_any_instance_of(Gitlab::Shell).to receive(:import_repository) - .with(project.repository_storage_path, project.path_with_namespace, project.import_url) + .with(project.repository_storage_path, project.disk_path, project.import_url) .and_return(true) expect_any_instance_of(Repository).to receive(:after_import) @@ -1605,7 +1633,7 @@ describe Project do end it 'does not perform housekeeping when project repository does not exist' do - project = create(:empty_project, :import_started, import_type: :github) + project = create(:project, :import_started, import_type: :github) project.import_finish @@ -1613,7 +1641,7 @@ describe Project do end it 'does not perform housekeeping when project does not have a valid import type' do - project = create(:empty_project, :import_started, import_type: nil) + project = create(:project, :import_started, import_type: nil) project.import_finish @@ -1710,7 +1738,7 @@ describe Project do it 'schedules a RepositoryForkWorker job' do expect(RepositoryForkWorker).to receive(:perform_async) .with(project.id, forked_from_project.repository_storage_path, - forked_from_project.path_with_namespace, project.namespace.full_path) + forked_from_project.disk_path, project.namespace.full_path) project.add_import_job end @@ -1718,7 +1746,7 @@ describe Project do context 'not forked' do it 'schedules a RepositoryImportWorker job' do - project = create(:empty_project, import_url: generate(:url)) + project = create(:project, import_url: generate(:url)) expect(RepositoryImportWorker).to receive(:perform_async).with(project.id) @@ -1728,19 +1756,19 @@ describe Project do end describe '#gitlab_project_import?' do - subject(:project) { build(:empty_project, import_type: 'gitlab_project') } + subject(:project) { build(:project, import_type: 'gitlab_project') } it { expect(project.gitlab_project_import?).to be true } end describe '#gitea_import?' do - subject(:project) { build(:empty_project, import_type: 'gitea') } + subject(:project) { build(:project, import_type: 'gitea') } it { expect(project.gitea_import?).to be true } end describe '#lfs_enabled?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } shared_examples 'project overrides group' do it 'returns true when enabled in project' do @@ -1804,6 +1832,11 @@ describe Project do describe '#change_head' do let(:project) { create(:project, :repository) } + it 'returns error if branch does not exist' do + expect(project.change_head('unexisted-branch')).to be false + expect(project.errors.size).to eq(1) + end + it 'calls the before_change_head and after_change_head methods' do expect(project.repository).to receive(:before_change_head) expect(project.repository).to receive(:after_change_head) @@ -1830,7 +1863,7 @@ describe Project do end describe '#pushes_since_gc' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } after do project.reset_pushes_since_gc @@ -1852,7 +1885,7 @@ describe Project do end describe '#increment_pushes_since_gc' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } after do project.reset_pushes_since_gc @@ -1866,7 +1899,7 @@ describe Project do end describe '#reset_pushes_since_gc' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } after do project.reset_pushes_since_gc @@ -1883,7 +1916,7 @@ describe Project do describe '#deployment_variables' do context 'when project has no deployment service' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'returns an empty array' do expect(project.deployment_variables).to eq [] @@ -1902,7 +1935,7 @@ describe Project do end describe '#secret_variables_for' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:secret_variable) do create(:ci_variable, value: 'secret', project: project) @@ -1949,7 +1982,7 @@ describe Project do end describe '#protected_for?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { project.protected_for?('ref') } @@ -1986,7 +2019,7 @@ describe Project do end describe '#update_project_statistics' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it "is called after creation" do expect(project.statistics).to be_a ProjectStatistics @@ -2006,9 +2039,9 @@ describe Project do end describe 'inside_path' do - let!(:project1) { create(:empty_project, namespace: create(:namespace, path: 'name_pace')) } - let!(:project2) { create(:empty_project) } - let!(:project3) { create(:empty_project, namespace: create(:namespace, path: 'namespace')) } + let!(:project1) { create(:project, namespace: create(:namespace, path: 'name_pace')) } + let!(:project2) { create(:project) } + let!(:project3) { create(:project, namespace: create(:namespace, path: 'namespace')) } let!(:path) { project1.namespace.full_path } it 'returns correct project' do @@ -2017,7 +2050,7 @@ describe Project do end describe '#route_map_for' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:route_map) do <<-MAP.strip_heredoc - source: /source/(.*)/ @@ -2054,7 +2087,7 @@ describe Project do end describe '#public_path_for_source_path' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:route_map) do Gitlab::RouteMap.new(<<-MAP.strip_heredoc) - source: /source/(.*)/ @@ -2093,13 +2126,13 @@ describe Project do end describe '#parent' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it { expect(project.parent).to eq(project.namespace) } end describe '#parent_changed?' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do project.namespace_id = 7 @@ -2125,7 +2158,7 @@ describe Project do end context 'top-level group' do - let(:project) { create :empty_project, namespace: group, name: project_name } + let(:project) { create :project, namespace: group, name: project_name } context 'group page' do let(:project_name) { 'group.example.com' } @@ -2141,7 +2174,7 @@ describe Project do end context 'nested group' do - let(:project) { create :empty_project, namespace: nested_group, name: project_name } + let(:project) { create :project, namespace: nested_group, name: project_name } let(:expected_url) { "http://group.example.com/#{nested_group.path}/#{project.path}" } context 'group page' do @@ -2159,7 +2192,7 @@ describe Project do end describe '#http_url_to_repo' do - let(:project) { create :empty_project } + let(:project) { create :project } it 'returns the url to the repo without a username' do expect(project.http_url_to_repo).to eq("#{project.web_url}.git") @@ -2168,7 +2201,7 @@ describe Project do end describe '#pipeline_status' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'builds a pipeline status' do expect(project.pipeline_status).to be_a(Gitlab::Cache::Ci::ProjectPipelineStatus) end @@ -2199,7 +2232,7 @@ describe Project do describe '#last_repository_updated_at' do it 'sets to created_at upon creation' do - project = create(:empty_project, created_at: 2.hours.ago) + project = create(:project, created_at: 2.hours.ago) expect(project.last_repository_updated_at.to_i).to eq(project.created_at.to_i) end @@ -2209,10 +2242,10 @@ describe Project do let!(:user) { create(:user) } let!(:private_project) do - create(:empty_project, :private, creator: user, namespace: user.namespace) + create(:project, :private, creator: user, namespace: user.namespace) end - let!(:public_project) { create(:empty_project, :public) } + let!(:public_project) { create(:project, :public) } context 'with a user' do let(:projects) do @@ -2238,19 +2271,53 @@ describe Project do end describe '#remove_private_deploy_keys' do - it 'removes the private deploy keys of a project' do - project = create(:empty_project) + let!(:project) { create(:project) } + + context 'for a private deploy key' do + let!(:key) { create(:deploy_key, public: false) } + let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) } + + context 'when the key is not linked to another project' do + it 'removes the key' do + project.remove_private_deploy_keys - private_key = create(:deploy_key, public: false) - public_key = create(:deploy_key, public: true) + expect(project.deploy_keys).not_to include(key) + end + end + + context 'when the key is linked to another project' do + before do + another_project = create(:project) + create(:deploy_keys_project, deploy_key: key, project: another_project) + end + + it 'does not remove the key' do + project.remove_private_deploy_keys + + expect(project.deploy_keys).to include(key) + end + end + end + + context 'for a public deploy key' do + let!(:key) { create(:deploy_key, public: true) } + let!(:deploy_keys_project) { create(:deploy_keys_project, deploy_key: key, project: project) } + + it 'does not remove the key' do + project.remove_private_deploy_keys + + expect(project.deploy_keys).to include(key) + end + end + end - create(:deploy_keys_project, deploy_key: private_key, project: project) - create(:deploy_keys_project, deploy_key: public_key, project: project) + describe '#forks_count' do + it 'returns the number of forks' do + project = build(:project) - project.remove_private_deploy_keys + allow(project.forks).to receive(:count).and_return(1) - expect(project.deploy_keys.where(public: false).any?).to eq(false) - expect(project.deploy_keys.where(public: true).any?).to eq(true) + expect(project.forks_count).to eq(1) end end end diff --git a/spec/models/project_statistics_spec.rb b/spec/models/project_statistics_spec.rb index be1b37730b1..59e20e84c2f 100644 --- a/spec/models/project_statistics_spec.rb +++ b/spec/models/project_statistics_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe ProjectStatistics do - let(:project) { create :empty_project } + let(:project) { create :project } let(:statistics) { project.statistics } describe 'constants' do diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 68228a038a8..314824b32da 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -7,7 +7,7 @@ describe ProjectTeam do let(:nonmember) { create(:user) } context 'personal project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do project.add_master(master) @@ -37,7 +37,7 @@ describe ProjectTeam do context 'group project' do let(:group) { create(:group) } - let!(:project) { create(:empty_project, group: group) } + let!(:project) { create(:project, group: group) } before do group.add_master(master) @@ -75,7 +75,7 @@ describe ProjectTeam do describe '#fetch_members' do context 'personal project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'returns project members' do user = create(:user) @@ -119,7 +119,7 @@ describe ProjectTeam do context 'group project' do let(:group) { create(:group) } - let!(:project) { create(:empty_project, group: group) } + let!(:project) { create(:project, group: group) } it 'returns project members' do group_member = create(:group_member, group: group) @@ -139,7 +139,7 @@ describe ProjectTeam do describe '#find_member' do context 'personal project' do let(:project) do - create(:empty_project, :public, :access_requestable) + create(:project, :public, :access_requestable) end let(:requester) { create(:user) } @@ -160,7 +160,7 @@ describe ProjectTeam do context 'group project' do let(:group) { create(:group, :access_requestable) } - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } let(:requester) { create(:user) } before do @@ -182,7 +182,7 @@ describe ProjectTeam do it 'returns Master role' do user = create(:user) group = create(:group) - project = create(:empty_project, namespace: group) + project = create(:project, namespace: group) group.add_master(user) @@ -192,7 +192,7 @@ describe ProjectTeam do it 'returns Owner role' do user = create(:user) group = create(:group) - project = create(:empty_project, namespace: group) + project = create(:project, namespace: group) group.add_owner(user) @@ -205,7 +205,7 @@ describe ProjectTeam do context 'personal project' do let(:project) do - create(:empty_project, :public, :access_requestable) + create(:project, :public, :access_requestable) end context 'when project is not shared with group' do @@ -253,7 +253,7 @@ describe ProjectTeam do context 'group project' do let(:group) { create(:group, :access_requestable) } let!(:project) do - create(:empty_project, group: group) + create(:project, group: group) end before do @@ -277,15 +277,15 @@ describe ProjectTeam do let(:master) { create(:user) } let(:personal_project) do - create(:empty_project, namespace: developer.namespace) + create(:project, namespace: developer.namespace) end let(:group_project) do - create(:empty_project, namespace: group) + create(:project, namespace: group) end - let(:members_project) { create(:empty_project) } - let(:shared_project) { create(:empty_project) } + let(:members_project) { create(:project) } + let(:shared_project) { create(:project) } before do group.add_master(master) diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index c6ceb092810..953df7746eb 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" describe ProjectWiki do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:repository) { project.repository } let(:user) { project.owner } let(:gitlab_shell) { Gitlab::Shell.new } @@ -15,19 +15,23 @@ describe ProjectWiki do describe "#path_with_namespace" do it "returns the project path with namespace with the .wiki extension" do - expect(subject.path_with_namespace).to eq(project.path_with_namespace + ".wiki") + expect(subject.path_with_namespace).to eq(project.full_path + '.wiki') + end + + it 'returns the same value as #full_path' do + expect(subject.path_with_namespace).to eq(subject.full_path) end end describe '#web_url' do it 'returns the full web URL to the wiki' do - expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/wikis/home") + expect(subject.web_url).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}/wikis/home") end end describe "#url_to_repo" do it "returns the correct ssh url to the repo" do - expect(subject.url_to_repo).to eq(gitlab_shell.url_to_repo(subject.path_with_namespace)) + expect(subject.url_to_repo).to eq(gitlab_shell.url_to_repo(subject.full_path)) end end @@ -38,10 +42,10 @@ describe ProjectWiki do end describe "#http_url_to_repo" do - let(:project) { create :empty_project } + let(:project) { create :project } it 'returns the full http url to the repo' do - expected_url = "#{Gitlab.config.gitlab.url}/#{subject.path_with_namespace}.git" + expected_url = "#{Gitlab.config.gitlab.url}/#{subject.full_path}.git" expect(project_wiki.http_url_to_repo).to eq(expected_url) expect(project_wiki.http_url_to_repo).not_to include('@') @@ -50,7 +54,7 @@ describe ProjectWiki do describe "#wiki_base_path" do it "returns the wiki base path" do - wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.path_with_namespace}/wikis" + wiki_base_path = "#{Gitlab.config.gitlab.relative_url_root}/#{project.full_path}/wikis" expect(subject.wiki_base_path).to eq(wiki_base_path) end @@ -77,7 +81,7 @@ describe ProjectWiki do allow_any_instance_of(Gitlab::Shell).to receive(:add_repository) do create_temp_repo("#{Rails.root}/tmp/test-git-base-path/non-existant.wiki.git") end - allow(project).to receive(:path_with_namespace).and_return("non-existant") + allow(project).to receive(:full_path).and_return("non-existant") end describe '#empty?' do @@ -219,7 +223,12 @@ describe ProjectWiki do before do create_page("update-page", "some content") @gollum_page = subject.wiki.paged("update-page") - subject.update_page(@gollum_page, "some other content", :markdown, "updated page") + subject.update_page( + @gollum_page, + content: "some other content", + format: :markdown, + message: "updated page" + ) @page = subject.pages.first.page end @@ -236,7 +245,12 @@ describe ProjectWiki do end it 'updates project activity' do - subject.update_page(@gollum_page, 'Yet more content', :markdown, 'Updated page again') + subject.update_page( + @gollum_page, + content: 'Yet more content', + format: :markdown, + message: 'Updated page again' + ) project.reload @@ -269,7 +283,7 @@ describe ProjectWiki do describe '#create_repo!' do it 'creates a repository' do expect(subject).to receive(:init_repo) - .with(subject.path_with_namespace) + .with(subject.full_path) .and_return(true) expect(subject.repository).to receive(:after_create) diff --git a/spec/models/protected_branch_spec.rb b/spec/models/protected_branch_spec.rb index a54af3bfe59..4c677200ae2 100644 --- a/spec/models/protected_branch_spec.rb +++ b/spec/models/protected_branch_spec.rb @@ -163,7 +163,7 @@ describe ProtectedBranch do end context "new project" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'returns false when default_protected_branch is unprotected' do stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE) diff --git a/spec/models/push_event_payload_spec.rb b/spec/models/push_event_payload_spec.rb new file mode 100644 index 00000000000..a049ad35584 --- /dev/null +++ b/spec/models/push_event_payload_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe PushEventPayload do + describe 'saving payloads' do + it 'does not allow commit messages longer than 70 characters' do + event = create(:push_event) + payload = build(:push_event_payload, event: event) + + expect(payload).to be_valid + + payload.commit_title = 'a' * 100 + + expect(payload).not_to be_valid + end + end +end diff --git a/spec/models/push_event_spec.rb b/spec/models/push_event_spec.rb new file mode 100644 index 00000000000..532fb024261 --- /dev/null +++ b/spec/models/push_event_spec.rb @@ -0,0 +1,202 @@ +require 'spec_helper' + +describe PushEvent do + let(:payload) { PushEventPayload.new } + + let(:event) do + event = described_class.new + + allow(event).to receive(:push_event_payload).and_return(payload) + + event + end + + describe '.sti_name' do + it 'returns Event::PUSHED' do + expect(described_class.sti_name).to eq(Event::PUSHED) + end + end + + describe '#push?' do + it 'returns true' do + expect(event).to be_push + end + end + + describe '#push_with_commits?' do + it 'returns true when both the first and last commit are present' do + allow(event).to receive(:commit_from).and_return('123') + allow(event).to receive(:commit_to).and_return('456') + + expect(event).to be_push_with_commits + end + + it 'returns false when the first commit is missing' do + allow(event).to receive(:commit_to).and_return('456') + + expect(event).not_to be_push_with_commits + end + + it 'returns false when the last commit is missing' do + allow(event).to receive(:commit_from).and_return('123') + + expect(event).not_to be_push_with_commits + end + end + + describe '#tag?' do + it 'returns true when pushing to a tag' do + allow(payload).to receive(:tag?).and_return(true) + + expect(event).to be_tag + end + + it 'returns false when pushing to a branch' do + allow(payload).to receive(:tag?).and_return(false) + + expect(event).not_to be_tag + end + end + + describe '#branch?' do + it 'returns true when pushing to a branch' do + allow(payload).to receive(:branch?).and_return(true) + + expect(event).to be_branch + end + + it 'returns false when pushing to a tag' do + allow(payload).to receive(:branch?).and_return(false) + + expect(event).not_to be_branch + end + end + + describe '#valid_push?' do + it 'returns true if a ref exists' do + allow(payload).to receive(:ref).and_return('master') + + expect(event).to be_valid_push + end + + it 'returns false when no ref is present' do + expect(event).not_to be_valid_push + end + end + + describe '#new_ref?' do + it 'returns true when pushing a new ref' do + allow(payload).to receive(:created?).and_return(true) + + expect(event).to be_new_ref + end + + it 'returns false when pushing to an existing ref' do + allow(payload).to receive(:created?).and_return(false) + + expect(event).not_to be_new_ref + end + end + + describe '#rm_ref?' do + it 'returns true when removing an existing ref' do + allow(payload).to receive(:removed?).and_return(true) + + expect(event).to be_rm_ref + end + + it 'returns false when pushing to an existing ref' do + allow(payload).to receive(:removed?).and_return(false) + + expect(event).not_to be_rm_ref + end + end + + describe '#commit_from' do + it 'returns the first commit SHA' do + allow(payload).to receive(:commit_from).and_return('123') + + expect(event.commit_from).to eq('123') + end + end + + describe '#commit_to' do + it 'returns the last commit SHA' do + allow(payload).to receive(:commit_to).and_return('123') + + expect(event.commit_to).to eq('123') + end + end + + describe '#ref_name' do + it 'returns the name of the ref' do + allow(payload).to receive(:ref).and_return('master') + + expect(event.ref_name).to eq('master') + end + end + + describe '#ref_type' do + it 'returns the type of the ref' do + allow(payload).to receive(:ref_type).and_return('branch') + + expect(event.ref_type).to eq('branch') + end + end + + describe '#branch_name' do + it 'returns the name of the branch' do + allow(payload).to receive(:ref).and_return('master') + + expect(event.branch_name).to eq('master') + end + end + + describe '#tag_name' do + it 'returns the name of the tag' do + allow(payload).to receive(:ref).and_return('1.2') + + expect(event.tag_name).to eq('1.2') + end + end + + describe '#commit_title' do + it 'returns the commit message' do + allow(payload).to receive(:commit_title).and_return('foo') + + expect(event.commit_title).to eq('foo') + end + end + + describe '#commit_id' do + it 'returns the SHA of the last commit if present' do + allow(event).to receive(:commit_to).and_return('123') + + expect(event.commit_id).to eq('123') + end + + it 'returns the SHA of the first commit if the last commit is not present' do + allow(event).to receive(:commit_to).and_return(nil) + allow(event).to receive(:commit_from).and_return('123') + + expect(event.commit_id).to eq('123') + end + end + + describe '#commits_count' do + it 'returns the number of commits' do + allow(payload).to receive(:commit_count).and_return(1) + + expect(event.commits_count).to eq(1) + end + end + + describe '#validate_push_action' do + it 'adds an error when the action is not PUSHED' do + event.action = Event::CREATED + event.validate_push_action + + expect(event.errors.count).to eq(1) + end + end +end diff --git a/spec/models/redirect_route_spec.rb b/spec/models/redirect_route_spec.rb index 80943877095..106ae59af29 100644 --- a/spec/models/redirect_route_spec.rb +++ b/spec/models/redirect_route_spec.rb @@ -20,8 +20,16 @@ describe RedirectRoute do let!(:redirect4) { group.redirect_routes.create(path: 'gitlabb/test/foo/bar') } let!(:redirect5) { group.redirect_routes.create(path: 'gitlabb/test/baz') } - it 'returns correct routes' do - expect(described_class.matching_path_and_descendants('gitlabb/test')).to match_array([redirect2, redirect3, redirect4, redirect5]) + context 'when the redirect route matches with same casing' do + it 'returns correct routes' do + expect(described_class.matching_path_and_descendants('gitlabb/test')).to match_array([redirect2, redirect3, redirect4, redirect5]) + end + end + + context 'when the redirect route matches with different casing' do + it 'returns correct routes' do + expect(described_class.matching_path_and_descendants('GitLABB/test')).to match_array([redirect2, redirect3, redirect4, redirect5]) + end end end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 07ed66e127a..4926d5d6c49 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1,11 +1,12 @@ require 'spec_helper' -describe Repository do +describe Repository, models: true do include RepoHelpers TestBlob = Struct.new(:path) let(:project) { create(:project, :repository) } let(:repository) { project.repository } + let(:broken_repository) { create(:project, :broken_storage).repository } let(:user) { create(:user) } let(:commit_options) do @@ -27,12 +28,27 @@ describe Repository do let(:author_email) { 'user@example.org' } let(:author_name) { 'John Doe' } + def expect_to_raise_storage_error + expect { yield }.to raise_error do |exception| + storage_exceptions = [Gitlab::Git::Storage::Inaccessible, Gitlab::Git::CommandError, GRPC::Unavailable] + expect(exception.class).to be_in(storage_exceptions) + end + end + describe '#branch_names_contains' do subject { repository.branch_names_contains(sample_commit.id) } it { is_expected.to include('master') } it { is_expected.not_to include('feature') } it { is_expected.not_to include('fix') } + + describe 'when storage is broken', broken_storage: true do + it 'should raise a storage error' do + expect_to_raise_storage_error do + broken_repository.branch_names_contains(sample_commit.id) + end + end + end end describe '#tag_names_contains' do @@ -139,24 +155,60 @@ describe Repository do end describe '#last_commit_for_path' do - subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id } + shared_examples 'getting last commit for path' do + subject { repository.last_commit_for_path(sample_commit.id, '.gitignore').id } + + it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } + + describe 'when storage is broken', broken_storage: true do + it 'should raise a storage error' do + expect_to_raise_storage_error do + broken_repository.last_commit_id_for_path(sample_commit.id, '.gitignore') + end + end + end + end + + context 'when Gitaly feature last_commit_for_path is enabled' do + it_behaves_like 'getting last commit for path' + end - it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } + context 'when Gitaly feature last_commit_for_path is disabled', skip_gitaly_mock: true do + it_behaves_like 'getting last commit for path' + end end describe '#last_commit_id_for_path' do - subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') } + shared_examples 'getting last commit ID for path' do + subject { repository.last_commit_id_for_path(sample_commit.id, '.gitignore') } + + it "returns last commit id for a given path" do + is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') + end + + it "caches last commit id for a given path" do + cache = repository.send(:cache) + key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}" - it "returns last commit id for a given path" do - is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') + expect(cache).to receive(:fetch).with(key).and_return('c1acaa5') + is_expected.to eq('c1acaa5') + end + + describe 'when storage is broken', broken_storage: true do + it 'should raise a storage error' do + expect_to_raise_storage_error do + broken_repository.last_commit_for_path(sample_commit.id, '.gitignore').id + end + end + end end - it "caches last commit id for a given path" do - cache = repository.send(:cache) - key = "last_commit_id_for_path:#{sample_commit.id}:#{Digest::SHA1.hexdigest('.gitignore')}" + context 'when Gitaly feature last_commit_for_path is enabled' do + it_behaves_like 'getting last commit ID for path' + end - expect(cache).to receive(:fetch).with(key).and_return('c1acaa5') - is_expected.to eq('c1acaa5') + context 'when Gitaly feature last_commit_for_path is disabled', skip_gitaly_mock: true do + it_behaves_like 'getting last commit ID for path' end end @@ -182,19 +234,37 @@ describe Repository do end describe '#find_commits_by_message' do - it 'returns commits with messages containing a given string' do - commit_ids = repository.find_commits_by_message('submodule').map(&:id) + shared_examples 'finding commits by message' do + it 'returns commits with messages containing a given string' do + commit_ids = repository.find_commits_by_message('submodule').map(&:id) + + expect(commit_ids).to include( + '5937ac0a7beb003549fc5fd26fc247adbce4a52e', + '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9', + 'cfe32cf61b73a0d5e9f13e774abde7ff789b1660' + ) + expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e') + end + + it 'is case insensitive' do + commit_ids = repository.find_commits_by_message('SUBMODULE').map(&:id) + + expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') + end + end - expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') - expect(commit_ids).to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') - expect(commit_ids).to include('cfe32cf61b73a0d5e9f13e774abde7ff789b1660') - expect(commit_ids).not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e') + context 'when Gitaly commits_by_message feature is enabled' do + it_behaves_like 'finding commits by message' end - it 'is case insensitive' do - commit_ids = repository.find_commits_by_message('SUBMODULE').map(&:id) + context 'when Gitaly commits_by_message feature is disabled', skip_gitaly_mock: true do + it_behaves_like 'finding commits by message' + end - expect(commit_ids).to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') + describe 'when storage is broken', broken_storage: true do + it 'should raise a storage error' do + expect_to_raise_storage_error { broken_repository.find_commits_by_message('s') } + end end end @@ -300,7 +370,7 @@ describe Repository do end context "when committing to another project" do - let(:forked_project) { create(:project) } + let(:forked_project) { create(:project, :repository) } it "creates a fork and commit to the forked project" do expect do @@ -515,12 +585,20 @@ describe Repository do end it 'properly handles query when repo is empty' do - repository = create(:empty_project).repository + repository = create(:project).repository results = repository.search_files_by_content('test', 'master') expect(results).to match_array([]) end + describe 'when storage is broken', broken_storage: true do + it 'should raise a storage error' do + expect_to_raise_storage_error do + broken_repository.search_files_by_content('feature', 'master') + end + end + end + describe 'result' do subject { results.first } @@ -543,12 +621,28 @@ describe Repository do end it 'properly handles query when repo is empty' do - repository = create(:empty_project).repository + repository = create(:project).repository results = repository.search_files_by_name('test', 'master') expect(results).to match_array([]) end + + describe 'when storage is broken', broken_storage: true do + it 'should raise a storage error' do + expect_to_raise_storage_error { broken_repository.search_files_by_name('files', 'master') } + end + end + end + + describe '#fetch_ref' do + describe 'when storage is broken', broken_storage: true do + it 'should raise a storage error' do + path = broken_repository.path_to_repo + + expect_to_raise_storage_error { broken_repository.fetch_ref(path, '1', '2') } + end + end end describe '#create_ref' do @@ -867,6 +961,27 @@ describe Repository do end end + context 'when temporary ref failed to be created from other project' do + let(:target_project) { create(:project, :empty_repo) } + + before do + expect(target_project.repository).to receive(:run_git) + end + + it 'raises Rugged::ReferenceError' do + raise_reference_error = raise_error(Rugged::ReferenceError) do |err| + expect(err.cause).to be_nil + end + + expect do + GitOperationService.new(user, target_project.repository) + .with_branch('feature', + start_project: project, + &:itself) + end.to raise_reference_error + end + end + context 'when the update adds more than one commit' do let(:old_rev) { '33f3729a45c02fc67d00adb1b8bca394b0e761d9' } @@ -942,7 +1057,7 @@ describe Repository do end it 'expires creation and branch cache' do - empty_repository = create(:empty_project, :empty_repo).repository + empty_repository = create(:project, :empty_repo).repository expect(empty_repository).to receive(:expire_exists_cache) expect(empty_repository).to receive(:expire_root_ref_cache) @@ -962,10 +1077,16 @@ describe Repository do end it 'returns false if no full path can be constructed' do - allow(repository).to receive(:path_with_namespace).and_return(nil) + allow(repository).to receive(:full_path).and_return(nil) expect(repository.exists?).to eq(false) end + + context 'with broken storage', broken_storage: true do + it 'should raise a storage error' do + expect_to_raise_storage_error { broken_repository.exists? } + end + end end describe '#exists?' do @@ -1124,7 +1245,7 @@ describe Repository do end describe 'skip_merges option' do - subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", limit: 100, skip_merges: true).map{ |k| k.id } } + subject { repository.commits(Gitlab::Git::BRANCH_REF_PREFIX + "'test'", limit: 100, skip_merges: true).map { |k| k.id } } it { is_expected.not_to include('e56497bb5f03a90a51293fc6d516788730953899') } end @@ -1804,7 +1925,7 @@ describe Repository do end describe '#commit_count_for_ref' do - let(:project) { create :empty_project } + let(:project) { create :project } context 'with a non-existing repository' do it 'returns 0' do diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index bdacc60fb53..fece370c03f 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -145,45 +145,71 @@ describe Route do describe '#delete_conflicting_redirects' do context 'when a redirect route with the same path exists' do - let!(:redirect1) { route.create_redirect(route.path) } + context 'when the redirect route has matching case' do + let!(:redirect1) { route.create_redirect(route.path) } - it 'deletes the redirect' do - route.delete_conflicting_redirects - expect(route.conflicting_redirects).to be_empty + it 'deletes the redirect' do + expect do + route.delete_conflicting_redirects + end.to change { RedirectRoute.count }.by(-1) + end + + context 'when redirect routes with paths descending from the route path exists' do + let!(:redirect2) { route.create_redirect("#{route.path}/foo") } + let!(:redirect3) { route.create_redirect("#{route.path}/foo/bar") } + let!(:redirect4) { route.create_redirect("#{route.path}/baz/quz") } + let!(:other_redirect) { route.create_redirect("other") } + + it 'deletes all redirects with paths that descend from the route path' do + expect do + route.delete_conflicting_redirects + end.to change { RedirectRoute.count }.by(-4) + end + end end - context 'when redirect routes with paths descending from the route path exists' do - let!(:redirect2) { route.create_redirect("#{route.path}/foo") } - let!(:redirect3) { route.create_redirect("#{route.path}/foo/bar") } - let!(:redirect4) { route.create_redirect("#{route.path}/baz/quz") } - let!(:other_redirect) { route.create_redirect("other") } + context 'when the redirect route is differently cased' do + let!(:redirect1) { route.create_redirect(route.path.upcase) } - it 'deletes all redirects with paths that descend from the route path' do - route.delete_conflicting_redirects - expect(route.conflicting_redirects).to be_empty + it 'deletes the redirect' do + expect do + route.delete_conflicting_redirects + end.to change { RedirectRoute.count }.by(-1) end end end end describe '#conflicting_redirects' do + it 'returns an ActiveRecord::Relation' do + expect(route.conflicting_redirects).to be_an(ActiveRecord::Relation) + end + context 'when a redirect route with the same path exists' do - let!(:redirect1) { route.create_redirect(route.path) } + context 'when the redirect route has matching case' do + let!(:redirect1) { route.create_redirect(route.path) } - it 'returns the redirect route' do - expect(route.conflicting_redirects).to be_an(ActiveRecord::Relation) - expect(route.conflicting_redirects).to match_array([redirect1]) + it 'returns the redirect route' do + expect(route.conflicting_redirects).to match_array([redirect1]) + end + + context 'when redirect routes with paths descending from the route path exists' do + let!(:redirect2) { route.create_redirect("#{route.path}/foo") } + let!(:redirect3) { route.create_redirect("#{route.path}/foo/bar") } + let!(:redirect4) { route.create_redirect("#{route.path}/baz/quz") } + let!(:other_redirect) { route.create_redirect("other") } + + it 'returns the redirect routes' do + expect(route.conflicting_redirects).to match_array([redirect1, redirect2, redirect3, redirect4]) + end + end end - context 'when redirect routes with paths descending from the route path exists' do - let!(:redirect2) { route.create_redirect("#{route.path}/foo") } - let!(:redirect3) { route.create_redirect("#{route.path}/foo/bar") } - let!(:redirect4) { route.create_redirect("#{route.path}/baz/quz") } - let!(:other_redirect) { route.create_redirect("other") } + context 'when the redirect route is differently cased' do + let!(:redirect1) { route.create_redirect(route.path.upcase) } - it 'returns the redirect routes' do - expect(route.conflicting_redirects).to be_an(ActiveRecord::Relation) - expect(route.conflicting_redirects).to match_array([redirect1, redirect2, redirect3, redirect4]) + it 'returns the redirect route' do + expect(route.conflicting_redirects).to match_array([redirect1]) end end end diff --git a/spec/models/sent_notification_spec.rb b/spec/models/sent_notification_spec.rb index 8b6b02916ae..8f05deb8b15 100644 --- a/spec/models/sent_notification_spec.rb +++ b/spec/models/sent_notification_spec.rb @@ -21,7 +21,7 @@ describe SentNotification do end context "when the noteable project and discussion project match" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:issue) { create(:issue, project: project) } let(:discussion_id) { create(:note, project: project, noteable: issue).discussion_id } subject { build(:sent_notification, project: project, noteable: issue, in_reply_to_discussion_id: discussion_id) } @@ -128,7 +128,7 @@ describe SentNotification do end context 'for commit' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:commit) { project.commit } subject { described_class.record(commit, project.creator.id) } diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index dba9fc4ac9b..0f2f906c667 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -23,7 +23,7 @@ describe Service do end context 'when repository is empty' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'returns true' do expect(service.can_test?).to be true @@ -46,7 +46,7 @@ describe Service do end context 'when repository is empty' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'test runs execute' do expect(service).to receive(:execute).with(data) @@ -69,7 +69,7 @@ describe Service do api_key: '123456789' }) end - let(:project) { create(:empty_project) } + let(:project) { create(:project) } describe 'is prefilled for projects pushover service' do it "has all fields prefilled" do @@ -88,7 +88,7 @@ describe Service do describe "{property}_changed?" do let(:service) do BambooService.create( - project: create(:empty_project), + project: create(:project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -128,7 +128,7 @@ describe Service do describe "{property}_touched?" do let(:service) do BambooService.create( - project: create(:empty_project), + project: create(:project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -168,7 +168,7 @@ describe Service do describe "{property}_was" do let(:service) do BambooService.create( - project: create(:empty_project), + project: create(:project), properties: { bamboo_url: 'http://gitlab.com', username: 'mic', @@ -208,7 +208,7 @@ describe Service do describe 'initialize service with no properties' do let(:service) do GitlabIssueTrackerService.create( - project: create(:empty_project), + project: create(:project), title: 'random title' ) end @@ -223,7 +223,7 @@ describe Service do end describe "callbacks" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:service) do RedmineService.new( project: project, diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb index 904bf2c6144..de3ca300ae3 100644 --- a/spec/models/snippet_spec.rb +++ b/spec/models/snippet_spec.rb @@ -33,7 +33,7 @@ describe Snippet do describe '#to_reference' do context 'when snippet belongs to a project' do - let(:project) { build(:empty_project, name: 'sample-project') } + let(:project) { build(:project, name: 'sample-project') } let(:snippet) { build(:snippet, id: 1, project: project) } it 'returns a String reference to the object' do @@ -41,7 +41,7 @@ describe Snippet do end it 'supports a cross-project reference' do - another_project = build(:empty_project, name: 'another-project', namespace: project.namespace) + another_project = build(:project, name: 'another-project', namespace: project.namespace) expect(snippet.to_reference(another_project)).to eq "sample-project$1" end end @@ -54,14 +54,14 @@ describe Snippet do end it 'still returns shortest reference when project arg present' do - another_project = build(:empty_project, name: 'another-project') + another_project = build(:project, name: 'another-project') expect(snippet.to_reference(another_project)).to eq "$1" end end end describe '#file_name' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'file_name is nil' do let(:snippet) { create(:snippet, project: project, file_name: nil) } @@ -132,7 +132,7 @@ describe Snippet do end describe '#participants' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:snippet) { create(:snippet, content: 'foo', project: project) } let!(:note1) do diff --git a/spec/models/trending_project_spec.rb b/spec/models/trending_project_spec.rb index cc28c6d4004..3b5e7ca0d39 100644 --- a/spec/models/trending_project_spec.rb +++ b/spec/models/trending_project_spec.rb @@ -2,11 +2,11 @@ require 'spec_helper' describe TrendingProject do let(:user) { create(:user) } - let(:public_project1) { create(:empty_project, :public) } - let(:public_project2) { create(:empty_project, :public) } - let(:public_project3) { create(:empty_project, :public) } - let(:private_project) { create(:empty_project, :private) } - let(:internal_project) { create(:empty_project, :internal) } + let(:public_project1) { create(:project, :public) } + let(:public_project2) { create(:project, :public) } + let(:public_project3) { create(:project, :public) } + let(:private_project) { create(:project, :private) } + let(:internal_project) { create(:project, :internal) } before do 3.times do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index ec98a3f3498..97bb91a6ac8 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -80,7 +80,7 @@ describe User do describe '#project_members' do it 'does not include project memberships for which user is a requester' do user = create(:user) - project = create(:empty_project, :public, :access_requestable) + project = create(:project, :public, :access_requestable) project.request_access(user) expect(user.project_members).to be_empty @@ -118,6 +118,17 @@ describe User do expect(user).to validate_uniqueness_of(:username).case_insensitive end + + context 'when username is changed' do + let(:user) { build_stubbed(:user, username: 'old_path', namespace: build_stubbed(:namespace)) } + + it 'validates move_dir is allowed for the namespace' do + expect(user.namespace).to receive(:any_project_has_container_registry_tags?).and_return(true) + user.username = 'new_path' + expect(user).to be_invalid + expect(user.errors.messages[:username].first).to match('cannot be changed if a personal project has container registry tags') + end + end end it { is_expected.to validate_presence_of(:projects_limit) } @@ -560,11 +571,11 @@ describe User do before do @user = create(:user) - @project = create(:empty_project, namespace: @user.namespace) - @project_2 = create(:empty_project, group: create(:group)) do |project| + @project = create(:project, namespace: @user.namespace) + @project_2 = create(:project, group: create(:group)) do |project| project.add_master(@user) end - @project_3 = create(:empty_project, group: create(:group)) do |project| + @project_3 = create(:project, group: create(:group)) do |project| project.add_developer(@user) end end @@ -609,7 +620,7 @@ describe User do describe 'namespaced' do before do @user = create :user - @project = create(:empty_project, namespace: @user.namespace) + @project = create(:project, namespace: @user.namespace) end it { expect(@user.several_namespaces?).to be_falsey } @@ -666,7 +677,7 @@ describe User do end describe '.without_projects' do - let!(:project) { create(:empty_project, :public, :access_requestable) } + let!(:project) { create(:project, :public, :access_requestable) } let!(:user) { create(:user) } let!(:user_without_project) { create(:user) } let!(:user_without_project2) { create(:user) } @@ -1196,8 +1207,8 @@ describe User do describe '#starred?' do it 'determines if user starred a project' do user = create :user - project1 = create(:empty_project, :public) - project2 = create(:empty_project, :public) + project1 = create(:project, :public) + project2 = create(:project, :public) expect(user.starred?(project1)).to be_falsey expect(user.starred?(project2)).to be_falsey @@ -1223,7 +1234,7 @@ describe User do describe '#toggle_star' do it 'toggles stars' do user = create :user - project = create(:empty_project, :public) + project = create(:project, :public) expect(user.starred?(project)).to be_falsey user.toggle_star(project) @@ -1276,11 +1287,11 @@ describe User do describe "#contributed_projects" do subject { create(:user) } - let!(:project1) { create(:empty_project) } - let!(:project2) { create(:empty_project, forked_from_project: project3) } - let!(:project3) { create(:empty_project) } + let!(:project1) { create(:project) } + let!(:project2) { create(:project, forked_from_project: project3) } + let!(:project3) { create(:project) } let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) } - let!(:push_event) { create(:event, :pushed, project: project1, target: project1, author: subject) } + let!(:push_event) { create(:push_event, project: project1, author: subject) } let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) } before do @@ -1322,10 +1333,18 @@ describe User do subject { create(:user) } let!(:project1) { create(:project, :repository) } let!(:project2) { create(:project, :repository, forked_from_project: project1) } - let!(:push_data) do - Gitlab::DataBuilder::Push.build_sample(project2, subject) + + let!(:push_event) do + event = create(:push_event, project: project2, author: subject) + + create(:push_event_payload, + event: event, + commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + commit_count: 0, + ref: 'master') + + event end - let!(:push_event) { create(:event, :pushed, project: project2, target: project1, author: subject, data: push_data) } before do project1.team << [subject, :master] @@ -1352,8 +1371,13 @@ describe User do expect(subject.recent_push(project1)).to eq(nil) expect(subject.recent_push(project2)).to eq(push_event) - push_data1 = Gitlab::DataBuilder::Push.build_sample(project1, subject) - push_event1 = create(:event, :pushed, project: project1, target: project1, author: subject, data: push_data1) + push_event1 = create(:push_event, project: project1, author: subject) + + create(:push_event_payload, + event: push_event1, + commit_to: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + commit_count: 0, + ref: 'master') expect(subject.recent_push([project1, project2])).to eq(push_event1) # Newest end @@ -1376,7 +1400,7 @@ describe User do context 'with a minimum access level' do it 'includes projects for which the user is an owner' do user = create(:user) - project = create(:empty_project, :private, namespace: user.namespace) + project = create(:project, :private, namespace: user.namespace) expect(user.authorized_projects(Gitlab::Access::REPORTER)) .to contain_exactly(project) @@ -1384,7 +1408,7 @@ describe User do it 'includes projects for which the user is a master' do user = create(:user) - project = create(:empty_project, :private) + project = create(:project, :private) project.team << [user, Gitlab::Access::MASTER] @@ -1395,7 +1419,7 @@ describe User do it "includes user's personal projects" do user = create(:user) - project = create(:empty_project, :private, namespace: user.namespace) + project = create(:project, :private, namespace: user.namespace) expect(user.authorized_projects).to include(project) end @@ -1403,7 +1427,7 @@ describe User do it "includes personal projects user has been given access to" do user1 = create(:user) user2 = create(:user) - project = create(:empty_project, :private, namespace: user1.namespace) + project = create(:project, :private, namespace: user1.namespace) project.team << [user2, Gitlab::Access::DEVELOPER] @@ -1412,7 +1436,7 @@ describe User do it "includes projects of groups user has been added to" do group = create(:group) - project = create(:empty_project, group: group) + project = create(:project, group: group) user = create(:user) group.add_developer(user) @@ -1422,7 +1446,7 @@ describe User do it "does not include projects of groups user has been removed from" do group = create(:group) - project = create(:empty_project, group: group) + project = create(:project, group: group) user = create(:user) member = group.add_developer(user) @@ -1434,7 +1458,7 @@ describe User do it "includes projects shared with user's group" do user = create(:user) - project = create(:empty_project, :private) + project = create(:project, :private) group = create(:group) group.add_reporter(user) @@ -1446,7 +1470,7 @@ describe User do it "does not include destroyed projects user had access to" do user1 = create(:user) user2 = create(:user) - project = create(:empty_project, :private, namespace: user1.namespace) + project = create(:project, :private, namespace: user1.namespace) project.team << [user2, Gitlab::Access::DEVELOPER] expect(user2.authorized_projects).to include(project) @@ -1457,7 +1481,7 @@ describe User do it "does not include projects of destroyed groups user had access to" do group = create(:group) - project = create(:empty_project, namespace: group) + project = create(:project, namespace: group) user = create(:user) group.add_developer(user) @@ -1472,9 +1496,9 @@ describe User do let(:user) { create(:user) } it 'includes projects for which the user access level is above or equal to reporter' do - reporter_project = create(:empty_project) { |p| p.add_reporter(user) } - developer_project = create(:empty_project) { |p| p.add_developer(user) } - master_project = create(:empty_project) { |p| p.add_master(user) } + reporter_project = create(:project) { |p| p.add_reporter(user) } + developer_project = create(:project) { |p| p.add_developer(user) } + master_project = create(:project) { |p| p.add_master(user) } expect(user.projects_where_can_admin_issues.to_a).to eq([master_project, developer_project, reporter_project]) expect(user.can?(:admin_issue, master_project)).to eq(true) @@ -1483,8 +1507,8 @@ describe User do end it 'does not include for which the user access level is below reporter' do - project = create(:empty_project) - guest_project = create(:empty_project) { |p| p.add_guest(user) } + project = create(:project) + guest_project = create(:project) { |p| p.add_guest(user) } expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, guest_project)).to eq(false) @@ -1492,14 +1516,14 @@ describe User do end it 'does not include archived projects' do - project = create(:empty_project, :archived) + project = create(:project, :archived) expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, project)).to eq(false) end it 'does not include projects for which issues are disabled' do - project = create(:empty_project, :issues_disabled) + project = create(:project, :issues_disabled) expect(user.projects_where_can_admin_issues.to_a).to be_empty expect(user.can?(:admin_issue, project)).to eq(false) @@ -1515,7 +1539,7 @@ describe User do end context 'without any projects' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'does not load' do expect(user.ci_authorized_runners).to be_empty @@ -1524,7 +1548,7 @@ describe User do context 'with personal projects runners' do let(:namespace) { create(:namespace, owner: user) } - let(:project) { create(:empty_project, namespace: namespace) } + let(:project) { create(:project, namespace: namespace) } it 'loads' do expect(user.ci_authorized_runners).to contain_exactly(runner) @@ -1555,7 +1579,7 @@ describe User do context 'with groups projects runners' do let(:group) { create(:group) } - let(:project) { create(:empty_project, group: group) } + let(:project) { create(:project, group: group) } def add_user(access) group.add_user(user, access) @@ -1565,7 +1589,7 @@ describe User do end context 'with other projects runners' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } def add_user(access) project.team << [user, access] @@ -1576,8 +1600,8 @@ describe User do end describe '#projects_with_reporter_access_limited_to' do - let(:project1) { create(:empty_project) } - let(:project2) { create(:empty_project) } + let(:project1) { create(:project) } + let(:project2) { create(:project) } let(:user) { create(:user) } before do @@ -1719,8 +1743,8 @@ describe User do end describe '#refresh_authorized_projects', clean_gitlab_redis_shared_state: true do - let(:project1) { create(:empty_project) } - let(:project2) { create(:empty_project) } + let(:project1) { create(:project) } + let(:project2) { create(:project) } let(:user) { create(:user) } before do @@ -1976,4 +2000,28 @@ describe User do expect(user.allow_password_authentication?).to be_falsey end end + + describe '#personal_projects_count' do + it 'returns the number of personal projects using a single query' do + user = build(:user) + projects = double(:projects, count: 1) + + expect(user).to receive(:personal_projects).once.and_return(projects) + + 2.times do + expect(user.personal_projects_count).to eq(1) + end + end + end + + describe '#projects_limit_left' do + it 'returns the number of projects that can be created by the user' do + user = build(:user) + + allow(user).to receive(:projects_limit).and_return(10) + allow(user).to receive(:personal_projects_count).and_return(5) + + expect(user.projects_limit_left).to eq(5) + end + end end diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 55d9c4ddd7b..40a222be24d 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -1,7 +1,7 @@ require "spec_helper" describe WikiPage do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { project.owner } let(:wiki) { ProjectWiki.new(project, user) } @@ -178,12 +178,12 @@ describe WikiPage do end it "updates the content of the page" do - @page.update("new content") + @page.update(content: "new content") @page = wiki.find_page(title) end it "returns true" do - expect(@page.update("more content")).to be_truthy + expect(@page.update(content: "more content")).to be_truthy end end end @@ -195,29 +195,42 @@ describe WikiPage do end after do - destroy_page("Update") + destroy_page(@page.title) end context "with valid attributes" do it "updates the content of the page" do - @page.update("new content") + new_content = "new content" + + @page.update(content: new_content) @page = wiki.find_page("Update") + + expect(@page.content).to eq("new content") + end + + it "updates the title of the page" do + new_title = "Index v.1.2.4" + + @page.update(title: new_title) + @page = wiki.find_page(new_title) + + expect(@page.title).to eq(new_title) end it "returns true" do - expect(@page.update("more content")).to be_truthy + expect(@page.update(content: "more content")).to be_truthy end end context 'with same last commit sha' do it 'returns true' do - expect(@page.update('more content', last_commit_sha: @page.last_commit_sha)).to be_truthy + expect(@page.update(content: 'more content', last_commit_sha: @page.last_commit_sha)).to be_truthy end end context 'with different last commit sha' do it 'raises exception' do - expect { @page.update('more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError) + expect { @page.update(content: 'more content', last_commit_sha: 'xxx') }.to raise_error(WikiPage::PageChangedError) end end end @@ -249,7 +262,7 @@ describe WikiPage do end it "returns an array of all commits for the page" do - 3.times { |i| @page.update("content #{i}") } + 3.times { |i| @page.update(content: "content #{i}") } expect(@page.versions.count).to eq(4) end end @@ -294,7 +307,7 @@ describe WikiPage do before do create_page('Update', 'content') @page = wiki.find_page('Update') - 3.times { |i| @page.update("content #{i}") } + 3.times { |i| @page.update(content: "content #{i}") } end after do @@ -338,7 +351,7 @@ describe WikiPage do end it 'returns false for updated wiki page' do - updated_wiki_page = original_wiki_page.update("Updated content") + updated_wiki_page = original_wiki_page.update(content: "Updated content") expect(original_wiki_page).not_to eq(updated_wiki_page) end end @@ -360,7 +373,7 @@ describe WikiPage do it 'is changed after page updated' do last_commit_sha_before_update = @page.last_commit_sha - @page.update("new content") + @page.update(content: "new content") @page = wiki.find_page("Update") expect(@page.last_commit_sha).not_to eq last_commit_sha_before_update diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index a83a83a7349..8e1bc3d1543 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -17,7 +17,7 @@ describe Ci::BuildPolicy do describe '#rules' do context 'when user does not have access to the project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } context 'when public builds are enabled' do it 'does not include ability to read build' do @@ -35,7 +35,7 @@ describe Ci::BuildPolicy do end context 'when anonymous user has access to the project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } context 'when public builds are enabled' do it 'includes ability to read build' do @@ -53,7 +53,7 @@ describe Ci::BuildPolicy do end context 'when team member has access to the project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } context 'team member is a guest' do before do @@ -97,7 +97,7 @@ describe Ci::BuildPolicy do end describe 'rules for protected ref' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, ref: 'some-ref', pipeline: pipeline) } before do diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb index b11b06d301f..48a8064c5fc 100644 --- a/spec/policies/ci/pipeline_policy_spec.rb +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -10,7 +10,7 @@ describe Ci::PipelinePolicy, :models do describe 'rules' do describe 'rules for protected ref' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.add_developer(user) diff --git a/spec/policies/ci/trigger_policy_spec.rb b/spec/policies/ci/trigger_policy_spec.rb index 3d3e3d3755b..be40dbb2aa9 100644 --- a/spec/policies/ci/trigger_policy_spec.rb +++ b/spec/policies/ci/trigger_policy_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::TriggerPolicy do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:trigger) { create(:ci_trigger, project: project, owner: owner) } let(:policies) do diff --git a/spec/policies/environment_policy_spec.rb b/spec/policies/environment_policy_spec.rb index 035e20c7452..de4cb5b30c5 100644 --- a/spec/policies/environment_policy_spec.rb +++ b/spec/policies/environment_policy_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe EnvironmentPolicy do let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:environment) do create(:environment, :with_review_app, project: project) @@ -14,7 +14,7 @@ describe EnvironmentPolicy do describe '#rules' do context 'when user does not have access to the project' do - let(:project) { create(:project, :private) } + let(:project) { create(:project, :private, :repository) } it 'does not include ability to stop environment' do expect(policy).to be_disallowed :stop_environment @@ -22,7 +22,7 @@ describe EnvironmentPolicy do end context 'when anonymous user has access to the project' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } it 'does not include ability to stop environment' do expect(policy).to be_disallowed :stop_environment @@ -30,7 +30,7 @@ describe EnvironmentPolicy do end context 'when team member has access to the project' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } before do project.add_developer(user) diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb index 279b96fb2af..be4c24c727c 100644 --- a/spec/policies/issue_policy_spec.rb +++ b/spec/policies/issue_policy_spec.rb @@ -14,7 +14,7 @@ describe IssuePolicy do context 'a private project' do let(:non_member) { create(:user) } - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:issue) { create(:issue, project: project, assignees: [assignee], author: author) } let(:issue_no_assignee) { create(:issue, project: project) } @@ -109,7 +109,7 @@ describe IssuePolicy do end context 'a public project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project, assignees: [assignee], author: author) } let(:issue_no_assignee) { create(:issue, project: project) } diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 1f51ced1beb..4dbaf7fb025 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -7,7 +7,7 @@ describe ProjectPolicy do let(:master) { create(:user) } let(:owner) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, :public, namespace: owner.namespace) } + let(:project) { create(:project, :public, namespace: owner.namespace) } let(:guest_permissions) do %i[ @@ -82,7 +82,7 @@ describe ProjectPolicy do end it 'does not include the read_issue permission when the issue author is not a member of the private project' do - project = create(:empty_project, :private) + project = create(:project, :private) issue = create(:issue, project: project) user = issue.author @@ -129,7 +129,7 @@ describe ProjectPolicy do context 'when a project has pending invites, and the current user is anonymous' do let(:group) { create(:group, :public) } - let(:project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } let(:user_permissions) { [:create_project, :create_issue, :create_note, :upload_file] } let(:anonymous_permissions) { guest_permissions - user_permissions } @@ -146,7 +146,7 @@ describe ProjectPolicy do end context 'abilities for non-public projects' do - let(:project) { create(:empty_project, namespace: owner.namespace) } + let(:project) { create(:project, namespace: owner.namespace) } subject { described_class.new(current_user, project) } diff --git a/spec/policies/project_snippet_policy_spec.rb b/spec/policies/project_snippet_policy_spec.rb index bae35ee31c6..f0bf46c480a 100644 --- a/spec/policies/project_snippet_policy_spec.rb +++ b/spec/policies/project_snippet_policy_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe ProjectSnippetPolicy do let(:regular_user) { create(:user) } let(:external_user) { create(:user, :external) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:author_permissions) do [ diff --git a/spec/presenters/ci/build_presenter_spec.rb b/spec/presenters/ci/build_presenter_spec.rb index f05d5c7fce5..a7a34ecac72 100644 --- a/spec/presenters/ci/build_presenter_spec.rb +++ b/spec/presenters/ci/build_presenter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::BuildPresenter do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } @@ -85,7 +85,7 @@ describe Ci::BuildPresenter do describe 'quack like a Ci::Build permission-wise' do context 'user is not allowed' do - let(:project) { create(:empty_project, public_builds: false) } + let(:project) { create(:project, public_builds: false) } it 'returns false' do expect(presenter.can?(nil, :read_build)).to be_falsy @@ -93,7 +93,7 @@ describe Ci::BuildPresenter do end context 'user is allowed' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } it 'returns true' do expect(presenter.can?(nil, :read_build)).to be_truthy diff --git a/spec/presenters/ci/pipeline_presenter_spec.rb b/spec/presenters/ci/pipeline_presenter_spec.rb index 9134d1cc31c..e4886a8f019 100644 --- a/spec/presenters/ci/pipeline_presenter_spec.rb +++ b/spec/presenters/ci/pipeline_presenter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Ci::PipelinePresenter do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } subject(:presenter) do diff --git a/spec/presenters/ci/variable_presenter_spec.rb b/spec/presenters/ci/variable_presenter_spec.rb index 9e6aae7bcad..db62f86edb0 100644 --- a/spec/presenters/ci/variable_presenter_spec.rb +++ b/spec/presenters/ci/variable_presenter_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Ci::VariablePresenter do include Gitlab::Routing.url_helpers - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:variable) { create(:ci_variable, project: project) } subject(:presenter) do diff --git a/spec/presenters/conversational_development_index/metric_presenter_spec.rb b/spec/presenters/conversational_development_index/metric_presenter_spec.rb index 1e015c71f5b..81eb05a9a6b 100644 --- a/spec/presenters/conversational_development_index/metric_presenter_spec.rb +++ b/spec/presenters/conversational_development_index/metric_presenter_spec.rb @@ -8,9 +8,9 @@ describe ConversationalDevelopmentIndex::MetricPresenter do it 'includes instance score, leader score and percentage score' do issues_card = subject.cards.first - expect(issues_card.instance_score).to eq 1.234 - expect(issues_card.leader_score).to eq 9.256 - expect(issues_card.percentage_score).to be_within(0.1).of(13.3) + expect(issues_card.instance_score).to eq(1.234) + expect(issues_card.leader_score).to eq(9.256) + expect(issues_card.percentage_score).to eq(13.331) end end diff --git a/spec/presenters/merge_request_presenter_spec.rb b/spec/presenters/merge_request_presenter_spec.rb index c1a0313b13c..2187be0190d 100644 --- a/spec/presenters/merge_request_presenter_spec.rb +++ b/spec/presenters/merge_request_presenter_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe MergeRequestPresenter do let(:resource) { create :merge_request, source_project: project } - let(:project) { create :empty_project } + let(:project) { create :project } let(:user) { create(:user) } describe '#ci_status' do @@ -71,7 +71,7 @@ describe MergeRequestPresenter do end describe '#conflict_resolution_path' do - let(:project) { create :empty_project } + let(:project) { create :project } let(:user) { create :user } let(:presenter) { described_class.new(resource, current_user: user) } let(:path) { presenter.conflict_resolution_path } @@ -105,7 +105,7 @@ describe MergeRequestPresenter do end context 'issues links' do - let(:project) { create(:project, :private, creator: user, namespace: user.namespace) } + let(:project) { create(:project, :private, :repository, creator: user, namespace: user.namespace) } let(:issue_a) { create(:issue, project: project) } let(:issue_b) { create(:issue, project: project) } diff --git a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb index 5c39e1b5f96..2cc0076d695 100644 --- a/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb +++ b/spec/presenters/projects/settings/deploy_keys_presenter_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::Settings::DeployKeysPresenter do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:deploy_key) { create(:deploy_key, public: true) } diff --git a/spec/requests/api/access_requests_spec.rb b/spec/requests/api/access_requests_spec.rb index c8eacb38e6f..6bd17697c33 100644 --- a/spec/requests/api/access_requests_spec.rb +++ b/spec/requests/api/access_requests_spec.rb @@ -7,7 +7,7 @@ describe API::AccessRequests do let(:stranger) { create(:user) } let(:project) do - create(:empty_project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| + create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| project.team << [developer, :developer] project.team << [master, :master] project.request_access(access_requester) diff --git a/spec/requests/api/award_emoji_spec.rb b/spec/requests/api/award_emoji_spec.rb index 6d822b5cb4f..1dd9f3f6ddc 100644 --- a/spec/requests/api/award_emoji_spec.rb +++ b/spec/requests/api/award_emoji_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::AwardEmoji do let(:user) { create(:user) } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let!(:award_emoji) { create(:award_emoji, awardable: issue, user: user) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } diff --git a/spec/requests/api/boards_spec.rb b/spec/requests/api/boards_spec.rb index c27db716ef8..43b381c2219 100644 --- a/spec/requests/api/boards_spec.rb +++ b/spec/requests/api/boards_spec.rb @@ -6,7 +6,7 @@ describe API::Boards do let(:non_member) { create(:user) } let(:guest) { create(:user) } let(:admin) { create(:user, :admin) } - let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) } + let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) } let!(:dev_label) do create(:label, title: 'Development', color: '#FFAABB', project: project) @@ -188,7 +188,7 @@ describe API::Boards do context "when the user is project owner" do let(:owner) { create(:user) } - let(:project) { create(:empty_project, namespace: owner.namespace) } + let(:project) { create(:project, namespace: owner.namespace) } it "deletes the list if an admin requests it" do delete api("#{base_url}/#{dev_list.id}", owner) diff --git a/spec/requests/api/circuit_breakers_spec.rb b/spec/requests/api/circuit_breakers_spec.rb new file mode 100644 index 00000000000..76521e55994 --- /dev/null +++ b/spec/requests/api/circuit_breakers_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe API::CircuitBreakers do + let(:user) { create(:user) } + let(:admin) { create(:admin) } + + describe 'GET circuit_breakers/repository_storage' do + it 'returns a 401 for anonymous users' do + get api('/circuit_breakers/repository_storage') + + expect(response).to have_http_status(401) + end + + it 'returns a 403 for users' do + get api('/circuit_breakers/repository_storage', user) + + expect(response).to have_http_status(403) + end + + it 'returns an Array of storages' do + expect(Gitlab::Git::Storage::Health).to receive(:for_all_storages) do + [Gitlab::Git::Storage::Health.new('broken', [{ name: 'prefix:broken:web01', failure_count: 4 }])] + end + + get api('/circuit_breakers/repository_storage', admin) + + expect(response).to have_http_status(200) + expect(json_response).to be_kind_of(Array) + expect(json_response.first['storage_name']).to eq('broken') + expect(json_response.first['failing_on_hosts']).to eq(['web01']) + expect(json_response.first['total_failures']).to eq(4) + end + + describe 'GET circuit_breakers/repository_storage/failing' do + it 'returns an array of failing storages' do + expect(Gitlab::Git::Storage::Health).to receive(:for_failing_storages) do + [Gitlab::Git::Storage::Health.new('broken', [{ name: 'prefix:broken:web01', failure_count: 4 }])] + end + + get api('/circuit_breakers/repository_storage/failing', admin) + + expect(response).to have_http_status(200) + expect(json_response).to be_kind_of(Array) + end + end + end + + describe 'DELETE circuit_breakers/repository_storage' do + it 'clears all circuit_breakers' do + expect(Gitlab::Git::Storage::CircuitBreaker).to receive(:reset_all!) + + delete api('/circuit_breakers/repository_storage', admin) + + expect(response).to have_http_status(204) + end + end +end diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb index 8b62aa268d9..3c02e6302b4 100644 --- a/spec/requests/api/commit_statuses_spec.rb +++ b/spec/requests/api/commit_statuses_spec.rb @@ -44,8 +44,8 @@ describe API::CommitStatuses do expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(statuses_id).to contain_exactly(status3.id, status4.id, status5.id, status6.id) - json_response.sort_by!{ |status| status['id'] } - expect(json_response.map{ |status| status['allow_failure'] }).to eq([true, false, false, false]) + json_response.sort_by! { |status| status['id'] } + expect(json_response.map { |status| status['allow_failure'] }).to eq([true, false, false, false]) end end diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 0dad547735d..992a6e8d76a 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -3,29 +3,27 @@ require 'mime/types' describe API::Commits do let(:user) { create(:user) } - let(:user2) { create(:user) } - let!(:project) { create(:project, :repository, creator: user, namespace: user.namespace) } - let!(:guest) { create(:project_member, :guest, user: user2, project: project) } - let!(:note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'a comment on a commit') } - let!(:another_note) { create(:note_on_commit, author: user, project: project, commit_id: project.repository.commit.id, note: 'another comment on a commit') } + let(:guest) { create(:user).tap { |u| project.add_guest(u) } } + let(:project) { create(:project, :repository, creator: user, path: 'my.project') } + let(:branch_with_dot) { project.repository.find_branch('ends-with.json') } + let(:branch_with_slash) { project.repository.find_branch('improve/awesome') } + + let(:project_id) { project.id } + let(:current_user) { nil } before do - project.team << [user, :reporter] + project.add_master(user) end - describe "List repository commits" do - context "authorized user" do - before do - project.team << [user2, :reporter] - end - + describe 'GET /projects/:id/repository/commits' do + context 'authorized user' do it "returns project commits" do commit = project.repository.commit - get api("/projects/#{project.id}/repository/commits", user) + get api("/projects/#{project_id}/repository/commits", user) expect(response).to have_http_status(200) - expect(json_response).to be_an Array + expect(response).to match_response_schema('public_api/v4/commits') expect(json_response.first['id']).to eq(commit.id) expect(json_response.first['committer_name']).to eq(commit.committer_name) expect(json_response.first['committer_email']).to eq(commit.committer_email) @@ -34,7 +32,7 @@ describe API::Commits do it 'include correct pagination headers' do commit_count = project.repository.count_commits(ref: 'master').to_s - get api("/projects/#{project.id}/repository/commits", user) + get api("/projects/#{project_id}/repository/commits", user) expect(response).to include_pagination_headers expect(response.headers['X-Total']).to eq(commit_count) @@ -44,8 +42,9 @@ describe API::Commits do context "unauthorized user" do it "does not return project commits" do - get api("/projects/#{project.id}/repository/commits") - expect(response).to have_http_status(401) + get api("/projects/#{project_id}/repository/commits") + + expect(response).to have_http_status(404) end end @@ -54,7 +53,7 @@ describe API::Commits do commits = project.repository.commits("master") after = commits.second.created_at - get api("/projects/#{project.id}/repository/commits?since=#{after.utc.iso8601}", user) + get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user) expect(json_response.size).to eq 2 expect(json_response.first["id"]).to eq(commits.first.id) @@ -66,7 +65,7 @@ describe API::Commits do after = commits.second.created_at commit_count = project.repository.count_commits(ref: 'master', after: after).to_s - get api("/projects/#{project.id}/repository/commits?since=#{after.utc.iso8601}", user) + get api("/projects/#{project_id}/repository/commits?since=#{after.utc.iso8601}", user) expect(response).to include_pagination_headers expect(response.headers['X-Total']).to eq(commit_count) @@ -79,7 +78,7 @@ describe API::Commits do commits = project.repository.commits("master") before = commits.second.created_at - get api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user) + get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user) if commits.size >= 20 expect(json_response.size).to eq(20) @@ -96,7 +95,7 @@ describe API::Commits do before = commits.second.created_at commit_count = project.repository.count_commits(ref: 'master', before: before).to_s - get api("/projects/#{project.id}/repository/commits?until=#{before.utc.iso8601}", user) + get api("/projects/#{project_id}/repository/commits?until=#{before.utc.iso8601}", user) expect(response).to include_pagination_headers expect(response.headers['X-Total']).to eq(commit_count) @@ -106,7 +105,7 @@ describe API::Commits do context "invalid xmlschema date parameters" do it "returns an invalid parameter error message" do - get api("/projects/#{project.id}/repository/commits?since=invalid-date", user) + get api("/projects/#{project_id}/repository/commits?since=invalid-date", user) expect(response).to have_http_status(400) expect(json_response['error']).to eq('since is invalid') @@ -118,7 +117,7 @@ describe API::Commits do path = 'files/ruby/popen.rb' commit_count = project.repository.count_commits(ref: 'master', path: path).to_s - get api("/projects/#{project.id}/repository/commits?path=#{path}", user) + get api("/projects/#{project_id}/repository/commits?path=#{path}", user) expect(json_response.size).to eq(3) expect(json_response.first["id"]).to eq("570e7b2abdd848b95f2f578043fc23bd6f6fd24d") @@ -130,7 +129,7 @@ describe API::Commits do path = 'files/ruby/popen.rb' commit_count = project.repository.count_commits(ref: 'master', path: path).to_s - get api("/projects/#{project.id}/repository/commits?path=#{path}", user) + get api("/projects/#{project_id}/repository/commits?path=#{path}", user) expect(response).to include_pagination_headers expect(response.headers['X-Total']).to eq(commit_count) @@ -143,7 +142,7 @@ describe API::Commits do let(:per_page) { 5 } let(:ref_name) { 'master' } let!(:request) do - get api("/projects/#{project.id}/repository/commits?page=#{page}&per_page=#{per_page}&ref_name=#{ref_name}", user) + get api("/projects/#{project_id}/repository/commits?page=#{page}&per_page=#{per_page}&ref_name=#{ref_name}", user) end it 'returns correct headers' do @@ -181,10 +180,10 @@ describe API::Commits do end describe "POST /projects/:id/repository/commits" do - let!(:url) { "/projects/#{project.id}/repository/commits" } + let!(:url) { "/projects/#{project_id}/repository/commits" } it 'returns a 403 unauthorized for user without permissions' do - post api(url, user2) + post api(url, guest) expect(response).to have_http_status(403) end @@ -227,7 +226,7 @@ describe API::Commits do it 'a new file in project repo' do post api(url, user), valid_c_params - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq(message) expect(json_response['committer_name']).to eq(user.name) expect(json_response['committer_email']).to eq(user.email) @@ -453,13 +452,17 @@ describe API::Commits do end end - describe "Get a single commit" do - context "authorized user" do - it "returns a commit by sha" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) + describe 'GET /projects/:id/repository/commits/:sha' do + let(:commit) { project.repository.commit } + let(:commit_id) { commit.id } + let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}" } - expect(response).to have_http_status(200) - commit = project.repository.commit + shared_examples_for 'ref commit' do + it 'returns the ref last commit' do + get api(route, current_user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/commit/detail') expect(json_response['id']).to eq(commit.id) expect(json_response['short_id']).to eq(commit.short_id) expect(json_response['title']).to eq(commit.title) @@ -474,222 +477,539 @@ describe API::Commits do expect(json_response['stats']['additions']).to eq(commit.stats.additions) expect(json_response['stats']['deletions']).to eq(commit.stats.deletions) expect(json_response['stats']['total']).to eq(commit.stats.total) + expect(json_response['status']).to be_nil end - it "returns a 404 error if not found" do - get api("/projects/#{project.id}/repository/commits/invalid_sha", user) - expect(response).to have_http_status(404) + context 'when ref does not exist' do + let(:commit_id) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + let(:message) { '404 Commit Not Found' } + end end - it "returns nil for commit without CI" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) + context 'when repository is disabled' do + include_context 'disabled repository' - expect(response).to have_http_status(200) - expect(json_response['status']).to be_nil + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end end + end - it "returns status for CI" do - pipeline = project.pipelines.create(source: :push, ref: 'master', sha: project.repository.commit.sha) - pipeline.update(status: 'success') + context 'when unauthenticated', 'and project is public' do + let(:project) { create(:project, :public, :repository) } - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) + it_behaves_like 'ref commit' + end - expect(response).to have_http_status(200) - expect(json_response['status']).to eq(pipeline.status) + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } end + end - it "returns status for CI when pipeline is created" do - project.pipelines.create(source: :push, ref: 'master', sha: project.repository.commit.sha) + context 'when authenticated', 'as a master' do + let(:current_user) { user } - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) + it_behaves_like 'ref commit' - expect(response).to have_http_status(200) - expect(json_response['status']).to eq("created") + context 'when branch contains a dot' do + let(:commit) { project.repository.commit(branch_with_dot.name) } + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref commit' end - end - context "unauthorized user" do - it "does not return the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}") - expect(response).to have_http_status(401) + context 'when branch contains a slash' do + let(:commit_id) { branch_with_slash.name } + + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + end + end + + context 'when branch contains an escaped slash' do + let(:commit) { project.repository.commit(branch_with_slash.name) } + let(:commit_id) { CGI.escape(branch_with_slash.name) } + + it_behaves_like 'ref commit' + end + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'ref commit' + + context 'when branch contains a dot' do + let(:commit) { project.repository.commit(branch_with_dot.name) } + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref commit' + end + end + + context 'when the ref has a pipeline' do + let!(:pipeline) { project.pipelines.create(source: :push, ref: 'master', sha: commit.sha) } + + it 'includes a "created" status' do + get api(route, current_user) + + expect(response).to have_http_status(200) + expect(response).to match_response_schema('public_api/v4/commit/detail') + expect(json_response['status']).to eq('created') + end + + context 'when pipeline succeeds' do + before do + pipeline.update(status: 'success') + end + + it 'includes a "success" status' do + get api(route, current_user) + + expect(response).to have_http_status(200) + expect(response).to match_response_schema('public_api/v4/commit/detail') + expect(json_response['status']).to eq('success') + end + end end end end - describe "Get the diff of a commit" do - context "authorized user" do - before do - project.team << [user2, :reporter] + describe 'GET /projects/:id/repository/commits/:sha/diff' do + let(:commit) { project.repository.commit } + let(:commit_id) { commit.id } + let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}/diff" } + + shared_examples_for 'ref diff' do + it 'returns the diff of the selected commit' do + get api(route, current_user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response.size).to be >= 1 + expect(json_response.first.keys).to include 'diff' end - it "returns the diff of the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user) - expect(response).to have_http_status(200) + context 'when ref does not exist' do + let(:commit_id) { 'unknown' } - expect(json_response).to be_an Array - expect(json_response.length).to be >= 1 - expect(json_response.first.keys).to include "diff" + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + let(:message) { '404 Commit Not Found' } + end end - it "returns a 404 error if invalid commit" do - get api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user) - expect(response).to have_http_status(404) + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end end end - context "unauthorized user" do - it "does not return the diff of the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff") - expect(response).to have_http_status(401) + context 'when unauthenticated', 'and project is public' do + let(:project) { create(:project, :public, :repository) } + + it_behaves_like 'ref diff' + end + + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } + end + end + + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + it_behaves_like 'ref diff' + + context 'when branch contains a dot' do + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref diff' + end + + context 'when branch contains a slash' do + let(:commit_id) { branch_with_slash.name } + + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + end + end + + context 'when branch contains an escaped slash' do + let(:commit_id) { CGI.escape(branch_with_slash.name) } + + it_behaves_like 'ref diff' + end + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'ref diff' + + context 'when branch contains a dot' do + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref diff' + end end end end - describe 'Get the comments of a commit' do - context 'authorized user' do - it 'returns merge_request comments' do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user) - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.length).to eq(2) - expect(json_response.first['note']).to eq('a comment on a commit') - expect(json_response.first['author']['id']).to eq(user.id) + describe 'GET /projects/:id/repository/commits/:sha/comments' do + let(:commit) { project.repository.commit } + let(:commit_id) { commit.id } + let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}/comments" } + + shared_examples_for 'ref comments' do + context 'when ref exists' do + before do + create(:note_on_commit, author: user, project: project, commit_id: commit.id, note: 'a comment on a commit') + create(:note_on_commit, author: user, project: project, commit_id: commit.id, note: 'another comment on a commit') + end + + it 'returns the diff of the selected commit' do + get api(route, current_user) + + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/commit_notes') + expect(json_response.size).to eq(2) + expect(json_response.first['note']).to eq('a comment on a commit') + expect(json_response.first['author']['id']).to eq(user.id) + end end - it 'returns a 404 error if merge_request_id not found' do - get api("/projects/#{project.id}/repository/commits/1234ab/comments", user) - expect(response).to have_http_status(404) + context 'when ref does not exist' do + let(:commit_id) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + let(:message) { '404 Commit Not Found' } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end + end + end + + context 'when unauthenticated', 'and project is public' do + let(:project) { create(:project, :public, :repository) } + + it_behaves_like 'ref comments' + end + + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } end end - context 'unauthorized user' do - it 'does not return the diff of the selected commit' do - get api("/projects/#{project.id}/repository/commits/1234ab/comments") - expect(response).to have_http_status(401) + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + it_behaves_like 'ref comments' + + context 'when branch contains a dot' do + let(:commit) { project.repository.commit(branch_with_dot.name) } + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref comments' + end + + context 'when branch contains a slash' do + let(:commit) { project.repository.commit(branch_with_slash.name) } + let(:commit_id) { branch_with_slash.name } + + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + end + end + + context 'when branch contains an escaped slash' do + let(:commit) { project.repository.commit(branch_with_slash.name) } + let(:commit_id) { CGI.escape(branch_with_slash.name) } + + it_behaves_like 'ref comments' + end + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'ref comments' + + context 'when branch contains a dot' do + let(:commit) { project.repository.commit(branch_with_dot.name) } + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref comments' + end end end context 'when the commit is present on two projects' do - let(:forked_project) { create(:project, :repository, creator: user2, namespace: user2.namespace) } - let!(:forked_project_note) { create(:note_on_commit, author: user2, project: forked_project, commit_id: forked_project.repository.commit.id, note: 'a comment on a commit for fork') } + let(:forked_project) { create(:project, :repository, creator: guest, namespace: guest.namespace) } + let!(:forked_project_note) { create(:note_on_commit, author: guest, project: forked_project, commit_id: forked_project.repository.commit.id, note: 'a comment on a commit for fork') } + let(:project_id) { forked_project.id } + let(:commit_id) { forked_project.repository.commit.id } it 'returns the comments for the target project' do - get api("/projects/#{forked_project.id}/repository/commits/#{forked_project.repository.commit.id}/comments", user2) + get api(route, guest) - expect(response).to have_http_status(200) - expect(json_response.length).to eq(1) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/commit_notes') + expect(json_response.size).to eq(1) expect(json_response.first['note']).to eq('a comment on a commit for fork') - expect(json_response.first['author']['id']).to eq(user2.id) + expect(json_response.first['author']['id']).to eq(guest.id) end end end describe 'POST :id/repository/commits/:sha/cherry_pick' do - let(:master_pickable_commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') } + let(:commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') } + let(:commit_id) { commit.id } + let(:branch) { 'master' } + let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}/cherry_pick" } + + shared_examples_for 'ref cherry-pick' do + context 'when ref exists' do + it 'cherry-picks the ref commit' do + post api(route, current_user), branch: branch + + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/commit/basic') + expect(json_response['title']).to eq(commit.title) + expect(json_response['message']).to eq(commit.message) + expect(json_response['author_name']).to eq(commit.author_name) + expect(json_response['committer_name']).to eq(user.name) + end + end - context 'authorized user' do - it 'cherry picks a commit' do - post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'master' + context 'when repository is disabled' do + include_context 'disabled repository' - expect(response).to have_http_status(201) - expect(json_response['title']).to eq(master_pickable_commit.title) - expect(json_response['message']).to eq(master_pickable_commit.message) - expect(json_response['author_name']).to eq(master_pickable_commit.author_name) - expect(json_response['committer_name']).to eq(user.name) + it_behaves_like '403 response' do + let(:request) { post api(route, current_user), branch: 'master' } + end end + end - it 'returns 400 if commit is already included in the target branch' do - post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'markdown' + context 'when unauthenticated', 'and project is public' do + let(:project) { create(:project, :public, :repository) } - expect(response).to have_http_status(400) - expect(json_response['message']).to include('Sorry, we cannot cherry-pick this commit automatically.') + it_behaves_like '403 response' do + let(:request) { post api(route), branch: 'master' } + end + end + + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { post api(route), branch: 'master' } + let(:message) { '404 Project Not Found' } end + end - it 'returns 400 if you are not allowed to push to the target branch' do - project.team << [user2, :developer] - protected_branch = create(:protected_branch, project: project, name: 'feature') + context 'when authenticated', 'as an owner' do + let(:current_user) { user } - post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user2), branch: protected_branch.name + it_behaves_like 'ref cherry-pick' - expect(response).to have_http_status(400) - expect(json_response['message']).to eq('You are not allowed to push into this branch') + context 'when ref does not exist' do + let(:commit_id) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { post api(route, current_user), branch: 'master' } + let(:message) { '404 Commit Not Found' } + end + end + + context 'when branch is missing' do + it_behaves_like '400 response' do + let(:request) { post api(route, current_user) } + end end - it 'returns 400 for missing parameters' do - post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user) + context 'when branch does not exist' do + it_behaves_like '404 response' do + let(:request) { post api(route, current_user), branch: 'foo' } + let(:message) { '404 Branch Not Found' } + end + end - expect(response).to have_http_status(400) - expect(json_response['error']).to eq('branch is missing') + context 'when commit is already included in the target branch' do + it_behaves_like '400 response' do + let(:request) { post api(route, current_user), branch: 'markdown' } + end end - it 'returns 404 if commit is not found' do - post api("/projects/#{project.id}/repository/commits/abcd0123/cherry_pick", user), branch: 'master' + context 'when ref contains a dot' do + let(:commit) { project.repository.commit(branch_with_dot.name) } + let(:commit_id) { branch_with_dot.name } - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('404 Commit Not Found') + it_behaves_like 'ref cherry-pick' end - it 'returns 404 if branch is not found' do - post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'foo' + context 'when ref contains a slash' do + let(:commit_id) { branch_with_slash.name } - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('404 Branch Not Found') + it_behaves_like '404 response' do + let(:request) { post api(route, current_user), branch: 'master' } + end end - it 'returns 400 for missing parameters' do - post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user) + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } - expect(response).to have_http_status(400) - expect(json_response['error']).to eq('branch is missing') + it_behaves_like 'ref cherry-pick' + + context 'when ref contains a dot' do + let(:commit) { project.repository.commit(branch_with_dot.name) } + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref cherry-pick' + end end end - context 'unauthorized user' do - it 'does not cherry pick the commit' do - post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick"), branch: 'master' + context 'when authenticated', 'as a developer' do + let(:current_user) { guest } + + before do + project.add_developer(guest) + end + + context 'when branch is protected' do + before do + create(:protected_branch, project: project, name: 'feature') + end + + it 'returns 400 if you are not allowed to push to the target branch' do + post api(route, current_user), branch: 'feature' - expect(response).to have_http_status(401) + expect(response).to have_gitlab_http_status(400) + expect(json_response['message']).to eq('You are not allowed to push into this branch') + end end end end - describe 'Post comment to commit' do - context 'authorized user' do - it 'returns comment' do - post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment' - expect(response).to have_http_status(201) - expect(json_response['note']).to eq('My comment') - expect(json_response['path']).to be_nil - expect(json_response['line']).to be_nil - expect(json_response['line_type']).to be_nil + describe 'POST /projects/:id/repository/commits/:sha/comments' do + let(:commit) { project.repository.commit } + let(:commit_id) { commit.id } + let(:note) { 'My comment' } + let(:route) { "/projects/#{project_id}/repository/commits/#{commit_id}/comments" } + + shared_examples_for 'ref new comment' do + context 'when ref exists' do + it 'creates the comment' do + post api(route, current_user), note: note + + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/commit_note') + expect(json_response['note']).to eq('My comment') + expect(json_response['path']).to be_nil + expect(json_response['line']).to be_nil + expect(json_response['line_type']).to be_nil + end end + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { post api(route, current_user), note: 'My comment' } + end + end + end + + context 'when unauthenticated', 'and project is public' do + let(:project) { create(:project, :public, :repository) } + + it_behaves_like '400 response' do + let(:request) { post api(route), note: 'My comment' } + end + end + + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { post api(route), note: 'My comment' } + let(:message) { '404 Project Not Found' } + end + end + + context 'when authenticated', 'as an owner' do + let(:current_user) { user } + + it_behaves_like 'ref new comment' + it 'returns the inline comment' do - post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user), note: 'My comment', path: project.repository.commit.raw_diffs.first.new_path, line: 1, line_type: 'new' + post api(route, current_user), note: 'My comment', path: project.repository.commit.raw_diffs.first.new_path, line: 1, line_type: 'new' - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/commit_note') expect(json_response['note']).to eq('My comment') expect(json_response['path']).to eq(project.repository.commit.raw_diffs.first.new_path) expect(json_response['line']).to eq(1) expect(json_response['line_type']).to eq('new') end + context 'when ref does not exist' do + let(:commit_id) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { post api(route, current_user), note: 'My comment' } + let(:message) { '404 Commit Not Found' } + end + end + it 'returns 400 if note is missing' do - post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments", user) - expect(response).to have_http_status(400) + post api(route, current_user) + + expect(response).to have_gitlab_http_status(400) end - it 'returns 404 if note is attached to non existent commit' do - post api("/projects/#{project.id}/repository/commits/1234ab/comments", user), note: 'My comment' - expect(response).to have_http_status(404) + context 'when ref contains a dot' do + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref new comment' end - end - context 'unauthorized user' do - it 'does not return the diff of the selected commit' do - post api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/comments") - expect(response).to have_http_status(401) + context 'when ref contains a slash' do + let(:commit_id) { branch_with_slash.name } + + it_behaves_like '404 response' do + let(:request) { post api(route, current_user), note: 'My comment' } + end + end + + context 'when ref contains an escaped slash' do + let(:commit_id) { CGI.escape(branch_with_slash.name) } + + it_behaves_like 'ref new comment' + end + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'ref new comment' + + context 'when ref contains a dot' do + let(:commit_id) { branch_with_dot.name } + + it_behaves_like 'ref new comment' + end end end end diff --git a/spec/requests/api/deploy_keys_spec.rb b/spec/requests/api/deploy_keys_spec.rb index 32439981b60..e497ec333a2 100644 --- a/spec/requests/api/deploy_keys_spec.rb +++ b/spec/requests/api/deploy_keys_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe API::DeployKeys do let(:user) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, creator_id: user.id) } - let(:project2) { create(:empty_project, creator_id: user.id) } + let(:project) { create(:project, creator_id: user.id) } + let(:project2) { create(:project, creator_id: user.id) } let(:deploy_key) { create(:deploy_key, public: true) } let!(:deploy_keys_project) do @@ -182,7 +182,7 @@ describe API::DeployKeys do delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", admin) expect(response).to have_http_status(204) - end.to change{ project.deploy_keys.count }.by(-1) + end.to change { project.deploy_keys.count }.by(-1) end it 'returns 404 Not Found with invalid ID' do @@ -193,7 +193,7 @@ describe API::DeployKeys do end describe 'POST /projects/:id/deploy_keys/:key_id/enable' do - let(:project2) { create(:empty_project) } + let(:project2) { create(:project) } context 'when the user can admin the project' do it 'enables the key' do diff --git a/spec/requests/api/environments_spec.rb b/spec/requests/api/environments_spec.rb index aae03c84e1f..87716c6fe3a 100644 --- a/spec/requests/api/environments_spec.rb +++ b/spec/requests/api/environments_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::Environments do let(:user) { create(:user) } let(:non_member) { create(:user) } - let(:project) { create(:empty_project, :private, namespace: user.namespace) } + let(:project) { create(:project, :private, namespace: user.namespace) } let!(:environment) { create(:environment, project: project) } before do @@ -13,7 +13,14 @@ describe API::Environments do describe 'GET /projects/:id/environments' do context 'as member of the project' do it 'returns project environments' do - project_data_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace) + project_data_keys = %w( + id description default_branch tag_list + ssh_url_to_repo http_url_to_repo web_url + name name_with_namespace + path path_with_namespace + star_count forks_count + created_at last_activity_at + ) get api("/projects/#{project.id}/environments", user) diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb index 1754ba66a96..a23d28994ce 100644 --- a/spec/requests/api/events_spec.rb +++ b/spec/requests/api/events_spec.rb @@ -5,7 +5,7 @@ describe API::Events do let(:user) { create(:user) } let(:non_member) { create(:user) } let(:other_user) { create(:user, username: 'otheruser') } - let(:private_project) { create(:empty_project, :private, creator_id: user.id, namespace: user.namespace) } + let(:private_project) { create(:project, :private, creator_id: user.id, namespace: user.namespace) } let(:closed_issue) { create(:closed_issue, project: private_project, author: user) } let!(:closed_issue_event) { create(:event, project: private_project, author: user, target: closed_issue, action: Event::CLOSED, created_at: Date.new(2016, 12, 30)) } @@ -59,8 +59,36 @@ describe API::Events do expect(json_response.size).to eq(1) end + context 'when the list of events includes push events' do + let(:event) do + create(:push_event, author: user, project: private_project) + end + + let!(:payload) { create(:push_event_payload, event: event) } + let(:payload_hash) { json_response[0]['push_data'] } + + before do + get api("/users/#{user.id}/events?action=pushed", user) + end + + it 'responds with HTTP 200 OK' do + expect(response).to have_http_status(200) + end + + it 'includes the push payload as a Hash' do + expect(payload_hash).to be_an_instance_of(Hash) + end + + it 'includes the push payload details' do + expect(payload_hash['commit_count']).to eq(payload.commit_count) + expect(payload_hash['action']).to eq(payload.action) + expect(payload_hash['ref_type']).to eq(payload.ref_type) + expect(payload_hash['commit_to']).to eq(payload.commit_to) + end + end + context 'when there are multiple events from different projects' do - let(:second_note) { create(:note_on_issue, project: create(:empty_project)) } + let(:second_note) { create(:note_on_issue, project: create(:project)) } before do second_note.project.add_user(user, :developer) @@ -106,7 +134,7 @@ describe API::Events do end it 'returns 200 status for a public project' do - public_project = create(:empty_project, :public) + public_project = create(:project, :public) get api("/projects/#{public_project.id}/events") @@ -138,5 +166,35 @@ describe API::Events do expect(response).to have_http_status(404) end end + + context 'when exists some events' do + let(:merge_request1) { create(:merge_request, :closed, author: user, assignee: user, source_project: private_project, title: 'Test') } + let(:merge_request2) { create(:merge_request, :closed, author: user, assignee: user, source_project: private_project, title: 'Test') } + + before do + create_event(merge_request1) + end + + it 'avoids N+1 queries' do + control_count = ActiveRecord::QueryRecorder.new do + get api("/projects/#{private_project.id}/events", user), target_type: :merge_request + end.count + + create_event(merge_request2) + + expect do + get api("/projects/#{private_project.id}/events", user), target_type: :merge_request + end.not_to exceed_query_limit(control_count) + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response.size).to eq(2) + expect(json_response.map { |r| r['target_id'] }).to match_array([merge_request1.id, merge_request2.id]) + end + + def create_event(target) + create(:event, project: private_project, author: user, target: target) + end + end end end diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 9e268adf950..ea97c556430 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -33,6 +33,15 @@ describe API::Files do expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n") end + it 'returns json when file has txt extension' do + file_path = "bar%2Fbranch-test.txt" + + get api(route(file_path), current_user), params + + expect(response).to have_http_status(200) + expect(response.content_type).to eq('application/json') + end + it 'returns file by commit sha' do # This file is deleted on HEAD file_path = "files%2Fjs%2Fcommit%2Ejs%2Ecoffee" @@ -80,7 +89,7 @@ describe API::Files do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository files' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -153,7 +162,7 @@ describe API::Files do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository raw files' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end @@ -220,6 +229,7 @@ describe API::Files do post api(route("new_file_with_author%2Etxt"), user), valid_params expect(response).to have_http_status(201) + expect(response.content_type).to eq('application/json') last_commit = project.repository.commit.raw expect(last_commit.author_email).to eq(author_email) expect(last_commit.author_name).to eq(author_name) diff --git a/spec/requests/api/group_milestones_spec.rb b/spec/requests/api/group_milestones_spec.rb index 9b24658771f..108721c6655 100644 --- a/spec/requests/api/group_milestones_spec.rb +++ b/spec/requests/api/group_milestones_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::GroupMilestones do let(:user) { create(:user) } let(:group) { create(:group, :private) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } let!(:group_member) { create(:group_member, group: group, user: user) } let!(:closed_milestone) { create(:closed_milestone, group: group, title: 'version1', description: 'closed milestone') } let!(:milestone) { create(:milestone, group: group, title: 'version2', description: 'open milestone') } diff --git a/spec/requests/api/group_variables_spec.rb b/spec/requests/api/group_variables_spec.rb new file mode 100644 index 00000000000..2179790d098 --- /dev/null +++ b/spec/requests/api/group_variables_spec.rb @@ -0,0 +1,221 @@ +require 'spec_helper' + +describe API::GroupVariables do + let(:group) { create(:group) } + let(:user) { create(:user) } + + describe 'GET /groups/:id/variables' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'returns group variables' do + get api("/groups/#{group.id}/variables", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_a(Array) + end + end + + context 'authorized user with invalid permissions' do + it 'does not return group variables' do + get api("/groups/#{group.id}/variables", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not return group variables' do + get api("/groups/#{group.id}/variables") + + expect(response).to have_http_status(401) + end + end + end + + describe 'GET /groups/:id/variables/:key' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'returns group variable details' do + get api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(200) + expect(json_response['value']).to eq(variable.value) + expect(json_response['protected']).to eq(variable.protected?) + end + + it 'responds with 404 Not Found if requesting non-existing variable' do + get api("/groups/#{group.id}/variables/non_existing_variable", user) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user with invalid permissions' do + it 'does not return group variable details' do + get api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not return group variable details' do + get api("/groups/#{group.id}/variables/#{variable.key}") + + expect(response).to have_http_status(401) + end + end + end + + describe 'POST /groups/:id/variables' do + context 'authorized user with proper permissions' do + let!(:variable) { create(:ci_group_variable, group: group) } + + before do + group.add_master(user) + end + + it 'creates variable' do + expect do + post api("/groups/#{group.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2', protected: true + end.to change {group.variables.count}.by(1) + + expect(response).to have_http_status(201) + expect(json_response['key']).to eq('TEST_VARIABLE_2') + expect(json_response['value']).to eq('VALUE_2') + expect(json_response['protected']).to be_truthy + end + + it 'creates variable with optional attributes' do + expect do + post api("/groups/#{group.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2' + end.to change {group.variables.count}.by(1) + + expect(response).to have_http_status(201) + expect(json_response['key']).to eq('TEST_VARIABLE_2') + expect(json_response['value']).to eq('VALUE_2') + expect(json_response['protected']).to be_falsey + end + + it 'does not allow to duplicate variable key' do + expect do + post api("/groups/#{group.id}/variables", user), key: variable.key, value: 'VALUE_2' + end.to change {group.variables.count}.by(0) + + expect(response).to have_http_status(400) + end + end + + context 'authorized user with invalid permissions' do + it 'does not create variable' do + post api("/groups/#{group.id}/variables", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not create variable' do + post api("/groups/#{group.id}/variables") + + expect(response).to have_http_status(401) + end + end + end + + describe 'PUT /groups/:id/variables/:key' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'updates variable data' do + initial_variable = group.variables.first + value_before = initial_variable.value + + put api("/groups/#{group.id}/variables/#{variable.key}", user), value: 'VALUE_1_UP', protected: true + + updated_variable = group.variables.first + + expect(response).to have_http_status(200) + expect(value_before).to eq(variable.value) + expect(updated_variable.value).to eq('VALUE_1_UP') + expect(updated_variable).to be_protected + end + + it 'responds with 404 Not Found if requesting non-existing variable' do + put api("/groups/#{group.id}/variables/non_existing_variable", user) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user with invalid permissions' do + it 'does not update variable' do + put api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not update variable' do + put api("/groups/#{group.id}/variables/#{variable.key}") + + expect(response).to have_http_status(401) + end + end + end + + describe 'DELETE /groups/:id/variables/:key' do + let!(:variable) { create(:ci_group_variable, group: group) } + + context 'authorized user with proper permissions' do + before do + group.add_master(user) + end + + it 'deletes variable' do + expect do + delete api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(204) + end.to change {group.variables.count}.by(-1) + end + + it 'responds with 404 Not Found if requesting non-existing variable' do + delete api("/groups/#{group.id}/variables/non_existing_variable", user) + + expect(response).to have_http_status(404) + end + end + + context 'authorized user with invalid permissions' do + it 'does not delete variable' do + delete api("/groups/#{group.id}/variables/#{variable.key}", user) + + expect(response).to have_http_status(403) + end + end + + context 'unauthorized user' do + it 'does not delete variable' do + delete api("/groups/#{group.id}/variables/#{variable.key}") + + expect(response).to have_http_status(401) + end + end + end +end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 1d7adc6ac45..313c38cd29c 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -9,9 +9,9 @@ describe API::Groups do let(:admin) { create(:admin) } let!(:group1) { create(:group, avatar: File.open(uploaded_image_temp_path)) } let!(:group2) { create(:group, :private) } - let!(:project1) { create(:empty_project, namespace: group1) } - let!(:project2) { create(:empty_project, namespace: group2) } - let!(:project3) { create(:empty_project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) } + let!(:project1) { create(:project, namespace: group1) } + let!(:project2) { create(:project, namespace: group2) } + let!(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) } before do group1.add_owner(user1) @@ -167,7 +167,7 @@ describe API::Groups do describe "GET /groups/:id" do context "when authenticated as user" do it "returns one of user1's groups" do - project = create(:empty_project, namespace: group2, path: 'Foo') + project = create(:project, namespace: group2, path: 'Foo') create(:project_group_link, project: project, group: group1) get api("/groups/#{group1.id}", user1) @@ -311,7 +311,7 @@ describe API::Groups do end it 'filters the groups projects' do - public_project = create(:empty_project, :public, path: 'test1', group: group1) + public_project = create(:project, :public, path: 'test1', group: group1) get api("/groups/#{group1.id}/projects", user1), visibility: 'public' @@ -509,10 +509,10 @@ describe API::Groups do end describe "POST /groups/:id/projects/:project_id" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:project_path) { CGI.escape(project.full_path) } - before(:each) do + before do allow_any_instance_of(Projects::TransferService) .to receive(:execute).and_return(true) end diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb index 7a1bd76af7a..d4006fe71a2 100644 --- a/spec/requests/api/helpers_spec.rb +++ b/spec/requests/api/helpers_spec.rb @@ -56,7 +56,7 @@ describe API::Helpers do end def doorkeeper_guard_returns(value) - allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ value } + allow_any_instance_of(self.class).to receive(:doorkeeper_guard) { value } end def error!(message, status, header) @@ -161,7 +161,7 @@ describe API::Helpers do describe "when authenticating using a user's private token" do it "returns nil for an invalid token" do env[API::APIGuard::PRIVATE_TOKEN_HEADER] = 'invalid token' - allow_any_instance_of(self.class).to receive(:doorkeeper_guard){ false } + allow_any_instance_of(self.class).to receive(:doorkeeper_guard) { false } expect(current_user).to be_nil end diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index ce9b9ac1eb3..e9c30dba8d4 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -181,13 +181,12 @@ describe API::Internal do describe "POST /internal/allowed", :clean_gitlab_redis_shared_state do context "access granted" do - before do - project.team << [user, :developer] - Timecop.freeze + around do |example| + Timecop.freeze { example.run } end - after do - Timecop.return + before do + project.team << [user, :developer] end context 'with env passed as a JSON' do @@ -301,7 +300,7 @@ describe API::Internal do context 'project as /namespace/project' do it do - pull(key, project_with_repo_path('/' + project.path_with_namespace)) + pull(key, project_with_repo_path('/' + project.full_path)) expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy @@ -312,7 +311,7 @@ describe API::Internal do context 'project as namespace/project' do it do - pull(key, project_with_repo_path(project.path_with_namespace)) + pull(key, project_with_repo_path(project.full_path)) expect(response).to have_http_status(200) expect(json_response["status"]).to be_truthy @@ -350,7 +349,7 @@ describe API::Internal do end context "blocked user" do - let(:personal_project) { create(:empty_project, namespace: user.namespace) } + let(:personal_project) { create(:project, namespace: user.namespace) } before do user.block diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 2c44be4e447..7d120e4a234 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -1,11 +1,9 @@ require 'spec_helper' -describe API::Issues do - include EmailHelpers - +describe API::Issues, :mailer do set(:user) { create(:user) } set(:project) do - create(:empty_project, :public, creator_id: user.id, namespace: user.namespace) + create(:project, :public, creator_id: user.id, namespace: user.namespace) end let(:user2) { create(:user) } @@ -296,7 +294,7 @@ describe API::Issues do describe "GET /groups/:id/issues" do let!(:group) { create(:group) } - let!(:group_project) { create(:empty_project, :public, creator_id: user.id, namespace: group) } + let!(:group_project) { create(:project, :public, creator_id: user.id, namespace: group) } let!(:group_closed_issue) do create :closed_issue, author: user, @@ -518,7 +516,7 @@ describe API::Issues do end it "returns 404 on private projects for other users" do - private_project = create(:empty_project, :private) + private_project = create(:project, :private) create(:issue, project: private_project) get api("/projects/#{private_project.id}/issues", non_member) @@ -527,7 +525,7 @@ describe API::Issues do end it 'returns no issues when user has access to project but not issues' do - restricted_project = create(:empty_project, :public, :issues_private) + restricted_project = create(:project, :public, :issues_private) create(:issue, project: restricted_project) get api("/projects/#{restricted_project.id}/issues", non_member) @@ -1299,7 +1297,7 @@ describe API::Issues do context "when the user is project owner" do let(:owner) { create(:user) } - let(:project) { create(:empty_project, namespace: owner.namespace) } + let(:project) { create(:project, namespace: owner.namespace) } it "deletes the issue if an admin requests it" do delete api("/projects/#{project.id}/issues/#{issue.iid}", owner) @@ -1324,8 +1322,8 @@ describe API::Issues do end describe '/projects/:id/issues/:issue_iid/move' do - let!(:target_project) { create(:empty_project, path: 'project2', creator_id: user.id, namespace: user.namespace ) } - let!(:target_project2) { create(:empty_project, creator_id: non_member.id, namespace: non_member.namespace ) } + let!(:target_project) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace ) } + let!(:target_project2) { create(:project, creator_id: non_member.id, namespace: non_member.namespace ) } it 'moves an issue' do post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index f7e2f1908bb..5a4257d1009 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::Labels do let(:user) { create(:user) } - let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } let!(:label1) { create(:label, title: 'label1', project: project) } let!(:priority_label) { create(:label, title: 'bug', project: project, priority: 3) } diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index e095053fa03..06aca698c91 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -7,7 +7,7 @@ describe API::Members do let(:stranger) { create(:user) } let(:project) do - create(:empty_project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| + create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| project.team << [developer, :developer] project.team << [master, :master] project.request_access(access_requester) diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 2760c4ffde2..0db645863fb 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -31,19 +31,19 @@ describe API::MergeRequests do it 'returns authentication error' do get api('/merge_requests') - expect(response).to have_http_status(401) + expect(response).to have_gitlab_http_status(401) end end context 'when authenticated' do - let!(:project2) { create(:empty_project, :public, namespace: user.namespace) } + let!(:project2) { create(:project, :public, namespace: user.namespace) } let!(:merge_request2) { create(:merge_request, :simple, author: user, assignee: user, source_project: project2, target_project: project2) } let(:user2) { create(:user) } it 'returns an array of all merge requests' do get api('/merge_requests', user), scope: :all - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.map { |mr| mr['id'] }) @@ -51,12 +51,12 @@ describe API::MergeRequests do end it 'does not return unauthorized merge requests' do - private_project = create(:empty_project, :private) + private_project = create(:project, :private) merge_request3 = create(:merge_request, :simple, source_project: private_project, target_project: private_project, source_branch: 'other-branch') get api('/merge_requests', user), scope: :all - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.map { |mr| mr['id'] }) @@ -68,7 +68,7 @@ describe API::MergeRequests do get api('/merge_requests', user2) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) expect(json_response.first['id']).to eq(merge_request3.id) @@ -79,7 +79,7 @@ describe API::MergeRequests do get api('/merge_requests', user), author_id: user2.id, scope: :all - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) expect(json_response.first['id']).to eq(merge_request3.id) @@ -90,7 +90,7 @@ describe API::MergeRequests do get api('/merge_requests', user), assignee_id: user2.id, scope: :all - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) expect(json_response.first['id']).to eq(merge_request3.id) @@ -101,7 +101,7 @@ describe API::MergeRequests do get api('/merge_requests', user2), scope: 'assigned-to-me' - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) expect(json_response.first['id']).to eq(merge_request3.id) @@ -112,7 +112,7 @@ describe API::MergeRequests do get api('/merge_requests', user2), scope: 'created-by-me' - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) expect(json_response.first['id']).to eq(merge_request3.id) @@ -125,7 +125,7 @@ describe API::MergeRequests do it "returns authentication error" do get api("/projects/#{project.id}/merge_requests") - expect(response).to have_http_status(401) + expect(response).to have_gitlab_http_status(401) end end @@ -145,7 +145,7 @@ describe API::MergeRequests do it "returns an array of all merge_requests" do get api("/projects/#{project.id}/merge_requests", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) @@ -166,7 +166,7 @@ describe API::MergeRequests do it "returns an array of all merge_requests using simple mode" do get api("/projects/#{project.id}/merge_requests?view=simple", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response.last.keys).to match_array(%w(id iid title web_url created_at description project_id state updated_at)) expect(json_response).to be_an Array @@ -182,7 +182,7 @@ describe API::MergeRequests do it "returns an array of all merge_requests" do get api("/projects/#{project.id}/merge_requests?state", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) @@ -192,7 +192,7 @@ describe API::MergeRequests do it "returns an array of open merge_requests" do get api("/projects/#{project.id}/merge_requests?state=opened", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -202,7 +202,7 @@ describe API::MergeRequests do it "returns an array of closed merge_requests" do get api("/projects/#{project.id}/merge_requests?state=closed", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -212,7 +212,7 @@ describe API::MergeRequests do it "returns an array of merged merge_requests" do get api("/projects/#{project.id}/merge_requests?state=merged", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -222,7 +222,7 @@ describe API::MergeRequests do it 'returns merge_request by "iids" array' do get api("/projects/#{project.id}/merge_requests", user), iids: [merge_request.iid, merge_request_closed.iid] - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(2) expect(json_response.first['title']).to eq merge_request_closed.title @@ -232,14 +232,14 @@ describe API::MergeRequests do it 'matches V4 response schema' do get api("/projects/#{project.id}/merge_requests", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to match_response_schema('public_api/v4/merge_requests') end it 'returns an empty array if no issue matches milestone' do get api("/projects/#{project.id}/merge_requests", user), milestone: '1.0.0' - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(0) end @@ -247,7 +247,7 @@ describe API::MergeRequests do it 'returns an empty array if milestone does not exist' do get api("/projects/#{project.id}/merge_requests", user), milestone: 'foo' - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(0) end @@ -262,7 +262,7 @@ describe API::MergeRequests do it 'returns an array of merge requests matching state in milestone' do get api("/projects/#{project.id}/merge_requests", user), milestone: '0.9', state: 'closed' - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) expect(json_response.first['id']).to eq(merge_request_closed.id) @@ -271,7 +271,7 @@ describe API::MergeRequests do it 'returns an array of labeled merge requests' do get api("/projects/#{project.id}/merge_requests?labels=#{label.title}", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(1) expect(json_response.first['labels']).to eq([label2.title, label.title]) @@ -280,7 +280,7 @@ describe API::MergeRequests do it 'returns an array of labeled merge requests where all labels match' do get api("/projects/#{project.id}/merge_requests?labels=#{label.title},foo,bar", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(0) end @@ -288,11 +288,31 @@ describe API::MergeRequests do it 'returns an empty array if no merge request matches labels' do get api("/projects/#{project.id}/merge_requests?labels=foo,bar", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(0) end + it 'returns an array of labeled merge requests that are merged for a milestone' do + bug_label = create(:label, title: 'bug', color: '#FFAABB', project: project) + + mr1 = create(:merge_request, state: "merged", source_project: project, target_project: project, milestone: milestone) + mr2 = create(:merge_request, state: "merged", source_project: project, target_project: project, milestone: milestone1) + mr3 = create(:merge_request, state: "closed", source_project: project, target_project: project, milestone: milestone1) + _mr = create(:merge_request, state: "merged", source_project: project, target_project: project, milestone: milestone1) + + create(:label_link, label: bug_label, target: mr1) + create(:label_link, label: bug_label, target: mr2) + create(:label_link, label: bug_label, target: mr3) + + get api("/projects/#{project.id}/merge_requests?labels=#{bug_label.title}&milestone=#{milestone1.title}&state=merged", user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + expect(json_response.first['id']).to eq(mr2.id) + end + context "with ordering" do before do @mr_later = mr_with_later_created_and_updated_at_time @@ -302,44 +322,44 @@ describe API::MergeRequests do it "returns an array of merge_requests in ascending order" do get api("/projects/#{project.id}/merge_requests?sort=asc", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['created_at'] } + response_dates = json_response.map { |merge_request| merge_request['created_at'] } expect(response_dates).to eq(response_dates.sort) end it "returns an array of merge_requests in descending order" do get api("/projects/#{project.id}/merge_requests?sort=desc", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['created_at'] } + response_dates = json_response.map { |merge_request| merge_request['created_at'] } expect(response_dates).to eq(response_dates.sort.reverse) end it "returns an array of merge_requests ordered by updated_at" do get api("/projects/#{project.id}/merge_requests?order_by=updated_at", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['updated_at'] } + response_dates = json_response.map { |merge_request| merge_request['updated_at'] } expect(response_dates).to eq(response_dates.sort.reverse) end it "returns an array of merge_requests ordered by created_at" do get api("/projects/#{project.id}/merge_requests?order_by=created_at&sort=asc", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['created_at'] } + response_dates = json_response.map { |merge_request| merge_request['created_at'] } expect(response_dates).to eq(response_dates.sort) end end @@ -350,7 +370,7 @@ describe API::MergeRequests do it 'exposes known attributes' do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['id']).to eq(merge_request.id) expect(json_response['iid']).to eq(merge_request.iid) expect(json_response['project_id']).to eq(merge_request.project.id) @@ -378,7 +398,7 @@ describe API::MergeRequests do it "returns merge_request" do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['title']).to eq(merge_request.title) expect(json_response['iid']).to eq(merge_request.iid) expect(json_response['work_in_progress']).to eq(false) @@ -389,13 +409,13 @@ describe API::MergeRequests do it "returns a 404 error if merge_request_iid not found" do get api("/projects/#{project.id}/merge_requests/999", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it "returns a 404 error if merge_request `id` is used instead of iid" do get api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end context 'Work in Progress' do @@ -403,7 +423,7 @@ describe API::MergeRequests do it "returns merge_request" do get api("/projects/#{project.id}/merge_requests/#{merge_request_wip.iid}", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['work_in_progress']).to eq(true) end end @@ -414,7 +434,7 @@ describe API::MergeRequests do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/commits", user) commit = merge_request.commits.first - expect(response.status).to eq 200 + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.size).to eq(merge_request.commits.size) @@ -424,13 +444,13 @@ describe API::MergeRequests do it 'returns a 404 when merge_request_iid not found' do get api("/projects/#{project.id}/merge_requests/999/commits", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it 'returns a 404 when merge_request id is used instead of iid' do get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/commits", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end end @@ -438,19 +458,19 @@ describe API::MergeRequests do it 'returns the change information of the merge_request' do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/changes", user) - expect(response.status).to eq 200 + expect(response).to have_gitlab_http_status(200) expect(json_response['changes'].size).to eq(merge_request.diffs.size) end it 'returns a 404 when merge_request_iid not found' do get api("/projects/#{project.id}/merge_requests/999/changes", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it 'returns a 404 when merge_request id is used instead of iid' do get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/changes", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end end @@ -465,7 +485,7 @@ describe API::MergeRequests do labels: 'label, label2', milestone_id: milestone.id - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq('Test merge_request') expect(json_response['labels']).to eq(%w(label label2)) expect(json_response['milestone']['id']).to eq(milestone.id) @@ -475,25 +495,25 @@ describe API::MergeRequests do it "returns 422 when source_branch equals target_branch" do post api("/projects/#{project.id}/merge_requests", user), title: "Test merge_request", source_branch: "master", target_branch: "master", author: user - expect(response).to have_http_status(422) + expect(response).to have_gitlab_http_status(422) end it "returns 400 when source_branch is missing" do post api("/projects/#{project.id}/merge_requests", user), title: "Test merge_request", target_branch: "master", author: user - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end it "returns 400 when target_branch is missing" do post api("/projects/#{project.id}/merge_requests", user), title: "Test merge_request", source_branch: "markdown", author: user - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end it "returns 400 when title is missing" do post api("/projects/#{project.id}/merge_requests", user), target_branch: 'master', source_branch: 'markdown' - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end it 'allows special label names' do @@ -503,7 +523,7 @@ describe API::MergeRequests do target_branch: 'master', author: user, labels: 'label, label?, label&foo, ?, &' - expect(response.status).to eq(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['labels']).to include 'label' expect(json_response['labels']).to include 'label?' expect(json_response['labels']).to include 'label&foo' @@ -529,7 +549,7 @@ describe API::MergeRequests do target_branch: 'master', author: user end.to change { MergeRequest.count }.by(0) - expect(response).to have_http_status(409) + expect(response).to have_gitlab_http_status(409) end end @@ -557,18 +577,20 @@ describe API::MergeRequests do context 'forked projects' do let!(:user2) { create(:user) } - let!(:fork_project) { create(:empty_project, forked_from_project: project, namespace: user2.namespace, creator_id: user2.id) } - let!(:unrelated_project) { create(:empty_project, namespace: create(:user).namespace, creator_id: user2.id) } + let!(:fork_project) { create(:project, forked_from_project: project, namespace: user2.namespace, creator_id: user2.id) } + let!(:unrelated_project) { create(:project, namespace: create(:user).namespace, creator_id: user2.id) } + + before do + fork_project.add_reporter(user2) - before :each do |each| - fork_project.team << [user2, :reporter] + allow_any_instance_of(MergeRequest).to receive(:write_ref) end it "returns merge_request" do post api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master", author: user2, target_project_id: project.id, description: 'Test description for Test merge_request' - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq('Test merge_request') expect(json_response['description']).to eq('Test description for Test merge_request') end @@ -579,7 +601,7 @@ describe API::MergeRequests do expect(fork_project.forked_from_project).to eq(project) post api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq('Test merge_request') end @@ -593,25 +615,25 @@ describe API::MergeRequests do author: user2, target_project_id: project.id - expect(response).to have_http_status(422) + expect(response).to have_gitlab_http_status(422) end it "returns 400 when source_branch is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end it "returns 400 when target_branch is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end it "returns 400 when title is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), target_branch: 'master', source_branch: 'markdown', author: user2, target_project_id: project.id - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end context 'when target_branch is specified' do @@ -622,7 +644,7 @@ describe API::MergeRequests do source_branch: 'markdown', author: user, target_project_id: fork_project.id - expect(response).to have_http_status(422) + expect(response).to have_gitlab_http_status(422) end it 'returns 422 if targeting a different fork' do @@ -632,14 +654,14 @@ describe API::MergeRequests do source_branch: 'markdown', author: user2, target_project_id: unrelated_project.id - expect(response).to have_http_status(422) + expect(response).to have_gitlab_http_status(422) end end it "returns 201 when target_branch is specified and for the same project" do post api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: 'master', source_branch: 'markdown', author: user2, target_project_id: fork_project.id - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) end end end @@ -654,7 +676,7 @@ describe API::MergeRequests do it "denies the deletion of the merge request" do delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", developer) - expect(response).to have_http_status(403) + expect(response).to have_gitlab_http_status(403) end end @@ -662,19 +684,19 @@ describe API::MergeRequests do it "destroys the merge request owners can destroy" do delete api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user) - expect(response).to have_http_status(204) + expect(response).to have_gitlab_http_status(204) end it "returns 404 for an invalid merge request IID" do delete api("/projects/#{project.id}/merge_requests/12345", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it "returns 404 if the merge request id is used instead of iid" do delete api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end end end @@ -685,7 +707,7 @@ describe API::MergeRequests do it "returns merge_request in case of success" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) end it "returns 406 if branch can't be merged" do @@ -694,21 +716,21 @@ describe API::MergeRequests do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user) - expect(response).to have_http_status(406) + expect(response).to have_gitlab_http_status(406) expect(json_response['message']).to eq('Branch cannot be merged') end it "returns 405 if merge_request is not open" do merge_request.close put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user) - expect(response).to have_http_status(405) + expect(response).to have_gitlab_http_status(405) expect(json_response['message']).to eq('405 Method Not Allowed') end it "returns 405 if merge_request is a work in progress" do merge_request.update_attribute(:title, "WIP: #{merge_request.title}") put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user) - expect(response).to have_http_status(405) + expect(response).to have_gitlab_http_status(405) expect(json_response['message']).to eq('405 Method Not Allowed') end @@ -717,7 +739,7 @@ describe API::MergeRequests do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user) - expect(response).to have_http_status(405) + expect(response).to have_gitlab_http_status(405) expect(json_response['message']).to eq('405 Method Not Allowed') end @@ -725,21 +747,21 @@ describe API::MergeRequests do user2 = create(:user) project.team << [user2, :reporter] put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user2) - expect(response).to have_http_status(401) + expect(response).to have_gitlab_http_status(401) expect(json_response['message']).to eq('401 Unauthorized') end it "returns 409 if the SHA parameter doesn't match" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), sha: merge_request.diff_head_sha.reverse - expect(response).to have_http_status(409) + expect(response).to have_gitlab_http_status(409) expect(json_response['message']).to start_with('SHA does not match HEAD of source branch') end it "succeeds if the SHA parameter matches" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), sha: merge_request.diff_head_sha - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) end it "enables merge when pipeline succeeds if the pipeline is active" do @@ -748,7 +770,7 @@ describe API::MergeRequests do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), merge_when_pipeline_succeeds: true - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['title']).to eq('Test') expect(json_response['merge_when_pipeline_succeeds']).to eq(true) end @@ -760,7 +782,7 @@ describe API::MergeRequests do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/merge", user), merge_when_pipeline_succeeds: true - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['title']).to eq('Test') expect(json_response['merge_when_pipeline_succeeds']).to eq(true) end @@ -768,13 +790,13 @@ describe API::MergeRequests do it "returns 404 for an invalid merge request IID" do put api("/projects/#{project.id}/merge_requests/12345/merge", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it "returns 404 if the merge request id is used instead of iid" do put api("/projects/#{project.id}/merge_requests/#{merge_request.id}/merge", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end end @@ -783,39 +805,39 @@ describe API::MergeRequests do it "returns merge_request" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), state_event: "close" - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['state']).to eq('closed') end end it "updates title and returns merge_request" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), title: "New title" - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['title']).to eq('New title') end it "updates description and returns merge_request" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), description: "New description" - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['description']).to eq('New description') end it "updates milestone_id and returns merge_request" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), milestone_id: milestone.id - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['milestone']['id']).to eq(milestone.id) end it "returns merge_request with renamed target_branch" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), target_branch: "wiki" - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['target_branch']).to eq('wiki') end it "returns merge_request that removes the source branch" do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), remove_source_branch: true - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response['force_remove_source_branch']).to be_truthy end @@ -836,7 +858,7 @@ describe API::MergeRequests do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), state_event: 'close', title: nil merge_request.reload - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) expect(merge_request.state).to eq('opened') end @@ -844,20 +866,20 @@ describe API::MergeRequests do put api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user), state_event: 'close', target_branch: nil merge_request.reload - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) expect(merge_request.state).to eq('opened') end it "returns 404 for an invalid merge request IID" do put api("/projects/#{project.id}/merge_requests/12345", user), state_event: "close" - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it "returns 404 if the merge request id is used instead of iid" do put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), state_event: "close" - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end end @@ -870,7 +892,7 @@ describe API::MergeRequests do get api("/projects/#{project.id}/merge_requests/#{mr.iid}/closes_issues", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(1) @@ -880,14 +902,14 @@ describe API::MergeRequests do it 'returns an empty array when there are no issues to be closed' do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/closes_issues", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(0) end it 'handles external issues' do - jira_project = create(:jira_project, :public, name: 'JIR_EXT1') + jira_project = create(:jira_project, :public, :repository, name: 'JIR_EXT1') ext_issue = ExternalIssue.new("#{jira_project.name}-123", jira_project) issue = create(:issue, project: jira_project) description = "Closes #{ext_issue.to_reference(jira_project)}\ncloses #{issue.to_reference}" @@ -896,7 +918,7 @@ describe API::MergeRequests do get api("/projects/#{jira_project.id}/merge_requests/#{merge_request.iid}/closes_issues", user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array expect(json_response.length).to eq(2) @@ -909,26 +931,26 @@ describe API::MergeRequests do end it 'returns 403 if the user has no access to the merge request' do - project = create(:empty_project, :private) + project = create(:project, :private) merge_request = create(:merge_request, :simple, source_project: project) guest = create(:user) project.team << [guest, :guest] get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/closes_issues", guest) - expect(response).to have_http_status(403) + expect(response).to have_gitlab_http_status(403) end it "returns 404 for an invalid merge request IID" do get api("/projects/#{project.id}/merge_requests/12345/closes_issues", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it "returns 404 if the merge request id is used instead of iid" do get api("/projects/#{project.id}/merge_requests/#{merge_request.id}/closes_issues", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end end @@ -936,26 +958,26 @@ describe API::MergeRequests do it 'subscribes to a merge request' do post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/subscribe", admin) - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['subscribed']).to eq(true) end it 'returns 304 if already subscribed' do post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/subscribe", user) - expect(response).to have_http_status(304) + expect(response).to have_gitlab_http_status(304) end it 'returns 404 if the merge request is not found' do post api("/projects/#{project.id}/merge_requests/123/subscribe", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it 'returns 404 if the merge request id is used instead of iid' do post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/subscribe", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it 'returns 403 if user has no access to read code' do @@ -964,7 +986,7 @@ describe API::MergeRequests do post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/subscribe", guest) - expect(response).to have_http_status(403) + expect(response).to have_gitlab_http_status(403) end end @@ -972,26 +994,26 @@ describe API::MergeRequests do it 'unsubscribes from a merge request' do post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/unsubscribe", user) - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['subscribed']).to eq(false) end it 'returns 304 if not subscribed' do post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/unsubscribe", admin) - expect(response).to have_http_status(304) + expect(response).to have_gitlab_http_status(304) end it 'returns 404 if the merge request is not found' do post api("/projects/#{project.id}/merge_requests/123/unsubscribe", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it 'returns 404 if the merge request id is used instead of iid' do post api("/projects/#{project.id}/merge_requests/#{merge_request.id}/unsubscribe", user) - expect(response).to have_http_status(404) + expect(response).to have_gitlab_http_status(404) end it 'returns 403 if user has no access to read code' do @@ -1000,7 +1022,7 @@ describe API::MergeRequests do post api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/unsubscribe", guest) - expect(response).to have_http_status(403) + expect(response).to have_gitlab_http_status(403) end end diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb index 4701ad585c9..75e5062a99c 100644 --- a/spec/requests/api/notes_spec.rb +++ b/spec/requests/api/notes_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::Notes do let(:user) { create(:user) } - let!(:project) { create(:empty_project, :public, namespace: user.namespace) } + let!(:project) { create(:project, :public, namespace: user.namespace) } let!(:issue) { create(:issue, project: project, author: user) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } let!(:snippet) { create(:project_snippet, project: project, author: user) } @@ -13,12 +13,12 @@ describe API::Notes do # For testing the cross-reference of a private issue in a public issue let(:private_user) { create(:user) } let(:private_project) do - create(:empty_project, namespace: private_user.namespace) + create(:project, namespace: private_user.namespace) .tap { |p| p.team << [private_user, :master] } end let(:private_issue) { create(:issue, project: private_project) } - let(:ext_proj) { create(:empty_project, :public) } + let(:ext_proj) { create(:project, :public) } let(:ext_issue) { create(:issue, project: ext_proj) } let!(:cross_reference_note) do @@ -272,7 +272,7 @@ describe API::Notes do context 'when user does not have access to read the noteable' do it 'responds with 404' do - project = create(:empty_project, :private) { |p| p.add_guest(user) } + project = create(:project, :private) { |p| p.add_guest(user) } issue = create(:issue, :confidential, project: project) post api("/projects/#{project.id}/issues/#{issue.iid}/notes", user), @@ -283,7 +283,7 @@ describe API::Notes do end context 'when user does not have access to create noteable' do - let(:private_issue) { create(:issue, project: create(:empty_project, :private)) } + let(:private_issue) { create(:issue, project: create(:project, :private)) } ## # We are posting to project user has access to, but we use issue id diff --git a/spec/requests/api/notification_settings_spec.rb b/spec/requests/api/notification_settings_spec.rb index f619b7e6eaf..7968659a1ec 100644 --- a/spec/requests/api/notification_settings_spec.rb +++ b/spec/requests/api/notification_settings_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::NotificationSettings do let(:user) { create(:user) } let!(:group) { create(:group) } - let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: group) } + let!(:project) { create(:project, :public, creator_id: user.id, namespace: group) } describe "GET /notification_settings" do it "returns global notification settings for the current user" do @@ -72,8 +72,8 @@ describe API::NotificationSettings do expect(response).to have_http_status(200) expect(json_response['level']).to eq(user.reload.notification_settings_for(project).level) - expect(json_response['events']['new_note']).to eq(true) - expect(json_response['events']['new_issue']).to eq(false) + expect(json_response['events']['new_note']).to be_truthy + expect(json_response['events']['new_issue']).to be_falsey end end diff --git a/spec/requests/api/pipeline_schedules_spec.rb b/spec/requests/api/pipeline_schedules_spec.rb index b34555d2815..1fc0ec528b9 100644 --- a/spec/requests/api/pipeline_schedules_spec.rb +++ b/spec/requests/api/pipeline_schedules_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::PipelineSchedules do set(:developer) { create(:user) } set(:user) { create(:user) } - set(:project) { create(:project) } + set(:project) { create(:project, :repository) } before do project.add_developer(developer) @@ -53,7 +53,7 @@ describe API::PipelineSchedules do it 'returns matched pipeline schedules' do get api("/projects/#{project.id}/pipeline_schedules", developer), scope: target - expect(json_response.map{ |r| r['active'] }).to all(eq(active?(target))) + expect(json_response.map { |r| r['active'] }).to all(eq(active?(target))) end end diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb index 0f9330b062d..2829c243af3 100644 --- a/spec/requests/api/project_hooks_spec.rb +++ b/spec/requests/api/project_hooks_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::ProjectHooks, 'ProjectHooks' do let(:user) { create(:user) } let(:user3) { create(:user) } - let!(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } + let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } let!(:hook) do create(:project_hook, :all_events_enabled, @@ -205,7 +205,7 @@ describe API::ProjectHooks, 'ProjectHooks' do it "returns a 404 if a user attempts to delete project hooks he/she does not own" do test_user = create(:user) - other_project = create(:empty_project) + other_project = create(:project) other_project.team << [test_user, :master] delete api("/projects/#{other_project.id}/hooks/#{hook.id}", test_user) diff --git a/spec/requests/api/project_milestones_spec.rb b/spec/requests/api/project_milestones_spec.rb index fe8fdbfd7e4..72e1574b55f 100644 --- a/spec/requests/api/project_milestones_spec.rb +++ b/spec/requests/api/project_milestones_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::ProjectMilestones do let(:user) { create(:user) } - let!(:project) { create(:empty_project, namespace: user.namespace ) } + let!(:project) { create(:project, namespace: user.namespace ) } let!(:closed_milestone) { create(:closed_milestone, project: project, title: 'version1', description: 'closed milestone') } let!(:milestone) { create(:milestone, project: project, title: 'version2', description: 'open milestone') } diff --git a/spec/requests/api/project_snippets_spec.rb b/spec/requests/api/project_snippets_spec.rb index f220972bae3..2b541f5719e 100644 --- a/spec/requests/api/project_snippets_spec.rb +++ b/spec/requests/api/project_snippets_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe API::ProjectSnippets do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:admin) { create(:admin) } diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 6ed68fcff09..a89a58ff713 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -8,8 +8,8 @@ describe API::Projects do let(:user2) { create(:user) } let(:user3) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } - let(:project2) { create(:empty_project, path: 'project2', creator_id: user.id, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } + let(:project2) { create(:project, path: 'project2', namespace: user.namespace) } let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') } let(:project_member) { create(:project_member, :developer, user: user3, project: project) } let(:user4) { create(:user) } @@ -33,7 +33,7 @@ describe API::Projects do access_level: ProjectMember::MASTER) end let(:project4) do - create(:empty_project, + create(:project, name: 'third_project', path: 'third_project', creator_id: user4.id, @@ -61,7 +61,7 @@ describe API::Projects do if defined?(additional_project) additional_project else - create(:empty_project, :public) + create(:project, :public) end expect do @@ -70,7 +70,7 @@ describe API::Projects do end end - let!(:public_project) { create(:empty_project, :public, name: 'public_project') } + let!(:public_project) { create(:project, :public, name: 'public_project') } before do project project2 @@ -103,12 +103,12 @@ describe API::Projects do context 'when some projects are in a group' do before do - create(:empty_project, :public, group: create(:group)) + create(:project, :public, group: create(:group)) end it_behaves_like 'projects response without N + 1 queries' do let(:current_user) { user } - let(:additional_project) { create(:empty_project, :public, group: create(:group)) } + let(:additional_project) { create(:project, :public, group: create(:group)) } end end @@ -186,7 +186,14 @@ describe API::Projects do context 'and with simple=true' do it 'returns a simplified version of all the projects' do - expected_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace) + expected_keys = %w( + id description default_branch tag_list + ssh_url_to_repo http_url_to_repo web_url + name name_with_namespace + path path_with_namespace + star_count forks_count + created_at last_activity_at + ) get api('/projects?simple=true', user) @@ -268,7 +275,7 @@ describe API::Projects do end context 'and with starred=true' do - let(:public_project) { create(:empty_project, :public) } + let(:public_project) { create(:project, :public) } before do project_member @@ -286,11 +293,11 @@ describe API::Projects do end context 'and with all query parameters' do - let!(:project5) { create(:empty_project, :public, path: 'gitlab5', namespace: create(:namespace)) } - let!(:project6) { create(:empty_project, :public, path: 'project6', namespace: user.namespace) } - let!(:project7) { create(:empty_project, :public, path: 'gitlab7', namespace: user.namespace) } - let!(:project8) { create(:empty_project, path: 'gitlab8', namespace: user.namespace) } - let!(:project9) { create(:empty_project, :public, path: 'gitlab9') } + let!(:project5) { create(:project, :public, path: 'gitlab5', namespace: create(:namespace)) } + let!(:project6) { create(:project, :public, path: 'project6', namespace: user.namespace) } + let!(:project7) { create(:project, :public, path: 'gitlab7', namespace: user.namespace) } + let!(:project8) { create(:project, path: 'gitlab8', namespace: user.namespace) } + let!(:project9) { create(:project, :public, path: 'gitlab9') } before do user.update_attributes(starred_projects: [project5, project7, project8, project9]) @@ -539,7 +546,7 @@ describe API::Projects do end describe 'GET /users/:user_id/projects/' do - let!(:public_project) { create(:empty_project, :public, name: 'public_project', creator_id: user4.id, namespace: user4.namespace) } + let!(:public_project) { create(:project, :public, name: 'public_project', creator_id: user4.id, namespace: user4.namespace) } it 'returns error when user not found' do get api('/users/9999/projects/') @@ -682,13 +689,14 @@ describe API::Projects do describe 'GET /projects/:id' do context 'when unauthenticated' do it 'returns the public projects' do - public_project = create(:empty_project, :public) + public_project = create(:project, :public) get api("/projects/#{public_project.id}") expect(response).to have_http_status(200) expect(json_response['id']).to eq(public_project.id) expect(json_response['description']).to eq(public_project.description) + expect(json_response['default_branch']).to eq(public_project.default_branch) expect(json_response.keys).not_to include('permissions') end end @@ -766,7 +774,7 @@ describe API::Projects do it 'handles users with dots' do dot_user = create(:user, username: 'dot.user') - project = create(:empty_project, creator_id: dot_user.id, namespace: dot_user.namespace) + project = create(:project, creator_id: dot_user.id, namespace: dot_user.namespace) get api("/projects/#{CGI.escape(project.full_path)}", dot_user) expect(response).to have_http_status(200) @@ -831,7 +839,7 @@ describe API::Projects do end it 'filters related URIs when their feature is not enabled' do - project = create(:empty_project, :public, + project = create(:project, :public, :merge_requests_disabled, :issues_disabled, creator_id: user.id, @@ -876,7 +884,7 @@ describe API::Projects do end context 'group project' do - let(:project2) { create(:empty_project, group: create(:group)) } + let(:project2) { create(:project, group: create(:group)) } before do project2.group.add_owner(user) @@ -916,7 +924,7 @@ describe API::Projects do context 'when unauthenticated' do it_behaves_like 'project users response' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:current_user) { nil } end end @@ -1036,11 +1044,11 @@ describe API::Projects do end describe 'fork management' do - let(:project_fork_target) { create(:empty_project) } - let(:project_fork_source) { create(:empty_project, :public) } + let(:project_fork_target) { create(:project) } + let(:project_fork_source) { create(:project, :public) } describe 'POST /projects/:id/fork/:forked_from_id' do - let(:new_project_fork_source) { create(:empty_project, :public) } + let(:new_project_fork_source) { create(:project, :public) } it "is not available for non admin users" do post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) @@ -1057,6 +1065,14 @@ describe API::Projects do expect(project_fork_target.forked?).to be_truthy end + it 'refreshes the forks count cachce' do + expect(project_fork_source.forks_count).to be_zero + + post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) + + expect(project_fork_source.forks_count).to eq(1) + end + it 'fails if forked_from project which does not exist' do post api("/projects/#{project_fork_target.id}/fork/9999", admin) expect(response).to have_http_status(404) @@ -1081,7 +1097,7 @@ describe API::Projects do end context 'when users belong to project group' do - let(:project_fork_target) { create(:empty_project, group: create(:group)) } + let(:project_fork_target) { create(:project, group: create(:group)) } before do project_fork_target.group.add_owner user diff --git a/spec/requests/api/protected_branches_spec.rb b/spec/requests/api/protected_branches_spec.rb new file mode 100644 index 00000000000..e4f9c47fb33 --- /dev/null +++ b/spec/requests/api/protected_branches_spec.rb @@ -0,0 +1,232 @@ +require 'spec_helper' + +describe API::ProtectedBranches do + let(:user) { create(:user) } + let!(:project) { create(:project, :repository) } + let(:protected_name) { 'feature' } + let(:branch_name) { protected_name } + let!(:protected_branch) do + create(:protected_branch, project: project, name: protected_name) + end + + describe "GET /projects/:id/protected_branches" do + let(:route) { "/projects/#{project.id}/protected_branches" } + + shared_examples_for 'protected branches' do + it 'returns the protected branches' do + get api(route, user), per_page: 100 + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + + protected_branch_names = json_response.map { |x| x['name'] } + expected_branch_names = project.protected_branches.map { |x| x['name'] } + expect(protected_branch_names).to match_array(expected_branch_names) + end + end + + context 'when authenticated as a master' do + before do + project.add_master(user) + end + + it_behaves_like 'protected branches' + end + + context 'when authenticated as a guest' do + before do + project.add_guest(user) + end + + it_behaves_like '403 response' do + let(:request) { get api(route, user) } + end + end + end + + describe "GET /projects/:id/protected_branches/:branch" do + let(:route) { "/projects/#{project.id}/protected_branches/#{branch_name}" } + + shared_examples_for 'protected branch' do + it 'returns the protected branch' do + get api(route, user) + + expect(response).to have_gitlab_http_status(200) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MASTER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(::Gitlab::Access::MASTER) + end + + context 'when protected branch does not exist' do + let(:branch_name) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { get api(route, user) } + let(:message) { '404 Not found' } + end + end + end + + context 'when authenticated as a master' do + before do + project.add_master(user) + end + + it_behaves_like 'protected branch' + + context 'when protected branch contains a wildcard' do + let(:protected_name) { 'feature*' } + + it_behaves_like 'protected branch' + end + end + + context 'when authenticated as a guest' do + before do + project.add_guest(user) + end + + it_behaves_like '403 response' do + let(:request) { get api(route, user) } + end + end + end + + describe 'POST /projects/:id/protected_branches' do + let(:branch_name) { 'new_branch' } + + context 'when authenticated as a master' do + before do + project.add_master(user) + end + + it 'protects a single branch' do + post api("/projects/#{project.id}/protected_branches", user), name: branch_name + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + end + + it 'protects a single branch and developers can push' do + post api("/projects/#{project.id}/protected_branches", user), + name: branch_name, push_access_level: 30 + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + end + + it 'protects a single branch and developers can merge' do + post api("/projects/#{project.id}/protected_branches", user), + name: branch_name, merge_access_level: 30 + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER) + end + + it 'protects a single branch and developers can push and merge' do + post api("/projects/#{project.id}/protected_branches", user), + name: branch_name, push_access_level: 30, merge_access_level: 30 + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::DEVELOPER) + end + + it 'protects a single branch and no one can push' do + post api("/projects/#{project.id}/protected_branches", user), + name: branch_name, push_access_level: 0 + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + end + + it 'protects a single branch and no one can merge' do + post api("/projects/#{project.id}/protected_branches", user), + name: branch_name, merge_access_level: 0 + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS) + end + + it 'protects a single branch and no one can push or merge' do + post api("/projects/#{project.id}/protected_branches", user), + name: branch_name, push_access_level: 0, merge_access_level: 0 + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::NO_ACCESS) + end + + it 'returns a 409 error if the same branch is protected twice' do + post api("/projects/#{project.id}/protected_branches", user), name: protected_name + expect(response).to have_gitlab_http_status(409) + end + + context 'when branch has a wildcard in its name' do + let(:branch_name) { 'feature/*' } + + it "protects multiple branches with a wildcard in the name" do + post api("/projects/#{project.id}/protected_branches", user), name: branch_name + + expect(response).to have_gitlab_http_status(201) + expect(json_response['name']).to eq(branch_name) + expect(json_response['push_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + expect(json_response['merge_access_levels'][0]['access_level']).to eq(Gitlab::Access::MASTER) + end + end + end + + context 'when authenticated as a guest' do + before do + project.add_guest(user) + end + + it "returns a 403 error if guest" do + post api("/projects/#{project.id}/protected_branches/", user), name: branch_name + + expect(response).to have_gitlab_http_status(403) + end + end + end + + describe "DELETE /projects/:id/protected_branches/unprotect/:branch" do + before do + project.add_master(user) + end + + it "unprotects a single branch" do + delete api("/projects/#{project.id}/protected_branches/#{branch_name}", user) + + expect(response).to have_gitlab_http_status(204) + end + + it "returns 404 if branch does not exist" do + delete api("/projects/#{project.id}/protected_branches/barfoo", user) + + expect(response).to have_gitlab_http_status(404) + end + + context 'when branch has a wildcard in its name' do + let(:protected_name) { 'feature*' } + + it "unprotects a wildcard branch" do + delete api("/projects/#{project.id}/protected_branches/#{branch_name}", user) + + expect(response).to have_gitlab_http_status(204) + end + end + end +end diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index ca5d98c78ef..e9ee3dd679d 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -42,7 +42,7 @@ describe API::Runner do end context 'when project token is used' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'creates runner' do post api('/runners'), token: project.runners_token @@ -182,7 +182,7 @@ describe API::Runner do end describe '/api/v4/jobs' do - let(:project) { create(:empty_project, shared_runners_enabled: false) } + let(:project) { create(:project, shared_runners_enabled: false) } let(:pipeline) { create(:ci_pipeline_without_jobs, project: project, ref: 'master') } let(:runner) { create(:ci_runner) } let!(:job) do @@ -683,7 +683,7 @@ describe API::Runner do end context 'when job has been updated recently' do - it { expect{ patch_the_trace }.not_to change { job.updated_at }} + it { expect { patch_the_trace }.not_to change { job.updated_at }} it "changes the job's trace" do patch_the_trace @@ -692,7 +692,7 @@ describe API::Runner do end context 'when Runner makes a force-patch' do - it { expect{ force_patch_the_trace }.not_to change { job.updated_at }} + it { expect { force_patch_the_trace }.not_to change { job.updated_at }} it "doesn't change the build.trace" do force_patch_the_trace diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb index 645a5389850..c8ff25f70fa 100644 --- a/spec/requests/api/runners_spec.rb +++ b/spec/requests/api/runners_spec.rb @@ -5,8 +5,8 @@ describe API::Runners do let(:user) { create(:user) } let(:user2) { create(:user) } - let(:project) { create(:empty_project, creator_id: user.id) } - let(:project2) { create(:empty_project, creator_id: user.id) } + let(:project) { create(:project, creator_id: user.id) } + let(:project2) { create(:project, creator_id: user.id) } let!(:shared_runner) { create(:ci_runner, :shared) } let!(:unused_specific_runner) { create(:ci_runner) } @@ -36,7 +36,7 @@ describe API::Runners do it 'returns user available runners' do get api('/runners', user) - shared = json_response.any?{ |r| r['is_shared'] } + shared = json_response.any? { |r| r['is_shared'] } expect(response).to have_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array @@ -46,7 +46,7 @@ describe API::Runners do it 'filters runners by scope' do get api('/runners?scope=active', user) - shared = json_response.any?{ |r| r['is_shared'] } + shared = json_response.any? { |r| r['is_shared'] } expect(response).to have_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array @@ -74,7 +74,7 @@ describe API::Runners do it 'returns all runners' do get api('/runners/all', admin) - shared = json_response.any?{ |r| r['is_shared'] } + shared = json_response.any? { |r| r['is_shared'] } expect(response).to have_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array @@ -93,7 +93,7 @@ describe API::Runners do it 'filters runners by scope' do get api('/runners/all?scope=specific', admin) - shared = json_response.any?{ |r| r['is_shared'] } + shared = json_response.any? { |r| r['is_shared'] } expect(response).to have_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array @@ -277,7 +277,7 @@ describe API::Runners do delete api("/runners/#{shared_runner.id}", admin) expect(response).to have_http_status(204) - end.to change{ Ci::Runner.shared.count }.by(-1) + end.to change { Ci::Runner.shared.count }.by(-1) end end @@ -287,7 +287,7 @@ describe API::Runners do delete api("/runners/#{unused_specific_runner.id}", admin) expect(response).to have_http_status(204) - end.to change{ Ci::Runner.specific.count }.by(-1) + end.to change { Ci::Runner.specific.count }.by(-1) end it 'deletes used runner' do @@ -295,7 +295,7 @@ describe API::Runners do delete api("/runners/#{specific_runner.id}", admin) expect(response).to have_http_status(204) - end.to change{ Ci::Runner.specific.count }.by(-1) + end.to change { Ci::Runner.specific.count }.by(-1) end end @@ -330,7 +330,7 @@ describe API::Runners do delete api("/runners/#{specific_runner.id}", user) expect(response).to have_http_status(204) - end.to change{ Ci::Runner.specific.count }.by(-1) + end.to change { Ci::Runner.specific.count }.by(-1) end end end @@ -349,7 +349,7 @@ describe API::Runners do it "returns project's runners" do get api("/projects/#{project.id}/runners", user) - shared = json_response.any?{ |r| r['is_shared'] } + shared = json_response.any? { |r| r['is_shared'] } expect(response).to have_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array @@ -385,14 +385,14 @@ describe API::Runners do it 'enables specific runner' do expect do post api("/projects/#{project.id}/runners", user), runner_id: specific_runner2.id - end.to change{ project.runners.count }.by(+1) + end.to change { project.runners.count }.by(+1) expect(response).to have_http_status(201) end it 'avoids changes when enabling already enabled runner' do expect do post api("/projects/#{project.id}/runners", user), runner_id: specific_runner.id - end.to change{ project.runners.count }.by(0) + end.to change { project.runners.count }.by(0) expect(response).to have_http_status(409) end @@ -401,7 +401,7 @@ describe API::Runners do expect do post api("/projects/#{project.id}/runners", user), runner_id: specific_runner2.id - end.to change{ project.runners.count }.by(0) + end.to change { project.runners.count }.by(0) expect(response).to have_http_status(403) end @@ -416,7 +416,7 @@ describe API::Runners do it 'enables any specific runner' do expect do post api("/projects/#{project.id}/runners", admin), runner_id: unused_specific_runner.id - end.to change{ project.runners.count }.by(+1) + end.to change { project.runners.count }.by(+1) expect(response).to have_http_status(201) end end @@ -461,7 +461,7 @@ describe API::Runners do delete api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user) expect(response).to have_http_status(204) - end.to change{ project.runners.count }.by(-1) + end.to change { project.runners.count }.by(-1) end end @@ -469,7 +469,7 @@ describe API::Runners do it "does not disable project's runner" do expect do delete api("/projects/#{project.id}/runners/#{specific_runner.id}", user) - end.to change{ project.runners.count }.by(0) + end.to change { project.runners.count }.by(0) expect(response).to have_http_status(403) end end diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb index 95df3429314..48d99841385 100644 --- a/spec/requests/api/services_spec.rb +++ b/spec/requests/api/services_spec.rb @@ -4,7 +4,7 @@ describe API::Services do let(:user) { create(:user) } let(:admin) { create(:admin) } let(:user2) { create(:user) } - let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } Service.available_services_names.each do |service| describe "PUT /projects/:id/services/#{service.dasherize}" do @@ -98,7 +98,7 @@ describe API::Services do end describe 'POST /projects/:id/services/:slug/trigger' do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } describe 'Mattermost Service' do let(:service_name) { 'mattermost_slash_commands' } diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index c3ed5cd8ece..97275b80d03 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -43,7 +43,9 @@ describe API::Settings, 'Settings' do default_artifacts_expire_in: '2 days', help_page_text: 'custom help text', help_page_hide_commercial_content: true, - help_page_support_url: 'http://example.com/help' + help_page_support_url: 'http://example.com/help', + project_export_enabled: false + expect(response).to have_http_status(200) expect(json_response['default_projects_limit']).to eq(3) expect(json_response['password_authentication_enabled']).to be_falsey @@ -58,6 +60,7 @@ describe API::Settings, 'Settings' do expect(json_response['help_page_text']).to eq('custom help text') expect(json_response['help_page_hide_commercial_content']).to be_truthy expect(json_response['help_page_support_url']).to eq('http://example.com/help') + expect(json_response['project_export_enabled']).to be_falsey end end diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb index 373fab4d98a..d09b8bc42f1 100644 --- a/spec/requests/api/snippets_spec.rb +++ b/spec/requests/api/snippets_spec.rb @@ -52,10 +52,10 @@ describe API::Snippets do expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly( public_snippet.id, public_snippet_other.id) - expect(json_response.map{ |snippet| snippet['web_url']} ).to include( + expect(json_response.map { |snippet| snippet['web_url']} ).to include( "http://localhost/snippets/#{public_snippet.id}", "http://localhost/snippets/#{public_snippet_other.id}") - expect(json_response.map{ |snippet| snippet['raw_url']} ).to include( + expect(json_response.map { |snippet| snippet['raw_url']} ).to include( "http://localhost/snippets/#{public_snippet.id}/raw", "http://localhost/snippets/#{public_snippet_other.id}/raw") end diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index ef7d0c3ee41..9884c1ec206 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -1,66 +1,85 @@ require 'spec_helper' -require 'mime/types' describe API::Tags do - include RepoHelpers - let(:user) { create(:user) } - let(:user2) { create(:user) } - let!(:project) { create(:project, :repository, creator: user) } - let!(:master) { create(:project_member, :master, user: user, project: project) } - let!(:guest) { create(:project_member, :guest, user: user2, project: project) } + let(:guest) { create(:user).tap { |u| project.add_guest(u) } } + let(:project) { create(:project, :repository, creator: user, path: 'my.project') } + let(:tag_name) { project.repository.find_tag('v1.1.0').name } - describe "GET /projects/:id/repository/tags" do - let(:tag_name) { project.repository.tag_names.sort.reverse.first } - let(:description) { 'Awesome release!' } + let(:project_id) { project.id } + let(:current_user) { nil } + + before do + project.add_master(user) + end + + describe 'GET /projects/:id/repository/tags' do + let(:route) { "/projects/#{project_id}/repository/tags" } shared_examples_for 'repository tags' do it 'returns the repository tags' do - get api("/projects/#{project.id}/repository/tags", current_user) + get api(route, current_user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/tags') expect(response).to include_pagination_headers - expect(json_response).to be_an Array expect(json_response.first['name']).to eq(tag_name) end - end - context 'when unauthenticated' do - it_behaves_like 'repository tags' do - let(:project) { create(:project, :public, :repository) } - let(:current_user) { nil } + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end end end - context 'when authenticated' do - it_behaves_like 'repository tags' do - let(:current_user) { user } + context 'when unauthenticated', 'and project is public' do + let(:project) { create(:project, :public, :repository) } + + it_behaves_like 'repository tags' + end + + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } end end - context 'without releases' do - it "returns an array of project tags" do - get api("/projects/#{project.id}/repository/tags", user) + context 'when authenticated', 'as a master' do + let(:current_user) { user } - expect(response).to have_http_status(200) - expect(response).to include_pagination_headers - expect(json_response).to be_an Array - expect(json_response.first['name']).to eq(tag_name) + it_behaves_like 'repository tags' + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository tags' + end + end + + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } end end context 'with releases' do + let(:description) { 'Awesome release!' } + before do release = project.releases.find_or_initialize_by(tag: tag_name) release.update_attributes(description: description) end - it "returns an array of project tags with release info" do - get api("/projects/#{project.id}/repository/tags", user) + it 'returns an array of project tags with release info' do + get api(route, user) - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/tags') expect(response).to include_pagination_headers - expect(json_response).to be_an Array expect(json_response.first['name']).to eq(tag_name) expect(json_response.first['message']).to eq('Version 1.1.0') expect(json_response.first['release']['description']).to eq(description) @@ -69,210 +88,342 @@ describe API::Tags do end describe 'GET /projects/:id/repository/tags/:tag_name' do - let(:tag_name) { project.repository.tag_names.sort.reverse.first } + let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}" } shared_examples_for 'repository tag' do - it 'returns the repository tag' do - get api("/projects/#{project.id}/repository/tags/#{tag_name}", current_user) - - expect(response).to have_http_status(200) + it 'returns the repository branch' do + get api(route, current_user) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/tag') expect(json_response['name']).to eq(tag_name) end - it 'returns 404 for an invalid tag name' do - get api("/projects/#{project.id}/repository/tags/foobar", current_user) + context 'when tag does not exist' do + let(:tag_name) { 'unknown' } - expect(response).to have_http_status(404) + it_behaves_like '404 response' do + let(:request) { get api(route, current_user) } + let(:message) { '404 Tag Not Found' } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end end end - context 'when unauthenticated' do - it_behaves_like 'repository tag' do - let(:project) { create(:project, :public, :repository) } - let(:current_user) { nil } + context 'when unauthenticated', 'and project is public' do + let(:project) { create(:project, :public, :repository) } + + it_behaves_like 'repository tag' + end + + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } end end - context 'when authenticated' do - it_behaves_like 'repository tag' do - let(:current_user) { user } + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + it_behaves_like 'repository tag' + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository tag' + end + end + + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } end end end describe 'POST /projects/:id/repository/tags' do - context 'lightweight tags' do + let(:tag_name) { 'new_tag' } + let(:route) { "/projects/#{project_id}/repository/tags" } + + shared_examples_for 'repository new tag' do it 'creates a new tag' do - post api("/projects/#{project.id}/repository/tags", user), - tag_name: 'v7.0.1', - ref: 'master' + post api(route, current_user), tag_name: tag_name, ref: 'master' - expect(response).to have_http_status(201) - expect(json_response['name']).to eq('v7.0.1') + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/tag') + expect(json_response['name']).to eq(tag_name) end - end - context 'lightweight tags with release notes' do - it 'creates a new tag' do - post api("/projects/#{project.id}/repository/tags", user), - tag_name: 'v7.0.1', - ref: 'master', - release_description: 'Wow' + context 'when repository is disabled' do + include_context 'disabled repository' - expect(response).to have_http_status(201) - expect(json_response['name']).to eq('v7.0.1') - expect(json_response['release']['description']).to eq('Wow') + it_behaves_like '403 response' do + let(:request) { post api(route, current_user) } + end end end - describe 'DELETE /projects/:id/repository/tags/:tag_name' do - let(:tag_name) { project.repository.tag_names.sort.reverse.first } + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { post api(route) } + let(:message) { '404 Project Not Found' } + end + end - before do - allow_any_instance_of(Repository).to receive(:rm_tag).and_return(true) + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { post api(route, guest) } end + end + + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + context "when a protected branch doesn't already exist" do + it_behaves_like 'repository new tag' - context 'delete tag' do - it 'deletes an existing tag' do - delete api("/projects/#{project.id}/repository/tags/#{tag_name}", user) + context 'when tag contains a dot' do + let(:tag_name) { 'v7.0.1' } - expect(response).to have_http_status(204) + it_behaves_like 'repository new tag' end - it 'raises 404 if the tag does not exist' do - delete api("/projects/#{project.id}/repository/tags/foobar", user) - expect(response).to have_http_status(404) + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository new tag' + + context 'when tag contains a dot' do + let(:tag_name) { 'v7.0.1' } + + it_behaves_like 'repository new tag' + end end end - end - context 'annotated tag' do - it 'creates a new annotated tag' do - # Identity must be set in .gitconfig to create annotated tag. - repo_path = project.repository.path_to_repo - system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name})) - system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email})) + it 'returns 400 if tag name is invalid' do + post api(route, current_user), tag_name: 'new design', ref: 'master' + + expect(response).to have_gitlab_http_status(400) + expect(json_response['message']).to eq('Tag name invalid') + end + + it 'returns 400 if tag already exists' do + post api(route, current_user), tag_name: 'new_design1', ref: 'master' - post api("/projects/#{project.id}/repository/tags", user), - tag_name: 'v7.1.0', - ref: 'master', - message: 'Release 7.1.0' + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/tag') - expect(response).to have_http_status(201) - expect(json_response['name']).to eq('v7.1.0') - expect(json_response['message']).to eq('Release 7.1.0') + post api(route, current_user), tag_name: 'new_design1', ref: 'master' + + expect(response).to have_gitlab_http_status(400) + expect(json_response['message']).to eq('Tag new_design1 already exists') end - end - it 'denies for user without push access' do - post api("/projects/#{project.id}/repository/tags", user2), - tag_name: 'v1.9.0', - ref: '621491c677087aa243f165eab467bfdfbee00be1' - expect(response).to have_http_status(403) + it 'returns 400 if ref name is invalid' do + post api(route, current_user), tag_name: 'new_design3', ref: 'foo' + + expect(response).to have_gitlab_http_status(400) + expect(json_response['message']).to eq('Target foo is invalid') + end + + context 'lightweight tags with release notes' do + it 'creates a new tag' do + post api(route, current_user), tag_name: tag_name, ref: 'master', release_description: 'Wow' + + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/tag') + expect(json_response['name']).to eq(tag_name) + expect(json_response['release']['description']).to eq('Wow') + end + end + + context 'annotated tag' do + it 'creates a new annotated tag' do + # Identity must be set in .gitconfig to create annotated tag. + repo_path = project.repository.path_to_repo + system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name})) + system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email})) + + post api(route, current_user), tag_name: 'v7.1.0', ref: 'master', message: 'Release 7.1.0' + + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/tag') + expect(json_response['name']).to eq('v7.1.0') + expect(json_response['message']).to eq('Release 7.1.0') + end + end end + end + + describe 'DELETE /projects/:id/repository/tags/:tag_name' do + let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}" } - it 'returns 400 if tag name is invalid' do - post api("/projects/#{project.id}/repository/tags", user), - tag_name: 'v 1.0.0', - ref: 'master' - expect(response).to have_http_status(400) - expect(json_response['message']).to eq('Tag name invalid') + before do + allow_any_instance_of(Repository).to receive(:rm_tag).and_return(true) end - it 'returns 400 if tag already exists' do - post api("/projects/#{project.id}/repository/tags", user), - tag_name: 'v8.0.0', - ref: 'master' - expect(response).to have_http_status(201) - post api("/projects/#{project.id}/repository/tags", user), - tag_name: 'v8.0.0', - ref: 'master' - expect(response).to have_http_status(400) - expect(json_response['message']).to eq('Tag v8.0.0 already exists') + shared_examples_for 'repository delete tag' do + it 'deletes a tag' do + delete api(route, current_user) + + expect(response).to have_gitlab_http_status(204) + end + + context 'when tag does not exist' do + let(:tag_name) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { delete api(route, current_user) } + let(:message) { 'No such tag' } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { delete api(route, current_user) } + end + end end - it 'returns 400 if ref name is invalid' do - post api("/projects/#{project.id}/repository/tags", user), - tag_name: 'mytag', - ref: 'foo' - expect(response).to have_http_status(400) - expect(json_response['message']).to eq('Target foo is invalid') + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + it_behaves_like 'repository delete tag' + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository delete tag' + end end end describe 'POST /projects/:id/repository/tags/:tag_name/release' do - let(:tag_name) { project.repository.tag_names.first } + let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}/release" } let(:description) { 'Awesome release!' } - it 'creates description for existing git tag' do - post api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user), - description: description + shared_examples_for 'repository new release' do + it 'creates description for existing git tag' do + post api(route, user), description: description - expect(response).to have_http_status(201) - expect(json_response['tag_name']).to eq(tag_name) - expect(json_response['description']).to eq(description) - end + expect(response).to have_gitlab_http_status(201) + expect(response).to match_response_schema('public_api/v4/release') + expect(json_response['tag_name']).to eq(tag_name) + expect(json_response['description']).to eq(description) + end + + context 'when tag does not exist' do + let(:tag_name) { 'unknown' } + + it_behaves_like '404 response' do + let(:request) { post api(route, current_user), description: description } + let(:message) { 'Tag does not exist' } + end + end - it 'returns 404 if the tag does not exist' do - post api("/projects/#{project.id}/repository/tags/foobar/release", user), - description: description + context 'when repository is disabled' do + include_context 'disabled repository' - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('Tag does not exist') + it_behaves_like '403 response' do + let(:request) { post api(route, current_user), description: description } + end + end end - context 'on tag with existing release' do - before do - release = project.releases.find_or_initialize_by(tag: tag_name) - release.update_attributes(description: description) + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + it_behaves_like 'repository new release' + + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository new release' end - it 'returns 409 if there is already a release' do - post api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user), - description: description + context 'on tag with existing release' do + before do + release = project.releases.find_or_initialize_by(tag: tag_name) + release.update_attributes(description: description) + end + + it 'returns 409 if there is already a release' do + post api(route, user), description: description - expect(response).to have_http_status(409) - expect(json_response['message']).to eq('Release already exists') + expect(response).to have_gitlab_http_status(409) + expect(json_response['message']).to eq('Release already exists') + end end end end describe 'PUT id/repository/tags/:tag_name/release' do - let(:tag_name) { project.repository.tag_names.first } + let(:route) { "/projects/#{project_id}/repository/tags/#{tag_name}/release" } let(:description) { 'Awesome release!' } let(:new_description) { 'The best release!' } - context 'on tag with existing release' do - before do - release = project.releases.find_or_initialize_by(tag: tag_name) - release.update_attributes(description: description) + shared_examples_for 'repository update release' do + context 'on tag with existing release' do + before do + release = project.releases.find_or_initialize_by(tag: tag_name) + release.update_attributes(description: description) + end + + it 'updates the release description' do + put api(route, current_user), description: new_description + + expect(response).to have_gitlab_http_status(200) + expect(json_response['tag_name']).to eq(tag_name) + expect(json_response['description']).to eq(new_description) + end end - it 'updates the release description' do - put api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user), - description: new_description + context 'when tag does not exist' do + let(:tag_name) { 'unknown' } - expect(response).to have_http_status(200) - expect(json_response['tag_name']).to eq(tag_name) - expect(json_response['description']).to eq(new_description) + it_behaves_like '404 response' do + let(:request) { put api(route, current_user), description: new_description } + let(:message) { 'Tag does not exist' } + end end - end - it 'returns 404 if the tag does not exist' do - put api("/projects/#{project.id}/repository/tags/foobar/release", user), - description: new_description + context 'when repository is disabled' do + include_context 'disabled repository' - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('Tag does not exist') + it_behaves_like '403 response' do + let(:request) { put api(route, current_user), description: new_description } + end + end end - it 'returns 404 if the release does not exist' do - put api("/projects/#{project.id}/repository/tags/#{tag_name}/release", user), - description: new_description + context 'when authenticated', 'as a master' do + let(:current_user) { user } + + it_behaves_like 'repository update release' - expect(response).to have_http_status(404) - expect(json_response['message']).to eq('Release does not exist') + context 'requesting with the escaped project full path' do + let(:project_id) { CGI.escape(project.full_path) } + + it_behaves_like 'repository update release' + end + + context 'when release does not exist' do + it_behaves_like '404 response' do + let(:request) { put api(route, current_user), description: new_description } + let(:message) { 'Release does not exist' } + end + end end end end diff --git a/spec/requests/api/todos_spec.rb b/spec/requests/api/todos_spec.rb index 9fc73c6e092..25d7f6dffcf 100644 --- a/spec/requests/api/todos_spec.rb +++ b/spec/requests/api/todos_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe API::Todos do - let(:project_1) { create(:project) } - let(:project_2) { create(:empty_project) } + let(:project_1) { create(:project, :repository) } + let(:project_2) { create(:project) } let(:author_1) { create(:user) } let(:author_2) { create(:user) } let(:john_doe) { create(:user, username: 'john_doe') } diff --git a/spec/requests/api/triggers_spec.rb b/spec/requests/api/triggers_spec.rb index 153596c2975..572e9a0fd07 100644 --- a/spec/requests/api/triggers_spec.rb +++ b/spec/requests/api/triggers_spec.rb @@ -13,7 +13,7 @@ describe API::Triggers do let!(:trigger_request) { create(:ci_trigger_request, trigger: trigger, created_at: '2015-01-01 12:13:14') } describe 'POST /projects/:project_id/trigger/pipeline' do - let!(:project2) { create(:project) } + let!(:project2) { create(:project, :repository) } let(:options) do { token: trigger_token @@ -185,7 +185,7 @@ describe API::Triggers do expect do post api("/projects/#{project.id}/triggers", user), description: 'trigger' - end.to change{project.triggers.count}.by(1) + end.to change {project.triggers.count}.by(1) expect(response).to have_http_status(201) expect(json_response).to include('description' => 'trigger') @@ -288,7 +288,7 @@ describe API::Triggers do delete api("/projects/#{project.id}/triggers/#{trigger.id}", user) expect(response).to have_http_status(204) - end.to change{project.triggers.count}.by(-1) + end.to change {project.triggers.count}.by(-1) end it 'responds with 404 Not Found if requesting non-existing trigger' do diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 66b165b438b..49739a1601a 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -16,38 +16,44 @@ describe API::Users do it "returns authorization error when the `username` parameter is not passed" do get api("/users") - expect(response).to have_http_status(403) + expect(response).to have_gitlab_http_status(403) end it "returns the user when a valid `username` parameter is passed" do - user = create(:user) - get api("/users"), username: user.username - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.size).to eq(1) expect(json_response[0]['id']).to eq(user.id) expect(json_response[0]['username']).to eq(user.username) end - it "returns authorization error when the `username` parameter refers to an inaccessible user" do - user = create(:user) - - stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) - - get api("/users"), username: user.username - - expect(response).to have_http_status(403) - end - it "returns an empty response when an invalid `username` parameter is passed" do get api("/users"), username: 'invalid' - expect(response).to have_http_status(200) + expect(response).to have_gitlab_http_status(200) expect(json_response).to be_an Array expect(json_response.size).to eq(0) end + + context "when public level is restricted" do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it "returns authorization error when the `username` parameter refers to an inaccessible user" do + get api("/users"), username: user.username + + expect(response).to have_gitlab_http_status(403) + end + + it "returns authorization error when the `username` parameter is not passed" do + get api("/users") + + expect(response).to have_gitlab_http_status(403) + end + end end context "when authenticated" do @@ -58,10 +64,10 @@ describe API::Users do end context 'when authenticate as a regular user' do - it "renders 403" do + it "renders 200" do get api("/users", user) - expect(response).to have_gitlab_http_status(403) + expect(response).to have_gitlab_http_status(200) end end @@ -211,9 +217,19 @@ describe API::Users do it "does not return the user's `is_admin` flag" do get api("/users/#{user.id}", user) + expect(response).to have_http_status(200) expect(json_response['is_admin']).to be_nil end + context 'when authenticated as admin' do + it 'includes the `is_admin` field' do + get api("/users/#{user.id}", admin) + + expect(response).to have_http_status(200) + expect(json_response['is_admin']).to be(false) + end + end + context 'for an anonymous user' do it "returns a user by id" do get api("/users/#{user.id}") diff --git a/spec/requests/api/v3/award_emoji_spec.rb b/spec/requests/api/v3/award_emoji_spec.rb index 9234710f488..681e8e04295 100644 --- a/spec/requests/api/v3/award_emoji_spec.rb +++ b/spec/requests/api/v3/award_emoji_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::V3::AwardEmoji do let(:user) { create(:user) } - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let!(:award_emoji) { create(:award_emoji, awardable: issue, user: user) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } diff --git a/spec/requests/api/v3/boards_spec.rb b/spec/requests/api/v3/boards_spec.rb index 4d786331d1b..b86aab2ec70 100644 --- a/spec/requests/api/v3/boards_spec.rb +++ b/spec/requests/api/v3/boards_spec.rb @@ -4,7 +4,7 @@ describe API::V3::Boards do let(:user) { create(:user) } let(:guest) { create(:user) } let(:non_member) { create(:user) } - let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) } + let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) } let!(:dev_label) do create(:label, title: 'Development', color: '#FFAABB', project: project) @@ -99,7 +99,7 @@ describe API::V3::Boards do context "when the user is project owner" do let(:owner) { create(:user) } - let(:project) { create(:empty_project, namespace: owner.namespace) } + let(:project) { create(:project, namespace: owner.namespace) } it "deletes the list if an admin requests it" do delete v3_api("#{base_url}/#{dev_list.id}", owner) diff --git a/spec/requests/api/v3/deploy_keys_spec.rb b/spec/requests/api/v3/deploy_keys_spec.rb index 94f4d93a8dc..2affd0cfa51 100644 --- a/spec/requests/api/v3/deploy_keys_spec.rb +++ b/spec/requests/api/v3/deploy_keys_spec.rb @@ -3,8 +3,8 @@ require 'spec_helper' describe API::V3::DeployKeys do let(:user) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, creator_id: user.id) } - let(:project2) { create(:empty_project, creator_id: user.id) } + let(:project) { create(:project, creator_id: user.id) } + let(:project2) { create(:project, creator_id: user.id) } let(:deploy_key) { create(:deploy_key, public: true) } let!(:deploy_keys_project) do @@ -87,7 +87,7 @@ describe API::V3::DeployKeys do expect do post v3_api("/projects/#{project.id}/#{path}", admin), key_attrs - end.to change{ project.deploy_keys.count }.by(1) + end.to change { project.deploy_keys.count }.by(1) end it 'returns an existing ssh key when attempting to add a duplicate' do @@ -122,7 +122,7 @@ describe API::V3::DeployKeys do it 'should delete existing key' do expect do delete v3_api("/projects/#{project.id}/#{path}/#{deploy_key.id}", admin) - end.to change{ project.deploy_keys.count }.by(-1) + end.to change { project.deploy_keys.count }.by(-1) end it 'should return 404 Not Found with invalid ID' do @@ -133,7 +133,7 @@ describe API::V3::DeployKeys do end describe "POST /projects/:id/#{path}/:key_id/enable" do - let(:project2) { create(:empty_project) } + let(:project2) { create(:project) } context 'when the user can admin the project' do it 'enables the key' do diff --git a/spec/requests/api/v3/environments_spec.rb b/spec/requests/api/v3/environments_spec.rb index 99f35723974..39264e819a3 100644 --- a/spec/requests/api/v3/environments_spec.rb +++ b/spec/requests/api/v3/environments_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::V3::Environments do let(:user) { create(:user) } let(:non_member) { create(:user) } - let(:project) { create(:empty_project, :private, namespace: user.namespace) } + let(:project) { create(:project, :private, namespace: user.namespace) } let!(:environment) { create(:environment, project: project) } before do diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb index 8b2d165c763..4ffa5d1784e 100644 --- a/spec/requests/api/v3/files_spec.rb +++ b/spec/requests/api/v3/files_spec.rb @@ -74,7 +74,7 @@ describe API::V3::Files do context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository files' do - let(:project) { create(:project, :public) } + let(:project) { create(:project, :public, :repository) } let(:current_user) { nil } end end diff --git a/spec/requests/api/v3/groups_spec.rb b/spec/requests/api/v3/groups_spec.rb index 5cdc528e190..778fcc73c30 100644 --- a/spec/requests/api/v3/groups_spec.rb +++ b/spec/requests/api/v3/groups_spec.rb @@ -9,9 +9,9 @@ describe API::V3::Groups do let(:admin) { create(:admin) } let!(:group1) { create(:group, avatar: File.open(uploaded_image_temp_path)) } let!(:group2) { create(:group, :private) } - let!(:project1) { create(:empty_project, namespace: group1) } - let!(:project2) { create(:empty_project, namespace: group2) } - let!(:project3) { create(:empty_project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) } + let!(:project1) { create(:project, namespace: group1) } + let!(:project2) { create(:project, namespace: group2) } + let!(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) } before do group1.add_owner(user1) @@ -165,7 +165,7 @@ describe API::V3::Groups do describe "GET /groups/:id" do context "when authenticated as user" do it "returns one of user1's groups" do - project = create(:empty_project, namespace: group2, path: 'Foo') + project = create(:project, namespace: group2, path: 'Foo') create(:project_group_link, project: project, group: group1) get v3_api("/groups/#{group1.id}", user1) @@ -307,7 +307,7 @@ describe API::V3::Groups do end it 'filters the groups projects' do - public_project = create(:empty_project, :public, path: 'test1', group: group1) + public_project = create(:project, :public, path: 'test1', group: group1) get v3_api("/groups/#{group1.id}/projects", user1), visibility: 'public' @@ -501,10 +501,10 @@ describe API::V3::Groups do end describe "POST /groups/:id/projects/:project_id" do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:project_path) { CGI.escape(project.full_path) } - before(:each) do + before do allow_any_instance_of(Projects::TransferService) .to receive(:execute).and_return(true) end diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb index 4dff09b6df8..9eb538c4b09 100644 --- a/spec/requests/api/v3/issues_spec.rb +++ b/spec/requests/api/v3/issues_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe API::V3::Issues do - include EmailHelpers - +describe API::V3::Issues, :mailer do let(:user) { create(:user) } let(:user2) { create(:user) } let(:non_member) { create(:user) } @@ -10,7 +8,7 @@ describe API::V3::Issues do let(:author) { create(:author) } let(:assignee) { create(:assignee) } let(:admin) { create(:user, :admin) } - let!(:project) { create(:empty_project, :public, creator_id: user.id, namespace: user.namespace ) } + let!(:project) { create(:project, :public, creator_id: user.id, namespace: user.namespace ) } let!(:closed_issue) do create :closed_issue, author: user, @@ -243,7 +241,7 @@ describe API::V3::Issues do describe "GET /groups/:id/issues" do let!(:group) { create(:group) } - let!(:group_project) { create(:empty_project, :public, creator_id: user.id, namespace: group) } + let!(:group_project) { create(:project, :public, creator_id: user.id, namespace: group) } let!(:group_closed_issue) do create :closed_issue, author: user, @@ -453,7 +451,7 @@ describe API::V3::Issues do end it "returns 404 on private projects for other users" do - private_project = create(:empty_project, :private) + private_project = create(:project, :private) create(:issue, project: private_project) get v3_api("/projects/#{private_project.id}/issues", non_member) @@ -462,7 +460,7 @@ describe API::V3::Issues do end it 'returns no issues when user has access to project but not issues' do - restricted_project = create(:empty_project, :public, issues_access_level: ProjectFeature::PRIVATE) + restricted_project = create(:project, :public, issues_access_level: ProjectFeature::PRIVATE) create(:issue, project: restricted_project) get v3_api("/projects/#{restricted_project.id}/issues", non_member) @@ -1172,7 +1170,7 @@ describe API::V3::Issues do context "when the user is project owner" do let(:owner) { create(:user) } - let(:project) { create(:empty_project, namespace: owner.namespace) } + let(:project) { create(:project, namespace: owner.namespace) } it "deletes the issue if an admin requests it" do delete v3_api("/projects/#{project.id}/issues/#{issue.id}", owner) @@ -1192,8 +1190,8 @@ describe API::V3::Issues do end describe '/projects/:id/issues/:issue_id/move' do - let!(:target_project) { create(:empty_project, path: 'project2', creator_id: user.id, namespace: user.namespace ) } - let!(:target_project2) { create(:empty_project, creator_id: non_member.id, namespace: non_member.namespace ) } + let!(:target_project) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace ) } + let!(:target_project2) { create(:project, creator_id: non_member.id, namespace: non_member.namespace ) } it 'moves an issue' do post v3_api("/projects/#{project.id}/issues/#{issue.id}/move", user), diff --git a/spec/requests/api/v3/labels_spec.rb b/spec/requests/api/v3/labels_spec.rb index 62faa1cb129..32f37a08024 100644 --- a/spec/requests/api/v3/labels_spec.rb +++ b/spec/requests/api/v3/labels_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::V3::Labels do let(:user) { create(:user) } - let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } let!(:label1) { create(:label, title: 'label1', project: project) } let!(:priority_label) { create(:label, title: 'bug', project: project, priority: 3) } diff --git a/spec/requests/api/v3/members_spec.rb b/spec/requests/api/v3/members_spec.rb index 623f02902b8..bc918a8eb02 100644 --- a/spec/requests/api/v3/members_spec.rb +++ b/spec/requests/api/v3/members_spec.rb @@ -7,7 +7,7 @@ describe API::V3::Members do let(:stranger) { create(:user) } let(:project) do - create(:empty_project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| + create(:project, :public, :access_requestable, creator_id: master.id, namespace: master.namespace) do |project| project.team << [developer, :developer] project.team << [master, :master] project.request_access(access_requester) diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb index 4f9e63f2ace..86f38dd4ec1 100644 --- a/spec/requests/api/v3/merge_requests_spec.rb +++ b/spec/requests/api/v3/merge_requests_spec.rb @@ -90,7 +90,7 @@ describe API::MergeRequests do expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['created_at'] } + response_dates = json_response.map { |merge_request| merge_request['created_at'] } expect(response_dates).to eq(response_dates.sort) end @@ -99,7 +99,7 @@ describe API::MergeRequests do expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['created_at'] } + response_dates = json_response.map { |merge_request| merge_request['created_at'] } expect(response_dates).to eq(response_dates.sort.reverse) end @@ -108,7 +108,7 @@ describe API::MergeRequests do expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['updated_at'] } + response_dates = json_response.map { |merge_request| merge_request['updated_at'] } expect(response_dates).to eq(response_dates.sort.reverse) end @@ -117,7 +117,7 @@ describe API::MergeRequests do expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(3) - response_dates = json_response.map{ |merge_request| merge_request['created_at'] } + response_dates = json_response.map { |merge_request| merge_request['created_at'] } expect(response_dates).to eq(response_dates.sort) end end @@ -312,18 +312,20 @@ describe API::MergeRequests do context 'forked projects' do let!(:user2) { create(:user) } - let!(:fork_project) { create(:empty_project, forked_from_project: project, namespace: user2.namespace, creator_id: user2.id) } - let!(:unrelated_project) { create(:empty_project, namespace: create(:user).namespace, creator_id: user2.id) } + let!(:fork_project) { create(:project, forked_from_project: project, namespace: user2.namespace, creator_id: user2.id) } + let!(:unrelated_project) { create(:project, namespace: create(:user).namespace, creator_id: user2.id) } - before :each do |each| - fork_project.team << [user2, :reporter] + before do + fork_project.add_reporter(user2) + + allow_any_instance_of(MergeRequest).to receive(:write_ref) end it "returns merge_request" do post v3_api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master", author: user2, target_project_id: project.id, description: 'Test description for Test merge_request' - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq('Test merge_request') expect(json_response['description']).to eq('Test description for Test merge_request') end @@ -334,7 +336,7 @@ describe API::MergeRequests do expect(fork_project.forked_from_project).to eq(project) post v3_api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) expect(json_response['title']).to eq('Test merge_request') end @@ -348,25 +350,25 @@ describe API::MergeRequests do author: user2, target_project_id: project.id - expect(response).to have_http_status(422) + expect(response).to have_gitlab_http_status(422) end it "returns 400 when source_branch is missing" do post v3_api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end it "returns 400 when target_branch is missing" do post v3_api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end it "returns 400 when title is missing" do post v3_api("/projects/#{fork_project.id}/merge_requests", user2), target_branch: 'master', source_branch: 'markdown', author: user2, target_project_id: project.id - expect(response).to have_http_status(400) + expect(response).to have_gitlab_http_status(400) end context 'when target_branch is specified' do @@ -377,7 +379,7 @@ describe API::MergeRequests do source_branch: 'markdown', author: user, target_project_id: fork_project.id - expect(response).to have_http_status(422) + expect(response).to have_gitlab_http_status(422) end it 'returns 422 if targeting a different fork' do @@ -387,14 +389,14 @@ describe API::MergeRequests do source_branch: 'markdown', author: user2, target_project_id: unrelated_project.id - expect(response).to have_http_status(422) + expect(response).to have_gitlab_http_status(422) end end it "returns 201 when target_branch is specified and for the same project" do post v3_api("/projects/#{fork_project.id}/merge_requests", user2), title: 'Test merge_request', target_branch: 'master', source_branch: 'markdown', author: user2, target_project_id: fork_project.id - expect(response).to have_http_status(201) + expect(response).to have_gitlab_http_status(201) end end end @@ -635,7 +637,7 @@ describe API::MergeRequests do end it 'handles external issues' do - jira_project = create(:jira_project, :public, name: 'JIR_EXT1') + jira_project = create(:jira_project, :public, :repository, name: 'JIR_EXT1') issue = ExternalIssue.new("#{jira_project.name}-123", jira_project) merge_request = create(:merge_request, :simple, author: user, assignee: user, source_project: jira_project) merge_request.update_attribute(:description, "Closes #{issue.to_reference(jira_project)}") @@ -650,7 +652,7 @@ describe API::MergeRequests do end it 'returns 403 if the user has no access to the merge request' do - project = create(:empty_project, :private) + project = create(:project, :private, :repository) merge_request = create(:merge_request, :simple, source_project: project) guest = create(:user) project.team << [guest, :guest] diff --git a/spec/requests/api/v3/milestones_spec.rb b/spec/requests/api/v3/milestones_spec.rb index f04efc990a7..feaa87faec7 100644 --- a/spec/requests/api/v3/milestones_spec.rb +++ b/spec/requests/api/v3/milestones_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::V3::Milestones do let(:user) { create(:user) } - let!(:project) { create(:empty_project, namespace: user.namespace ) } + let!(:project) { create(:project, namespace: user.namespace ) } let!(:closed_milestone) { create(:closed_milestone, project: project) } let!(:milestone) { create(:milestone, project: project) } @@ -194,7 +194,7 @@ describe API::V3::Milestones do end describe 'confidential issues' do - let(:public_project) { create(:empty_project, :public) } + let(:public_project) { create(:project, :public) } let(:milestone) { create(:milestone, project: public_project) } let(:issue) { create(:issue, project: public_project) } let(:confidential_issue) { create(:issue, confidential: true, project: public_project) } diff --git a/spec/requests/api/v3/notes_spec.rb b/spec/requests/api/v3/notes_spec.rb index b5f98a9a545..56729692eed 100644 --- a/spec/requests/api/v3/notes_spec.rb +++ b/spec/requests/api/v3/notes_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe API::V3::Notes do let(:user) { create(:user) } - let!(:project) { create(:empty_project, :public, namespace: user.namespace) } + let!(:project) { create(:project, :public, namespace: user.namespace) } let!(:issue) { create(:issue, project: project, author: user) } let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, author: user) } let!(:snippet) { create(:project_snippet, project: project, author: user) } @@ -13,12 +13,12 @@ describe API::V3::Notes do # For testing the cross-reference of a private issue in a public issue let(:private_user) { create(:user) } let(:private_project) do - create(:empty_project, namespace: private_user.namespace) + create(:project, namespace: private_user.namespace) .tap { |p| p.team << [private_user, :master] } end let(:private_issue) { create(:issue, project: private_project) } - let(:ext_proj) { create(:empty_project, :public) } + let(:ext_proj) { create(:project, :public) } let(:ext_issue) { create(:issue, project: ext_proj) } let!(:cross_reference_note) do @@ -268,7 +268,7 @@ describe API::V3::Notes do context 'when user does not have access to read the noteable' do it 'responds with 404' do - project = create(:empty_project, :private) { |p| p.add_guest(user) } + project = create(:project, :private) { |p| p.add_guest(user) } issue = create(:issue, :confidential, project: project) post v3_api("/projects/#{project.id}/issues/#{issue.id}/notes", user), @@ -279,7 +279,7 @@ describe API::V3::Notes do end context 'when user does not have access to create noteable' do - let(:private_issue) { create(:issue, project: create(:empty_project, :private)) } + let(:private_issue) { create(:issue, project: create(:project, :private)) } ## # We are posting to project user has access to, but we use issue id diff --git a/spec/requests/api/v3/project_snippets_spec.rb b/spec/requests/api/v3/project_snippets_spec.rb index 1950c64c690..3963924a066 100644 --- a/spec/requests/api/v3/project_snippets_spec.rb +++ b/spec/requests/api/v3/project_snippets_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' describe API::ProjectSnippets do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:user) { create(:user) } let(:admin) { create(:admin) } @@ -30,7 +30,7 @@ describe API::ProjectSnippets do expect(response).to have_http_status(200) expect(json_response.size).to eq(3) - expect(json_response.map{ |snippet| snippet['id']} ).to include(public_snippet.id, internal_snippet.id, private_snippet.id) + expect(json_response.map { |snippet| snippet['id']} ).to include(public_snippet.id, internal_snippet.id, private_snippet.id) expect(json_response.last).to have_key('web_url') end diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index bbfcaab1ea1..a514166274a 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -7,8 +7,8 @@ describe API::V3::Projects do let(:user2) { create(:user) } let(:user3) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } - let(:project2) { create(:empty_project, path: 'project2', creator_id: user.id, namespace: user.namespace) } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let(:project2) { create(:project, path: 'project2', creator_id: user.id, namespace: user.namespace) } let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') } let(:project_member) { create(:project_member, :developer, user: user3, project: project) } let(:user4) { create(:user) } @@ -31,7 +31,7 @@ describe API::V3::Projects do access_level: ProjectMember::MASTER) end let(:project4) do - create(:empty_project, + create(:project, name: 'third_project', path: 'third_project', creator_id: user4.id, @@ -82,7 +82,14 @@ describe API::V3::Projects do context 'GET /projects?simple=true' do it 'returns a simplified version of all the projects' do - expected_keys = %w(id http_url_to_repo web_url name name_with_namespace path path_with_namespace) + expected_keys = %w( + id description default_branch tag_list + ssh_url_to_repo http_url_to_repo web_url + name name_with_namespace + path path_with_namespace + star_count forks_count + created_at last_activity_at + ) get v3_api('/projects?simple=true', user) @@ -125,7 +132,7 @@ describe API::V3::Projects do end context 'and using archived' do - let!(:archived_project) { create(:empty_project, creator_id: user.id, namespace: user.namespace, archived: true) } + let!(:archived_project) { create(:project, creator_id: user.id, namespace: user.namespace, archived: true) } it 'returns archived project' do get v3_api('/projects?archived=true', user) @@ -281,7 +288,7 @@ describe API::V3::Projects do end end - let!(:public_project) { create(:empty_project, :public) } + let!(:public_project) { create(:project, :public) } before do project project2 @@ -312,7 +319,7 @@ describe API::V3::Projects do end describe 'GET /projects/starred' do - let(:public_project) { create(:empty_project, :public) } + let(:public_project) { create(:project, :public) } before do project_member @@ -637,13 +644,14 @@ describe API::V3::Projects do describe 'GET /projects/:id' do context 'when unauthenticated' do it 'returns the public projects' do - public_project = create(:empty_project, :public) + public_project = create(:project, :public) get v3_api("/projects/#{public_project.id}") expect(response).to have_http_status(200) expect(json_response['id']).to eq(public_project.id) expect(json_response['description']).to eq(public_project.description) + expect(json_response['default_branch']).to eq(public_project.default_branch) expect(json_response.keys).not_to include('permissions') end end @@ -718,7 +726,7 @@ describe API::V3::Projects do it 'handles users with dots' do dot_user = create(:user, username: 'dot.user') - project = create(:empty_project, creator_id: dot_user.id, namespace: dot_user.namespace) + project = create(:project, creator_id: dot_user.id, namespace: dot_user.namespace) get v3_api("/projects/#{CGI.escape(project.full_path)}", dot_user) expect(response).to have_http_status(200) @@ -766,7 +774,7 @@ describe API::V3::Projects do end context 'group project' do - let(:project2) { create(:empty_project, group: create(:group)) } + let(:project2) { create(:project, group: create(:group)) } before { project2.group.add_owner(user) } @@ -811,7 +819,7 @@ describe API::V3::Projects do context 'when unauthenticated' do it_behaves_like 'project events response' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:current_user) { nil } end end @@ -861,7 +869,7 @@ describe API::V3::Projects do context 'when unauthenticated' do it_behaves_like 'project users response' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:current_user) { nil } end end @@ -975,11 +983,11 @@ describe API::V3::Projects do end describe 'fork management' do - let(:project_fork_target) { create(:empty_project) } - let(:project_fork_source) { create(:empty_project, :public) } + let(:project_fork_target) { create(:project) } + let(:project_fork_source) { create(:project, :public) } describe 'POST /projects/:id/fork/:forked_from_id' do - let(:new_project_fork_source) { create(:empty_project, :public) } + let(:new_project_fork_source) { create(:project, :public) } it "is not available for non admin users" do post v3_api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) @@ -996,6 +1004,14 @@ describe API::V3::Projects do expect(project_fork_target.forked?).to be_truthy end + it 'refreshes the forks count cachce' do + expect(project_fork_source.forks_count).to be_zero + + post v3_api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) + + expect(project_fork_source.forks_count).to eq(1) + end + it 'fails if forked_from project which does not exist' do post v3_api("/projects/#{project_fork_target.id}/fork/9999", admin) expect(response).to have_http_status(404) @@ -1020,7 +1036,7 @@ describe API::V3::Projects do end context 'when users belong to project group' do - let(:project_fork_target) { create(:empty_project, group: create(:group)) } + let(:project_fork_target) { create(:project, group: create(:group)) } before do project_fork_target.group.add_owner user @@ -1140,16 +1156,16 @@ describe API::V3::Projects do describe 'GET /projects/search/:query' do let!(:query) { 'query'} - let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } - let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } - let!(:post) { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:pre_post) { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:unfound) { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } - let!(:internal) { create(:empty_project, :internal, name: "internal #{query}") } - let!(:unfound_internal) { create(:empty_project, :internal, name: 'unfound internal') } - let!(:public) { create(:empty_project, :public, name: "public #{query}") } - let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') } - let!(:one_dot_two) { create(:empty_project, :public, name: "one.dot.two") } + let!(:search) { create(:project, name: query, creator_id: user.id, namespace: user.namespace) } + let!(:pre) { create(:project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } + let!(:post) { create(:project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:pre_post) { create(:project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:unfound) { create(:project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } + let!(:internal) { create(:project, :internal, name: "internal #{query}") } + let!(:unfound_internal) { create(:project, :internal, name: 'unfound internal') } + let!(:public) { create(:project, :public, name: "public #{query}") } + let!(:unfound_public) { create(:project, :public, name: 'unfound public') } + let!(:one_dot_two) { create(:project, :public, name: "one.dot.two") } shared_examples_for 'project search response' do |args = {}| it 'returns project search responses' do diff --git a/spec/requests/api/v3/runners_spec.rb b/spec/requests/api/v3/runners_spec.rb index dbda2cf34c3..a31eb3f1d43 100644 --- a/spec/requests/api/v3/runners_spec.rb +++ b/spec/requests/api/v3/runners_spec.rb @@ -5,8 +5,8 @@ describe API::V3::Runners do let(:user) { create(:user) } let(:user2) { create(:user) } - let(:project) { create(:empty_project, creator_id: user.id) } - let(:project2) { create(:empty_project, creator_id: user.id) } + let(:project) { create(:project, creator_id: user.id) } + let(:project2) { create(:project, creator_id: user.id) } let!(:shared_runner) { create(:ci_runner, :shared) } let!(:unused_specific_runner) { create(:ci_runner) } @@ -38,7 +38,7 @@ describe API::V3::Runners do delete v3_api("/runners/#{shared_runner.id}", admin) expect(response).to have_http_status(200) - end.to change{ Ci::Runner.shared.count }.by(-1) + end.to change { Ci::Runner.shared.count }.by(-1) end end @@ -48,7 +48,7 @@ describe API::V3::Runners do delete v3_api("/runners/#{unused_specific_runner.id}", admin) expect(response).to have_http_status(200) - end.to change{ Ci::Runner.specific.count }.by(-1) + end.to change { Ci::Runner.specific.count }.by(-1) end it 'deletes used runner' do @@ -56,7 +56,7 @@ describe API::V3::Runners do delete v3_api("/runners/#{specific_runner.id}", admin) expect(response).to have_http_status(200) - end.to change{ Ci::Runner.specific.count }.by(-1) + end.to change { Ci::Runner.specific.count }.by(-1) end end @@ -91,7 +91,7 @@ describe API::V3::Runners do delete v3_api("/runners/#{specific_runner.id}", user) expect(response).to have_http_status(200) - end.to change{ Ci::Runner.specific.count }.by(-1) + end.to change { Ci::Runner.specific.count }.by(-1) end end end @@ -113,7 +113,7 @@ describe API::V3::Runners do delete v3_api("/projects/#{project.id}/runners/#{two_projects_runner.id}", user) expect(response).to have_http_status(200) - end.to change{ project.runners.count }.by(-1) + end.to change { project.runners.count }.by(-1) end end @@ -121,7 +121,7 @@ describe API::V3::Runners do it "does not disable project's runner" do expect do delete v3_api("/projects/#{project.id}/runners/#{specific_runner.id}", user) - end.to change{ project.runners.count }.by(0) + end.to change { project.runners.count }.by(0) expect(response).to have_http_status(403) end end diff --git a/spec/requests/api/v3/services_spec.rb b/spec/requests/api/v3/services_spec.rb index 3ba62de822a..f0fa48e22df 100644 --- a/spec/requests/api/v3/services_spec.rb +++ b/spec/requests/api/v3/services_spec.rb @@ -2,7 +2,7 @@ require "spec_helper" describe API::V3::Services do let(:user) { create(:user) } - let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } available_services = Service.available_services_names available_services.delete('prometheus') diff --git a/spec/requests/api/v3/snippets_spec.rb b/spec/requests/api/v3/snippets_spec.rb index 1bc2258ebd3..9ead3cad8bb 100644 --- a/spec/requests/api/v3/snippets_spec.rb +++ b/spec/requests/api/v3/snippets_spec.rb @@ -45,10 +45,10 @@ describe API::V3::Snippets do expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly( public_snippet.id, public_snippet_other.id) - expect(json_response.map{ |snippet| snippet['web_url']} ).to include( + expect(json_response.map { |snippet| snippet['web_url']} ).to include( "http://localhost/snippets/#{public_snippet.id}", "http://localhost/snippets/#{public_snippet_other.id}") - expect(json_response.map{ |snippet| snippet['raw_url']} ).to include( + expect(json_response.map { |snippet| snippet['raw_url']} ).to include( "http://localhost/snippets/#{public_snippet.id}/raw", "http://localhost/snippets/#{public_snippet_other.id}/raw") end diff --git a/spec/requests/api/v3/todos_spec.rb b/spec/requests/api/v3/todos_spec.rb index 9c2c4d64257..8f5c3fbf8dd 100644 --- a/spec/requests/api/v3/todos_spec.rb +++ b/spec/requests/api/v3/todos_spec.rb @@ -1,8 +1,8 @@ require 'spec_helper' describe API::V3::Todos do - let(:project_1) { create(:empty_project) } - let(:project_2) { create(:empty_project) } + let(:project_1) { create(:project) } + let(:project_2) { create(:project) } let(:author_1) { create(:user) } let(:author_2) { create(:user) } let(:john_doe) { create(:user, username: 'john_doe') } diff --git a/spec/requests/api/v3/triggers_spec.rb b/spec/requests/api/v3/triggers_spec.rb index 60212660fb6..075de2c0cba 100644 --- a/spec/requests/api/v3/triggers_spec.rb +++ b/spec/requests/api/v3/triggers_spec.rb @@ -171,7 +171,7 @@ describe API::V3::Triggers do it 'creates trigger' do expect do post v3_api("/projects/#{project.id}/triggers", user) - end.to change{project.triggers.count}.by(1) + end.to change {project.triggers.count}.by(1) expect(response).to have_http_status(201) expect(json_response).to be_a(Hash) @@ -202,7 +202,7 @@ describe API::V3::Triggers do delete v3_api("/projects/#{project.id}/triggers/#{trigger.token}", user) expect(response).to have_http_status(200) - end.to change{project.triggers.count}.by(-1) + end.to change {project.triggers.count}.by(-1) end it 'responds with 404 Not Found if requesting non-existing trigger' do diff --git a/spec/requests/api/v3/users_spec.rb b/spec/requests/api/v3/users_spec.rb index de7499a4e43..227b8d1b0c1 100644 --- a/spec/requests/api/v3/users_spec.rb +++ b/spec/requests/api/v3/users_spec.rb @@ -232,7 +232,7 @@ describe API::V3::Users do describe 'GET /users/:id/events' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:note) { create(:note_on_issue, note: 'What an awesome day!', project: project) } before do @@ -252,6 +252,31 @@ describe API::V3::Users do end context "as a user than can see the event's project" do + context 'when the list of events includes push events' do + let(:event) { create(:push_event, author: user, project: project) } + let!(:payload) { create(:push_event_payload, event: event) } + let(:payload_hash) { json_response[0]['push_data'] } + + before do + get api("/users/#{user.id}/events?action=pushed", user) + end + + it 'responds with HTTP 200 OK' do + expect(response).to have_http_status(200) + end + + it 'includes the push payload as a Hash' do + expect(payload_hash).to be_an_instance_of(Hash) + end + + it 'includes the push payload details' do + expect(payload_hash['commit_count']).to eq(payload.commit_count) + expect(payload_hash['action']).to eq(payload.action) + expect(payload_hash['ref_type']).to eq(payload.ref_type) + expect(payload_hash['commit_to']).to eq(payload.commit_to) + end + end + context 'joined event' do it 'returns the "joined" event' do get v3_api("/users/#{user.id}/events", user) @@ -276,7 +301,7 @@ describe API::V3::Users do end context 'when there are multiple events from different projects' do - let(:second_note) { create(:note_on_issue, project: create(:empty_project)) } + let(:second_note) { create(:note_on_issue, project: create(:project)) } let(:third_note) { create(:note_on_issue, project: project) } before do diff --git a/spec/requests/api/variables_spec.rb b/spec/requests/api/variables_spec.rb index e0975024b80..48592e12822 100644 --- a/spec/requests/api/variables_spec.rb +++ b/spec/requests/api/variables_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::Variables do let(:user) { create(:user) } let(:user2) { create(:user) } - let!(:project) { create(:empty_project, creator_id: user.id) } + let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:project_member, :master, user: user, project: project) } let!(:developer) { create(:project_member, :developer, user: user2, project: project) } let!(:variable) { create(:ci_variable, project: project) } @@ -74,7 +74,7 @@ describe API::Variables do it 'creates variable' do expect do post api("/projects/#{project.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2', protected: true - end.to change{project.variables.count}.by(1) + end.to change {project.variables.count}.by(1) expect(response).to have_http_status(201) expect(json_response['key']).to eq('TEST_VARIABLE_2') @@ -85,7 +85,7 @@ describe API::Variables do it 'creates variable with optional attributes' do expect do post api("/projects/#{project.id}/variables", user), key: 'TEST_VARIABLE_2', value: 'VALUE_2' - end.to change{project.variables.count}.by(1) + end.to change {project.variables.count}.by(1) expect(response).to have_http_status(201) expect(json_response['key']).to eq('TEST_VARIABLE_2') @@ -96,7 +96,7 @@ describe API::Variables do it 'does not allow to duplicate variable key' do expect do post api("/projects/#{project.id}/variables", user), key: variable.key, value: 'VALUE_2' - end.to change{project.variables.count}.by(0) + end.to change {project.variables.count}.by(0) expect(response).to have_http_status(400) end @@ -166,7 +166,7 @@ describe API::Variables do delete api("/projects/#{project.id}/variables/#{variable.key}", user) expect(response).to have_http_status(204) - end.to change{project.variables.count}.by(-1) + end.to change {project.variables.count}.by(-1) end it 'responds with 404 Not Found if requesting non-existing variable' do diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 49e815ee16c..ebd67eb1e94 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::API::Builds do let(:runner) { FactoryGirl.create(:ci_runner, tag_list: %w(mysql ruby)) } - let(:project) { FactoryGirl.create(:empty_project, shared_runners_enabled: false) } + let(:project) { FactoryGirl.create(:project, shared_runners_enabled: false) } let(:last_update) { nil } describe "Builds API for runners" do @@ -421,7 +421,7 @@ describe Ci::API::Builds do end context 'when build has been updated recently' do - it { expect{ patch_the_trace }.not_to change { build.updated_at }} + it { expect { patch_the_trace }.not_to change { build.updated_at }} it 'changes the build trace' do patch_the_trace @@ -430,7 +430,7 @@ describe Ci::API::Builds do end context 'when Runner makes a force-patch' do - it { expect{ force_patch_the_trace }.not_to change { build.updated_at }} + it { expect { force_patch_the_trace }.not_to change { build.updated_at }} it "doesn't change the build.trace" do force_patch_the_trace diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb index 78b2be350cd..75059dd20a0 100644 --- a/spec/requests/ci/api/runners_spec.rb +++ b/spec/requests/ci/api/runners_spec.rb @@ -70,7 +70,7 @@ describe Ci::API::Runners do end context 'when project token is provided' do - let(:project) { FactoryGirl.create(:empty_project) } + let(:project) { FactoryGirl.create(:project) } before do post ci_api("/runners/register"), token: project.runners_token diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb index e481ca916ab..7c77ebb69a2 100644 --- a/spec/requests/ci/api/triggers_spec.rb +++ b/spec/requests/ci/api/triggers_spec.rb @@ -4,7 +4,7 @@ describe Ci::API::Triggers do describe 'POST /projects/:project_id/refs/:ref/trigger' do let!(:trigger_token) { 'secure token' } let!(:project) { create(:project, :repository, ci_id: 10) } - let!(:project2) { create(:empty_project, ci_id: 11) } + let!(:project2) { create(:project, ci_id: 11) } let!(:trigger) do create(:ci_trigger, diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index d4a3e8b13e1..ecac40e301b 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -123,7 +123,7 @@ describe 'Git HTTP requests' do context "when requesting the Wiki" do let(:wiki) { ProjectWiki.new(project) } - let(:path) { "/#{wiki.repository.path_with_namespace}.git" } + let(:path) { "/#{wiki.repository.full_path}.git" } context "when the project is public" do let(:project) { create(:project, :repository, :public, :wiki_enabled) } @@ -139,7 +139,7 @@ describe 'Git HTTP requests' do download(path) do |response| json_body = ActiveSupport::JSON.decode(response.body) - expect(json_body['RepoPath']).to include(wiki.repository.path_with_namespace) + expect(json_body['RepoPath']).to include(wiki.repository.full_path) end end end @@ -222,7 +222,7 @@ describe 'Git HTTP requests' do end context "when the project exists" do - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } context "when the project is public" do let(:project) { create(:project, :repository, :public) } @@ -286,7 +286,7 @@ describe 'Git HTTP requests' do context 'when the request is not from gitlab-workhorse' do it 'raises an exception' do expect do - get("/#{project.path_with_namespace}.git/info/refs?service=git-upload-pack") + get("/#{project.full_path}.git/info/refs?service=git-upload-pack") end.to raise_error(JWT::DecodeError) end end @@ -294,7 +294,7 @@ describe 'Git HTTP requests' do context 'when the repo is public' do context 'but the repo is disabled' do let(:project) { create(:project, :public, :repository, :repository_disabled) } - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { {} } it_behaves_like 'pulls require Basic HTTP Authentication' @@ -303,7 +303,7 @@ describe 'Git HTTP requests' do context 'but the repo is enabled' do let(:project) { create(:project, :public, :repository, :repository_enabled) } - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { {} } it_behaves_like 'pulls are allowed' @@ -421,7 +421,7 @@ describe 'Git HTTP requests' do @token = Doorkeeper::AccessToken.create!(application_id: application.id, resource_owner_id: user.id, scopes: "api") end - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { { user: 'oauth2', password: @token.token } } it_behaves_like 'pulls are allowed' @@ -431,7 +431,7 @@ describe 'Git HTTP requests' do context 'when user has 2FA enabled' do let(:user) { create(:user, :two_factor) } let(:access_token) { create(:personal_access_token, user: user) } - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } before do project.team << [user, :master] @@ -573,14 +573,14 @@ describe 'Git HTTP requests' do context "when a gitlab ci token is provided" do let(:project) { create(:project, :repository) } let(:build) { create(:ci_build, :running) } - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } before do build.update!(project: project) # can't associate it on factory create end context 'when build created by system is authenticated' do - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { { user: 'gitlab-ci-token', password: build.token } } it_behaves_like 'pulls are allowed' @@ -602,7 +602,7 @@ describe 'Git HTTP requests' do # We are "authenticated" as CI using a valid token here. But we are # not authorized to see any other project, so return "not found". it "rejects pulls for other project with 404 Not Found" do - clone_get("#{other_project.path_with_namespace}.git", env) + clone_get("#{other_project.full_path}.git", env) expect(response).to have_http_status(:not_found) expect(response.body).to eq(git_access_error(:project_not_found)) @@ -616,13 +616,13 @@ describe 'Git HTTP requests' do end shared_examples 'can download code only' do - let(:path) { "#{project.path_with_namespace}.git" } + let(:path) { "#{project.full_path}.git" } let(:env) { { user: 'gitlab-ci-token', password: build.token } } it_behaves_like 'pulls are allowed' context 'when the repo does not exist' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'rejects pulls with 403 Forbidden' do clone_get path, env @@ -646,7 +646,7 @@ describe 'Git HTTP requests' do it_behaves_like 'can download code only' it 'downloads from other project get status 403' do - clone_get "#{other_project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token + clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token expect(response).to have_http_status(:forbidden) end @@ -658,7 +658,7 @@ describe 'Git HTTP requests' do it_behaves_like 'can download code only' it 'downloads from other project get status 404' do - clone_get "#{other_project.path_with_namespace}.git", user: 'gitlab-ci-token', password: build.token + clone_get "#{other_project.full_path}.git", user: 'gitlab-ci-token', password: build.token expect(response).to have_http_status(:not_found) end @@ -671,7 +671,7 @@ describe 'Git HTTP requests' do let(:project) { create(:project, :repository, :public, path: 'project.git-project') } context "GET info/refs" do - let(:path) { "/#{project.path_with_namespace}/info/refs" } + let(:path) { "/#{project.full_path}/info/refs" } context "when no params are added" do before do @@ -679,7 +679,7 @@ describe 'Git HTTP requests' do end it "redirects to the .git suffix version" do - expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs") + expect(response).to redirect_to("/#{project.full_path}.git/info/refs") end end @@ -691,7 +691,7 @@ describe 'Git HTTP requests' do end it "redirects to the .git suffix version" do - expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}") + expect(response).to redirect_to("/#{project.full_path}.git/info/refs?service=#{params[:service]}") end end @@ -703,7 +703,7 @@ describe 'Git HTTP requests' do end it "redirects to the .git suffix version" do - expect(response).to redirect_to("/#{project.path_with_namespace}.git/info/refs?service=#{params[:service]}") + expect(response).to redirect_to("/#{project.full_path}.git/info/refs?service=#{params[:service]}") end end @@ -722,13 +722,13 @@ describe 'Git HTTP requests' do context "POST git-upload-pack" do it "fails to find a route" do - expect { clone_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError) + expect { clone_post(project.full_path) }.to raise_error(ActionController::RoutingError) end end context "POST git-receive-pack" do it "fails to find a route" do - expect { push_post(project.path_with_namespace) }.to raise_error(ActionController::RoutingError) + expect { push_post(project.full_path) }.to raise_error(ActionController::RoutingError) end end end @@ -744,7 +744,7 @@ describe 'Git HTTP requests' do Blob.decorate(Gitlab::Git::Blob.find(project.repository, 'master', 'bar/branch-test.txt'), project) end - get "/#{project.path_with_namespace}/blob/master/info/refs" + get "/#{project.full_path}/blob/master/info/refs" end it "returns the file" do @@ -754,7 +754,7 @@ describe 'Git HTTP requests' do context "when the file does not exist" do before do - get "/#{project.path_with_namespace}/blob/master/info/refs" + get "/#{project.full_path}/blob/master/info/refs" end it "returns not found" do diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index 697b150ab34..27d09b8202e 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -20,7 +20,7 @@ describe 'Git LFS API and storage' do let(:sample_size) { lfs_object.size } describe 'when lfs is disabled' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:body) do { 'objects' => [ @@ -46,7 +46,7 @@ describe 'Git LFS API and storage' do end context 'project specific LFS settings' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:body) do { 'objects' => [ @@ -151,7 +151,7 @@ describe 'Git LFS API and storage' do end describe 'deprecated API' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do enable_lfs @@ -188,7 +188,7 @@ describe 'Git LFS API and storage' do end describe 'when fetching lfs object' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:update_permissions) { } before do @@ -281,7 +281,7 @@ describe 'Git LFS API and storage' do shared_examples 'can download LFS only from own projects' do context 'for owned project' do - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } let(:update_permissions) do project.lfs_objects << lfs_object @@ -302,7 +302,7 @@ describe 'Git LFS API and storage' do end context 'for other project' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, project: other_project) } let(:update_permissions) do @@ -368,7 +368,7 @@ describe 'Git LFS API and storage' do end describe 'download' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:body) do { 'operation' => 'download', @@ -408,7 +408,7 @@ describe 'Git LFS API and storage' do end context 'when downloading an lfs object that is assigned to other project' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:update_lfs_permissions) do other_project.lfs_objects << lfs_object end @@ -559,7 +559,7 @@ describe 'Git LFS API and storage' do end context 'for other project' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, project: other_project) } it 'rejects downloading code' do @@ -662,7 +662,7 @@ describe 'Git LFS API and storage' do end context 'when pushing an lfs object that already exists' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:update_lfs_permissions) do other_project.lfs_objects << lfs_object end @@ -701,7 +701,7 @@ describe 'Git LFS API and storage' do expect(json_response['objects']).to be_kind_of(Array) expect(json_response['objects'].first['oid']).to eq("91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897") expect(json_response['objects'].first['size']).to eq(1575078) - expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") + expect(json_response['objects'].first['actions']['upload']['href']).to eq("#{Gitlab.config.gitlab.url}/#{project.full_path}.git/gitlab-lfs/objects/91eff75a492a3ed0dfcb544d7f31326bc4014c8551849c192fd1e48d4dd2c897/1575078") expect(json_response['objects'].first['actions']['upload']['header']).to eq('Authorization' => authorization) end end @@ -765,7 +765,7 @@ describe 'Git LFS API and storage' do end context 'tries to push to other project' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, project: other_project) } let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) } @@ -806,7 +806,7 @@ describe 'Git LFS API and storage' do end describe 'unsupported' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:authorization) { authorize_user } let(:body) do { @@ -894,7 +894,7 @@ describe 'Git LFS API and storage' do end describe 'to one project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } describe 'when user is authenticated' do let(:authorization) { authorize_user } @@ -986,7 +986,7 @@ describe 'Git LFS API and storage' do end context 'tries to push to other project' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, project: other_project) } let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) } @@ -1086,7 +1086,7 @@ describe 'Git LFS API and storage' do end context 'tries to push to other project' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:pipeline) { create(:ci_empty_pipeline, project: other_project) } let(:build) { create(:ci_build, :running, pipeline: pipeline, user: user) } @@ -1111,7 +1111,7 @@ describe 'Git LFS API and storage' do end describe 'and second project not related to fork or a source project' do - let(:second_project) { create(:empty_project) } + let(:second_project) { create(:project) } let(:authorization) { authorize_user } before do diff --git a/spec/requests/request_profiler_spec.rb b/spec/requests/request_profiler_spec.rb index 51fbfecec4b..9afeb2983b0 100644 --- a/spec/requests/request_profiler_spec.rb +++ b/spec/requests/request_profiler_spec.rb @@ -15,7 +15,7 @@ describe 'Request Profiler' do it 'creates a profile of the request' do project = create(:project, namespace: user.namespace) time = Time.now - path = "/#{project.path_with_namespace}" + path = "/#{project.full_path}" Timecop.freeze(time) do get path, nil, 'X-Profile-Token' => Gitlab::RequestProfiler.profile_token diff --git a/spec/routing/environments_spec.rb b/spec/routing/environments_spec.rb index 9b70c2a24be..aacbe300966 100644 --- a/spec/routing/environments_spec.rb +++ b/spec/routing/environments_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'environments routing' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:environment) do create(:environment, project: project, diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index c02409b2e0b..39d44245c3f 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -165,15 +165,19 @@ describe 'project routing' do # edit_project_repository GET /:project_id/repository/edit(.:format) projects/repositories#edit describe Projects::RepositoriesController, 'routing' do it 'to #archive' do - expect(get('/gitlab/gitlabhq/repository/archive')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq') + expect(get('/gitlab/gitlabhq/repository/master/archive')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', ref: 'master') end it 'to #archive format:zip' do - expect(get('/gitlab/gitlabhq/repository/archive.zip')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'zip') + expect(get('/gitlab/gitlabhq/repository/master/archive.zip')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'zip', ref: 'master') end it 'to #archive format:tar.bz2' do - expect(get('/gitlab/gitlabhq/repository/archive.tar.bz2')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'tar.bz2') + expect(get('/gitlab/gitlabhq/repository/master/archive.tar.bz2')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', format: 'tar.bz2', ref: 'master') + end + + it 'to #archive with "/" in route' do + expect(get('/gitlab/gitlabhq/repository/improve/awesome/archive')).to route_to('projects/repositories#archive', namespace_id: 'gitlab', project_id: 'gitlabhq', ref: 'improve/awesome') end end diff --git a/spec/rubocop/cop/migration/safer_boolean_column_spec.rb b/spec/rubocop/cop/migration/safer_boolean_column_spec.rb new file mode 100644 index 00000000000..1006594499a --- /dev/null +++ b/spec/rubocop/cop/migration/safer_boolean_column_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +require 'rubocop' +require 'rubocop/rspec/support' + +require_relative '../../../../rubocop/cop/migration/safer_boolean_column' + +describe RuboCop::Cop::Migration::SaferBooleanColumn do + include CopHelper + + subject(:cop) { described_class.new } + + context 'in migration' do + before do + allow(cop).to receive(:in_migration?).and_return(true) + end + + described_class::SMALL_TABLES.each do |table| + context "for the #{table} table" do + sources_and_offense = [ + ["add_column :#{table}, :column, :boolean, default: true", 'should disallow nulls'], + ["add_column :#{table}, :column, :boolean, default: false", 'should disallow nulls'], + ["add_column :#{table}, :column, :boolean, default: nil", 'should have a default and should disallow nulls'], + ["add_column :#{table}, :column, :boolean, null: false", 'should have a default'], + ["add_column :#{table}, :column, :boolean, null: true", 'should have a default and should disallow nulls'], + ["add_column :#{table}, :column, :boolean", 'should have a default and should disallow nulls'], + ["add_column :#{table}, :column, :boolean, default: nil, null: false", 'should have a default'], + ["add_column :#{table}, :column, :boolean, default: nil, null: true", 'should have a default and should disallow nulls'], + ["add_column :#{table}, :column, :boolean, default: false, null: true", 'should disallow nulls'] + ] + + sources_and_offense.each do |source, offense| + context "given the source \"#{source}\"" do + it "registers the offense matching \"#{offense}\"" do + inspect_source(cop, source) + + aggregate_failures do + expect(cop.offenses.first.message).to match(offense) + end + end + end + end + + inoffensive_sources = [ + "add_column :#{table}, :column, :boolean, default: true, null: false", + "add_column :#{table}, :column, :boolean, default: false, null: false" + ] + + inoffensive_sources.each do |source| + context "given the source \"#{source}\"" do + it "registers no offense" do + inspect_source(cop, source) + + aggregate_failures do + expect(cop.offenses).to be_empty + end + end + end + end + end + end + + it 'registers no offense for tables not listed in SMALL_TABLES' do + inspect_source(cop, "add_column :large_table, :column, :boolean") + + expect(cop.offenses).to be_empty + end + + it 'registers no offense for non-boolean columns' do + table = described_class::SMALL_TABLES.sample + inspect_source(cop, "add_column :#{table}, :column, :string") + + expect(cop.offenses).to be_empty + end + end + + context 'outside of migration' do + it 'registers no offense' do + table = described_class::SMALL_TABLES.sample + inspect_source(cop, "add_column :#{table}, :column, :boolean") + + expect(cop.offenses).to be_empty + end + end +end diff --git a/spec/serializers/analytics_build_entity_spec.rb b/spec/serializers/analytics_build_entity_spec.rb index 86e703a6448..1ff4908972a 100644 --- a/spec/serializers/analytics_build_entity_spec.rb +++ b/spec/serializers/analytics_build_entity_spec.rb @@ -13,12 +13,8 @@ describe AnalyticsBuildEntity do subject { entity.as_json } - before do - Timecop.freeze - end - - after do - Timecop.return + around do |example| + Timecop.freeze { example.run } end it 'contains the URL' do @@ -47,7 +43,7 @@ describe AnalyticsBuildEntity do let(:finished_at) { nil } it 'does not blow up' do - expect{ subject[:date] }.not_to raise_error + expect { subject[:date] }.not_to raise_error end it 'shows the right message' do @@ -63,7 +59,7 @@ describe AnalyticsBuildEntity do let(:started_at) { nil } it 'does not blow up' do - expect{ subject[:date] }.not_to raise_error + expect { subject[:date] }.not_to raise_error end it 'shows the right message' do @@ -79,7 +75,7 @@ describe AnalyticsBuildEntity do let(:finished_at) { nil } it 'does not blow up' do - expect{ subject[:date] }.not_to raise_error + expect { subject[:date] }.not_to raise_error end it 'shows the right message' do diff --git a/spec/serializers/analytics_issue_entity_spec.rb b/spec/serializers/analytics_issue_entity_spec.rb index 75d606d5eb3..89588b4df2b 100644 --- a/spec/serializers/analytics_issue_entity_spec.rb +++ b/spec/serializers/analytics_issue_entity_spec.rb @@ -13,7 +13,7 @@ describe AnalyticsIssueEntity do } end - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:request) { EntityRequest.new(project: project, entity: :merge_request) } let(:entity) do diff --git a/spec/serializers/analytics_issue_serializer_spec.rb b/spec/serializers/analytics_issue_serializer_spec.rb index 7c14c198a74..5befc28f4fa 100644 --- a/spec/serializers/analytics_issue_serializer_spec.rb +++ b/spec/serializers/analytics_issue_serializer_spec.rb @@ -8,7 +8,7 @@ describe AnalyticsIssueSerializer do end let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:resource) do { total_time: "172802.724419", diff --git a/spec/serializers/analytics_merge_request_serializer_spec.rb b/spec/serializers/analytics_merge_request_serializer_spec.rb index 56cb08acfc6..62067cc0ef2 100644 --- a/spec/serializers/analytics_merge_request_serializer_spec.rb +++ b/spec/serializers/analytics_merge_request_serializer_spec.rb @@ -8,7 +8,7 @@ describe AnalyticsMergeRequestSerializer do end let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:resource) do { total_time: "172802.724419", diff --git a/spec/serializers/analytics_summary_serializer_spec.rb b/spec/serializers/analytics_summary_serializer_spec.rb index 5d7a94c2d02..236c244b402 100644 --- a/spec/serializers/analytics_summary_serializer_spec.rb +++ b/spec/serializers/analytics_summary_serializer_spec.rb @@ -5,7 +5,7 @@ describe AnalyticsSummarySerializer do described_class.new.represent(resource) end - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:resource) do diff --git a/spec/serializers/build_details_entity_spec.rb b/spec/serializers/build_details_entity_spec.rb index 1332572fffc..5b7822d5d8e 100644 --- a/spec/serializers/build_details_entity_spec.rb +++ b/spec/serializers/build_details_entity_spec.rb @@ -57,7 +57,7 @@ describe BuildDetailsEntity do context 'when merge request is from a fork' do let(:fork_project) do - create(:empty_project, forked_from_project: project) + create(:project, forked_from_project: project) end let(:pipeline) { create(:ci_pipeline, project: fork_project) } diff --git a/spec/serializers/deploy_key_entity_spec.rb b/spec/serializers/deploy_key_entity_spec.rb index 8149de869f1..d3aefa2c9eb 100644 --- a/spec/serializers/deploy_key_entity_spec.rb +++ b/spec/serializers/deploy_key_entity_spec.rb @@ -4,9 +4,9 @@ describe DeployKeyEntity do include RequestAwareEntity let(:user) { create(:user) } - let(:project) { create(:empty_project, :internal)} - let(:project_private) { create(:empty_project, :private)} - let!(:project_pending_delete) { create(:empty_project, :internal, pending_delete: true) } + let(:project) { create(:project, :internal)} + let(:project_private) { create(:project, :private)} + let!(:project_pending_delete) { create(:project, :internal, pending_delete: true) } let(:deploy_key) { create(:deploy_key) } let!(:deploy_key_internal) { create(:deploy_keys_project, project: project, deploy_key: deploy_key) } let!(:deploy_key_private) { create(:deploy_keys_project, project: project_private, deploy_key: deploy_key) } diff --git a/spec/serializers/environment_serializer_spec.rb b/spec/serializers/environment_serializer_spec.rb index 4c52a00b442..ca9b520fb38 100644 --- a/spec/serializers/environment_serializer_spec.rb +++ b/spec/serializers/environment_serializer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe EnvironmentSerializer do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:json) do described_class @@ -39,7 +39,7 @@ describe EnvironmentSerializer do end context 'when there is a collection of objects provided' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:resource) { create_list(:environment, 2) } it 'contains important elements of environment' do diff --git a/spec/serializers/merge_request_entity_spec.rb b/spec/serializers/merge_request_entity_spec.rb index b3d58b2636f..a2fd5b7daae 100644 --- a/spec/serializers/merge_request_entity_spec.rb +++ b/spec/serializers/merge_request_entity_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe MergeRequestEntity do - let(:project) { create :empty_project } + let(:project) { create :project } let(:resource) { create(:merge_request, source_project: project, target_project: project) } let(:user) { create(:user) } @@ -47,7 +47,7 @@ describe MergeRequestEntity do :cancel_merge_when_pipeline_succeeds_path, :create_issue_to_resolve_discussions_path, :source_branch_path, :target_branch_commits_path, - :target_branch_tree_path, :commits_count) + :target_branch_tree_path, :commits_count, :merge_ongoing) end it 'has email_patches_path' do diff --git a/spec/serializers/pipeline_details_entity_spec.rb b/spec/serializers/pipeline_details_entity_spec.rb index b990370a271..f60d1843581 100644 --- a/spec/serializers/pipeline_details_entity_spec.rb +++ b/spec/serializers/pipeline_details_entity_spec.rb @@ -42,7 +42,7 @@ describe PipelineDetailsEntity do end context 'when pipeline is retryable' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) do create(:ci_pipeline, status: :success, project: project) @@ -70,7 +70,7 @@ describe PipelineDetailsEntity do end context 'when pipeline is cancelable' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) do create(:ci_pipeline, status: :running, project: project) diff --git a/spec/serializers/pipeline_entity_spec.rb b/spec/serializers/pipeline_entity_spec.rb index 5b01cc4fc9e..881f2b6bfd8 100644 --- a/spec/serializers/pipeline_entity_spec.rb +++ b/spec/serializers/pipeline_entity_spec.rb @@ -42,7 +42,7 @@ describe PipelineEntity do end context 'when pipeline is retryable' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) do create(:ci_pipeline, status: :success, project: project) @@ -70,7 +70,7 @@ describe PipelineEntity do end context 'when pipeline is cancelable' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) do create(:ci_pipeline, status: :running, project: project) diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 262bc4acb69..2de8daba6b5 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -100,7 +100,7 @@ describe PipelineSerializer do context 'number of queries' do let(:resource) { Ci::Pipeline.all } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do Ci::Pipeline::AVAILABLE_STATUSES.each do |status| @@ -111,7 +111,7 @@ describe PipelineSerializer do shared_examples 'no N+1 queries' do it 'verifies number of queries', :request_store do recorded = ActiveRecord::QueryRecorder.new { subject } - expect(recorded.count).to be_within(1).of(59) + expect(recorded.count).to be_within(1).of(57) expect(recorded.cached_count).to eq(0) end end diff --git a/spec/serializers/runner_entity_spec.rb b/spec/serializers/runner_entity_spec.rb index 4f25a8dcfa0..439ba2cbca2 100644 --- a/spec/serializers/runner_entity_spec.rb +++ b/spec/serializers/runner_entity_spec.rb @@ -4,7 +4,7 @@ describe RunnerEntity do let(:runner) { create(:ci_runner, :specific) } let(:entity) { described_class.new(runner, request: request, current_user: user) } let(:request) { double('request') } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:admin) } before do diff --git a/spec/services/auth/container_registry_authentication_service_spec.rb b/spec/services/auth/container_registry_authentication_service_spec.rb index 66a8a93b168..1c2d0b3e0dc 100644 --- a/spec/services/auth/container_registry_authentication_service_spec.rb +++ b/spec/services/auth/container_registry_authentication_service_spec.rb @@ -8,7 +8,7 @@ describe Auth::ContainerRegistryAuthenticationService do let(:payload) { JWT.decode(subject[:token], rsa_key).first } let(:authentication_abilities) do - [:read_container_image, :create_container_image] + [:read_container_image, :create_container_image, :admin_container_image] end subject do @@ -46,7 +46,7 @@ describe Auth::ContainerRegistryAuthenticationService do shared_examples 'an accessible' do let(:access) do [{ 'type' => 'repository', - 'name' => project.path_with_namespace, + 'name' => project.full_path, 'actions' => actions }] end @@ -59,6 +59,12 @@ describe Auth::ContainerRegistryAuthenticationService do it { expect(payload).to include('access' => []) } end + shared_examples 'a deletable' do + it_behaves_like 'an accessible' do + let(:actions) { ['*'] } + end + end + shared_examples 'a pullable' do it_behaves_like 'an accessible' do let(:actions) { ['pull'] } @@ -96,8 +102,8 @@ describe Auth::ContainerRegistryAuthenticationService do end describe '#full_access_token' do - let(:project) { create(:empty_project) } - let(:token) { described_class.full_access_token(project.path_with_namespace) } + let(:project) { create(:project) } + let(:token) { described_class.full_access_token(project.full_path) } subject { { token: token } } @@ -112,7 +118,7 @@ describe Auth::ContainerRegistryAuthenticationService do let(:current_user) { create(:user) } context 'for private project' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } context 'allow to use scope-less authentication' do it_behaves_like 'a valid token' @@ -120,25 +126,38 @@ describe Auth::ContainerRegistryAuthenticationService do context 'allow developer to push images' do before do - project.team << [current_user, :developer] + project.add_developer(current_user) end let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end it_behaves_like 'a pushable' it_behaves_like 'container repository factory' end + context 'disallow developer to delete images' do + before do + project.add_developer(current_user) + end + + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:*" } + end + + it_behaves_like 'an inaccessible' + it_behaves_like 'not a container repository factory' + end + context 'allow reporter to pull images' do before do - project.team << [current_user, :reporter] + project.add_reporter(current_user) end context 'when pulling from root level repository' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a pullable' @@ -146,13 +165,26 @@ describe Auth::ContainerRegistryAuthenticationService do end end + context 'disallow reporter to delete images' do + before do + project.add_reporter(current_user) + end + + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:*" } + end + + it_behaves_like 'an inaccessible' + it_behaves_like 'not a container repository factory' + end + context 'return a least of privileges' do before do - project.team << [current_user, :reporter] + project.add_reporter(current_user) end let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push,pull" } + { scope: "repository:#{project.full_path}:push,pull" } end it_behaves_like 'a pullable' @@ -161,11 +193,24 @@ describe Auth::ContainerRegistryAuthenticationService do context 'disallow guest to pull or push images' do before do - project.team << [current_user, :guest] + project.add_guest(current_user) + end + + let(:current_params) do + { scope: "repository:#{project.full_path}:pull,push" } + end + + it_behaves_like 'an inaccessible' + it_behaves_like 'not a container repository factory' + end + + context 'disallow guest to delete images' do + before do + project.add_guest(current_user) end let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull,push" } + { scope: "repository:#{project.path_with_namespace}:*" } end it_behaves_like 'an inaccessible' @@ -174,11 +219,11 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'for public project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } context 'allow anyone to pull images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a pullable' @@ -187,7 +232,16 @@ describe Auth::ContainerRegistryAuthenticationService do context 'disallow anyone to push images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } + end + + it_behaves_like 'an inaccessible' + it_behaves_like 'not a container repository factory' + end + + context 'disallow anyone to delete images' do + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:*" } end it_behaves_like 'an inaccessible' @@ -205,12 +259,12 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'for internal project' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } context 'for internal user' do context 'allow anyone to pull images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a pullable' @@ -219,7 +273,16 @@ describe Auth::ContainerRegistryAuthenticationService do context 'disallow anyone to push images' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } + end + + it_behaves_like 'an inaccessible' + it_behaves_like 'not a container repository factory' + end + + context 'disallow anyone to delete images' do + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:*" } end it_behaves_like 'an inaccessible' @@ -228,19 +291,56 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'for external user' do - let(:current_user) { create(:user, external: true) } - let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull,push" } + context 'disallow anyone to pull or push images' do + let(:current_user) { create(:user, external: true) } + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:pull,push" } + end + + it_behaves_like 'an inaccessible' + it_behaves_like 'not a container repository factory' end - it_behaves_like 'an inaccessible' - it_behaves_like 'not a container repository factory' + context 'disallow anyone to delete images' do + let(:current_user) { create(:user, external: true) } + let(:current_params) do + { scope: "repository:#{project.path_with_namespace}:*" } + end + + it_behaves_like 'an inaccessible' + it_behaves_like 'not a container repository factory' + end + end + end + end + + context 'delete authorized as master' do + let(:current_project) { create(:project) } + let(:current_user) { create(:user) } + + let(:authentication_abilities) do + [:admin_container_image] + end + + before do + current_project.add_master(current_user) + end + + it_behaves_like 'a valid token' + + context 'allow to delete images' do + let(:current_params) do + { scope: "repository:#{current_project.path_with_namespace}:*" } + end + + it_behaves_like 'a deletable' do + let(:project) { current_project } end end end context 'build authorized as user' do - let(:current_project) { create(:empty_project) } + let(:current_project) { create(:project) } let(:current_user) { create(:user) } let(:authentication_abilities) do @@ -248,14 +348,14 @@ describe Auth::ContainerRegistryAuthenticationService do end before do - current_project.team << [current_user, :developer] + current_project.add_developer(current_user) end it_behaves_like 'a valid token' context 'allow to pull and push images' do let(:current_params) do - { scope: "repository:#{current_project.path_with_namespace}:pull,push" } + { scope: "repository:#{current_project.full_path}:pull,push" } end it_behaves_like 'a pullable and pushable' do @@ -267,14 +367,24 @@ describe Auth::ContainerRegistryAuthenticationService do end end + context 'disallow to delete images' do + let(:current_params) do + { scope: "repository:#{current_project.path_with_namespace}:*" } + end + + it_behaves_like 'an inaccessible' do + let(:project) { current_project } + end + end + context 'for other projects' do context 'when pulling' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end context 'allow for public' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } it_behaves_like 'a pullable' it_behaves_like 'not a container repository factory' @@ -288,7 +398,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when you are member' do before do - project.team << [current_user, :developer] + project.add_developer(current_user) end it_behaves_like 'a pullable' @@ -296,7 +406,7 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'when you are owner' do - let(:project) { create(:empty_project, namespace: current_user.namespace) } + let(:project) { create(:project, namespace: current_user.namespace) } it_behaves_like 'a pullable' it_behaves_like 'not a container repository factory' @@ -304,7 +414,7 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'for private' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } it_behaves_like 'pullable for being team member' @@ -318,7 +428,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when you are member' do before do - project.team << [current_user, :developer] + project.add_developer(current_user) end it_behaves_like 'a pullable' @@ -326,7 +436,7 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'when you are owner' do - let(:project) { create(:empty_project, namespace: current_user.namespace) } + let(:project) { create(:project, namespace: current_user.namespace) } it_behaves_like 'a pullable' it_behaves_like 'not a container repository factory' @@ -337,15 +447,15 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when pushing' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end context 'disallow for all' do context 'when you are member' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } before do - project.team << [current_user, :developer] + project.add_developer(current_user) end it_behaves_like 'an inaccessible' @@ -353,7 +463,7 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'when you are owner' do - let(:project) { create(:empty_project, :public, namespace: current_user.namespace) } + let(:project) { create(:project, :public, namespace: current_user.namespace) } it_behaves_like 'an inaccessible' it_behaves_like 'not a container repository factory' @@ -363,7 +473,7 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'for project without container registry' do - let(:project) { create(:empty_project, :public, container_registry_enabled: false) } + let(:project) { create(:project, :public, container_registry_enabled: false) } before do project.update(container_registry_enabled: false) @@ -371,7 +481,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'disallow when pulling' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'an inaccessible' @@ -396,21 +506,21 @@ describe Auth::ContainerRegistryAuthenticationService do end context 'for private project' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull" } + { scope: "repository:#{project.full_path}:pull" } end it_behaves_like 'a forbidden' end context 'for public project' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } context 'when pulling and pushing' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:pull,push" } + { scope: "repository:#{project.full_path}:pull,push" } end it_behaves_like 'a pullable' @@ -419,7 +529,7 @@ describe Auth::ContainerRegistryAuthenticationService do context 'when pushing' do let(:current_params) do - { scope: "repository:#{project.path_with_namespace}:push" } + { scope: "repository:#{project.full_path}:push" } end it_behaves_like 'a forbidden' diff --git a/spec/services/boards/create_service_spec.rb b/spec/services/boards/create_service_spec.rb index 6e3227303fe..db51a524e79 100644 --- a/spec/services/boards/create_service_spec.rb +++ b/spec/services/boards/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Boards::CreateService do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject(:service) { described_class.new(project, double) } diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb index 23ad66e454b..f2ddaa903da 100644 --- a/spec/services/boards/issues/create_service_spec.rb +++ b/spec/services/boards/issues/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Boards::Issues::CreateService do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } let(:label) { create(:label, project: project, name: 'in-progress') } diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index b1b5d807a78..01ee3856c99 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Boards::Issues::ListService do describe '#execute' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:bug) { create(:label, project: project, name: 'Bug') } diff --git a/spec/services/boards/issues/move_service_spec.rb b/spec/services/boards/issues/move_service_spec.rb index 15a32350ae2..63dfe80d672 100644 --- a/spec/services/boards/issues/move_service_spec.rb +++ b/spec/services/boards/issues/move_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Boards::Issues::MoveService do describe '#execute' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board1) { create(:board, project: project) } let(:bug) { create(:label, project: project, name: 'Bug') } diff --git a/spec/services/boards/list_service_spec.rb b/spec/services/boards/list_service_spec.rb index a95b12eeaa3..1d0be99fb35 100644 --- a/spec/services/boards/list_service_spec.rb +++ b/spec/services/boards/list_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Boards::ListService do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject(:service) { described_class.new(project, double) } diff --git a/spec/services/boards/lists/create_service_spec.rb b/spec/services/boards/lists/create_service_spec.rb index 86d3227a78d..7d0b396cd06 100644 --- a/spec/services/boards/lists/create_service_spec.rb +++ b/spec/services/boards/lists/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Boards::Lists::CreateService do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } let(:label) { create(:label, project: project, name: 'in-progress') } diff --git a/spec/services/boards/lists/destroy_service_spec.rb b/spec/services/boards/lists/destroy_service_spec.rb index ad6ae83286d..bd98625b44f 100644 --- a/spec/services/boards/lists/destroy_service_spec.rb +++ b/spec/services/boards/lists/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Boards::Lists::DestroyService do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } diff --git a/spec/services/boards/lists/generate_service_spec.rb b/spec/services/boards/lists/generate_service_spec.rb index 7dec9f7a4a5..592f25059ac 100644 --- a/spec/services/boards/lists/generate_service_spec.rb +++ b/spec/services/boards/lists/generate_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Boards::Lists::GenerateService do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } diff --git a/spec/services/boards/lists/list_service_spec.rb b/spec/services/boards/lists/list_service_spec.rb index c93788d4516..b189857e4f4 100644 --- a/spec/services/boards/lists/list_service_spec.rb +++ b/spec/services/boards/lists/list_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Boards::Lists::ListService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:label) { create(:label, project: project) } let!(:list) { create(:list, board: board, label: label) } diff --git a/spec/services/boards/lists/move_service_spec.rb b/spec/services/boards/lists/move_service_spec.rb index 43e125a21df..a9d218bad49 100644 --- a/spec/services/boards/lists/move_service_spec.rb +++ b/spec/services/boards/lists/move_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Boards::Lists::MoveService do describe '#execute' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:board) { create(:board, project: project) } let(:user) { create(:user) } diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 4ec495f612e..53d4fcfed18 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -66,7 +66,7 @@ describe Ci::CreatePipelineService do context 'when there is no pipeline for source branch' do it "does not update merge request head pipeline" do - merge_request = create(:merge_request, source_branch: 'other_branch', target_branch: "branch_1", source_project: project) + merge_request = create(:merge_request, source_branch: 'feature', target_branch: "branch_1", source_project: project) head_pipeline = pipeline @@ -75,7 +75,7 @@ describe Ci::CreatePipelineService do end context 'when merge request target project is different from source project' do - let!(:target_project) { create(:project) } + let!(:target_project) { create(:project, :repository) } let!(:forked_project_link) { create(:forked_project_link, forked_to_project: project, forked_from_project: target_project) } it 'updates head pipeline for merge request' do diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 945a2fe1a6b..9a6875e448c 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Ci::PipelineTriggerService, services: true do +describe Ci::PipelineTriggerService do let(:project) { create(:project, :repository) } before do @@ -18,7 +18,7 @@ describe Ci::PipelineTriggerService, services: true do context 'when trigger belongs to a different project' do let(:params) { { token: trigger.token, ref: 'master', variables: nil } } - let(:trigger) { create(:ci_trigger, project: create(:empty_project), owner: user) } + let(:trigger) { create(:ci_trigger, project: create(:project), owner: user) } it 'does nothing' do expect { result }.not_to change { Ci::Pipeline.count } diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb index 1ced26ff98d..330ec81e87d 100644 --- a/spec/services/ci/play_build_service_spec.rb +++ b/spec/services/ci/play_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::PlayBuildService, '#execute' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, :manual, pipeline: pipeline) } @@ -11,7 +11,7 @@ describe Ci::PlayBuildService, '#execute' do end context 'when project does not have repository yet' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'allows user to play build if protected branch rules are met' do project.add_developer(user) @@ -33,7 +33,7 @@ describe Ci::PlayBuildService, '#execute' do end context 'when project has repository' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } it 'allows user with developer role to play a build' do project.add_developer(user) diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 3a702742681..214adc9960f 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::ProcessPipelineService, '#execute' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) do create(:ci_empty_pipeline, ref: 'master', project: project) diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 23c0f715c3e..8eb0d2d10a4 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' module Ci describe RegisterJobService do - let!(:project) { FactoryGirl.create :empty_project, shared_runners_enabled: false } + let!(:project) { FactoryGirl.create :project, shared_runners_enabled: false } let!(:pipeline) { FactoryGirl.create :ci_pipeline, project: project } let!(:pending_build) { FactoryGirl.create :ci_build, pipeline: pipeline } let!(:shared_runner) { FactoryGirl.create(:ci_runner, is_shared: true) } @@ -72,9 +72,9 @@ module Ci end context 'for multiple builds' do - let!(:project2) { create :empty_project, shared_runners_enabled: true } + let!(:project2) { create :project, shared_runners_enabled: true } let!(:pipeline2) { create :ci_pipeline, project: project2 } - let!(:project3) { create :empty_project, shared_runners_enabled: true } + let!(:project3) { create :project, shared_runners_enabled: true } let!(:pipeline3) { create :ci_pipeline, project: project3 } let!(:build1_project1) { pending_build } let!(:build2_project1) { FactoryGirl.create :ci_build, pipeline: pipeline } diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index fd8a57d28f0..cec667071cc 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::RetryBuildService do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index 90b0c5a4dce..6ce75c65c8c 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Ci::RetryPipelineService, '#execute' do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:service) { described_class.new(project, user) } diff --git a/spec/services/create_deployment_service_spec.rb b/spec/services/create_deployment_service_spec.rb index 049b082277a..08267d6e6a0 100644 --- a/spec/services/create_deployment_service_spec.rb +++ b/spec/services/create_deployment_service_spec.rb @@ -20,6 +20,10 @@ describe CreateDeploymentService do let(:service) { described_class.new(job) } + before do + allow_any_instance_of(Deployment).to receive(:create_ref) + end + describe '#execute' do subject { service.execute } diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/delete_merged_branches_service_spec.rb index 4b872d667cf..03c682ae0d7 100644 --- a/spec/services/delete_merged_branches_service_spec.rb +++ b/spec/services/delete_merged_branches_service_spec.rb @@ -32,6 +32,14 @@ describe DeleteMergedBranchesService do expect(project.repository.branch_names).to include('improve/awesome') end + it 'keeps wildcard protected branches' do + create(:protected_branch, project: project, name: 'improve/*') + + service.execute + + expect(project.repository.branch_names).to include('improve/awesome') + end + context 'user without rights' do let(:user) { create(:user) } diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index 00104ae1fd9..02d7ddeb86b 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -114,21 +114,61 @@ describe EventCreateService do end describe '#push', :clean_gitlab_redis_shared_state do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } + let(:push_data) do + { + commits: [ + { + id: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + message: 'This is a commit' + } + ], + before: '0000000000000000000000000000000000000000', + after: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + total_commits_count: 1, + ref: 'refs/heads/my-branch' + } + end + it 'creates a new event' do - expect { service.push(project, user, {}) }.to change { Event.count } + expect { service.push(project, user, push_data) }.to change { Event.count } + end + + it 'creates the push event payload' do + expect(PushEventPayloadService).to receive(:new) + .with(an_instance_of(PushEvent), push_data) + .and_call_original + + service.push(project, user, push_data) end it 'updates user last activity' do - expect { service.push(project, user, {}) }.to change { user_activity(user) } + expect { service.push(project, user, push_data) } + .to change { user_activity(user) } + end + + it 'does not create any event data when an error is raised' do + payload_service = double(:service) + + allow(payload_service).to receive(:execute) + .and_raise(RuntimeError) + + allow(PushEventPayloadService).to receive(:new) + .and_return(payload_service) + + expect { service.push(project, user, push_data) } + .to raise_error(RuntimeError) + + expect(Event.count).to eq(0) + expect(PushEventPayload.count).to eq(0) end end describe 'Project' do let(:user) { create :user } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } describe '#join_project' do subject { service.join_project(project, user) } diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 3fb677b65be..8485605b398 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -132,7 +132,7 @@ describe GitPushService, services: true do end it "creates a new pipeline" do - expect{ subject }.to change{ Ci::Pipeline.count } + expect { subject }.to change { Ci::Pipeline.count } expect(Ci::Pipeline.last).to be_push end end @@ -141,10 +141,13 @@ describe GitPushService, services: true do let!(:push_data) { push_data_from_service(project, user, oldrev, newrev, ref) } let(:event) { Event.find_by_action(Event::PUSHED) } - it { expect(event).not_to be_nil } + it { expect(event).to be_an_instance_of(PushEvent) } it { expect(event.project).to eq(project) } it { expect(event.action).to eq(Event::PUSHED) } - it { expect(event.data).to eq(push_data) } + it { expect(event.push_event_payload).to be_an_instance_of(PushEventPayload) } + it { expect(event.push_event_payload.commit_from).to eq(oldrev) } + it { expect(event.push_event_payload.commit_to).to eq(newrev) } + it { expect(event.push_event_payload.ref).to eq('master') } context "Updates merge requests" do it "when pushing a new branch for the first time" do @@ -453,7 +456,7 @@ describe GitPushService, services: true do let(:message) { "this is some work.\n\ncloses JIRA-1" } let(:comment_body) do { - body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]." + body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.full_path}/commit/#{closing_commit.id}]." }.to_json end diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index f877c145390..05695aa8188 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -39,7 +39,7 @@ describe GitTagPushService do end it "creates a new pipeline" do - expect{ subject }.to change{ Ci::Pipeline.count } + expect { subject }.to change { Ci::Pipeline.count } expect(Ci::Pipeline.last).to be_push end end diff --git a/spec/services/groups/destroy_service_spec.rb b/spec/services/groups/destroy_service_spec.rb index c18870ea100..1b2ce3cd03e 100644 --- a/spec/services/groups/destroy_service_spec.rb +++ b/spec/services/groups/destroy_service_spec.rb @@ -6,7 +6,7 @@ describe Groups::DestroyService do let!(:user) { create(:user) } let!(:group) { create(:group) } let!(:nested_group) { create(:group, parent: group) } - let!(:project) { create(:empty_project, namespace: group) } + let!(:project) { create(:project, namespace: group) } let!(:notification_setting) { create(:notification_setting, source: group)} let!(:gitlab_shell) { Gitlab::Shell.new } let!(:remove_path) { group.path + "+#{group.id}+deleted" } diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index 9902e1aff8b..44f22a3b37b 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -13,7 +13,7 @@ describe Groups::UpdateService do before do public_group.add_user(user, Gitlab::Access::MASTER) - create(:empty_project, :public, group: public_group) + create(:project, :public, group: public_group) end it "does not change permission level" do @@ -27,7 +27,7 @@ describe Groups::UpdateService do before do internal_group.add_user(user, Gitlab::Access::MASTER) - create(:empty_project, :internal, group: internal_group) + create(:project, :internal, group: internal_group) end it "does not change permission level" do @@ -69,7 +69,7 @@ describe Groups::UpdateService do before do internal_group.add_user(user, Gitlab::Access::MASTER) - create(:empty_project, :internal, group: internal_group) + create(:project, :internal, group: internal_group) end it 'returns true' do diff --git a/spec/services/issuable/bulk_update_service_spec.rb b/spec/services/issuable/bulk_update_service_spec.rb index 055aa6156cb..bdaab88d673 100644 --- a/spec/services/issuable/bulk_update_service_spec.rb +++ b/spec/services/issuable/bulk_update_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Issuable::BulkUpdateService do let(:user) { create(:user) } - let(:project) { create(:empty_project, namespace: user.namespace) } + let(:project) { create(:project, namespace: user.namespace) } def bulk_update(issuables, extra_params = {}) bulk_update_params = extra_params @@ -118,7 +118,7 @@ describe Issuable::BulkUpdateService do context 'when the new assignee ID is not present' do it 'does not unassign' do expect { bulk_update(issue, assignee_ids: []) } - .not_to change{ issue.reload.assignees } + .not_to change { issue.reload.assignees } end end end diff --git a/spec/services/issues/create_service_spec.rb b/spec/services/issues/create_service_spec.rb index a48748e274d..9b2d9e79f4f 100644 --- a/spec/services/issues/create_service_spec.rb +++ b/spec/services/issues/create_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Issues::CreateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } describe '#execute' do @@ -351,14 +351,14 @@ describe Issues::CreateService do end it 'marks related spam_log as recaptcha_verified' do - expect { issue }.to change{SpamLog.last.recaptcha_verified}.from(false).to(true) + expect { issue }.to change {SpamLog.last.recaptcha_verified}.from(false).to(true) end context 'when spam log does not belong to a user' do let(:log_user) { create(:user) } it 'does not mark spam_log as recaptcha_verified' do - expect { issue }.not_to change{SpamLog.last.recaptcha_verified} + expect { issue }.not_to change {SpamLog.last.recaptcha_verified} end end end @@ -378,7 +378,7 @@ describe Issues::CreateService do end it 'creates a new spam_log' do - expect{issue}.to change{SpamLog.count}.from(0).to(1) + expect {issue}.to change {SpamLog.count}.from(0).to(1) end it 'assigns a spam_log to an issue' do diff --git a/spec/services/issues/duplicate_service_spec.rb b/spec/services/issues/duplicate_service_spec.rb index ed55664e382..089e77cc88b 100644 --- a/spec/services/issues/duplicate_service_spec.rb +++ b/spec/services/issues/duplicate_service_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' describe Issues::DuplicateService do let(:user) { create(:user) } - let(:canonical_project) { create(:empty_project) } - let(:duplicate_project) { create(:empty_project) } + let(:canonical_project) { create(:project) } + let(:duplicate_project) { create(:project) } let(:canonical_issue) { create(:issue, project: canonical_project) } let(:duplicate_issue) { create(:issue, project: duplicate_project) } diff --git a/spec/services/issues/move_service_spec.rb b/spec/services/issues/move_service_spec.rb index 171fc7334c4..f2b35a8fadf 100644 --- a/spec/services/issues/move_service_spec.rb +++ b/spec/services/issues/move_service_spec.rb @@ -5,8 +5,8 @@ describe Issues::MoveService do let(:author) { create(:user) } let(:title) { 'Some issue' } let(:description) { 'Some issue description' } - let(:old_project) { create(:empty_project) } - let(:new_project) { create(:empty_project) } + let(:old_project) { create(:project) } + let(:new_project) { create(:project) } let(:milestone1) { create(:milestone, project_id: old_project.id, title: 'v9.0') } let(:old_issue) do diff --git a/spec/services/issues/reopen_service_spec.rb b/spec/services/issues/reopen_service_spec.rb index 1ff988e9b47..205e9ebd237 100644 --- a/spec/services/issues/reopen_service_spec.rb +++ b/spec/services/issues/reopen_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Issues::ReopenService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, :closed, project: project) } describe '#execute' do diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb index fac66791ffb..67a86c50fc1 100644 --- a/spec/services/issues/resolve_discussions_spec.rb +++ b/spec/services/issues/resolve_discussions_spec.rb @@ -20,7 +20,7 @@ describe Issues::ResolveDiscussions do describe "for resolving discussions" do let(:discussion) { create(:diff_note_on_merge_request, project: project, note: "Almost done").to_discussion } let(:merge_request) { discussion.noteable } - let(:other_merge_request) { create(:merge_request, source_project: project, source_branch: "other") } + let(:other_merge_request) { create(:merge_request, source_project: project, source_branch: "fix") } describe "#merge_request_for_resolving_discussion" do let(:service) { DummyService.new(project, user, merge_request_to_resolve_discussions_of: merge_request.iid) } diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb index eec2096fa34..34fb16edc84 100644 --- a/spec/services/issues/update_service_spec.rb +++ b/spec/services/issues/update_service_spec.rb @@ -1,13 +1,11 @@ # coding: utf-8 require 'spec_helper' -describe Issues::UpdateService do - include EmailHelpers - +describe Issues::UpdateService, :mailer do let(:user) { create(:user) } let(:user2) { create(:user) } let(:user3) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:label) { create(:label, project: project) } let(:label2) { create(:label) } @@ -480,7 +478,7 @@ describe Issues::UpdateService do feature_visibility_attr = :"#{issue.model_name.plural}_access_level" project.project_feature.update_attribute(feature_visibility_attr, ProjectFeature::PRIVATE) - expect{ update_issue(assignee_ids: [assignee.id]) }.not_to change{ issue.assignees } + expect { update_issue(assignee_ids: [assignee.id]) }.not_to change { issue.assignees } end end end diff --git a/spec/services/labels/create_service_spec.rb b/spec/services/labels/create_service_spec.rb index ecb88653001..438e6dbc628 100644 --- a/spec/services/labels/create_service_spec.rb +++ b/spec/services/labels/create_service_spec.rb @@ -4,7 +4,7 @@ describe Labels::CreateService do describe '#execute' do let(:project) { create(:project) } let(:group) { create(:group) } - + let(:hex_color) { '#FF0000' } let(:named_color) { 'red' } let(:upcase_color) { 'RED' } diff --git a/spec/services/labels/find_or_create_service_spec.rb b/spec/services/labels/find_or_create_service_spec.rb index 2d3a15a1c11..a781fbc7f7d 100644 --- a/spec/services/labels/find_or_create_service_spec.rb +++ b/spec/services/labels/find_or_create_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Labels::FindOrCreateService do describe '#execute' do let(:group) { create(:group) } - let(:project) { create(:empty_project, namespace: group) } + let(:project) { create(:project, namespace: group) } let(:params) do { diff --git a/spec/services/labels/promote_service_spec.rb b/spec/services/labels/promote_service_spec.rb index 7cea877ad88..8809b282127 100644 --- a/spec/services/labels/promote_service_spec.rb +++ b/spec/services/labels/promote_service_spec.rb @@ -5,7 +5,7 @@ describe Labels::PromoteService do let!(:user) { create(:user) } context 'project without group' do - let!(:project_1) { create(:empty_project) } + let!(:project_1) { create(:project) } let!(:project_label_1_1) { create(:label, project: project_1) } @@ -27,10 +27,10 @@ describe Labels::PromoteService do let!(:group_1) { create(:group) } let!(:group_2) { create(:group) } - let!(:project_1) { create(:empty_project, namespace: group_1) } - let!(:project_2) { create(:empty_project, namespace: group_1) } - let!(:project_3) { create(:empty_project, namespace: group_1) } - let!(:project_4) { create(:empty_project, namespace: group_2) } + let!(:project_1) { create(:project, namespace: group_1) } + let!(:project_2) { create(:project, namespace: group_1) } + let!(:project_3) { create(:project, namespace: group_1) } + let!(:project_4) { create(:project, namespace: group_2) } # Labels/issues can't be lazily created so we might as well eager initialize # all other objects too since we use them inside diff --git a/spec/services/labels/transfer_service_spec.rb b/spec/services/labels/transfer_service_spec.rb index f70edd3d16e..ae819c011de 100644 --- a/spec/services/labels/transfer_service_spec.rb +++ b/spec/services/labels/transfer_service_spec.rb @@ -6,8 +6,8 @@ describe Labels::TransferService do let(:group_1) { create(:group) } let(:group_2) { create(:group) } let(:group_3) { create(:group) } - let(:project_1) { create(:empty_project, namespace: group_2) } - let(:project_2) { create(:empty_project, namespace: group_3) } + let(:project_1) { create(:project, namespace: group_2) } + let(:project_2) { create(:project, namespace: group_3) } let(:group_label_1) { create(:group_label, group: group_1, name: 'Group Label 1') } let(:group_label_2) { create(:group_label, group: group_1, name: 'Group Label 2') } diff --git a/spec/services/labels/update_service_spec.rb b/spec/services/labels/update_service_spec.rb index bb95fe20fbf..c3fe33045fa 100644 --- a/spec/services/labels/update_service_spec.rb +++ b/spec/services/labels/update_service_spec.rb @@ -13,7 +13,7 @@ describe Labels::UpdateService do let(:expected_saved_color) { hex_color } - before(:each) do + before do @label = Labels::CreateService.new(title: 'Initial', color: '#000000').execute(project: project) expect(@label).to be_persisted end diff --git a/spec/services/members/approve_access_request_service_spec.rb b/spec/services/members/approve_access_request_service_spec.rb index ddba96b8d03..302c488d6c6 100644 --- a/spec/services/members/approve_access_request_service_spec.rb +++ b/spec/services/members/approve_access_request_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Members::ApproveAccessRequestService do let(:user) { create(:user) } let(:access_requester) { create(:user) } - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) { create(:project, :public, :access_requestable) } let(:group) { create(:group, :public, :access_requestable) } let(:opts) { {} } diff --git a/spec/services/members/authorized_destroy_service_spec.rb b/spec/services/members/authorized_destroy_service_spec.rb index f0abbc46ca3..2d04d824180 100644 --- a/spec/services/members/authorized_destroy_service_spec.rb +++ b/spec/services/members/authorized_destroy_service_spec.rb @@ -2,9 +2,9 @@ require 'spec_helper' describe Members::AuthorizedDestroyService do let(:member_user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:group) { create(:group, :public) } - let(:group_project) { create(:empty_project, :public, group: group) } + let(:group_project) { create(:project, :public, group: group) } def number_of_assigned_issuables(user) Issue.assigned_to(user).count + MergeRequest.assigned_to(user).count diff --git a/spec/services/members/create_service_spec.rb b/spec/services/members/create_service_spec.rb index c73a229823d..2a793e0eb4d 100644 --- a/spec/services/members/create_service_spec.rb +++ b/spec/services/members/create_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Members::CreateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:project_user) { create(:user) } diff --git a/spec/services/members/destroy_service_spec.rb b/spec/services/members/destroy_service_spec.rb index 0e30b343eaf..72f5e27180d 100644 --- a/spec/services/members/destroy_service_spec.rb +++ b/spec/services/members/destroy_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Members::DestroyService do let(:user) { create(:user) } let(:member_user) { create(:user) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:group) { create(:group, :public) } shared_examples 'a service raising ActiveRecord::RecordNotFound' do diff --git a/spec/services/members/request_access_service_spec.rb b/spec/services/members/request_access_service_spec.rb index f39d4f47904..0a704bba521 100644 --- a/spec/services/members/request_access_service_spec.rb +++ b/spec/services/members/request_access_service_spec.rb @@ -29,7 +29,7 @@ describe Members::RequestAccessService do end context 'when current user cannot request access to the project' do - %i[empty_project group].each do |source_type| + %i[project group].each do |source_type| it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do let(:source) { create(source_type, :private) } end @@ -37,7 +37,7 @@ describe Members::RequestAccessService do end context 'when access requests are disabled' do - %i[empty_project group].each do |source_type| + %i[project group].each do |source_type| it_behaves_like 'a service raising Gitlab::Access::AccessDeniedError' do let(:source) { create(source_type, :public) } end @@ -45,7 +45,7 @@ describe Members::RequestAccessService do end context 'when current user can request access to the project' do - %i[empty_project group].each do |source_type| + %i[project group].each do |source_type| it_behaves_like 'a service creating a access request' do let(:source) { create(source_type, :public, :access_requestable) } end diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index ea192e51f89..b46c419de14 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -264,8 +264,8 @@ describe MergeRequests::BuildService do end context 'upstream project has disabled merge requests' do - let(:upstream_project) { create(:empty_project, :merge_requests_disabled) } - let(:project) { create(:empty_project, forked_from_project: upstream_project) } + let(:upstream_project) { create(:project, :merge_requests_disabled) } + let(:project) { create(:project, forked_from_project: upstream_project) } let(:commits) { Commit.decorate([commit_1], project) } it 'sets target project correctly' do diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb index 672d86e4028..25599dea19f 100644 --- a/spec/services/merge_requests/get_urls_service_spec.rb +++ b/spec/services/merge_requests/get_urls_service_spec.rb @@ -3,7 +3,7 @@ require "spec_helper" describe MergeRequests::GetUrlsService do let(:project) { create(:project, :public, :repository) } let(:service) { described_class.new(project) } - let(:source_branch) { "my_branch" } + let(:source_branch) { "merge-test" } let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{source_branch}" } let(:show_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/#{merge_request.iid}" } let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" } @@ -111,9 +111,9 @@ describe MergeRequests::GetUrlsService do end context 'pushing new branch and existing branch (with merge request created) at once' do - let!(:merge_request) { create(:merge_request, source_project: project, source_branch: "existing_branch") } + let!(:merge_request) { create(:merge_request, source_project: project, source_branch: "markdown") } let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" } - let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/existing_branch" } + let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/markdown" } let(:changes) { "#{new_branch_changes}\n#{existing_branch_changes}" } let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" } @@ -124,7 +124,7 @@ describe MergeRequests::GetUrlsService do url: new_merge_request_url, new_merge_request: true }, { - branch_name: "existing_branch", + branch_name: "markdown", url: show_merge_request_url, new_merge_request: false }]) diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index dd3ac9c4ac6..681feee61d1 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe MergeRequests::UpdateService do - include EmailHelpers - +describe MergeRequests::UpdateService, :mailer do let(:project) { create(:project, :repository) } let(:user) { create(:user) } let(:user2) { create(:user) } @@ -511,7 +509,7 @@ describe MergeRequests::UpdateService do feature_visibility_attr = :"#{merge_request.model_name.plural}_access_level" project.project_feature.update_attribute(feature_visibility_attr, ProjectFeature::PRIVATE) - expect{ update_merge_request(assignee_id: assignee) }.not_to change{ merge_request.assignee } + expect { update_merge_request(assignee_id: assignee) }.not_to change { merge_request.assignee } end end end diff --git a/spec/services/milestones/close_service_spec.rb b/spec/services/milestones/close_service_spec.rb index fa0686d8061..2bdf224804d 100644 --- a/spec/services/milestones/close_service_spec.rb +++ b/spec/services/milestones/close_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Milestones::CloseService do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:milestone) { create(:milestone, title: "Milestone v1.2", project: project) } before do diff --git a/spec/services/milestones/create_service_spec.rb b/spec/services/milestones/create_service_spec.rb index c6fe8e65912..8837b91051d 100644 --- a/spec/services/milestones/create_service_spec.rb +++ b/spec/services/milestones/create_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Milestones::CreateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } describe '#execute' do diff --git a/spec/services/note_summary_spec.rb b/spec/services/note_summary_spec.rb index dda579c7080..a6cc2251e48 100644 --- a/spec/services/note_summary_spec.rb +++ b/spec/services/note_summary_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe NoteSummary do - let(:project) { build(:empty_project) } + let(:project) { build(:project) } let(:noteable) { build(:issue) } let(:user) { build(:user) } diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb index c08a5a940bb..661d26946e7 100644 --- a/spec/services/notes/create_service_spec.rb +++ b/spec/services/notes/create_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Notes::CreateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } let(:opts) do diff --git a/spec/services/notes/destroy_service_spec.rb b/spec/services/notes/destroy_service_spec.rb index 4330190caaa..c9a99a43edb 100644 --- a/spec/services/notes/destroy_service_spec.rb +++ b/spec/services/notes/destroy_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Notes::DestroyService do describe '#execute' do it 'deletes a note' do - project = create(:empty_project) + project = create(:project) issue = create(:issue, project: project) note = create(:note, project: project, noteable: issue) diff --git a/spec/services/notes/post_process_service_spec.rb b/spec/services/notes/post_process_service_spec.rb index bf9320e5fce..a2b3638059f 100644 --- a/spec/services/notes/post_process_service_spec.rb +++ b/spec/services/notes/post_process_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Notes::PostProcessService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:user) { create(:user) } diff --git a/spec/services/notes/quick_actions_service_spec.rb b/spec/services/notes/quick_actions_service_spec.rb index fc4cd3dc2b7..0280a19098b 100644 --- a/spec/services/notes/quick_actions_service_spec.rb +++ b/spec/services/notes/quick_actions_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Notes::QuickActionsService do shared_context 'note on noteable' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:master) { create(:user).tap { |u| project.team << [u, :master] } } let(:assignee) { create(:user) } @@ -225,7 +225,7 @@ describe Notes::QuickActionsService do context 'CE restriction for issue assignees' do describe '/assign' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:master) { create(:user).tap { |u| project.team << [u, :master] } } let(:assignee) { create(:user) } let(:master) { create(:user) } diff --git a/spec/services/notes/update_service_spec.rb b/spec/services/notes/update_service_spec.rb index dea2dc02d00..3210539f3ee 100644 --- a/spec/services/notes/update_service_spec.rb +++ b/spec/services/notes/update_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Notes::UpdateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:user2) { create(:user) } let(:user3) { create(:user) } diff --git a/spec/services/notification_recipient_service_spec.rb b/spec/services/notification_recipient_service_spec.rb deleted file mode 100644 index 77233dc1b2f..00000000000 --- a/spec/services/notification_recipient_service_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'spec_helper' - -describe NotificationRecipientService do - set(:user) { create(:user) } - set(:project) { create(:empty_project, :public) } - set(:issue) { create(:issue, project: project) } - - set(:watcher) do - watcher = create(:user) - setting = watcher.notification_settings_for(project) - setting.level = :watch - setting.save - - watcher - end - - subject { described_class.new(project) } - - describe '#build_recipients' do - it 'does not modify the participants of the target' do - expect { subject.build_recipients(issue, user, action: :new_issue) } - .not_to change { issue.participants(user) } - end - end - - describe '#build_new_note_recipients' do - set(:note) { create(:note_on_issue, noteable: issue, project: project) } - - it 'does not modify the participants of the target' do - expect { subject.build_new_note_recipients(note) } - .not_to change { note.noteable.participants(note.author) } - end - end -end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 49d6fc7853f..44b2d28d1d4 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -1,12 +1,10 @@ require 'spec_helper' -describe NotificationService do - include EmailHelpers - +describe NotificationService, :mailer do let(:notification) { described_class.new } let(:assignee) { create(:user) } - around(:each) do |example| + around do |example| perform_enqueued_jobs do example.run end @@ -14,7 +12,6 @@ describe NotificationService do shared_examples 'notifications for new mentions' do def send_notifications(*new_mentions) - reset_delivered_emails! notification.send(notification_method, mentionable, new_mentions, @u_disabled) end @@ -83,12 +80,16 @@ describe NotificationService do describe 'Keys' do describe '#new_key' do - let!(:key) { create(:personal_key) } + let(:key_options) { {} } + let!(:key) { create(:personal_key, key_options) } it { expect(notification.new_key(key)).to be_truthy } + it { should_email(key.user) } - it 'sends email to key owner' do - expect{ notification.new_key(key) }.to change{ ActionMailer::Base.deliveries.size }.by(1) + describe 'never emails the ghost user' do + let(:key_options) { { user: User.ghost } } + + it { should_not_email_anyone } end end end @@ -100,7 +101,7 @@ describe NotificationService do it { expect(notification.new_gpg_key(key)).to be_truthy } it 'sends email to key owner' do - expect{ notification.new_gpg_key(key) }.to change{ ActionMailer::Base.deliveries.size }.by(1) + expect { notification.new_gpg_key(key) }.to change { ActionMailer::Base.deliveries.size }.by(1) end end end @@ -112,14 +113,14 @@ describe NotificationService do it { expect(notification.new_email(email)).to be_truthy } it 'sends email to email owner' do - expect{ notification.new_email(email) }.to change{ ActionMailer::Base.deliveries.size }.by(1) + expect { notification.new_email(email) }.to change { ActionMailer::Base.deliveries.size }.by(1) end end end describe 'Notes' do context 'issue note' do - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:issue) { create(:issue, project: project, assignees: [assignee]) } let(:mentioned_issue) { create(:issue, assignees: issue.assignees) } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced, @outsider also') } @@ -137,12 +138,11 @@ describe NotificationService do describe '#new_note' do it do add_users_with_subscription(note.project, issue) + reset_delivered_emails! # Ensure create SentNotification by noteable = issue 6 times, not noteable = note expect(SentNotification).to receive(:record).with(issue, any_args).exactly(8).times - reset_delivered_emails! - notification.new_note(note) should_email(@u_watcher) @@ -165,9 +165,10 @@ describe NotificationService do it "emails the note author if they've opted into notifications about their activity" do add_users_with_subscription(note.project, issue) - note.author.notified_of_own_activity = true reset_delivered_emails! + note.author.notified_of_own_activity = true + notification.new_note(note) should_email(note.author) @@ -228,7 +229,7 @@ describe NotificationService do end context 'confidential issue note' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:author) { create(:user) } let(:assignee) { create(:user) } let(:non_member) { create(:user) } @@ -260,7 +261,7 @@ describe NotificationService do end context 'issue note mention' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project, assignees: [assignee]) } let(:mentioned_issue) { create(:issue, assignees: issue.assignees) } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') } @@ -303,12 +304,17 @@ describe NotificationService do end context 'project snippet note' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:snippet) { create(:project_snippet, project: project, author: create(:user)) } let(:note) { create(:note_on_project_snippet, noteable: snippet, project_id: snippet.project.id, note: '@all mentioned') } before do build_team(note.project) + + # make sure these users can read the project snippet! + project.add_guest(@u_guest_watcher) + project.add_guest(@u_guest_custom) + note.project.add_master(note.author) reset_delivered_emails! end @@ -464,8 +470,8 @@ describe NotificationService do describe 'Issues' do let(:group) { create(:group) } - let(:project) { create(:empty_project, :public, namespace: group) } - let(:another_project) { create(:empty_project, :public, namespace: group) } + let(:project) { create(:project, :public, namespace: group) } + let(:another_project) { create(:project, :public, namespace: group) } let(:issue) { create :issue, project: project, assignees: [assignee], description: 'cc @participant' } before do @@ -694,17 +700,6 @@ describe NotificationService do let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } } let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } } - it "emails subscribers of the issue's added labels only" do - notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled) - - should_not_email(subscriber_to_label_1) - should_not_email(subscriber_to_group_label_1) - should_not_email(subscriber_to_group_label_2_on_another_project) - should_email(subscriber_1_to_group_label_2) - should_email(subscriber_2_to_group_label_2) - should_email(subscriber_to_label_2) - end - it "emails the current user if they've opted into notifications about their activity" do subscriber_to_label_2.notified_of_own_activity = true notification.relabeled_issue(issue, [group_label_2, label_2], subscriber_to_label_2) @@ -721,6 +716,12 @@ describe NotificationService do it "doesn't send email to anyone but subscribers of the given labels" do notification.relabeled_issue(issue, [group_label_2, label_2], @u_disabled) + should_not_email(subscriber_to_label_1) + should_not_email(subscriber_to_group_label_1) + should_not_email(subscriber_to_group_label_2_on_another_project) + should_email(subscriber_1_to_group_label_2) + should_email(subscriber_2_to_group_label_2) + should_email(subscriber_to_label_2) should_not_email(issue.assignees.first) should_not_email(issue.author) should_not_email(@u_watcher) @@ -730,12 +731,6 @@ describe NotificationService do should_not_email(@watcher_and_subscriber) should_not_email(@unsubscriber) should_not_email(@u_participating) - should_not_email(subscriber_to_label_1) - should_not_email(subscriber_to_group_label_1) - should_not_email(subscriber_to_group_label_2_on_another_project) - should_email(subscriber_1_to_group_label_2) - should_email(subscriber_2_to_group_label_2) - should_email(subscriber_to_label_2) end context 'confidential issues' do @@ -866,7 +861,7 @@ describe NotificationService do describe 'Merge Requests' do let(:group) { create(:group) } let(:project) { create(:project, :public, :repository, namespace: group) } - let(:another_project) { create(:empty_project, :public, namespace: group) } + let(:another_project) { create(:project, :public, namespace: group) } let(:merge_request) { create :merge_request, source_project: project, assignee: create(:user), description: 'cc @participant' } before do @@ -878,11 +873,6 @@ describe NotificationService do end describe '#new_merge_request' do - before do - update_custom_notification(:new_merge_request, @u_guest_custom, resource: project) - update_custom_notification(:new_merge_request, @u_custom_global) - end - it do notification.new_merge_request(merge_request, @u_disabled) @@ -1008,7 +998,7 @@ describe NotificationService do let!(:subscriber_to_label_1) { create(:user) { |u| label_1.toggle_subscription(u, project) } } let!(:subscriber_to_label_2) { create(:user) { |u| label_2.toggle_subscription(u, project) } } - it "emails subscribers of the merge request's added labels only" do + it "doesn't send email to anyone but subscribers of the given labels" do notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled) should_not_email(subscriber_to_label_1) @@ -1017,11 +1007,6 @@ describe NotificationService do should_email(subscriber_1_to_group_label_2) should_email(subscriber_2_to_group_label_2) should_email(subscriber_to_label_2) - end - - it "doesn't send email to anyone but subscribers of the given labels" do - notification.relabeled_merge_request(merge_request, [group_label_2, label_2], @u_disabled) - should_not_email(merge_request.assignee) should_not_email(merge_request.author) should_not_email(@u_watcher) @@ -1031,12 +1016,6 @@ describe NotificationService do should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_lazy_participant) - should_not_email(subscriber_to_label_1) - should_not_email(subscriber_to_group_label_1) - should_not_email(subscriber_to_group_label_2_on_another_project) - should_email(subscriber_1_to_group_label_2) - should_email(subscriber_2_to_group_label_2) - should_email(subscriber_to_label_2) end end @@ -1081,12 +1060,12 @@ describe NotificationService do should_email(merge_request.assignee) should_email(@u_watcher) + should_email(@u_guest_watcher) + should_email(@u_guest_custom) + should_email(@u_custom_global) should_email(@u_participant_mentioned) should_email(@subscriber) should_email(@watcher_and_subscriber) - should_email(@u_guest_watcher) - should_email(@u_custom_global) - should_email(@u_guest_custom) should_not_email(@unsubscriber) should_not_email(@u_participating) should_not_email(@u_disabled) @@ -1177,7 +1156,7 @@ describe NotificationService do end describe 'Projects' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do build_team(project) @@ -1198,19 +1177,39 @@ describe NotificationService do end end - describe '#project_exported' do - it do - notification.project_exported(project, @u_disabled) + context 'user with notifications disabled' do + describe '#project_exported' do + it do + notification.project_exported(project, @u_disabled) - should_only_email(@u_disabled) + should_not_email_anyone + end + end + + describe '#project_not_exported' do + it do + notification.project_not_exported(project, @u_disabled, ['error']) + + should_not_email_anyone + end end end - describe '#project_not_exported' do - it do - notification.project_not_exported(project, @u_disabled, ['error']) + context 'user with notifications enabled' do + describe '#project_exported' do + it do + notification.project_exported(project, @u_participating) + + should_only_email(@u_participating) + end + end + + describe '#project_not_exported' do + it do + notification.project_not_exported(project, @u_participating, ['error']) - should_only_email(@u_disabled) + should_only_email(@u_participating) + end end end end @@ -1221,7 +1220,7 @@ describe NotificationService do let(:group) { create(:group) } let(:member) { create(:user) } - before(:each) do + before do group.add_owner(creator) group.add_developer(member, creator) end @@ -1234,14 +1233,43 @@ describe NotificationService do end.to change { ActionMailer::Base.deliveries.size }.by(1) end end + + describe '#new_group_member' do + let(:group) { create(:group) } + let(:added_user) { create(:user) } + + def create_member! + GroupMember.create( + group: group, + user: added_user, + access_level: Gitlab::Access::GUEST + ) + end + + it 'sends a notification' do + create_member! + should_only_email(added_user) + end + + describe 'when notifications are disabled' do + before do + create_global_setting_for(added_user, :disabled) + end + + it 'does not send a notification' do + create_member! + should_not_email_anyone + end + end + end end describe 'ProjectMember' do describe '#decline_group_invite' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:member) { create(:user) } - before(:each) do + before do project.add_developer(member, current_user: project.owner) end @@ -1253,10 +1281,35 @@ describe NotificationService do end.to change { ActionMailer::Base.deliveries.size }.by(1) end end + + describe '#new_project_member' do + let(:project) { create(:project) } + let(:added_user) { create(:user) } + + def create_member! + create(:project_member, user: added_user, project: project) + end + + it do + create_member! + should_only_email(added_user) + end + + describe 'when notifications are disabled' do + before do + create_global_setting_for(added_user, :disabled) + end + + it do + create_member! + should_not_email_anyone + end + end + end end context 'guest user in private project' do - let(:private_project) { create(:empty_project, :private) } + let(:private_project) { create(:project, :private) } let(:guest) { create(:user) } let(:developer) { create(:user) } let(:assignee) { create(:user) } diff --git a/spec/services/preview_markdown_service_spec.rb b/spec/services/preview_markdown_service_spec.rb index 4fd9cb23ae1..64a9559791f 100644 --- a/spec/services/preview_markdown_service_spec.rb +++ b/spec/services/preview_markdown_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe PreviewMarkdownService do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } before do project.add_developer(user) diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb index fc7238862ab..426593be428 100644 --- a/spec/services/projects/autocomplete_service_spec.rb +++ b/spec/services/projects/autocomplete_service_spec.rb @@ -8,7 +8,7 @@ describe Projects::AutocompleteService do let(:non_member) { create(:user) } let(:member) { create(:user) } let(:admin) { create(:admin) } - let(:project) { create(:empty_project, :public) } + let(:project) { create(: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, assignees: [assignee]) } @@ -88,4 +88,31 @@ describe Projects::AutocompleteService do end end end + + describe '#milestones' do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:project) { create(:project, group: group) } + let!(:group_milestone) { create(:milestone, group: group) } + let!(:project_milestone) { create(:milestone, project: project) } + + let(:milestone_titles) { described_class.new(project, user).milestones.map(&:title) } + + it 'includes project and group milestones' do + expect(milestone_titles).to eq([group_milestone.title, project_milestone.title]) + end + + it 'does not include closed milestones' do + group_milestone.close + + expect(milestone_titles).to eq([project_milestone.title]) + end + + it 'does not include milestones from other projects in the group' do + other_project = create(:project, group: group) + project_milestone.update!(project: other_project) + + expect(milestone_titles).to eq([group_milestone.title]) + end + end end diff --git a/spec/services/projects/create_from_template_service_spec.rb b/spec/services/projects/create_from_template_service_spec.rb new file mode 100644 index 00000000000..9919ec254c6 --- /dev/null +++ b/spec/services/projects/create_from_template_service_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe Projects::CreateFromTemplateService do + let(:user) { create(:user) } + let(:project_params) do + { + path: user.to_param, + template_name: 'rails' + } + end + + subject { described_class.new(user, project_params) } + + it 'calls the importer service' do + expect_any_instance_of(Projects::GitlabProjectsImportService).to receive(:execute) + + subject.execute + end + + it 'returns the project thats created' do + project = subject.execute + + expect(project).to be_saved + expect(project.scheduled?).to be(true) + end +end diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 85b05ef6d05..c867139d1de 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -142,13 +142,13 @@ describe Projects::DestroyService do context 'when `execute` raises unexpected error' do before do expect_any_instance_of(Project) - .to receive(:destroy!).and_raise(Exception.new("Other error message")) + .to receive(:destroy!).and_raise(Exception.new('Other error message')) end it 'allows error to bubble up and rolls back project deletion' do expect do Sidekiq::Testing.inline! { destroy_project(project, user, {}) } - end.to raise_error + end.to raise_error(Exception, 'Other error message') expect(project.reload.pending_delete).to be(false) expect(project.delete_error).to include("Other error message") diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb index 701f6cc8c6a..da236052ebf 100644 --- a/spec/services/projects/download_service_spec.rb +++ b/spec/services/projects/download_service_spec.rb @@ -4,7 +4,7 @@ describe Projects::DownloadService do describe 'File service' do before do @user = create(:user) - @project = create(:empty_project, creator_id: @user.id, namespace: @user.namespace) + @project = create(:project, creator_id: @user.id, namespace: @user.namespace) end context 'for a URL that is not on whitelist' do diff --git a/spec/services/projects/enable_deploy_key_service_spec.rb b/spec/services/projects/enable_deploy_key_service_spec.rb index 9b8c24ba112..835dae68fcd 100644 --- a/spec/services/projects/enable_deploy_key_service_spec.rb +++ b/spec/services/projects/enable_deploy_key_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::EnableDeployKeyService do let(:deploy_key) { create(:deploy_key, public: true) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { project.creator} let!(:params) { { key_id: deploy_key.id } } diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index c90536ba346..21c4b30734c 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -50,6 +50,14 @@ describe Projects::ForkService do expect(@from_project.avatar.file).to be_exists end + + it 'flushes the forks count cache of the source project' do + expect(@from_project.forks_count).to be_zero + + fork_project(@from_project, @to_user) + + expect(@from_project.forks_count).to eq(1) + end end end diff --git a/spec/services/projects/forks_count_service_spec.rb b/spec/services/projects/forks_count_service_spec.rb new file mode 100644 index 00000000000..cf299c5d09b --- /dev/null +++ b/spec/services/projects/forks_count_service_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Projects::ForksCountService do + let(:project) { build(:project, id: 42) } + let(:service) { described_class.new(project) } + + describe '#count' do + it 'returns the number of forks' do + allow(service).to receive(:uncached_count).and_return(1) + + expect(service.count).to eq(1) + end + + it 'caches the forks count', :use_clean_rails_memory_store_caching do + expect(service).to receive(:uncached_count).once.and_return(1) + + 2.times { service.count } + end + end + + describe '#refresh_cache', :use_clean_rails_memory_store_caching do + it 'refreshes the cache' do + expect(service).to receive(:uncached_count).once.and_return(1) + + service.refresh_cache + + expect(service.count).to eq(1) + end + end + + describe '#delete_cache', :use_clean_rails_memory_store_caching do + it 'removes the cache' do + expect(service).to receive(:uncached_count).twice.and_return(1) + + service.count + service.delete_cache + service.count + end + end +end diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb index ebed802708d..385f56e447f 100644 --- a/spec/services/projects/housekeeping_service_spec.rb +++ b/spec/services/projects/housekeeping_service_spec.rb @@ -24,7 +24,7 @@ describe Projects::HousekeepingService do end context 'when no lease can be obtained' do - before(:each) do + before do expect(subject).to receive(:try_obtain_lease).and_return(false) end diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index 67fe610f92a..034065aab00 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::ImportService do - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let(:user) { project.creator } subject { described_class.new(project, user) } @@ -26,7 +26,7 @@ describe Projects::ImportService do result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The repository could not be created." + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - The repository could not be created." end end @@ -38,8 +38,7 @@ describe Projects::ImportService do context 'with a Github repository' do it 'succeeds if repository import is successfully' do - expect_any_instance_of(Repository).to receive(:fetch_remote).and_return(true) - expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(true) + expect_any_instance_of(Github::Import).to receive(:execute).and_return(true) result = subject.execute @@ -52,16 +51,7 @@ describe Projects::ImportService do result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Failed to import the repository" - end - - it 'does not remove the GitHub remote' do - expect_any_instance_of(Repository).to receive(:fetch_remote).and_return(true) - expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(true) - - subject.execute - - expect(project.repository.raw_repository.remote_names).to include('github') + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The remote data could not be imported." end end @@ -86,7 +76,7 @@ describe Projects::ImportService do result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Failed to import the repository" + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Failed to import the repository" end end end @@ -102,8 +92,7 @@ describe Projects::ImportService do end it 'succeeds if importer succeeds' do - allow_any_instance_of(Repository).to receive(:fetch_remote).and_return(true) - allow_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(true) + allow_any_instance_of(Github::Import).to receive(:execute).and_return(true) result = subject.execute @@ -111,10 +100,7 @@ describe Projects::ImportService do end it 'flushes various caches' do - allow_any_instance_of(Repository).to receive(:fetch_remote) - .and_return(true) - - allow_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute) + allow_any_instance_of(Github::Import).to receive(:execute) .and_return(true) expect_any_instance_of(Repository).to receive(:expire_content_cache) @@ -123,29 +109,27 @@ describe Projects::ImportService do end it 'fails if importer fails' do - allow_any_instance_of(Repository).to receive(:fetch_remote).and_return(true) - allow_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(false) + allow_any_instance_of(Github::Import).to receive(:execute).and_return(false) result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The remote data could not be imported." + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - The remote data could not be imported." end it 'fails if importer raise an error' do - allow_any_instance_of(Gitlab::Shell).to receive(:fetch_remote).and_return(true) - allow_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_raise(Projects::ImportService::Error.new('Github: failed to connect API')) + allow_any_instance_of(Github::Import).to receive(:execute).and_raise(Projects::ImportService::Error.new('Github: failed to connect API')) result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Github: failed to connect API" + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Github: failed to connect API" end it 'expires content cache after error' do - allow_any_instance_of(Project).to receive(:repository_exists?).and_return(false, true) + allow_any_instance_of(Project).to receive(:repository_exists?).and_return(false) - expect_any_instance_of(Gitlab::Shell).to receive(:fetch_remote).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) + expect_any_instance_of(Repository).to receive(:fetch_remote).and_raise(Gitlab::Shell::Error.new) expect_any_instance_of(Repository).to receive(:expire_content_cache) subject.execute diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb index 8777e63a101..0d18ceb8ff8 100644 --- a/spec/services/projects/participants_service_spec.rb +++ b/spec/services/projects/participants_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Projects::ParticipantsService do describe '#groups' do describe 'avatar_url' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:group) { create(:group, avatar: fixture_file_upload(Rails.root + 'spec/fixtures/dk.png')) } let(:user) { create(:user) } let!(:group_member) { create(:group_member, group: group, user: user) } diff --git a/spec/services/projects/propagate_service_template_spec.rb b/spec/services/projects/propagate_service_template_spec.rb index 2763437f184..f4c59735c43 100644 --- a/spec/services/projects/propagate_service_template_spec.rb +++ b/spec/services/projects/propagate_service_template_spec.rb @@ -15,7 +15,7 @@ describe Projects::PropagateServiceTemplate do }) end - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } it 'creates services for projects' do expect(project.pushover_service).to be_nil @@ -76,7 +76,7 @@ describe Projects::PropagateServiceTemplate do before do stub_const 'Projects::PropagateServiceTemplate::BATCH_SIZE', 3 - project_total.times { create(:empty_project) } + project_total.times { create(:project) } described_class.propagate(service_template) end diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index ae32e85b2a7..2cb60cbcfc4 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -37,18 +37,18 @@ describe Projects::TransferService do end it 'executes system hooks' do - expect_any_instance_of(described_class).to receive(:execute_system_hooks) - - transfer_project(project, user, group) + transfer_project(project, user, group) do |service| + expect(service).to receive(:execute_system_hooks) + end end end context 'when transfer fails' do let!(:original_path) { project_path(project) } - def attempt_project_transfer + def attempt_project_transfer(&block) expect do - transfer_project(project, user, group) + transfer_project(project, user, group, &block) end.to raise_error(ActiveRecord::ActiveRecordError) end @@ -59,7 +59,7 @@ describe Projects::TransferService do end def project_path(project) - File.join(project.repository_storage_path, "#{project.path_with_namespace}.git") + File.join(project.repository_storage_path, "#{project.disk_path}.git") end def current_path @@ -80,9 +80,9 @@ describe Projects::TransferService do end it "doesn't run system hooks" do - expect_any_instance_of(described_class).not_to receive(:execute_system_hooks) - - attempt_project_transfer + attempt_project_transfer do |service| + expect(service).not_to receive(:execute_system_hooks) + end end end @@ -120,7 +120,11 @@ describe Projects::TransferService do end def transfer_project(project, user, new_namespace) - Projects::TransferService.new(project, user).execute(new_namespace) + service = Projects::TransferService.new(project, user) + + yield(service) if block_given? + + service.execute(new_namespace) end context 'visibility level' do diff --git a/spec/services/projects/unlink_fork_service_spec.rb b/spec/services/projects/unlink_fork_service_spec.rb index 2ae8d5f7c54..4f1ab697460 100644 --- a/spec/services/projects/unlink_fork_service_spec.rb +++ b/spec/services/projects/unlink_fork_service_spec.rb @@ -29,4 +29,14 @@ describe Projects::UnlinkForkService do subject.execute end + + it 'refreshes the forks count cache of the source project' do + source = fork_project.forked_from_project + + expect(source.forks_count).to eq(1) + + subject.execute + + expect(source.forks_count).to be_zero + end end diff --git a/spec/services/projects/update_pages_configuration_service_spec.rb b/spec/services/projects/update_pages_configuration_service_spec.rb index 42925e73978..e4d4e6ff3dd 100644 --- a/spec/services/projects/update_pages_configuration_service_spec.rb +++ b/spec/services/projects/update_pages_configuration_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::UpdatePagesConfigurationService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } subject { described_class.new(project) } describe "#update" do diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index d7b0df9a671..1b282e82187 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -5,7 +5,7 @@ describe Projects::UpdateService, '#execute' do let(:admin) { create(:admin) } let(:project) do - create(:empty_project, creator: user, namespace: user.namespace) + create(:project, creator: user, namespace: user.namespace) end context 'when changing visibility level' do @@ -59,7 +59,7 @@ describe Projects::UpdateService, '#execute' do end describe 'when updating project that has forks' do - let(:project) { create(:empty_project, :internal) } + let(:project) { create(:project, :internal) } let(:forked_project) { create(:forked_project_with_submodules, :internal) } before do @@ -101,6 +101,13 @@ describe Projects::UpdateService, '#execute' do expect(Project.find(project.id).default_branch).to eq 'feature' end + + it 'does not change a default branch' do + # The branch 'unexisted-branch' does not exist. + update_project(project, admin, default_branch: 'unexisted-branch') + + expect(Project.find(project.id).default_branch).to eq 'master' + end end context 'when updating a project that contains container images' do diff --git a/spec/services/protected_branches/create_service_spec.rb b/spec/services/protected_branches/create_service_spec.rb index 592f9b5929e..835e83d6dba 100644 --- a/spec/services/protected_branches/create_service_spec.rb +++ b/spec/services/protected_branches/create_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProtectedBranches::CreateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { project.owner } let(:params) do { diff --git a/spec/services/protected_branches/update_service_spec.rb b/spec/services/protected_branches/update_service_spec.rb index 5698101af54..9fa5983db66 100644 --- a/spec/services/protected_branches/update_service_spec.rb +++ b/spec/services/protected_branches/update_service_spec.rb @@ -19,7 +19,7 @@ describe ProtectedBranches::UpdateService do let(:user) { create(:user) } it "raises error" do - expect{ service.execute(protected_branch) }.to raise_error(Gitlab::Access::AccessDeniedError) + expect { service.execute(protected_branch) }.to raise_error(Gitlab::Access::AccessDeniedError) end end end diff --git a/spec/services/protected_tags/create_service_spec.rb b/spec/services/protected_tags/create_service_spec.rb index 3a3cc9c1573..c3ed95aaebf 100644 --- a/spec/services/protected_tags/create_service_spec.rb +++ b/spec/services/protected_tags/create_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ProtectedTags::CreateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { project.owner } let(:params) do { diff --git a/spec/services/protected_tags/update_service_spec.rb b/spec/services/protected_tags/update_service_spec.rb index d333430088d..2ece4e3b07b 100644 --- a/spec/services/protected_tags/update_service_spec.rb +++ b/spec/services/protected_tags/update_service_spec.rb @@ -19,7 +19,7 @@ describe ProtectedTags::UpdateService do let(:user) { create(:user) } it "raises error" do - expect{ service.execute(protected_tag) }.to raise_error(Gitlab::Access::AccessDeniedError) + expect { service.execute(protected_tag) }.to raise_error(Gitlab::Access::AccessDeniedError) end end end diff --git a/spec/services/push_event_payload_service_spec.rb b/spec/services/push_event_payload_service_spec.rb new file mode 100644 index 00000000000..81956200bff --- /dev/null +++ b/spec/services/push_event_payload_service_spec.rb @@ -0,0 +1,218 @@ +require 'spec_helper' + +describe PushEventPayloadService do + let(:event) { create(:push_event) } + + describe '#execute' do + let(:push_data) do + { + commits: [ + { + id: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + message: 'This is a commit' + } + ], + before: '0000000000000000000000000000000000000000', + after: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2', + total_commits_count: 1, + ref: 'refs/heads/my-branch' + } + end + + it 'creates a new PushEventPayload row' do + payload = described_class.new(event, push_data).execute + + expect(payload.commit_count).to eq(1) + expect(payload.action).to eq('created') + expect(payload.ref_type).to eq('branch') + expect(payload.commit_from).to be_nil + expect(payload.commit_to).to eq(push_data[:after]) + expect(payload.ref).to eq('my-branch') + expect(payload.commit_title).to eq('This is a commit') + expect(payload.event_id).to eq(event.id) + end + + it 'sets the push_event_payload association of the used event' do + payload = described_class.new(event, push_data).execute + + expect(event.push_event_payload).to eq(payload) + end + end + + describe '#commit_title' do + it 'returns nil if no commits were pushed' do + service = described_class.new(event, commits: []) + + expect(service.commit_title).to be_nil + end + + it 'returns a String limited to 70 characters' do + service = described_class.new(event, commits: [{ message: 'a' * 100 }]) + + expect(service.commit_title).to eq(('a' * 67) + '...') + end + + it 'does not truncate the commit message if it is shorter than 70 characters' do + service = described_class.new(event, commits: [{ message: 'Hello' }]) + + expect(service.commit_title).to eq('Hello') + end + + it 'includes the first line of a commit message if the message spans multiple lines' do + service = described_class + .new(event, commits: [{ message: "Hello\n\nworld" }]) + + expect(service.commit_title).to eq('Hello') + end + end + + describe '#commit_from_id' do + it 'returns nil when creating a new ref' do + service = described_class.new(event, before: Gitlab::Git::BLANK_SHA) + + expect(service.commit_from_id).to be_nil + end + + it 'returns the ID of the first commit when pushing to an existing ref' do + service = described_class.new(event, before: '123') + + expect(service.commit_from_id).to eq('123') + end + end + + describe '#commit_to_id' do + it 'returns nil when removing an existing ref' do + service = described_class.new(event, after: Gitlab::Git::BLANK_SHA) + + expect(service.commit_to_id).to be_nil + end + end + + describe '#commit_count' do + it 'returns the number of commits' do + service = described_class.new(event, total_commits_count: 1) + + expect(service.commit_count).to eq(1) + end + + it 'raises when the push data does not contain the commits count' do + service = described_class.new(event, {}) + + expect { service.commit_count }.to raise_error(KeyError) + end + end + + describe '#ref' do + it 'returns the name of the ref' do + service = described_class.new(event, ref: 'refs/heads/foo') + + expect(service.ref).to eq('refs/heads/foo') + end + + it 'raises when the push data does not contain the ref name' do + service = described_class.new(event, {}) + + expect { service.ref }.to raise_error(KeyError) + end + end + + describe '#revision_before' do + it 'returns the revision from before the push' do + service = described_class.new(event, before: 'foo') + + expect(service.revision_before).to eq('foo') + end + + it 'raises when the push data does not contain the before revision' do + service = described_class.new(event, {}) + + expect { service.revision_before }.to raise_error(KeyError) + end + end + + describe '#revision_after' do + it 'returns the revision from after the push' do + service = described_class.new(event, after: 'foo') + + expect(service.revision_after).to eq('foo') + end + + it 'raises when the push data does not contain the after revision' do + service = described_class.new(event, {}) + + expect { service.revision_after }.to raise_error(KeyError) + end + end + + describe '#trimmed_ref' do + it 'returns the ref name without its prefix' do + service = described_class.new(event, ref: 'refs/heads/foo') + + expect(service.trimmed_ref).to eq('foo') + end + end + + describe '#create?' do + it 'returns true when creating a new ref' do + service = described_class.new(event, before: Gitlab::Git::BLANK_SHA) + + expect(service.create?).to eq(true) + end + + it 'returns false when pushing to an existing ref' do + service = described_class.new(event, before: 'foo') + + expect(service.create?).to eq(false) + end + end + + describe '#remove?' do + it 'returns true when removing an existing ref' do + service = described_class.new(event, after: Gitlab::Git::BLANK_SHA) + + expect(service.remove?).to eq(true) + end + + it 'returns false pushing to an existing ref' do + service = described_class.new(event, after: 'foo') + + expect(service.remove?).to eq(false) + end + end + + describe '#action' do + it 'returns :created when creating a ref' do + service = described_class.new(event, before: Gitlab::Git::BLANK_SHA) + + expect(service.action).to eq(:created) + end + + it 'returns :removed when removing an existing ref' do + service = described_class.new(event, + before: '123', + after: Gitlab::Git::BLANK_SHA) + + expect(service.action).to eq(:removed) + end + + it 'returns :pushed when pushing to an existing ref' do + service = described_class.new(event, before: '123', after: '456') + + expect(service.action).to eq(:pushed) + end + end + + describe '#ref_type' do + it 'returns :tag for a tag' do + service = described_class.new(event, ref: 'refs/tags/1.2') + + expect(service.ref_type).to eq(:tag) + end + + it 'returns :branch for a branch' do + service = described_class.new(event, ref: 'refs/heads/master') + + expect(service.ref_type).to eq(:branch) + end + end +end diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index 42a4a2591ea..30fa0ee6873 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe QuickActions::InterpretService do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:developer) { create(:user) } let(:developer2) { create(:user) } let(:issue) { create(:issue, project: project) } @@ -9,13 +9,13 @@ describe QuickActions::InterpretService do let(:inprogress) { create(:label, project: project, title: 'In Progress') } let(:bug) { create(:label, project: project, title: 'Bug') } let(:note) { build(:note, commit_id: merge_request.diff_head_sha) } + let(:service) { described_class.new(project, developer) } before do project.team << [developer, :developer] end describe '#execute' do - let(:service) { described_class.new(project, developer) } let(:merge_request) { create(:merge_request, source_project: project) } shared_examples 'reopen command' do @@ -270,6 +270,22 @@ describe QuickActions::InterpretService do end end + shared_examples 'shrug command' do + it 'appends ¯\_(ツ)_/¯ to the comment' do + new_content, _ = service.execute(content, issuable) + + expect(new_content).to end_with(described_class::SHRUG) + end + end + + shared_examples 'tableflip command' do + it 'appends (╯°□°)╯︵ â”»â”â”» to the comment' do + new_content, _ = service.execute(content, issuable) + + expect(new_content).to end_with(described_class::TABLEFLIP) + end + end + it_behaves_like 'reopen command' do let(:content) { '/reopen' } let(:issuable) { issue } @@ -408,6 +424,26 @@ describe QuickActions::InterpretService do end end + context 'assign command with me alias' do + let(:content) { "/assign me" } + + context 'Issue' do + it 'fetches assignee and populates assignee_ids if content contains /assign' do + _, updates = service.execute(content, issue) + + expect(updates).to eq(assignee_ids: [developer.id]) + end + end + + context 'Merge Request' do + it 'fetches assignee and populates assignee_ids if content contains /assign' do + _, updates = service.execute(content, merge_request) + + expect(updates).to eq(assignee_ids: [developer.id]) + end + end + end + it_behaves_like 'empty command' do let(:content) { '/assign @abcd1234' } let(:issuable) { issue } @@ -667,7 +703,7 @@ describe QuickActions::InterpretService do context 'cross project references' do it_behaves_like 'duplicate command' do - let(:other_project) { create(:empty_project, :public) } + let(:other_project) { create(:project, :public) } let(:issue_duplicate) { create(:issue, project: other_project) } let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" } let(:issuable) { issue } @@ -679,7 +715,7 @@ describe QuickActions::InterpretService do end it_behaves_like 'empty command' do - let(:other_project) { create(:empty_project, :private) } + let(:other_project) { create(:project, :private) } let(:issue_duplicate) { create(:issue, project: other_project) } let(:content) { "/duplicate #{issue_duplicate.to_reference(project)}" } @@ -775,6 +811,30 @@ describe QuickActions::InterpretService do end end + context '/shrug command' do + it_behaves_like 'shrug command' do + let(:content) { '/shrug people are people' } + let(:issuable) { issue } + end + + it_behaves_like 'shrug command' do + let(:content) { '/shrug' } + let(:issuable) { issue } + end + end + + context '/tableflip command' do + it_behaves_like 'tableflip command' do + let(:content) { '/tableflip curse your sudden but enviable betrayal' } + let(:issuable) { issue } + end + + it_behaves_like 'tableflip command' do + let(:content) { '/tableflip' } + let(:issuable) { issue } + end + end + context '/target_branch command' do let(:non_empty_project) { create(:project, :repository) } let(:another_merge_request) { create(:merge_request, author: developer, source_project: non_empty_project) } diff --git a/spec/services/search/global_service_spec.rb b/spec/services/search/global_service_spec.rb index de921573b1a..1309240b430 100644 --- a/spec/services/search/global_service_spec.rb +++ b/spec/services/search/global_service_spec.rb @@ -4,10 +4,10 @@ describe Search::GlobalService do let(:user) { create(:user) } let(:internal_user) { create(:user) } - let!(:found_project) { create(:empty_project, :private, name: 'searchable_project') } - let!(:unfound_project) { create(:empty_project, :private, name: 'unfound_project') } - let!(:internal_project) { create(:empty_project, :internal, name: 'searchable_internal_project') } - let!(:public_project) { create(:empty_project, :public, name: 'searchable_public_project') } + let!(:found_project) { create(:project, :private, name: 'searchable_project') } + let!(:unfound_project) { create(:project, :private, name: 'unfound_project') } + let!(:internal_project) { create(:project, :internal, name: 'searchable_internal_project') } + let!(:public_project) { create(:project, :public, name: 'searchable_public_project') } before do found_project.add_master(user) diff --git a/spec/services/search/group_service_spec.rb b/spec/services/search/group_service_spec.rb index cb3f02d2883..cbc553a60cf 100644 --- a/spec/services/search/group_service_spec.rb +++ b/spec/services/search/group_service_spec.rb @@ -8,14 +8,14 @@ describe Search::GroupService do let(:nested_group) { create(:group, :nested) } # These projects shouldn't be found - let!(:outside_project) { create(:empty_project, :public, name: "Outside #{term}") } - let!(:private_project) { create(:empty_project, :private, namespace: nested_group, name: "Private #{term}" )} - let!(:other_project) { create(:empty_project, :public, namespace: nested_group, name: term.reverse) } + let!(:outside_project) { create(:project, :public, name: "Outside #{term}") } + let!(:private_project) { create(:project, :private, namespace: nested_group, name: "Private #{term}" )} + let!(:other_project) { create(:project, :public, namespace: nested_group, name: term.reverse) } # These projects should be found - let!(:project1) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 1") } - let!(:project2) { create(:empty_project, :internal, namespace: nested_group, name: "Inner #{term} 2") } - let!(:project3) { create(:empty_project, :internal, namespace: nested_group.parent, name: "Outer #{term}") } + let!(:project1) { create(:project, :internal, namespace: nested_group, name: "Inner #{term} 1") } + let!(:project2) { create(:project, :internal, namespace: nested_group, name: "Inner #{term} 2") } + let!(:project3) { create(:project, :internal, namespace: nested_group.parent, name: "Outer #{term}") } let(:results) { described_class.new(user, search_group, search: term).execute } subject { results.objects('projects') } diff --git a/spec/services/search/snippet_service_spec.rb b/spec/services/search/snippet_service_spec.rb index 69438a3fa36..eae9bd4f5cf 100644 --- a/spec/services/search/snippet_service_spec.rb +++ b/spec/services/search/snippet_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Search::SnippetService do let(:author) { create(:author) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let!(:public_snippet) { create(:snippet, :public, content: 'password: XXX') } let!(:internal_snippet) { create(:snippet, :internal, content: 'password: XXX') } diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb index a6ef7561bc8..02de83a2df8 100644 --- a/spec/services/search_service_spec.rb +++ b/spec/services/search_service_spec.rb @@ -7,13 +7,13 @@ describe SearchService do let(:inaccessible_group) { create(:group, :private) } let!(:group_member) { create(:group_member, group: accessible_group, user: user) } - let!(:accessible_project) { create(:empty_project, :private, name: 'accessible_project') } - let!(:inaccessible_project) { create(:empty_project, :private, name: 'inaccessible_project') } + let!(:accessible_project) { create(:project, :private, name: 'accessible_project') } + let!(:inaccessible_project) { create(:project, :private, name: 'inaccessible_project') } let(:note) { create(:note_on_issue, project: accessible_project) } let(:snippet) { create(:snippet, author: user) } - let(:group_project) { create(:empty_project, group: accessible_group, name: 'group_project') } - let(:public_project) { create(:empty_project, :public, name: 'public_project') } + let(:group_project) { create(:project, group: accessible_group, name: 'group_project') } + let(:public_project) { create(:project, :public, name: 'public_project') } before do accessible_project.add_master(user) @@ -28,7 +28,7 @@ describe SearchService do end it 'returns the project for guests' do - search_project = create :empty_project + search_project = create :project search_project.add_guest(user) project = described_class.new(user, project_id: search_project.id).project diff --git a/spec/services/spam_service_spec.rb b/spec/services/spam_service_spec.rb index 46349c3e951..a14dfa3f01f 100644 --- a/spec/services/spam_service_spec.rb +++ b/spec/services/spam_service_spec.rb @@ -15,7 +15,7 @@ describe SpamService do end context 'when recaptcha was not verified' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:issue) { create(:issue, project: project) } let(:request) { double(:request, env: {}) } diff --git a/spec/services/submit_usage_ping_service_spec.rb b/spec/services/submit_usage_ping_service_spec.rb index 817fa4262d5..c8a6fc1a99b 100644 --- a/spec/services/submit_usage_ping_service_spec.rb +++ b/spec/services/submit_usage_ping_service_spec.rb @@ -46,6 +46,8 @@ describe SubmitUsagePingService do .by(1) expect(ConversationalDevelopmentIndex::Metric.last.leader_issues).to eq 10.2 + expect(ConversationalDevelopmentIndex::Metric.last.instance_issues).to eq 3.2 + expect(ConversationalDevelopmentIndex::Metric.last.percentage_issues).to eq 31.37 end end @@ -60,6 +62,7 @@ describe SubmitUsagePingService do conv_index: { leader_issues: 10.2, instance_issues: 3.2, + percentage_issues: 31.37, leader_notes: 25.3, instance_notes: 23.2, @@ -86,7 +89,9 @@ describe SubmitUsagePingService do instance_projects_prometheus_active: 0.30, leader_service_desk_issues: 15.8, - instance_service_desk_issues: 15.1 + instance_service_desk_issues: 15.1, + + non_existing_column: 'value' } } end diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index b2d9862e71e..8b5d9187785 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe SystemHooksService do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:project_member) { create(:project_member) } let(:key) { create(:key, user: user) } let(:deploy_key) { create(:key) } diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index cb59493c343..6d36affa9dc 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' describe SystemNoteService do include Gitlab::Routing - let(:project) { create(:empty_project) } + let(:group) { create(:group) } + let(:project) { create(:project, group: group) } let(:author) { create(:user) } let(:noteable) { create(:issue, project: project) } let(:issue) { noteable } @@ -34,7 +35,7 @@ describe SystemNoteService do context 'metadata' do it 'creates a new system note metadata record' do - expect { subject }.to change{ SystemNoteMetadata.count }.from(0).to(1) + expect { subject }.to change { SystemNoteMetadata.count }.from(0).to(1) end it 'creates a record correctly' do @@ -242,25 +243,51 @@ describe SystemNoteService do end describe '.change_milestone' do - subject { described_class.change_milestone(noteable, project, author, milestone) } + context 'for a project milestone' do + subject { described_class.change_milestone(noteable, project, author, milestone) } - let(:milestone) { create(:milestone, project: project) } + let(:milestone) { create(:milestone, project: project) } - it_behaves_like 'a system note' do - let(:action) { 'milestone' } - end + it_behaves_like 'a system note' do + let(:action) { 'milestone' } + end - context 'when milestone added' do - it 'sets the note text' do - expect(subject.note).to eq "changed milestone to #{milestone.to_reference}" + context 'when milestone added' do + it 'sets the note text' do + expect(subject.note).to eq "changed milestone to #{milestone.to_reference}" + end + end + + context 'when milestone removed' do + let(:milestone) { nil } + + it 'sets the note text' do + expect(subject.note).to eq 'removed milestone' + end end end - context 'when milestone removed' do - let(:milestone) { nil } + context 'for a group milestone' do + subject { described_class.change_milestone(noteable, project, author, milestone) } - it 'sets the note text' do - expect(subject.note).to eq 'removed milestone' + let(:milestone) { create(:milestone, group: group) } + + it_behaves_like 'a system note' do + let(:action) { 'milestone' } + end + + context 'when milestone added' do + it 'sets the note text to use the milestone name' do + expect(subject.note).to eq "changed milestone to #{milestone.to_reference(format: :name)}" + end + end + + context 'when milestone removed' do + let(:milestone) { nil } + + it 'sets the note text' do + expect(subject.note).to eq 'removed milestone' + end end end end @@ -450,7 +477,7 @@ describe SystemNoteService do end it 'does not create a system note metadata record' do - expect { subject }.not_to change{ SystemNoteMetadata.count } + expect { subject }.not_to change { SystemNoteMetadata.count } end end @@ -648,7 +675,7 @@ describe SystemNoteService do end describe '.noteable_moved' do - let(:new_project) { create(:empty_project) } + let(:new_project) { create(:project) } let(:new_noteable) { create(:issue, project: new_project) } subject do @@ -667,7 +694,7 @@ describe SystemNoteService do end it 'mentions referenced project' do - expect(subject.note).to include new_project.path_with_namespace + expect(subject.note).to include new_project.full_path end end @@ -718,7 +745,7 @@ describe SystemNoteService do describe 'JIRA integration' do include JiraServiceHelper - let(:project) { create(:jira_project) } + let(:project) { create(:jira_project, :repository) } let(:author) { create(:user) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, :simple, target_project: project, source_project: project) } @@ -873,7 +900,7 @@ describe SystemNoteService do describe "existing reference" do before do allow(JIRA::Resource::Remotelink).to receive(:all).and_return([]) - message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.path_with_namespace}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]:\n'#{commit.title.chomp}'" + message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.full_path}|http://localhost/#{project.full_path}/commit/#{commit.id}]:\n'#{commit.title.chomp}'" allow_any_instance_of(JIRA::Resource::Issue).to receive(:comments).and_return([OpenStruct.new(body: message)]) end @@ -1116,7 +1143,7 @@ describe SystemNoteService do end context 'across different projects' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:canonical_issue) { create(:issue, project: other_project) } it_behaves_like 'a system note' do @@ -1141,7 +1168,7 @@ describe SystemNoteService do end context 'across different projects' do - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let(:duplicate_issue) { create(:issue, project: other_project) } it_behaves_like 'a system note' do diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb index 230e40de9e0..a9b34a5258a 100644 --- a/spec/services/todo_service_spec.rb +++ b/spec/services/todo_service_spec.rb @@ -10,7 +10,7 @@ describe TodoService do let(:john_doe) { create(:user) } let(:skipped) { create(:user) } let(:skip_users) { [skipped] } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:mentions) { 'FYI: ' + [author, assignee, john_doe, member, guest, non_member, admin, skipped].map(&:to_reference).join(' ') } let(:directly_addressed) { [author, assignee, john_doe, member, guest, non_member, admin, skipped].map(&:to_reference).join(' ') } let(:directly_addressed_and_mentioned) { member.to_reference + ", what do you think? cc: " + [guest, admin, skipped].map(&:to_reference).join(' ') } @@ -103,7 +103,7 @@ describe TodoService do context 'when a private group is mentioned' do let(:group) { create(:group, :private) } - let(:project) { create(:empty_project, :private, group: group) } + let(:project) { create(:project, :private, group: group) } let(:issue) { create(:issue, author: author, project: project, description: group.to_reference) } before do @@ -336,7 +336,7 @@ describe TodoService do describe '#mark_todos_as_done' do it_behaves_like 'updating todos state', :mark_todos_as_done, :pending, :done do - let(:collection) { [first_todo, second_todo] } + let(:collection) { Todo.all } end end @@ -348,7 +348,7 @@ describe TodoService do describe '#mark_todos_as_pending' do it_behaves_like 'updating todos state', :mark_todos_as_pending, :done, :pending do - let(:collection) { [first_todo, second_todo] } + let(:collection) { Todo.all } end end @@ -586,13 +586,13 @@ describe TodoService do it 'does not create a directly addressed todo if user was already mentioned or addressed and todo is pending' do create(:todo, :directly_addressed, user: member, project: project, target: addressed_mr_assigned, author: author) - expect{ service.update_merge_request(addressed_mr_assigned, author) }.not_to change(member.todos, :count) + expect { service.update_merge_request(addressed_mr_assigned, author) }.not_to change(member.todos, :count) end it 'does not create a directly addressed todo if user was already mentioned or addressed and todo is done' do create(:todo, :directly_addressed, user: skipped, project: project, target: addressed_mr_assigned, author: author) - expect{ service.update_merge_request(addressed_mr_assigned, author, skip_users) }.not_to change(skipped.todos, :count) + expect { service.update_merge_request(addressed_mr_assigned, author, skip_users) }.not_to change(skipped.todos, :count) end context 'with a task list' do @@ -880,14 +880,16 @@ describe TodoService do it 'marks an array of todos as done' do todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) - expect { described_class.new.mark_todos_as_done([todo], john_doe) } + todos = TodosFinder.new(john_doe, {}).execute + expect { described_class.new.mark_todos_as_done(todos, john_doe) } .to change { todo.reload.state }.from('pending').to('done') end it 'returns the ids of updated todos' do # Needed on API todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) - expect(described_class.new.mark_todos_as_done([todo], john_doe)).to eq([todo.id]) + todos = TodosFinder.new(john_doe, {}).execute + expect(described_class.new.mark_todos_as_done(todos, john_doe)).to eq([todo.id]) end context 'when some of the todos are done already' do @@ -907,11 +909,32 @@ describe TodoService do expect(described_class.new.mark_todos_as_done(Todo.all, john_doe)).to eq([]) end end + end + + describe '#mark_todos_as_done_by_ids' do + let(:issue) { create(:issue, project: project, author: author, assignees: [john_doe]) } + let(:another_issue) { create(:issue, project: project, author: author, assignees: [john_doe]) } + + it 'marks an array of todo ids as done' do + todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) + another_todo = create(:todo, :mentioned, user: john_doe, target: another_issue, project: project) + + expect { described_class.new.mark_todos_as_done_by_ids([todo.id, another_todo.id], john_doe) } + .to change { john_doe.todos.done.count }.from(0).to(2) + end + + it 'marks a single todo id as done' do + todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) + + expect { described_class.new.mark_todos_as_done_by_ids(todo.id, john_doe) } + .to change { todo.reload.state }.from('pending').to('done') + end it 'caches the number of todos of a user', :use_clean_rails_memory_store_caching do create(:todo, :mentioned, user: john_doe, target: issue, project: project) todo = create(:todo, :mentioned, user: john_doe, target: issue, project: project) - described_class.new.mark_todos_as_done([todo], john_doe) + + described_class.new.mark_todos_as_done_by_ids(todo, john_doe) expect_any_instance_of(TodosFinder).not_to receive(:execute) diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb index cf76a18f171..24f3a5c5ff0 100644 --- a/spec/services/upload_service_spec.rb +++ b/spec/services/upload_service_spec.rb @@ -4,7 +4,7 @@ describe UploadService do describe 'File service' do before do @user = create(:user) - @project = create(:empty_project, creator_id: @user.id, namespace: @user.namespace) + @project = create(:project, creator_id: @user.id, namespace: @user.namespace) end context 'for valid gif file' do diff --git a/spec/services/users/destroy_service_spec.rb b/spec/services/users/destroy_service_spec.rb index 786335120fd..a82567f6f43 100644 --- a/spec/services/users/destroy_service_spec.rb +++ b/spec/services/users/destroy_service_spec.rb @@ -5,7 +5,7 @@ describe Users::DestroyService do let!(:user) { create(:user) } let!(:admin) { create(:admin) } let!(:namespace) { create(:namespace, owner: user) } - let!(:project) { create(:empty_project, namespace: namespace) } + let!(:project) { create(:project, namespace: namespace) } let(:service) { described_class.new(admin) } context 'no options are given' do @@ -66,7 +66,7 @@ describe Users::DestroyService do end context "a deleted user's merge_requests" do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do project.add_developer(user) diff --git a/spec/services/users/migrate_to_ghost_user_service_spec.rb b/spec/services/users/migrate_to_ghost_user_service_spec.rb index a0030ce8809..ac3a8738cac 100644 --- a/spec/services/users/migrate_to_ghost_user_service_spec.rb +++ b/spec/services/users/migrate_to_ghost_user_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Users::MigrateToGhostUserService do let!(:user) { create(:user) } - let!(:project) { create(:project) } + let!(:project) { create(:project, :repository) } let(:service) { described_class.new(user) } context "migrating a user's associated records to the ghost user" do diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb index 1c0f55d2965..08fd26d67fd 100644 --- a/spec/services/users/refresh_authorized_projects_service_spec.rb +++ b/spec/services/users/refresh_authorized_projects_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Users::RefreshAuthorizedProjectsService do # We're using let! here so that any expectations for the service class are not # triggered twice. - let!(:project) { create(:empty_project) } + let!(:project) { create(:project) } let(:user) { project.namespace.owner } let(:service) { described_class.new(user) } @@ -28,7 +28,7 @@ describe Users::RefreshAuthorizedProjectsService do end it 'updates the authorized projects of the user' do - project2 = create(:empty_project) + project2 = create(:project) to_remove = user.project_authorizations .create!(project: project2, access_level: Gitlab::Access::MASTER) @@ -109,7 +109,7 @@ describe Users::RefreshAuthorizedProjectsService do end context 'projects the user is a member of' do - let!(:other_project) { create(:empty_project) } + let!(:other_project) { create(:project) } before do other_project.team.add_reporter(user) @@ -122,7 +122,7 @@ describe Users::RefreshAuthorizedProjectsService do context 'projects of groups the user is a member of' do let(:group) { create(:group) } - let!(:other_project) { create(:empty_project, group: group) } + let!(:other_project) { create(:project, group: group) } before do group.add_owner(user) @@ -136,7 +136,7 @@ describe Users::RefreshAuthorizedProjectsService do context 'projects of subgroups of groups the user is a member of', :nested_groups do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } - let!(:other_project) { create(:empty_project, group: nested_group) } + let!(:other_project) { create(:project, group: nested_group) } before do group.add_master(user) @@ -149,7 +149,7 @@ describe Users::RefreshAuthorizedProjectsService do context 'projects shared with groups the user is a member of' do let(:group) { create(:group) } - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let!(:project_group_link) { create(:project_group_link, project: other_project, group: group, group_access: Gitlab::Access::GUEST) } before do @@ -164,7 +164,7 @@ describe Users::RefreshAuthorizedProjectsService do context 'projects shared with subgroups of groups the user is a member of', :nested_groups do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } - let(:other_project) { create(:empty_project) } + let(:other_project) { create(:project) } let!(:project_group_link) { create(:project_group_link, project: other_project, group: nested_group, group_access: Gitlab::Access::DEVELOPER) } before do diff --git a/spec/services/web_hook_service_spec.rb b/spec/services/web_hook_service_spec.rb index e79c12daa1c..365cb6b8f09 100644 --- a/spec/services/web_hook_service_spec.rb +++ b/spec/services/web_hook_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe WebHookService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:project_hook) { create(:project_hook) } let(:headers) do { @@ -15,7 +15,7 @@ describe WebHookService do let(:service_instance) { described_class.new(project_hook, data, 'push_hooks') } describe '#execute' do - before(:each) do + before do project.hooks << [project_hook] WebMock.stub_request(:post, project_hook.url) @@ -112,6 +112,23 @@ describe WebHookService do end end + context 'with unsafe response body' do + before do + WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: "\xBB") + service_instance.execute + end + + it 'log successful execution' do + expect(hook_log.trigger).to eq('push_hooks') + expect(hook_log.url).to eq(project_hook.url) + expect(hook_log.request_headers).to eq(headers) + expect(hook_log.response_body).to eq('') + expect(hook_log.response_status).to eq('200') + expect(hook_log.execution_duration).to be > 0 + expect(hook_log.internal_error_message).to be_nil + end + end + context 'should not log ServiceHooks' do let(:service_hook) { create(:service_hook) } let(:service_instance) { described_class.new(service_hook, data, 'service_hook') } diff --git a/spec/services/wiki_pages/create_service_spec.rb b/spec/services/wiki_pages/create_service_spec.rb index fa3863e9b30..b270194d9b8 100644 --- a/spec/services/wiki_pages/create_service_spec.rb +++ b/spec/services/wiki_pages/create_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe WikiPages::CreateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:opts) do diff --git a/spec/services/wiki_pages/destroy_service_spec.rb b/spec/services/wiki_pages/destroy_service_spec.rb index 1668cd00ca8..2938126914b 100644 --- a/spec/services/wiki_pages/destroy_service_spec.rb +++ b/spec/services/wiki_pages/destroy_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe WikiPages::DestroyService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:page) { create(:wiki_page) } diff --git a/spec/services/wiki_pages/update_service_spec.rb b/spec/services/wiki_pages/update_service_spec.rb index a672c84034b..2399db7d3d4 100644 --- a/spec/services/wiki_pages/update_service_spec.rb +++ b/spec/services/wiki_pages/update_service_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe WikiPages::UpdateService do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:page) { create(:wiki_page) } @@ -9,7 +9,8 @@ describe WikiPages::UpdateService do { content: 'New content for wiki page', format: 'markdown', - message: 'New wiki message' + message: 'New wiki message', + title: 'New Title' } end @@ -27,6 +28,7 @@ describe WikiPages::UpdateService do expect(updated_page.message).to eq(opts[:message]) expect(updated_page.content).to eq(opts[:content]) expect(updated_page.format).to eq(opts[:format].to_sym) + expect(updated_page.title).to eq(opts[:title]) end it 'executes webhooks' do diff --git a/spec/simplecov_env.rb b/spec/simplecov_env.rb index ac2c89b3ff9..25ddf932d42 100644 --- a/spec/simplecov_env.rb +++ b/spec/simplecov_env.rb @@ -36,18 +36,25 @@ module SimpleCovEnv track_files '{app,lib}/**/*.rb' add_filter '/vendor/ruby/' + add_filter 'app/controllers/sherlock/' add_filter 'config/initializers/' + add_filter 'db/fixtures/' + add_filter 'lib/gitlab/sidekiq_middleware/' + add_filter 'lib/system_check/' add_group 'Controllers', 'app/controllers' - add_group 'Models', 'app/models' - add_group 'Mailers', 'app/mailers' - add_group 'Helpers', 'app/helpers' - add_group 'Workers', %w(app/jobs app/workers) - add_group 'Libraries', 'lib' - add_group 'Services', 'app/services' - add_group 'Finders', 'app/finders' - add_group 'Uploaders', 'app/uploaders' - add_group 'Validators', 'app/validators' + add_group 'Finders', 'app/finders' + add_group 'Helpers', 'app/helpers' + add_group 'Libraries', 'lib' + add_group 'Mailers', 'app/mailers' + add_group 'Models', 'app/models' + add_group 'Policies', 'app/policies' + add_group 'Presenters', 'app/presenters' + add_group 'Serializers', 'app/serializers' + add_group 'Services', 'app/services' + add_group 'Uploaders', 'app/uploaders' + add_group 'Validators', 'app/validators' + add_group 'Workers', %w(app/jobs app/workers) merge_timeout 365.days end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 85335643921..3eea39d4bf4 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -8,6 +8,7 @@ require File.expand_path("../../config/environment", __FILE__) require 'rspec/rails' require 'shoulda/matchers' require 'rspec/retry' +require 'rspec-parameterized' rspec_profiling_is_configured = ENV['RSPEC_PROFILING_POSTGRES_URL'].present? || @@ -49,7 +50,7 @@ RSpec.configure do |config| config.include SearchHelpers, type: :feature config.include WaitForRequests, :js config.include StubConfiguration - config.include EmailHelpers, type: :mailer + config.include EmailHelpers, :mailer, type: :mailer config.include TestEnv config.include ActiveJob::TestHelper config.include ActiveSupport::Testing::TimeHelpers @@ -69,7 +70,14 @@ RSpec.configure do |config| config.raise_errors_for_deprecations! + if ENV['CI'] + # This includes the first try, i.e. tests will be run 4 times before failing. + config.default_retry_count = 4 + config.reporter.register_listener(RspecFlaky::Listener.new, :example_passed, :dump_summary) + end + config.before(:suite) do + Timecop.safe_mode = true TestEnv.init end @@ -93,10 +101,8 @@ RSpec.configure do |config| RequestStore.clear! end - if ENV['CI'] - config.around(:each) do |ex| - ex.run_with_retry retry: 2 - end + config.before(:example, :mailer) do + reset_delivered_emails! end config.around(:each, :use_clean_rails_memory_store_caching) do |example| @@ -129,10 +135,14 @@ RSpec.configure do |config| config.before(:example, :migration) do ActiveRecord::Migrator .migrate(migrations_paths, previous_migration.version) + + reset_column_in_migration_models end config.after(:example, :migration) do ActiveRecord::Migrator.migrate(migrations_paths) + + reset_column_in_migration_models end config.around(:each, :nested_groups) do |example| diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb index 480e7d5151f..4bb5113957e 100644 --- a/spec/support/api/milestones_shared_examples.rb +++ b/spec/support/api/milestones_shared_examples.rb @@ -50,7 +50,7 @@ shared_examples_for 'group and project milestones' do |route_definition| expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.length).to eq(2) - expect(json_response.map{ |m| m['id'] }).to match_array([closed_milestone.id, other_milestone.id]) + expect(json_response.map { |m| m['id'] }).to match_array([closed_milestone.id, other_milestone.id]) end it 'does not return any milestone if none found' do @@ -239,7 +239,7 @@ shared_examples_for 'group and project milestones' do |route_definition| end describe 'confidential issues' do - let!(:public_project) { create(:empty_project, :public) } + let!(:public_project) { create(:project, :public) } let!(:context_group) { try(:group) } let!(:milestone) do context_group ? create(:milestone, group: context_group) : create(:milestone, project: public_project) diff --git a/spec/support/api/schema_matcher.rb b/spec/support/api/schema_matcher.rb index 67599f77adb..6591d56e473 100644 --- a/spec/support/api/schema_matcher.rb +++ b/spec/support/api/schema_matcher.rb @@ -1,23 +1,25 @@ -def schema_path(schema) - schema_directory = "#{Dir.pwd}/spec/fixtures/api/schemas" - "#{schema_directory}/#{schema}.json" +module SchemaPath + def self.expand(schema, dir = '') + Rails.root.join('spec', dir, "fixtures/api/schemas/#{schema}.json").to_s + end end -RSpec::Matchers.define :match_response_schema do |schema, **options| +RSpec::Matchers.define :match_response_schema do |schema, dir: '', **options| match do |response| - @errors = JSON::Validator.fully_validate(schema_path(schema), response.body, options) + @errors = JSON::Validator.fully_validate( + SchemaPath.expand(schema, dir), response.body, options) @errors.empty? end failure_message do |response| - "didn't match the schema defined by #{schema_path(schema)}" \ + "didn't match the schema defined by #{SchemaPath.expand(schema, dir)}" \ " The validation errors were:\n#{@errors.join("\n")}" end end -RSpec::Matchers.define :match_schema do |schema, **options| +RSpec::Matchers.define :match_schema do |schema, dir: '', **options| match do |data| - JSON::Validator.validate!(schema_path(schema), data, options) + JSON::Validator.validate!(SchemaPath.expand(schema, dir), data, options) end end diff --git a/spec/support/chat_slash_commands_shared_examples.rb b/spec/support/chat_slash_commands_shared_examples.rb index 978b0b9cc30..dc97a39f051 100644 --- a/spec/support/chat_slash_commands_shared_examples.rb +++ b/spec/support/chat_slash_commands_shared_examples.rb @@ -36,7 +36,7 @@ RSpec.shared_examples 'chat slash commands service' do end context 'with a token passed' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:params) { { token: 'token' } } before do diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb index a8d9566b4e4..4eec3127464 100644 --- a/spec/support/controllers/githubish_import_controller_shared_examples.rb +++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb @@ -56,7 +56,7 @@ shared_examples 'a GitHub-ish import controller: GET status' do end it "assigns variables" do - project = create(:empty_project, import_type: provider, creator_id: user.id) + project = create(:project, import_type: provider, creator_id: user.id) stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo]) get :status @@ -69,7 +69,7 @@ shared_examples 'a GitHub-ish import controller: GET status' do end it "does not show already added project" do - project = create(:empty_project, import_type: provider, creator_id: user.id, import_source: 'asd/vim') + project = create(:project, import_type: provider, creator_id: user.id, import_source: 'asd/vim') stub_client(repos: [repo], orgs: []) get :status diff --git a/spec/support/cycle_analytics_helpers.rb b/spec/support/cycle_analytics_helpers.rb index c0a5491a430..30911e7fa86 100644 --- a/spec/support/cycle_analytics_helpers.rb +++ b/spec/support/cycle_analytics_helpers.rb @@ -41,7 +41,9 @@ module CycleAnalyticsHelpers target_branch: 'master' } - MergeRequests::CreateService.new(project, user, opts).execute + mr = MergeRequests::CreateService.new(project, user, opts).execute + NewMergeRequestWorker.new.perform(mr, user) + mr end def merge_merge_requests_closing_issue(issue) diff --git a/spec/support/features/issuable_slash_commands_shared_examples.rb b/spec/support/features/issuable_slash_commands_shared_examples.rb index 035428a7d9b..68f0ce8afb3 100644 --- a/spec/support/features/issuable_slash_commands_shared_examples.rb +++ b/spec/support/features/issuable_slash_commands_shared_examples.rb @@ -5,7 +5,14 @@ shared_examples 'issuable record that supports quick actions in its description include QuickActionsHelpers let(:master) { create(:user) } - let(:project) { create(:project, :public) } + let(:project) do + case issuable_type + when :merge_request + create(:project, :public, :repository) + when :issue + create(:project, :public) + end + end let!(:milestone) { create(:milestone, project: project, title: 'ASAP') } let!(:label_bug) { create(:label, project: project, title: 'bug') } let!(:label_feature) { create(:label, project: project, title: 'feature') } @@ -272,6 +279,17 @@ shared_examples 'issuable record that supports quick actions in its description expect(issuable.subscribed?(master, project)).to be_falsy end end + + context "with a note assigning the #{issuable_type} to the current user" do + it "assigns the #{issuable_type} to the current user" do + write_note("/assign me") + + expect(page).not_to have_content '/assign me' + expect(page).to have_content 'Commands applied' + + expect(issuable.reload.assignees).to eq [master] + end + end end describe "preview of note on #{issuable_type}" do diff --git a/spec/support/features/reportable_note_shared_examples.rb b/spec/support/features/reportable_note_shared_examples.rb index 27e079c01dd..cb483ae9a5a 100644 --- a/spec/support/features/reportable_note_shared_examples.rb +++ b/spec/support/features/reportable_note_shared_examples.rb @@ -7,15 +7,18 @@ shared_examples 'reportable note' do let(:more_actions_selector) { '.more-actions.dropdown' } let(:abuse_report_path) { new_abuse_report_path(user_id: note.author.id, ref_url: noteable_note_url(note)) } + it 'has an edit button' do + expect(comment).to have_selector('.js-note-edit') + end + it 'has a `More actions` dropdown' do expect(comment).to have_selector(more_actions_selector) end - it 'dropdown has Edit, Report and Delete links' do + it 'dropdown has Report and Delete links' do dropdown = comment.find(more_actions_selector) open_dropdown(dropdown) - expect(dropdown).to have_button('Edit comment') expect(dropdown).to have_link('Report as abuse', href: abuse_report_path) expect(dropdown).to have_link('Delete comment', href: note_url(note, project)) end diff --git a/spec/support/gitlab-git-test.git/objects/3e/20715310a699808282e772720b9c04a0696bcc b/spec/support/gitlab-git-test.git/objects/3e/20715310a699808282e772720b9c04a0696bcc Binary files differnew file mode 100644 index 00000000000..86bf37ac887 --- /dev/null +++ b/spec/support/gitlab-git-test.git/objects/3e/20715310a699808282e772720b9c04a0696bcc diff --git a/spec/support/gitlab-git-test.git/objects/95/96bc54a6f0c0c98248fe97077eb5ccf48a98d0 b/spec/support/gitlab-git-test.git/objects/95/96bc54a6f0c0c98248fe97077eb5ccf48a98d0 new file mode 100644 index 00000000000..d90cb028e9b --- /dev/null +++ b/spec/support/gitlab-git-test.git/objects/95/96bc54a6f0c0c98248fe97077eb5ccf48a98d0 @@ -0,0 +1,2 @@ +x•OËn1䜯ð 9&O ¡ž¹"õnoYD6Õ’ýÒª?Ðã¼ì™Òj;w»¾ªÂQ £õG‹rN˜(‘ÆH‘PrAÇrRÌ7¯ºtpâ²Mì#MœÂ”c´ê…NrsI +Ž“%Þú½páÒ>Û«²®pzüÀ¯¹?Y¥Õ3XäBB̰GB4ƒ
ûpÿ?k®›ÔvÛžú‚y~Wø])[‡¥Áa<þ“ÍCP_
\ No newline at end of file diff --git a/spec/support/gitlab-git-test.git/packed-refs b/spec/support/gitlab-git-test.git/packed-refs index ce5ab1f705b..507e4ce785a 100644 --- a/spec/support/gitlab-git-test.git/packed-refs +++ b/spec/support/gitlab-git-test.git/packed-refs @@ -8,6 +8,7 @@ 46e1395e609395de004cacd4b142865ab0e52a29 refs/heads/gitattributes-updated 4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6 refs/heads/master 5937ac0a7beb003549fc5fd26fc247adbce4a52e refs/heads/merge-test +9596bc54a6f0c0c98248fe97077eb5ccf48a98d0 refs/heads/missing-gitmodules f4e6814c3e4e7a0de82a9e7cd20c626cc963a2f8 refs/tags/v1.0.0 ^6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9 8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b refs/tags/v1.1.0 diff --git a/spec/support/gpg_helpers.rb b/spec/support/gpg_helpers.rb index 96ea6f28b30..65b38626a51 100644 --- a/spec/support/gpg_helpers.rb +++ b/spec/support/gpg_helpers.rb @@ -1,4 +1,6 @@ module GpgHelpers + SIGNED_COMMIT_SHA = '8a852d50dda17cc8fd1408d2fd0c5b0f24c76ca4'.freeze + module User1 extend self diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb index 57b6abe12b7..2011408be93 100644 --- a/spec/support/import_export/export_file_helper.rb +++ b/spec/support/import_export/export_file_helper.rb @@ -6,7 +6,7 @@ module ExportFileHelper ObjectWithParent = Struct.new(:object, :parent, :key_found) def setup_project - project = create(:project, :public) + project = create(:project, :public, :repository) create(:release, project: project) diff --git a/spec/support/issuable_shared_examples.rb b/spec/support/issuable_shared_examples.rb index 970fe10db2b..42f3b4db23c 100644 --- a/spec/support/issuable_shared_examples.rb +++ b/spec/support/issuable_shared_examples.rb @@ -21,15 +21,15 @@ shared_examples 'system notes for milestones' do create(:group_member, group: group, user: user) end - it 'does not create system note' do + it 'creates a system note' do expect do update_issuable(milestone: group_milestone) - end.not_to change { Note.system.count } + end.to change { Note.system.count }.by(1) end end context 'project milestones' do - it 'creates system note' do + it 'creates a system note' do expect do update_issuable(milestone: create(:milestone)) end.to change { Note.system.count }.by(1) diff --git a/spec/support/issuables_list_metadata_shared_examples.rb b/spec/support/issuables_list_metadata_shared_examples.rb index 3406e4c3161..75982432ab4 100644 --- a/spec/support/issuables_list_metadata_shared_examples.rb +++ b/spec/support/issuables_list_metadata_shared_examples.rb @@ -2,19 +2,15 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil| before do @issuable_ids = [] - 2.times do |n| + %w[fix improve/awesome].each do |source_branch| issuable = if issuable_type == :issue create(issuable_type, project: project) else - create(issuable_type, source_project: project, source_branch: "#{n}-feature") + create(issuable_type, source_project: project, source_branch: source_branch) end @issuable_ids << issuable.id - - issuable.id.times { create(:note, noteable: issuable, project: issuable.project) } - (issuable.id + 1).times { create(:award_emoji, :downvote, awardable: issuable) } - (issuable.id + 2).times { create(:award_emoji, :upvote, awardable: issuable) } end end @@ -27,15 +23,14 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil| meta_data = assigns(:issuable_meta_data) - @issuable_ids.each do |id| - expect(meta_data[id].notes_count).to eq(id) - expect(meta_data[id].downvotes).to eq(id + 1) - expect(meta_data[id].upvotes).to eq(id + 2) + aggregate_failures do + expect(meta_data.keys).to match_array(@issuable_ids) + expect(meta_data.values).to all(be_kind_of(Issuable::IssuableMeta)) end end describe "when given empty collection" do - let(:project2) { create(:empty_project, :public) } + let(:project2) { create(:project, :public) } it "doesn't execute any queries with false conditions" do get_action = diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index c714d1b08a6..3e117530151 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -1,3 +1,5 @@ +require_relative 'devise_helpers' + module LoginHelpers include DeviseHelpers diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb index 21a054af4e1..c90359d7cfa 100644 --- a/spec/support/markdown_feature.rb +++ b/spec/support/markdown_feature.rb @@ -23,7 +23,7 @@ class MarkdownFeature # Direct references ---------------------------------------------------------- def project - @project ||= create(:project, :repository).tap do |project| + @project ||= create(:project, :repository, group: group).tap do |project| project.team << [user, :master] end end @@ -75,6 +75,10 @@ class MarkdownFeature @milestone ||= create(:milestone, name: 'next goal', project: project) end + def group_milestone + @group_milestone ||= create(:milestone, name: 'group-milestone', group: group) + end + # Cross-references ----------------------------------------------------------- def xproject diff --git a/spec/support/matchers/markdown_matchers.rb b/spec/support/matchers/markdown_matchers.rb index 7afa57fb76b..d12b2757427 100644 --- a/spec/support/matchers/markdown_matchers.rb +++ b/spec/support/matchers/markdown_matchers.rb @@ -155,7 +155,7 @@ module MarkdownMatchers set_default_markdown_messages match do |actual| - expect(actual).to have_selector('a.gfm.gfm-milestone', count: 6) + expect(actual).to have_selector('a.gfm.gfm-milestone', count: 8) end end diff --git a/spec/support/matchers/query_matcher.rb b/spec/support/matchers/query_matcher.rb index ac8c4ab91d9..bb0feca7c43 100644 --- a/spec/support/matchers/query_matcher.rb +++ b/spec/support/matchers/query_matcher.rb @@ -28,6 +28,6 @@ RSpec::Matchers.define :make_queries_matching do |matcher, expected_count = nil| def query_count(regex, &block) @recorder = ActiveRecord::QueryRecorder.new(&block).log - @recorder.select{ |q| q.match(regex) } + @recorder.select { |q| q.match(regex) } end end diff --git a/spec/support/migrations_helpers.rb b/spec/support/migrations_helpers.rb index 91fbb4eaf48..aabdad13047 100644 --- a/spec/support/migrations_helpers.rb +++ b/spec/support/migrations_helpers.rb @@ -15,6 +15,16 @@ module MigrationsHelpers ActiveRecord::Migrator.migrations(migrations_paths) end + def reset_column_in_migration_models + described_class.constants.sort.each do |name| + const = described_class.const_get(name) + + if const.is_a?(Class) && const < ActiveRecord::Base + const.reset_column_information + end + end + end + def previous_migration migrations.each_cons(2) do |previous, migration| break previous if migration.name == described_class.name diff --git a/spec/support/notify_shared_examples.rb b/spec/support/notify_shared_examples.rb index 76411065265..136f92c6419 100644 --- a/spec/support/notify_shared_examples.rb +++ b/spec/support/notify_shared_examples.rb @@ -3,11 +3,10 @@ shared_context 'gitlab email notification' do let(:gitlab_sender) { Gitlab.config.gitlab.email_from } let(:gitlab_sender_reply_to) { Gitlab.config.gitlab.email_reply_to } let(:recipient) { create(:user, email: 'recipient@example.com') } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:new_user_address) { 'newguy@example.com' } before do - reset_delivered_emails! email = recipient.emails.create(email: "notifications@example.com") recipient.update_attribute(:notification_email, email.email) stub_incoming_email_setting(enabled: true, address: "reply+%{key}@#{Gitlab.config.gitlab.host}") @@ -50,7 +49,7 @@ shared_examples 'an email with X-GitLab headers containing project details' do aggregate_failures do is_expected.to have_header('X-GitLab-Project', /#{project.name}/) is_expected.to have_header('X-GitLab-Project-Id', /#{project.id}/) - is_expected.to have_header('X-GitLab-Project-Path', /#{project.path_with_namespace}/) + is_expected.to have_header('X-GitLab-Project-Path', /#{project.full_path}/) end end end diff --git a/spec/support/project_features_apply_to_issuables_shared_examples.rb b/spec/support/project_features_apply_to_issuables_shared_examples.rb index 81b51509e0b..639b0924197 100644 --- a/spec/support/project_features_apply_to_issuables_shared_examples.rb +++ b/spec/support/project_features_apply_to_issuables_shared_examples.rb @@ -5,7 +5,7 @@ shared_examples 'project features apply to issuables' do |klass| let(:user_in_group) { create(:group_member, :developer, user: create(:user), group: group ).user } let(:user_outside_group) { create(:user) } - let(:project) { create(:empty_project, :public, project_args) } + let(:project) { create(:project, :public, project_args) } def project_args feature = "#{described_class.model_name.plural}_access_level".to_sym diff --git a/spec/support/project_hook_data_shared_example.rb b/spec/support/project_hook_data_shared_example.rb index 7dbaa6a6459..1eb405d4be8 100644 --- a/spec/support/project_hook_data_shared_example.rb +++ b/spec/support/project_hook_data_shared_example.rb @@ -8,7 +8,7 @@ RSpec.shared_examples 'project hook data with deprecateds' do |project_key: :pro expect(data[project_key][:git_ssh_url]).to eq(project.ssh_url_to_repo) expect(data[project_key][:namespace]).to eq(project.namespace.name) expect(data[project_key][:visibility_level]).to eq(project.visibility_level) - expect(data[project_key][:path_with_namespace]).to eq(project.path_with_namespace) + expect(data[project_key][:path_with_namespace]).to eq(project.full_path) expect(data[project_key][:default_branch]).to eq(project.default_branch) expect(data[project_key][:homepage]).to eq(project.web_url) expect(data[project_key][:url]).to eq(project.url_to_repo) @@ -27,7 +27,7 @@ RSpec.shared_examples 'project hook data' do |project_key: :project| expect(data[project_key][:git_ssh_url]).to eq(project.ssh_url_to_repo) expect(data[project_key][:namespace]).to eq(project.namespace.name) expect(data[project_key][:visibility_level]).to eq(project.visibility_level) - expect(data[project_key][:path_with_namespace]).to eq(project.path_with_namespace) + expect(data[project_key][:path_with_namespace]).to eq(project.full_path) expect(data[project_key][:default_branch]).to eq(project.default_branch) end end diff --git a/spec/support/prometheus/additional_metrics_shared_examples.rb b/spec/support/prometheus/additional_metrics_shared_examples.rb index 016e16fc8d4..620fa37d455 100644 --- a/spec/support/prometheus/additional_metrics_shared_examples.rb +++ b/spec/support/prometheus/additional_metrics_shared_examples.rb @@ -10,11 +10,61 @@ RSpec.shared_examples 'additional metrics query' do [{ 'metric': {}, 'values': [[1488758662.506, '0.00002996364761904785'], [1488758722.506, '0.00003090239047619091']] }] end + let(:client) { double('prometheus_client') } + let(:query_result) { described_class.new(client).query(*query_params) } + let(:environment) { create(:environment, slug: 'environment-slug') } + before do allow(client).to receive(:label_values).and_return(metric_names) allow(metric_group_class).to receive(:all).and_return([simple_metric_group(metrics: [simple_metric])]) end + context 'metrics query context' do + subject! { described_class.new(client) } + + shared_examples 'query context containing environment slug and filter' do + it 'contains ci_environment_slug' do + expect(subject).to receive(:query_metrics).with(hash_including(ci_environment_slug: environment.slug)) + + subject.query(*query_params) + end + + it 'contains environment filter' do + expect(subject).to receive(:query_metrics).with( + hash_including( + environment_filter: "container_name!=\"POD\",environment=\"#{environment.slug}\"" + ) + ) + + subject.query(*query_params) + end + end + + describe 'project has Kubernetes service' do + let(:project) { create(:kubernetes_project) } + let(:environment) { create(:environment, slug: 'environment-slug', project: project) } + let(:kube_namespace) { project.kubernetes_service.actual_namespace } + + it_behaves_like 'query context containing environment slug and filter' + + it 'query context contains kube_namespace' do + expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: kube_namespace)) + + subject.query(*query_params) + end + end + + describe 'project without Kubernetes service' do + it_behaves_like 'query context containing environment slug and filter' + + it 'query context contains empty kube_namespace' do + expect(subject).to receive(:query_metrics).with(hash_including(kube_namespace: '')) + + subject.query(*query_params) + end + end + end + context 'with one group where two metrics is found' do before do allow(metric_group_class).to receive(:all).and_return([simple_metric_group]) @@ -51,6 +101,7 @@ RSpec.shared_examples 'additional metrics query' do context 'with two groups with one metric each' do let(:metrics) { [simple_metric(queries: [simple_query])] } + before do allow(metric_group_class).to receive(:all).and_return( [ diff --git a/spec/support/rake_helpers.rb b/spec/support/rake_helpers.rb index 5cb415111d2..86bfeed107c 100644 --- a/spec/support/rake_helpers.rb +++ b/spec/support/rake_helpers.rb @@ -5,11 +5,15 @@ module RakeHelpers end def stub_warn_user_is_not_gitlab - allow_any_instance_of(Object).to receive(:warn_user_is_not_gitlab) + allow(main_object).to receive(:warn_user_is_not_gitlab) end def silence_output - allow($stdout).to receive(:puts) - allow($stdout).to receive(:print) + allow(main_object).to receive(:puts) + allow(main_object).to receive(:print) + end + + def main_object + @main_object ||= TOPLEVEL_BINDING.eval('self') end end diff --git a/spec/support/redis/redis_shared_examples.rb b/spec/support/redis/redis_shared_examples.rb index f9552e41894..8676f895a83 100644 --- a/spec/support/redis/redis_shared_examples.rb +++ b/spec/support/redis/redis_shared_examples.rb @@ -3,12 +3,12 @@ RSpec.shared_examples "redis_shared_examples" do let(:test_redis_url) { "redis://redishost:#{redis_port}"} - before(:each) do + before do stub_env(environment_config_file_name, Rails.root.join(config_file_name)) clear_raw_config end - after(:each) do + after do clear_raw_config end diff --git a/spec/support/seed_repo.rb b/spec/support/seed_repo.rb index cfe7fc980a8..b4868e82cd7 100644 --- a/spec/support/seed_repo.rb +++ b/spec/support/seed_repo.rb @@ -97,6 +97,7 @@ module SeedRepo gitattributes-updated master merge-test + missing-gitmodules ].freeze TAGS = %w[ v1.0.0 diff --git a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb index 855051921f0..adfd256dff1 100644 --- a/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb +++ b/spec/support/services/migrate_to_ghost_user_service_shared_examples.rb @@ -3,7 +3,14 @@ require "spec_helper" shared_examples "migrating a deleted user's associated records to the ghost user" do |record_class, fields| record_class_name = record_class.to_s.titleize.downcase - let(:project) { create(:project) } + let(:project) do + case record_class + when MergeRequest + create(:project, :repository) + else + create(:project) + end + end before do project.add_developer(user) diff --git a/spec/support/stored_repositories.rb b/spec/support/stored_repositories.rb index df18926d58c..f3deae0f455 100644 --- a/spec/support/stored_repositories.rb +++ b/spec/support/stored_repositories.rb @@ -2,4 +2,16 @@ RSpec.configure do |config| config.before(:each, :repository) do TestEnv.clean_test_path end + + config.before(:all, :broken_storage) do + FileUtils.rm_rf Gitlab.config.repositories.storages.broken['path'] + end + + config.before(:each, :broken_storage) do + allow(Gitlab::GitalyClient).to receive(:call) do + raise GRPC::Unavailable.new('Gitaly broken in this spec') + end + + Gitlab::Git::Storage::CircuitBreaker.reset_all! + end end diff --git a/spec/support/stub_configuration.rb b/spec/support/stub_configuration.rb index 516f8878679..37c89d37aa0 100644 --- a/spec/support/stub_configuration.rb +++ b/spec/support/stub_configuration.rb @@ -38,6 +38,17 @@ module StubConfiguration allow(Gitlab.config.backup).to receive_messages(to_settings(messages)) end + def stub_storage_settings(messages) + messages.each do |storage_name, storage_settings| + storage_settings['failure_count_threshold'] ||= 10 + storage_settings['failure_wait_time'] ||= 30 + storage_settings['failure_reset_time'] ||= 1800 + storage_settings['storage_timeout'] ||= 5 + end + + allow(Gitlab.config.repositories).to receive(:storages).and_return(messages) + end + private # Modifies stubbed messages to also stub possible predicate versions diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 86f9568c12e..1e39f80699c 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -122,32 +122,60 @@ module TestEnv end def setup_gitlab_shell - shell_needs_update = component_needs_update?(Gitlab.config.gitlab_shell.path, + puts "\n==> Setting up Gitlab Shell..." + start = Time.now + gitlab_shell_dir = Gitlab.config.gitlab_shell.path + shell_needs_update = component_needs_update?(gitlab_shell_dir, Gitlab::Shell.version_required) unless !shell_needs_update || system('rake', 'gitlab:shell:install') - raise 'Can`t clone gitlab-shell' + puts "\nGitLab Shell failed to install, cleaning up #{gitlab_shell_dir}!\n" + FileUtils.rm_rf(gitlab_shell_dir) + exit 1 end + + puts " GitLab Shell setup in #{Time.now - start} seconds...\n" end def setup_gitaly + puts "\n==> Setting up Gitaly..." + start = Time.now socket_path = Gitlab::GitalyClient.address('default').sub(/\Aunix:/, '') gitaly_dir = File.dirname(socket_path) + + if gitaly_dir_stale?(gitaly_dir) + puts " Gitaly is outdated, cleaning up #{gitaly_dir}!" + FileUtils.rm_rf(gitaly_dir) + end + gitaly_needs_update = component_needs_update?(gitaly_dir, Gitlab::GitalyClient.expected_server_version) unless !gitaly_needs_update || system('rake', "gitlab:gitaly:install[#{gitaly_dir}]") - raise "Can't clone gitaly" + puts "\nGitaly failed to install, cleaning up #{gitaly_dir}!\n" + FileUtils.rm_rf(gitaly_dir) + exit 1 end start_gitaly(gitaly_dir) + puts " Gitaly setup in #{Time.now - start} seconds...\n" + end + + def gitaly_dir_stale?(dir) + gitaly_executable = File.join(dir, 'gitaly') + return false unless File.exist?(gitaly_executable) + + File.mtime(gitaly_executable) < File.mtime(Rails.root.join('GITALY_SERVER_VERSION')) end def start_gitaly(gitaly_dir) - gitaly_exec = File.join(gitaly_dir, 'gitaly') - gitaly_config = File.join(gitaly_dir, 'config.toml') - log_file = Rails.root.join('log/gitaly-test.log').to_s - @gitaly_pid = Bundler.with_original_env { spawn(gitaly_exec, gitaly_config, [:out, :err] => log_file) } + if ENV['CI'].present? + # Gitaly has been spawned outside this process already + return + end + + spawn_script = Rails.root.join('scripts/gitaly-test-spawn').to_s + @gitaly_pid = Bundler.with_original_env { IO.popen([spawn_script], &:read).to_i } end def stop_gitaly @@ -208,7 +236,6 @@ module TestEnv # Otherwise they'd be created by the first test, often timing out and # causing a transient test failure def eager_load_driver_server - return unless ENV['CI'] return unless defined?(Capybara) puts "Starting the Capybara driver server..." @@ -223,6 +250,14 @@ module TestEnv "#{forked_repo_path}_bare" end + def with_empty_bare_repository(name = nil) + path = Rails.root.join('tmp/tests', name || 'empty-bare-repository').to_s + + yield(Rugged::Repository.init_at(path, :bare)) + ensure + FileUtils.rm_rf(path) + end + private def factory_repo_path diff --git a/spec/support/unique_ip_check_shared_examples.rb b/spec/support/unique_ip_check_shared_examples.rb index ff0b47899f5..2dfa5fbecea 100644 --- a/spec/support/unique_ip_check_shared_examples.rb +++ b/spec/support/unique_ip_check_shared_examples.rb @@ -1,6 +1,6 @@ shared_context 'unique ips sign in limit' do include StubENV - before(:each) do + before do Gitlab::Redis::Cache.with(&:flushall) Gitlab::Redis::Queues.with(&:flushall) Gitlab::Redis::SharedState.with(&:flushall) diff --git a/spec/support/updating_mentions_shared_examples.rb b/spec/support/updating_mentions_shared_examples.rb index eeec3e1d79b..565d3203e4f 100644 --- a/spec/support/updating_mentions_shared_examples.rb +++ b/spec/support/updating_mentions_shared_examples.rb @@ -7,8 +7,6 @@ RSpec.shared_examples 'updating mentions' do |service_class| end def update_mentionable(opts) - reset_delivered_emails! - perform_enqueued_jobs do service_class.new(project, user, opts).execute(mentionable) end diff --git a/spec/tasks/config_lint_spec.rb b/spec/tasks/config_lint_spec.rb index ed6c5b09663..83d54259dfa 100644 --- a/spec/tasks/config_lint_spec.rb +++ b/spec/tasks/config_lint_spec.rb @@ -2,19 +2,19 @@ require 'rake_helper' Rake.application.rake_require 'tasks/config_lint' describe ConfigLint do - let(:files){ ['lib/support/fake.sh'] } + let(:files) { ['lib/support/fake.sh'] } it 'errors out if any bash scripts have errors' do - expect { described_class.run(files){ system('exit 1') } }.to raise_error(SystemExit) + expect { described_class.run(files) { system('exit 1') } }.to raise_error(SystemExit) end it 'passes if all scripts are fine' do - expect { described_class.run(files){ system('exit 0') } }.not_to raise_error + expect { described_class.run(files) { system('exit 0') } }.not_to raise_error end end describe 'config_lint rake task' do - before(:each) do + before do # Prevent `system` from actually being called allow(Kernel).to receive(:system).and_return(true) end diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index 71580a788d0..0c8c8a2ab05 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -117,9 +117,9 @@ describe 'gitlab:app namespace rake task' do describe 'backup creation and deletion using custom_hooks' do let(:project) { create(:project, :repository) } - let(:user_backup_path) { "repositories/#{project.path_with_namespace}" } + let(:user_backup_path) { "repositories/#{project.disk_path}" } - before(:each) do + before do @origin_cd = Dir.pwd path = File.join(project.repository.path_to_repo, filename) @@ -130,7 +130,7 @@ describe 'gitlab:app namespace rake task' do create_backup end - after(:each) do + after do ENV["SKIP"] = "" FileUtils.rm(@backup_tar) Dir.chdir(@origin_cd) @@ -261,8 +261,8 @@ describe 'gitlab:app namespace rake task' do %W{tar -tvf #{@backup_tar} repositories} ) expect(exit_status).to eq(0) - expect(tar_contents).to match("repositories/#{project_a.path_with_namespace}.bundle") - expect(tar_contents).to match("repositories/#{project_b.path_with_namespace}.bundle") + expect(tar_contents).to match("repositories/#{project_a.disk_path}.bundle") + expect(tar_contents).to match("repositories/#{project_b.disk_path}.bundle") end end end # backup_create task diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb index d42d2423f15..b29d63c7d67 100644 --- a/spec/tasks/gitlab/gitaly_rake_spec.rb +++ b/spec/tasks/gitlab/gitaly_rake_spec.rb @@ -20,7 +20,7 @@ describe 'gitlab:gitaly namespace rake task' do context 'when an underlying Git command fail' do it 'aborts and display a help message' do - expect_any_instance_of(Object) + expect(main_object) .to receive(:checkout_or_clone_version).and_raise 'Git error' expect { run_rake_task('gitlab:gitaly:install', clone_path) }.to raise_error 'Git error' @@ -33,7 +33,7 @@ describe 'gitlab:gitaly namespace rake task' do end it 'calls checkout_or_clone_version with the right arguments' do - expect_any_instance_of(Object) + expect(main_object) .to receive(:checkout_or_clone_version).with(version: version, repo: repo, target_dir: clone_path) run_rake_task('gitlab:gitaly:install', clone_path) @@ -41,20 +41,30 @@ describe 'gitlab:gitaly namespace rake task' do end describe 'gmake/make' do + let(:command_preamble) { %w[/usr/bin/env -u RUBYOPT -u BUNDLE_GEMFILE] } + + before(:all) do + @old_env_ci = ENV.delete('CI') + end + + after(:all) do + ENV['CI'] = @old_env_ci if @old_env_ci + end + before do FileUtils.mkdir_p(clone_path) expect(Dir).to receive(:chdir).with(clone_path).and_call_original + allow(Bundler).to receive(:bundle_path).and_return('/fake/bundle_path') end context 'gmake is available' do before do - expect_any_instance_of(Object).to receive(:checkout_or_clone_version) - allow_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true) + expect(main_object).to receive(:checkout_or_clone_version) end it 'calls gmake in the gitaly directory' do expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['/usr/bin/gmake', 0]) - expect_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true) + expect(main_object).to receive(:run_command!).with(command_preamble + %w[gmake BUNDLE_PATH=/fake/bundle_path]).and_return(true) run_rake_task('gitlab:gitaly:install', clone_path) end @@ -62,16 +72,27 @@ describe 'gitlab:gitaly namespace rake task' do context 'gmake is not available' do before do - expect_any_instance_of(Object).to receive(:checkout_or_clone_version) - allow_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true) + expect(main_object).to receive(:checkout_or_clone_version) + expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['', 42]) end it 'calls make in the gitaly directory' do - expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['', 42]) - expect_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true) + expect(main_object).to receive(:run_command!).with(command_preamble + %w[make BUNDLE_PATH=/fake/bundle_path]).and_return(true) run_rake_task('gitlab:gitaly:install', clone_path) end + + context 'when Rails.env is not "test"' do + before do + allow(Rails.env).to receive(:test?).and_return(false) + end + + it 'calls make in the gitaly directory without BUNDLE_PATH' do + expect(main_object).to receive(:run_command!).with(command_preamble + ['make']).and_return(true) + + run_rake_task('gitlab:gitaly:install', clone_path) + end + end end end end @@ -97,6 +118,8 @@ describe 'gitlab:gitaly namespace rake task' do # Gitaly storage configuration generated from #{Gitlab.config.source} on #{Time.current.to_s(:long)} # This is in TOML format suitable for use in Gitaly's config.toml file. socket_path = "/path/to/my.socket" + [gitlab-shell] + dir = "#{Gitlab.config.gitlab_shell.path}" [[storage]] name = "default" path = "/path/to/default" diff --git a/spec/tasks/gitlab/shell_rake_spec.rb b/spec/tasks/gitlab/shell_rake_spec.rb index ee3614c50f6..65155cb044d 100644 --- a/spec/tasks/gitlab/shell_rake_spec.rb +++ b/spec/tasks/gitlab/shell_rake_spec.rb @@ -22,7 +22,8 @@ describe 'gitlab:shell rake tasks' do describe 'create_hooks task' do it 'calls gitlab-shell bin/create_hooks' do expect_any_instance_of(Object).to receive(:system) - .with("#{Gitlab.config.gitlab_shell.path}/bin/create-hooks", *repository_storage_paths_args) + .with("#{Gitlab.config.gitlab_shell.path}/bin/create-hooks", + *Gitlab::TaskHelpers.repository_storage_paths_args) run_rake_task('gitlab:shell:create_hooks') end diff --git a/spec/tasks/gitlab/workhorse_rake_spec.rb b/spec/tasks/gitlab/workhorse_rake_spec.rb index 1b68f3044a4..42516d36c67 100644 --- a/spec/tasks/gitlab/workhorse_rake_spec.rb +++ b/spec/tasks/gitlab/workhorse_rake_spec.rb @@ -20,7 +20,7 @@ describe 'gitlab:workhorse namespace rake task' do context 'when an underlying Git command fail' do it 'aborts and display a help message' do - expect_any_instance_of(Object) + expect(main_object) .to receive(:checkout_or_clone_version).and_raise 'Git error' expect { run_rake_task('gitlab:workhorse:install', clone_path) }.to raise_error 'Git error' @@ -33,7 +33,7 @@ describe 'gitlab:workhorse namespace rake task' do end it 'calls checkout_or_clone_version with the right arguments' do - expect_any_instance_of(Object) + expect(main_object) .to receive(:checkout_or_clone_version).with(version: version, repo: repo, target_dir: clone_path) run_rake_task('gitlab:workhorse:install', clone_path) @@ -48,13 +48,13 @@ describe 'gitlab:workhorse namespace rake task' do context 'gmake is available' do before do - expect_any_instance_of(Object).to receive(:checkout_or_clone_version) - allow_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true) + expect(main_object).to receive(:checkout_or_clone_version) + allow(Object).to receive(:run_command!).with(['gmake']).and_return(true) end it 'calls gmake in the gitlab-workhorse directory' do expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['/usr/bin/gmake', 0]) - expect_any_instance_of(Object).to receive(:run_command!).with(['gmake']).and_return(true) + expect(main_object).to receive(:run_command!).with(['gmake']).and_return(true) run_rake_task('gitlab:workhorse:install', clone_path) end @@ -62,13 +62,13 @@ describe 'gitlab:workhorse namespace rake task' do context 'gmake is not available' do before do - expect_any_instance_of(Object).to receive(:checkout_or_clone_version) - allow_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true) + expect(main_object).to receive(:checkout_or_clone_version) + allow(main_object).to receive(:run_command!).with(['make']).and_return(true) end it 'calls make in the gitlab-workhorse directory' do expect(Gitlab::Popen).to receive(:popen).with(%w[which gmake]).and_return(['', 42]) - expect_any_instance_of(Object).to receive(:run_command!).with(['make']).and_return(true) + expect(main_object).to receive(:run_command!).with(['make']).and_return(true) run_rake_task('gitlab:workhorse:install', clone_path) end diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb index d7c1b390f9a..0cf462e9553 100644 --- a/spec/uploaders/file_mover_spec.rb +++ b/spec/uploaders/file_mover_spec.rb @@ -4,11 +4,11 @@ describe FileMover do let(:filename) { 'banana_sample.gif' } let(:file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) } let(:temp_description) do - 'test  same ![banana_sample]'\ - '(/uploads/system/temp/secret55/banana_sample.gif)' + 'test  same ![banana_sample]'\ + '(/uploads/-/system/temp/secret55/banana_sample.gif)' end let(:temp_file_path) { File.join('secret55', filename).to_s } - let(:file_path) { File.join('uploads', 'system', 'personal_snippet', snippet.id.to_s, 'secret55', filename).to_s } + let(:file_path) { File.join('uploads', '-', 'system', 'personal_snippet', snippet.id.to_s, 'secret55', filename).to_s } let(:snippet) { create(:personal_snippet, description: temp_description) } @@ -28,8 +28,8 @@ describe FileMover do expect(snippet.reload.description) .to eq( - "test "\ - " same " + "test "\ + " same " ) end @@ -50,8 +50,8 @@ describe FileMover do expect(snippet.reload.description) .to eq( - "test "\ - " same " + "test "\ + " same " ) end diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index 47e9365e13d..2492d56a5cf 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe FileUploader do - let(:uploader) { described_class.new(build_stubbed(:empty_project)) } + let(:uploader) { described_class.new(build_stubbed(:project)) } describe '.absolute_path' do it 'returns the correct absolute path by building it dynamically' do @@ -17,7 +17,7 @@ describe FileUploader do describe "#store_dir" do it "stores in the namespace path" do - project = build_stubbed(:empty_project) + project = build_stubbed(:project) uploader = described_class.new(project) expect(uploader.store_dir).to include(project.path_with_namespace) diff --git a/spec/uploaders/personal_file_uploader_spec.rb b/spec/uploaders/personal_file_uploader_spec.rb index eb55e8ebd24..cbafa9f478d 100644 --- a/spec/uploaders/personal_file_uploader_spec.rb +++ b/spec/uploaders/personal_file_uploader_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe PersonalFileUploader do - let(:uploader) { described_class.new(build_stubbed(:empty_project)) } + let(:uploader) { described_class.new(build_stubbed(:project)) } let(:snippet) { create(:personal_snippet) } describe '.absolute_path' do @@ -10,7 +10,7 @@ describe PersonalFileUploader do dynamic_segment = "personal_snippet/#{snippet.id}" - expect(described_class.absolute_path(upload)).to end_with("/system/#{dynamic_segment}/secret/foo.jpg") + expect(described_class.absolute_path(upload)).to end_with("/-/system/#{dynamic_segment}/secret/foo.jpg") end end @@ -19,7 +19,7 @@ describe PersonalFileUploader do uploader = described_class.new(snippet, 'secret') allow(uploader).to receive(:file).and_return(double(extension: 'txt', filename: 'file_name')) - expected_url = "/uploads/system/personal_snippet/#{snippet.id}/secret/file_name" + expected_url = "/uploads/-/system/personal_snippet/#{snippet.id}/secret/file_name" expect(uploader.to_h).to eq( alt: 'file_name', diff --git a/spec/validators/dynamic_path_validator_spec.rb b/spec/validators/dynamic_path_validator_spec.rb index 8bd5306ff98..08e1c5a728a 100644 --- a/spec/validators/dynamic_path_validator_spec.rb +++ b/spec/validators/dynamic_path_validator_spec.rb @@ -86,7 +86,7 @@ describe DynamicPathValidator do end it 'updating to an invalid path is not allowed' do - project = create(:empty_project) + project = create(:project) project.path = 'update' validator.validate_each(project, :path, 'update') diff --git a/spec/views/admin/dashboard/index.html.haml_spec.rb b/spec/views/admin/dashboard/index.html.haml_spec.rb index 68d2d72876e..df742bf6848 100644 --- a/spec/views/admin/dashboard/index.html.haml_spec.rb +++ b/spec/views/admin/dashboard/index.html.haml_spec.rb @@ -4,7 +4,7 @@ describe 'admin/dashboard/index.html.haml' do include Devise::Test::ControllerHelpers before do - assign(:projects, create_list(:empty_project, 1)) + assign(:projects, create_list(:project, 1)) assign(:users, create_list(:user, 1)) assign(:groups, create_list(:group, 1)) diff --git a/spec/views/ci/status/_badge.html.haml_spec.rb b/spec/views/ci/status/_badge.html.haml_spec.rb index de0b59f83f8..49f57969239 100644 --- a/spec/views/ci/status/_badge.html.haml_spec.rb +++ b/spec/views/ci/status/_badge.html.haml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'ci/status/_badge' do let(:user) { create(:user) } - let(:project) { create(:empty_project, :private) } + let(:project) { create(:project, :private) } let(:pipeline) { create(:ci_pipeline, project: project) } context 'when rendering status for build' do diff --git a/spec/views/layouts/nav/_project.html.haml_spec.rb b/spec/views/layouts/nav/_project.html.haml_spec.rb index fd1637ca91b..faea2505e40 100644 --- a/spec/views/layouts/nav/_project.html.haml_spec.rb +++ b/spec/views/layouts/nav/_project.html.haml_spec.rb @@ -5,7 +5,7 @@ describe 'layouts/nav/_project' do before do stub_container_registry_config(enabled: true) - assign(:project, create(:project)) + assign(:project, create(:project, :repository)) allow(view).to receive(:current_ref).and_return('master') allow(view).to receive(:can?).and_return(true) diff --git a/spec/views/notify/pipeline_failed_email.html.haml_spec.rb b/spec/views/notify/pipeline_failed_email.html.haml_spec.rb index f627f9165fb..d9d73f789c5 100644 --- a/spec/views/notify/pipeline_failed_email.html.haml_spec.rb +++ b/spec/views/notify/pipeline_failed_email.html.haml_spec.rb @@ -4,7 +4,7 @@ describe 'notify/pipeline_failed_email.html.haml' do include Devise::Test::ControllerHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, :simple, source_project: project) } let(:pipeline) do diff --git a/spec/views/notify/pipeline_success_email.html.haml_spec.rb b/spec/views/notify/pipeline_success_email.html.haml_spec.rb index ecd096ee579..a793b37e412 100644 --- a/spec/views/notify/pipeline_success_email.html.haml_spec.rb +++ b/spec/views/notify/pipeline_success_email.html.haml_spec.rb @@ -4,7 +4,7 @@ describe 'notify/pipeline_success_email.html.haml' do include Devise::Test::ControllerHelpers let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } let(:merge_request) { create(:merge_request, :simple, source_project: project) } let(:pipeline) do diff --git a/spec/views/projects/_home_panel.html.haml_spec.rb b/spec/views/projects/_home_panel.html.haml_spec.rb index f8c6cb6b5c6..62af946dcab 100644 --- a/spec/views/projects/_home_panel.html.haml_spec.rb +++ b/spec/views/projects/_home_panel.html.haml_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'projects/_home_panel' do - let(:project) { create(:empty_project, :public) } + let(:project) { create(:project, :public) } let(:notification_settings) do user&.notification_settings_for(project) diff --git a/spec/views/projects/blob/_viewer.html.haml_spec.rb b/spec/views/projects/blob/_viewer.html.haml_spec.rb index af833168bd9..aedbaa66d34 100644 --- a/spec/views/projects/blob/_viewer.html.haml_spec.rb +++ b/spec/views/projects/blob/_viewer.html.haml_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'projects/blob/_viewer.html.haml' do include FakeBlobHelpers - let(:project) { build(:empty_project) } + let(:project) { build(:project) } let(:viewer_class) do Class.new(BlobViewer::Base) do diff --git a/spec/views/projects/commits/_commit.html.haml_spec.rb b/spec/views/projects/commits/_commit.html.haml_spec.rb new file mode 100644 index 00000000000..4c247361bd7 --- /dev/null +++ b/spec/views/projects/commits/_commit.html.haml_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'projects/commits/_commit.html.haml' do + context 'with a singed commit' do + let(:project) { create(:project, :repository) } + let(:repository) { project.repository } + let(:ref) { GpgHelpers::SIGNED_COMMIT_SHA } + let(:commit) { repository.commit(ref) } + + it 'does not display a loading spinner for GPG status' do + render partial: 'projects/commits/commit', locals: { + project: project, + ref: ref, + commit: commit + } + + within '.gpg-status-box' do + expect(page).not_to have_css('i.fa.fa-spinner.fa-spin') + end + end + end +end diff --git a/spec/views/projects/edit.html.haml_spec.rb b/spec/views/projects/edit.html.haml_spec.rb index d2575702ecc..1af422941d7 100644 --- a/spec/views/projects/edit.html.haml_spec.rb +++ b/spec/views/projects/edit.html.haml_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'projects/edit' do include Devise::Test::ControllerHelpers - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:user) { create(:admin) } before do @@ -11,14 +11,26 @@ describe 'projects/edit' do allow(controller).to receive(:current_user).and_return(user) allow(view).to receive_messages(current_user: user, can?: true) - allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) end context 'LFS enabled setting' do it 'displays the correct elements' do + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + render + expect(rendered).to have_select('project_lfs_enabled') expect(rendered).to have_content('Git Large File Storage') end end + + context 'project export disabled' do + it 'does not display the project export option' do + stub_application_setting(project_export_enabled?: false) + + render + + expect(rendered).not_to have_content('Export project') + end + end end diff --git a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb index 37ce7121ccb..9c0be249a50 100644 --- a/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb +++ b/spec/views/projects/notes/_more_actions_dropdown.html.haml_spec.rb @@ -4,7 +4,7 @@ describe 'projects/notes/_more_actions_dropdown' do let(:author_user) { create(:user) } let(:not_author_user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let!(:note) { create(:note_on_issue, author: author_user, noteable: issue, project: project) } @@ -24,18 +24,16 @@ describe 'projects/notes/_more_actions_dropdown' do expect(rendered).not_to have_selector('.dropdown.more-actions') end - it 'shows Report as abuse, Edit and Delete buttons if editable and not current users comment' do + it 'shows Report as abuse and Delete buttons if editable and not current users comment' do render 'projects/notes/more_actions_dropdown', current_user: not_author_user, note_editable: true, note: note expect(rendered).to have_link('Report as abuse') - expect(rendered).to have_button('Edit comment') expect(rendered).to have_link('Delete comment') end - it 'shows Edit and Delete buttons if editable and current users comment' do + it 'shows Delete button if editable and current users comment' do render 'projects/notes/more_actions_dropdown', current_user: author_user, note_editable: true, note: note - expect(rendered).to have_button('Edit comment') expect(rendered).to have_link('Delete comment') end end diff --git a/spec/views/projects/registry/repositories/index.html.haml_spec.rb b/spec/views/projects/registry/repositories/index.html.haml_spec.rb index f13b657d474..cf0aa44a4a2 100644 --- a/spec/views/projects/registry/repositories/index.html.haml_spec.rb +++ b/spec/views/projects/registry/repositories/index.html.haml_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'projects/registry/repositories/index' do let(:group) { create(:group, path: 'group') } - let(:project) { create(:empty_project, group: group, path: 'test') } + let(:project) { create(:project, group: group, path: 'test') } let(:repository) do create(:container_repository, project: project, name: 'image') diff --git a/spec/views/projects/tags/index.html.haml_spec.rb b/spec/views/projects/tags/index.html.haml_spec.rb index f65cd9f398f..cb97d17988c 100644 --- a/spec/views/projects/tags/index.html.haml_spec.rb +++ b/spec/views/projects/tags/index.html.haml_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'projects/tags/index' do - let(:project) { create(:project) } + let(:project) { create(:project, :repository) } before do assign(:project, project) diff --git a/spec/views/shared/projects/_project.html.haml_spec.rb b/spec/views/shared/projects/_project.html.haml_spec.rb index 43334c2c236..b500016016a 100644 --- a/spec/views/shared/projects/_project.html.haml_spec.rb +++ b/spec/views/shared/projects/_project.html.haml_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'shared/projects/_project.html.haml' do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } it 'should render creator avatar if project has a creator' do render 'shared/projects/project', use_creator_avatar: true, project: project diff --git a/spec/workers/authorized_projects_worker_spec.rb b/spec/workers/authorized_projects_worker_spec.rb index bd5cc651c2b..03b9b99e263 100644 --- a/spec/workers/authorized_projects_worker_spec.rb +++ b/spec/workers/authorized_projects_worker_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe AuthorizedProjectsWorker do - let(:project) { create(:empty_project) } + let(:project) { create(:project) } describe '.bulk_perform_and_wait' do it 'schedules the ids and waits for the jobs to complete' do diff --git a/spec/workers/email_receiver_worker_spec.rb b/spec/workers/email_receiver_worker_spec.rb index fe70501eeac..e4e77c667b3 100644 --- a/spec/workers/email_receiver_worker_spec.rb +++ b/spec/workers/email_receiver_worker_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -describe EmailReceiverWorker do +describe EmailReceiverWorker, :mailer do let(:raw_message) { fixture_file('emails/valid_reply.eml') } context "when reply by email is enabled" do @@ -17,12 +17,16 @@ describe EmailReceiverWorker do context "when an error occurs" do before do - allow_any_instance_of(Gitlab::Email::Receiver).to receive(:execute).and_raise(Gitlab::Email::EmptyEmailError) + allow_any_instance_of(Gitlab::Email::Receiver).to receive(:execute).and_raise(error) end - it "sends out a rejection email" do - perform_enqueued_jobs do - described_class.new.perform(raw_message) + context 'when the error is Gitlab::Email::EmptyEmailError' do + let(:error) { Gitlab::Email::EmptyEmailError } + + it 'sends out a rejection email' do + perform_enqueued_jobs do + described_class.new.perform(raw_message) + end email = ActionMailer::Base.deliveries.last expect(email).not_to be_nil @@ -30,6 +34,18 @@ describe EmailReceiverWorker do expect(email.subject).to include("Rejected") end end + + context 'when the error is Gitlab::Email::AutoGeneratedEmailError' do + let(:error) { Gitlab::Email::AutoGeneratedEmailError } + + it 'does not send out any rejection email' do + perform_enqueued_jobs do + described_class.new.perform(raw_message) + end + + should_not_email_anyone + end + end end end diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb index 5b6b38e0f76..318aad4bc1e 100644 --- a/spec/workers/emails_on_push_worker_spec.rb +++ b/spec/workers/emails_on_push_worker_spec.rb @@ -1,8 +1,7 @@ require 'spec_helper' -describe EmailsOnPushWorker do +describe EmailsOnPushWorker, :mailer do include RepoHelpers - include EmailHelpers include EmailSpec::Matchers let(:project) { create(:project, :repository) } @@ -90,7 +89,6 @@ describe EmailsOnPushWorker do context "when there is an SMTP error" do before do - reset_delivered_emails! allow(Notify).to receive(:repository_push_email).and_raise(Net::SMTPFatalError) allow(subject).to receive_message_chain(:logger, :info) perform @@ -114,8 +112,6 @@ describe EmailsOnPushWorker do allow_any_instance_of(Mail::TestMailer).to receive(:deliver!).and_wrap_original do |original, mail| original.call(Mail.new(mail.encoded)) end - - reset_delivered_emails! end it "sends the mail to each of the recipients" do diff --git a/spec/workers/expire_pipeline_cache_worker_spec.rb b/spec/workers/expire_pipeline_cache_worker_spec.rb index e4f78999489..54c9a69d329 100644 --- a/spec/workers/expire_pipeline_cache_worker_spec.rb +++ b/spec/workers/expire_pipeline_cache_worker_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe ExpirePipelineCacheWorker do let(:user) { create(:user) } - let(:project) { create(:empty_project) } + let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } subject { described_class.new } diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index 309b3172da1..05f971dfd13 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -9,17 +9,51 @@ describe GitGarbageCollectWorker do subject { described_class.new } describe "#perform" do - it "flushes ref caches when the task is 'gc'" do - expect(subject).to receive(:command).with(:gc).and_return([:the, :command]) - expect(Gitlab::Popen).to receive(:popen) - .with([:the, :command], project.repository.path_to_repo).and_return(["", 0]) + shared_examples 'flushing ref caches' do |gitaly| + it "flushes ref caches when the task if 'gc'" do + expect(subject).to receive(:command).with(:gc).and_return([:the, :command]) + + if gitaly + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect) + .and_return(nil) + else + expect(Gitlab::Popen).to receive(:popen) + .with([:the, :command], project.repository.path_to_repo).and_return(["", 0]) + end + + expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original + expect_any_instance_of(Repository).to receive(:branch_names).and_call_original + expect_any_instance_of(Repository).to receive(:branch_count).and_call_original + expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original + + subject.perform(project.id) + end + end + + context "with Gitaly turned on" do + it_should_behave_like 'flushing ref caches', true + end + + context "with Gitaly turned off", skip_gitaly_mock: true do + it_should_behave_like 'flushing ref caches', false + end - expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original - expect_any_instance_of(Repository).to receive(:branch_names).and_call_original - expect_any_instance_of(Repository).to receive(:branch_count).and_call_original - expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original + context "repack_full" do + it "calls Gitaly" do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_full) + .and_return(nil) - subject.perform(project.id) + subject.perform(project.id, :full_repack) + end + end + + context "repack_incremental" do + it "calls Gitaly" do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:repack_incremental) + .and_return(nil) + + subject.perform(project.id, :incremental_repack) + end end shared_examples 'gc tasks' do diff --git a/spec/workers/group_destroy_worker_spec.rb b/spec/workers/group_destroy_worker_spec.rb index c78efc67076..a170c84ab12 100644 --- a/spec/workers/group_destroy_worker_spec.rb +++ b/spec/workers/group_destroy_worker_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe GroupDestroyWorker do let(:group) { create(:group) } let(:user) { create(:admin) } - let!(:project) { create(:empty_project, namespace: group) } + let!(:project) { create(:project, namespace: group) } subject { described_class.new } diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb index 303193bab9b..ee51000161a 100644 --- a/spec/workers/merge_worker_spec.rb +++ b/spec/workers/merge_worker_spec.rb @@ -27,4 +27,15 @@ describe MergeWorker do expect(source_project.repository.branch_names).not_to include('markdown') end end + + it 'persists merge_jid' do + merge_request = create(:merge_request, merge_jid: nil) + user = create(:user) + worker = described_class.new + + allow(worker).to receive(:jid) { '999' } + + expect { worker.perform(merge_request.id, user.id, {}) } + .to change { merge_request.reload.merge_jid }.from(nil).to('999') + end end diff --git a/spec/workers/namespaceless_project_destroy_worker_spec.rb b/spec/workers/namespaceless_project_destroy_worker_spec.rb index 8533b7b85e9..f2706254284 100644 --- a/spec/workers/namespaceless_project_destroy_worker_spec.rb +++ b/spec/workers/namespaceless_project_destroy_worker_spec.rb @@ -5,14 +5,14 @@ describe NamespacelessProjectDestroyWorker do before do # Stub after_save callbacks that will fail when Project has no namespace - allow_any_instance_of(Project).to receive(:ensure_dir_exist).and_return(nil) + allow_any_instance_of(Project).to receive(:ensure_storage_path_exist).and_return(nil) allow_any_instance_of(Project).to receive(:update_project_statistics).and_return(nil) end describe '#perform' do context 'project has namespace' do it 'does not do anything' do - project = create(:empty_project) + project = create(:project) subject.perform(project.id) @@ -22,7 +22,7 @@ describe NamespacelessProjectDestroyWorker do context 'project has no namespace' do let!(:project) do - project = build(:empty_project, namespace_id: nil) + project = build(:project, namespace_id: nil) project.save(validate: false) project end @@ -54,7 +54,7 @@ describe NamespacelessProjectDestroyWorker do end context 'project forked from another' do - let!(:parent_project) { create(:empty_project) } + let!(:parent_project) { create(:project) } before do create(:forked_project_link, forked_to_project: project, forked_from_project: parent_project) diff --git a/spec/workers/new_issue_worker_spec.rb b/spec/workers/new_issue_worker_spec.rb new file mode 100644 index 00000000000..4e15ccc534b --- /dev/null +++ b/spec/workers/new_issue_worker_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe NewIssueWorker do + describe '#perform' do + let(:worker) { described_class.new } + + context 'when an issue not found' do + it 'does not call Services' do + expect(EventCreateService).not_to receive(:new) + expect(NotificationService).not_to receive(:new) + + worker.perform(99, create(:user).id) + end + + it 'logs an error' do + expect(Rails.logger).to receive(:error).with('NewIssueWorker: couldn\'t find Issue with ID=99, skipping job') + + worker.perform(99, create(:user).id) + end + end + + context 'when a user not found' do + it 'does not call Services' do + expect(EventCreateService).not_to receive(:new) + expect(NotificationService).not_to receive(:new) + + worker.perform(create(:issue).id, 99) + end + + it 'logs an error' do + expect(Rails.logger).to receive(:error).with('NewIssueWorker: couldn\'t find User with ID=99, skipping job') + + worker.perform(create(:issue).id, 99) + end + end + + context 'when everything is ok' do + let(:project) { create(:project, :public) } + let(:mentioned) { create(:user) } + let(:user) { create(:user) } + let(:issue) { create(:issue, project: project, description: "issue for #{mentioned.to_reference}") } + + it 'creates a new event record' do + expect { worker.perform(issue.id, user.id) }.to change { Event.count }.from(0).to(1) + end + + it 'creates a notification for the assignee' do + expect(Notify).to receive(:new_issue_email).with(mentioned.id, issue.id).and_return(double(deliver_later: true)) + + worker.perform(issue.id, user.id) + end + end + end +end diff --git a/spec/workers/new_merge_request_worker_spec.rb b/spec/workers/new_merge_request_worker_spec.rb new file mode 100644 index 00000000000..9e0cbde45b1 --- /dev/null +++ b/spec/workers/new_merge_request_worker_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +describe NewMergeRequestWorker do + describe '#perform' do + let(:worker) { described_class.new } + + context 'when a merge request not found' do + it 'does not call Services' do + expect(EventCreateService).not_to receive(:new) + expect(NotificationService).not_to receive(:new) + + worker.perform(99, create(:user).id) + end + + it 'logs an error' do + expect(Rails.logger).to receive(:error).with('NewMergeRequestWorker: couldn\'t find MergeRequest with ID=99, skipping job') + + worker.perform(99, create(:user).id) + end + end + + context 'when a user not found' do + it 'does not call Services' do + expect(EventCreateService).not_to receive(:new) + expect(NotificationService).not_to receive(:new) + + worker.perform(create(:merge_request).id, 99) + end + + it 'logs an error' do + expect(Rails.logger).to receive(:error).with('NewMergeRequestWorker: couldn\'t find User with ID=99, skipping job') + + worker.perform(create(:merge_request).id, 99) + end + end + + context 'when everything is ok' do + let(:project) { create(:project, :public) } + let(:mentioned) { create(:user) } + let(:user) { create(:user) } + let(:merge_request) do + create(:merge_request, source_project: project, description: "mr for #{mentioned.to_reference}") + end + + it 'creates a new event record' do + expect { worker.perform(merge_request.id, user.id) }.to change { Event.count }.from(0).to(1) + end + + it 'creates a notification for the assignee' do + expect(Notify).to receive(:new_merge_request_email).with(mentioned.id, merge_request.id).and_return(double(deliver_later: true)) + + worker.perform(merge_request.id, user.id) + end + end + end +end diff --git a/spec/workers/pipeline_notification_worker_spec.rb b/spec/workers/pipeline_notification_worker_spec.rb index 139032d77bd..eb539ffd893 100644 --- a/spec/workers/pipeline_notification_worker_spec.rb +++ b/spec/workers/pipeline_notification_worker_spec.rb @@ -1,8 +1,6 @@ require 'spec_helper' -describe PipelineNotificationWorker do - include EmailHelpers - +describe PipelineNotificationWorker, :mailer do let(:pipeline) { create(:ci_pipeline) } describe '#execute' do diff --git a/spec/workers/pipeline_schedule_worker_spec.rb b/spec/workers/pipeline_schedule_worker_spec.rb index 14ed8b7811e..75197039f5a 100644 --- a/spec/workers/pipeline_schedule_worker_spec.rb +++ b/spec/workers/pipeline_schedule_worker_spec.rb @@ -23,7 +23,7 @@ describe PipelineScheduleWorker do context 'when there is a scheduled pipeline within next_run_at' do it 'creates a new pipeline' do - expect{ subject }.to change { project.pipelines.count }.by(1) + expect { subject }.to change { project.pipelines.count }.by(1) expect(Ci::Pipeline.last).to be_schedule end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index 74a9f90195c..af6a3c9f6c7 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -78,7 +78,7 @@ describe PostReceive do stub_ci_pipeline_to_return_yaml_file end - it { expect{ subject }.to change{ Ci::Pipeline.count }.by(2) } + it { expect { subject }.to change { Ci::Pipeline.count }.by(2) } end context "does not create a Ci::Pipeline" do @@ -86,7 +86,7 @@ describe PostReceive do stub_ci_pipeline_yaml_file(nil) end - it { expect{ subject }.not_to change{ Ci::Pipeline.count } } + it { expect { subject }.not_to change { Ci::Pipeline.count } } end end diff --git a/spec/workers/process_commit_worker_spec.rb b/spec/workers/process_commit_worker_spec.rb index 6ebc94bb544..24f8ca67594 100644 --- a/spec/workers/process_commit_worker_spec.rb +++ b/spec/workers/process_commit_worker_spec.rb @@ -33,7 +33,7 @@ describe ProcessCommitWorker do end context 'when commit already exists in upstream project' do - let(:forked) { create(:project, :public) } + let(:forked) { create(:project, :public, :repository) } it 'does not process commit message' do create(:forked_project_link, forked_to_project: forked, forked_from_project: project) diff --git a/spec/workers/prune_old_events_worker_spec.rb b/spec/workers/prune_old_events_worker_spec.rb index 35e1518a35e..ea974355050 100644 --- a/spec/workers/prune_old_events_worker_spec.rb +++ b/spec/workers/prune_old_events_worker_spec.rb @@ -2,9 +2,11 @@ require 'spec_helper' describe PruneOldEventsWorker do describe '#perform' do - let!(:expired_event) { create(:event, author_id: 0, created_at: 13.months.ago) } - let!(:not_expired_event) { create(:event, author_id: 0, created_at: 1.day.ago) } - let!(:exactly_12_months_event) { create(:event, author_id: 0, created_at: 12.months.ago) } + let(:user) { create(:user) } + + let!(:expired_event) { create(:event, :closed, author: user, created_at: 13.months.ago) } + let!(:not_expired_event) { create(:event, :closed, author: user, created_at: 1.day.ago) } + let!(:exactly_12_months_event) { create(:event, :closed, author: user, created_at: 12.months.ago) } it 'prunes events older than 12 months' do expect { subject.perform }.to change { Event.count }.by(-1) diff --git a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb index 1c183ce54f4..57f83c1dbe9 100644 --- a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb +++ b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb @@ -6,8 +6,8 @@ describe RemoveUnreferencedLfsObjectsWorker do describe '#perform' do let!(:unreferenced_lfs_object1) { create(:lfs_object, oid: '1') } let!(:unreferenced_lfs_object2) { create(:lfs_object, oid: '2') } - let!(:project1) { create(:empty_project, lfs_enabled: true) } - let!(:project2) { create(:empty_project, lfs_enabled: true) } + let!(:project1) { create(:project, lfs_enabled: true) } + let!(:project2) { create(:project, lfs_enabled: true) } let!(:referenced_lfs_object1) { create(:lfs_object, oid: '3') } let!(:referenced_lfs_object2) { create(:lfs_object, oid: '4') } let!(:lfs_objects_project1_1) do diff --git a/spec/workers/repository_check/batch_worker_spec.rb b/spec/workers/repository_check/batch_worker_spec.rb index bcd97a4f6ef..850b8cd8f5c 100644 --- a/spec/workers/repository_check/batch_worker_spec.rb +++ b/spec/workers/repository_check/batch_worker_spec.rb @@ -4,7 +4,7 @@ describe RepositoryCheck::BatchWorker do subject { described_class.new } it 'prefers projects that have never been checked' do - projects = create_list(:empty_project, 3, created_at: 1.week.ago) + projects = create_list(:project, 3, created_at: 1.week.ago) projects[0].update_column(:last_repository_check_at, 4.months.ago) projects[2].update_column(:last_repository_check_at, 3.months.ago) @@ -12,7 +12,7 @@ describe RepositoryCheck::BatchWorker do end it 'sorts projects by last_repository_check_at' do - projects = create_list(:empty_project, 3, created_at: 1.week.ago) + projects = create_list(:project, 3, created_at: 1.week.ago) projects[0].update_column(:last_repository_check_at, 2.months.ago) projects[1].update_column(:last_repository_check_at, 4.months.ago) projects[2].update_column(:last_repository_check_at, 3.months.ago) @@ -21,7 +21,7 @@ describe RepositoryCheck::BatchWorker do end it 'excludes projects that were checked recently' do - projects = create_list(:empty_project, 3, created_at: 1.week.ago) + projects = create_list(:project, 3, created_at: 1.week.ago) projects[0].update_column(:last_repository_check_at, 2.days.ago) projects[1].update_column(:last_repository_check_at, 2.months.ago) projects[2].update_column(:last_repository_check_at, 3.days.ago) @@ -30,7 +30,7 @@ describe RepositoryCheck::BatchWorker do end it 'does nothing when repository checks are disabled' do - create(:empty_project, created_at: 1.week.ago) + create(:project, created_at: 1.week.ago) current_settings = double('settings', repository_checks_enabled: false) expect(subject).to receive(:current_settings) { current_settings } @@ -38,7 +38,7 @@ describe RepositoryCheck::BatchWorker do end it 'skips projects created less than 24 hours ago' do - project = create(:empty_project) + project = create(:project) project.update_column(:created_at, 23.hours.ago) expect(subject.perform).to eq([]) diff --git a/spec/workers/repository_check/clear_worker_spec.rb b/spec/workers/repository_check/clear_worker_spec.rb index 3b1a64c5057..1c49415d46c 100644 --- a/spec/workers/repository_check/clear_worker_spec.rb +++ b/spec/workers/repository_check/clear_worker_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe RepositoryCheck::ClearWorker do it 'clears repository check columns' do - project = create(:empty_project) + project = create(:project) project.update_columns( last_repository_check_failed: true, last_repository_check_at: Time.now diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb index 6b30dabc80e..ca904e512ac 100644 --- a/spec/workers/repository_import_worker_spec.rb +++ b/spec/workers/repository_import_worker_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe RepositoryImportWorker do - let(:project) { create(:empty_project, :import_scheduled) } + let(:project) { create(:project, :import_scheduled) } subject { described_class.new } diff --git a/spec/workers/stuck_import_jobs_worker_spec.rb b/spec/workers/stuck_import_jobs_worker_spec.rb index 466277a5e5e..2f5b685a332 100644 --- a/spec/workers/stuck_import_jobs_worker_spec.rb +++ b/spec/workers/stuck_import_jobs_worker_spec.rb @@ -9,7 +9,7 @@ describe StuckImportJobsWorker do end describe 'long running import' do - let(:project) { create(:empty_project, import_jid: '123', import_status: 'started') } + let(:project) { create(:project, import_jid: '123', import_status: 'started') } before do allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return(['123']) @@ -21,7 +21,7 @@ describe StuckImportJobsWorker do end describe 'running import' do - let(:project) { create(:empty_project, import_jid: '123', import_status: 'started') } + let(:project) { create(:project, import_jid: '123', import_status: 'started') } before do allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return([]) diff --git a/spec/workers/stuck_merge_jobs_worker_spec.rb b/spec/workers/stuck_merge_jobs_worker_spec.rb new file mode 100644 index 00000000000..a5ad78393c9 --- /dev/null +++ b/spec/workers/stuck_merge_jobs_worker_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe StuckMergeJobsWorker do + describe 'perform' do + let(:worker) { described_class.new } + + context 'merge job identified as completed' do + it 'updates merge request to merged when locked but has merge_commit_sha' do + allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return(%w(123 456)) + mr_with_sha = create(:merge_request, :locked, merge_jid: '123', state: :locked, merge_commit_sha: 'foo-bar-baz') + mr_without_sha = create(:merge_request, :locked, merge_jid: '123', state: :locked, merge_commit_sha: nil) + + worker.perform + + expect(mr_with_sha.reload).to be_merged + expect(mr_without_sha.reload).to be_opened + end + + it 'updates merge request to opened when locked but has not been merged' do + allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return(%w(123)) + merge_request = create(:merge_request, :locked, merge_jid: '123', state: :locked) + + worker.perform + + expect(merge_request.reload).to be_opened + end + + it 'logs updated stuck merge job ids' do + allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return(%w(123 456)) + + create(:merge_request, :locked, merge_jid: '123') + create(:merge_request, :locked, merge_jid: '456') + + expect(Rails).to receive_message_chain(:logger, :info).with('Updated state of locked merge jobs. JIDs: 123, 456') + + worker.perform + end + end + + context 'merge job not identified as completed' do + it 'does not change merge request state when job is not completed yet' do + allow(Gitlab::SidekiqStatus).to receive(:completed_jids).and_return([]) + + merge_request = create(:merge_request, :locked, merge_jid: '123') + + expect { worker.perform }.not_to change { merge_request.reload.state }.from('locked') + end + end + end +end |
