diff options
Diffstat (limited to 'spec')
73 files changed, 834 insertions, 455 deletions
diff --git a/spec/controllers/profiles/personal_access_tokens_spec.rb b/spec/controllers/profiles/personal_access_tokens_spec.rb index dfed1de2046..98a43e278b2 100644 --- a/spec/controllers/profiles/personal_access_tokens_spec.rb +++ b/spec/controllers/profiles/personal_access_tokens_spec.rb @@ -12,7 +12,7 @@ describe Profiles::PersonalAccessTokensController do end it "allows creation of a token with scopes" do - name = FFaker::Product.brand + name = 'My PAT' scopes = %w[api read_user] post :create, personal_access_token: token_attributes.merge(scopes: scopes, name: name) diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 902911071c4..71dd9ef3eb4 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -68,4 +68,20 @@ describe RegistrationsController do end end end + + describe '#destroy' do + let(:user) { create(:user) } + + before do + sign_in(user) + end + + it 'schedules the user for destruction' do + expect(DeleteUserWorker).to receive(:perform_async).with(user.id, user.id) + + post(:destroy) + + expect(response.status).to eq(302) + end + end end diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb index a06c29dd91a..9c16a7bc08b 100644 --- a/spec/controllers/sessions_controller_spec.rb +++ b/spec/controllers/sessions_controller_spec.rb @@ -211,4 +211,20 @@ describe SessionsController do end end end + + describe '#new' do + before do + @request.env['devise.mapping'] = Devise.mappings[:user] + end + + it 'redirects correctly for referer on same host with params' do + search_path = '/search?search=seed_project' + allow(controller.request).to receive(:referer). + and_return('http://%{host}%{path}' % { host: Gitlab.config.gitlab.host, path: search_path }) + + get(:new, redirect_to_referer: :yes) + + expect(controller.stored_location_for(:redirect)).to eq(search_path) + end + end end diff --git a/spec/factories/chat_names.rb b/spec/factories/chat_names.rb index 24225468d55..9a0be1a4598 100644 --- a/spec/factories/chat_names.rb +++ b/spec/factories/chat_names.rb @@ -6,11 +6,7 @@ FactoryGirl.define do team_id 'T0001' team_domain 'Awesome Team' - sequence :chat_id do |n| - "U#{n}" - end - sequence :chat_name do |n| - "user#{n}" - end + sequence(:chat_id) { |n| "U#{n}" } + chat_name { generate(:username) } end end diff --git a/spec/factories/chat_teams.rb b/spec/factories/chat_teams.rb index 82f44fa3d15..ffedf69a69b 100644 --- a/spec/factories/chat_teams.rb +++ b/spec/factories/chat_teams.rb @@ -1,9 +1,6 @@ FactoryGirl.define do factory :chat_team, class: ChatTeam do - sequence :team_id do |n| - "abcdefghijklm#{n}" - end - + sequence(:team_id) { |n| "abcdefghijklm#{n}" } namespace factory: :group end end diff --git a/spec/factories/ci/pipelines.rb b/spec/factories/ci/pipelines.rb index b67c96bc00d..561fbc8e247 100644 --- a/spec/factories/ci/pipelines.rb +++ b/spec/factories/ci/pipelines.rb @@ -48,6 +48,10 @@ FactoryGirl.define do trait :success do status :success end + + trait :failed do + status :failed + end end end end diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb index c3b4aff55ba..05abf60d5ce 100644 --- a/spec/factories/ci/runners.rb +++ b/spec/factories/ci/runners.rb @@ -1,8 +1,6 @@ FactoryGirl.define do factory :ci_runner, class: Ci::Runner do - sequence :description do |n| - "My runner#{n}" - end + sequence(:description) { |n| "My runner#{n}" } platform "darwin" is_shared false diff --git a/spec/factories/emails.rb b/spec/factories/emails.rb index 9794772ac7d..8303861bcfe 100644 --- a/spec/factories/emails.rb +++ b/spec/factories/emails.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :email do user - email { FFaker::Internet.email('alias') } + email { generate(:email_alias) } end end diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb index 7e09f1ba8ea..0b6977e3b17 100644 --- a/spec/factories/issues.rb +++ b/spec/factories/issues.rb @@ -1,10 +1,6 @@ FactoryGirl.define do - sequence :issue_created_at do |n| - 4.hours.ago + ( 2 * n ).seconds - end - factory :issue do - title + title { generate(:title) } author project factory: :empty_project diff --git a/spec/factories/labels.rb b/spec/factories/labels.rb index 5ba8443c62c..22c2a1f15e2 100644 --- a/spec/factories/labels.rb +++ b/spec/factories/labels.rb @@ -1,7 +1,10 @@ FactoryGirl.define do - factory :label, class: ProjectLabel do - sequence(:title) { |n| "label#{n}" } + trait :base_label do + title { generate(:label_title) } color "#990000" + end + + factory :label, traits: [:base_label], class: ProjectLabel do project factory: :empty_project transient do @@ -15,9 +18,7 @@ FactoryGirl.define do end end - factory :group_label, class: GroupLabel do - sequence(:title) { |n| "label#{n}" } - color "#990000" + factory :group_label, traits: [:base_label] do group end end diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index ae0bbbd6aeb..e36fe326e1c 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :merge_request do - title + title { generate(:title) } author association :source_project, :repository, factory: :project target_project { source_project } diff --git a/spec/factories/oauth_applications.rb b/spec/factories/oauth_applications.rb index 86cdc208268..c7ede40f240 100644 --- a/spec/factories/oauth_applications.rb +++ b/spec/factories/oauth_applications.rb @@ -1,8 +1,8 @@ FactoryGirl.define do factory :oauth_application, class: 'Doorkeeper::Application', aliases: [:application] do - name { FFaker::Name.name } + sequence(:name) { |n| "OAuth App #{n}" } uid { Doorkeeper::OAuth::Helpers::UniqueToken.generate } - redirect_uri { FFaker::Internet.uri('http') } + redirect_uri { generate(:url) } owner owner_type 'User' end diff --git a/spec/factories/personal_access_tokens.rb b/spec/factories/personal_access_tokens.rb index 7b15ba47de1..06acaff6cd0 100644 --- a/spec/factories/personal_access_tokens.rb +++ b/spec/factories/personal_access_tokens.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :personal_access_token do user token { SecureRandom.hex(50) } - name { FFaker::Product.brand } + sequence(:name) { |n| "PAT #{n}" } revoked false expires_at { 5.days.from_now } scopes ['api'] diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb index 424ecc65759..39c2a9dd1fb 100644 --- a/spec/factories/project_hooks.rb +++ b/spec/factories/project_hooks.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :project_hook do - url { FFaker::Internet.uri('http') } + url { generate(:url) } trait :token do token { SecureRandom.hex(10) } diff --git a/spec/factories/sequences.rb b/spec/factories/sequences.rb new file mode 100644 index 00000000000..c0232ba5bf6 --- /dev/null +++ b/spec/factories/sequences.rb @@ -0,0 +1,12 @@ +FactoryGirl.define do + sequence(:username) { |n| "user#{n}" } + sequence(:name) { |n| "John Doe#{n}" } + sequence(:email) { |n| "user#{n}@example.org" } + sequence(:email_alias) { |n| "user.alias#{n}@example.org" } + sequence(:title) { |n| "My title #{n}" } + sequence(:filename) { |n| "filename-#{n}.rb" } + sequence(:url) { |n| "http://example#{n}.org" } + sequence(:label_title) { |n| "label#{n}" } + sequence(:branch) { |n| "my-branch-#{n}" } + sequence(:past_time) { |n| 4.hours.ago + (2 * n).seconds } +end diff --git a/spec/factories/service_hooks.rb b/spec/factories/service_hooks.rb index 6dd6af63f3e..e3f88ab8fcc 100644 --- a/spec/factories/service_hooks.rb +++ b/spec/factories/service_hooks.rb @@ -1,6 +1,6 @@ FactoryGirl.define do factory :service_hook do - url { FFaker::Internet.uri('http') } + url { generate(:url) } service end end diff --git a/spec/factories/snippets.rb b/spec/factories/snippets.rb index 365f12a0c95..18cb0f5de26 100644 --- a/spec/factories/snippets.rb +++ b/spec/factories/snippets.rb @@ -1,17 +1,9 @@ FactoryGirl.define do - sequence :title, aliases: [:content] do - FFaker::Lorem.sentence - end - - sequence :file_name do - FFaker::Internet.user_name - end - factory :snippet do author - title - content - file_name + title { generate(:title) } + content { generate(:title) } + file_name { generate(:filename) } trait :public do visibility_level Snippet::PUBLIC diff --git a/spec/factories/spam_logs.rb b/spec/factories/spam_logs.rb index a4f6d291269..e369f9f13e9 100644 --- a/spec/factories/spam_logs.rb +++ b/spec/factories/spam_logs.rb @@ -1,9 +1,9 @@ FactoryGirl.define do factory :spam_log do user - source_ip { FFaker::Internet.ip_v4_address } + sequence(:source_ip) { |n| "42.42.42.#{n % 255}" } noteable_type 'Issue' - title { FFaker::Lorem.sentence } - description { FFaker::Lorem.paragraph(5) } + sequence(:title) { |n| "Spam title #{n}" } + description { "Spam description\nwith\nmultiple\nlines" } end end diff --git a/spec/factories/system_hooks.rb b/spec/factories/system_hooks.rb index c786e9cb79b..841e1e293e8 100644 --- a/spec/factories/system_hooks.rb +++ b/spec/factories/system_hooks.rb @@ -1,5 +1,5 @@ FactoryGirl.define do factory :system_hook do - url { FFaker::Internet.uri('http') } + url { generate(:url) } end end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 249dabbaae8..e1ae94a08e4 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -1,10 +1,8 @@ FactoryGirl.define do - sequence(:name) { FFaker::Name.name } - factory :user, aliases: [:author, :assignee, :recipient, :owner, :creator, :resource_owner] do - email { FFaker::Internet.email } - name - sequence(:username) { |n| "#{FFaker::Internet.user_name}#{n}" } + email { generate(:email) } + name { generate(:name) } + username { generate(:username) } password "12345678" confirmed_at { Time.now } confirmation_token { nil } diff --git a/spec/features/admin/admin_browse_spam_logs_spec.rb b/spec/features/admin/admin_browse_spam_logs_spec.rb index 562ace92598..bee57472270 100644 --- a/spec/features/admin/admin_browse_spam_logs_spec.rb +++ b/spec/features/admin/admin_browse_spam_logs_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Admin browse spam logs' do - let!(:spam_log) { create(:spam_log) } + let!(:spam_log) { create(:spam_log, description: 'abcde ' * 20) } before do login_as :admin diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb index f246997d5a2..570c374a89b 100644 --- a/spec/features/admin/admin_hooks_spec.rb +++ b/spec/features/admin/admin_hooks_spec.rb @@ -26,7 +26,7 @@ describe "Admin::Hooks", feature: true do end describe "New Hook" do - let(:url) { FFaker::Internet.uri('http') } + let(:url) { generate(:url) } it 'adds new hook' do visit admin_hooks_path diff --git a/spec/features/admin/admin_users_impersonation_tokens_spec.rb b/spec/features/admin/admin_users_impersonation_tokens_spec.rb index 9ff5c2f9d40..ff23d486355 100644 --- a/spec/features/admin/admin_users_impersonation_tokens_spec.rb +++ b/spec/features/admin/admin_users_impersonation_tokens_spec.rb @@ -16,7 +16,7 @@ describe 'Admin > Users > Impersonation Tokens', feature: true, js: true do describe "token creation" do it "allows creation of a token" do - name = FFaker::Product.brand + name = 'Hello World' visit admin_user_impersonation_tokens_path(user_id: user.username) fill_in "Name", with: name diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb index ea7a97d1d4f..009e9c6b04c 100644 --- a/spec/features/auto_deploy_spec.rb +++ b/spec/features/auto_deploy_spec.rb @@ -42,7 +42,7 @@ describe 'Auto deploy' do it 'includes OpenShift as an available template', js: true do click_link 'Set up auto deploy' - click_button 'Choose a GitLab CI Yaml template' + click_button 'Apply a GitLab CI Yaml template' within '.gitlab-ci-yml-selector' do expect(page).to have_content('OpenShift') @@ -51,7 +51,7 @@ describe 'Auto deploy' do it 'creates a merge request using "auto-deploy" branch', js: true do click_link 'Set up auto deploy' - click_button 'Choose a GitLab CI Yaml template' + click_button 'Apply a GitLab CI Yaml template' within '.gitlab-ci-yml-selector' do click_on 'OpenShift' end diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index b90bf6268fd..3dc872ae520 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -46,16 +46,16 @@ describe 'issuable list', feature: true do end def create_issuables(issuable_type) - 3.times do + 3.times do |n| issuable = if issuable_type == :issue create(:issue, project: project, author: user) else - create(:merge_request, title: FFaker::Lorem.sentence, source_project: project, source_branch: FFaker::Name.name) + create(:merge_request, source_project: project, source_branch: generate(:branch)) end 2.times do - create(:note_on_issue, noteable: issuable, project: project, note: 'Test note') + create(:note_on_issue, noteable: issuable, project: project) end create(:award_emoji, :downvote, awardable: issuable) @@ -65,9 +65,8 @@ describe 'issuable list', feature: true do if issuable_type == :issue issue = Issue.reorder(:iid).first merge_request = create(:merge_request, - title: FFaker::Lorem.sentence, source_project: project, - source_branch: FFaker::Name.name) + source_branch: generate(:branch)) MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) end diff --git a/spec/features/issues/filtered_search/filter_issues_spec.rb b/spec/features/issues/filtered_search/filter_issues_spec.rb index f463312bf57..004e335dd38 100644 --- a/spec/features/issues/filtered_search/filter_issues_spec.rb +++ b/spec/features/issues/filtered_search/filter_issues_spec.rb @@ -6,8 +6,8 @@ describe 'Filter issues', js: true, feature: true do let!(:group) { create(:group) } let!(:project) { create(:project, group: group) } - let!(:user) { create(:user) } - let!(:user2) { create(:user) } + let!(:user) { create(:user, username: 'joe') } + let!(:user2) { create(:user, username: 'jane') } let!(:label) { create(:label, project: project) } let!(:wontfix) { create(:label, project: project, title: "Won't fix") } @@ -70,7 +70,7 @@ describe 'Filter issues', js: true, feature: true do issue_with_caps_label.labels << caps_sensitive_label issue_with_everything = create(:issue, - title: "Bug report with everything you thought was possible", + title: "Bug report foo was possible", project: project, milestone: milestone, author: user, @@ -687,10 +687,10 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by searched text, author, more text, assignee and even more text' do - input_filtered_search("bug author:@#{user.username} report assignee:@#{user.username} with") + input_filtered_search("bug author:@#{user.username} report assignee:@#{user.username} foo") expect_issues_list_count(1) - expect_filtered_search_input('bug report with') + expect_filtered_search_input('bug report foo') end it 'filters issues by searched text, author, assignee and label' do @@ -701,10 +701,10 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by searched text, author, text, assignee, text, label and text' do - input_filtered_search("bug author:@#{user.username} report assignee:@#{user.username} with label:~#{bug_label.title} everything") + input_filtered_search("bug author:@#{user.username} assignee:@#{user.username} report label:~#{bug_label.title} foo") expect_issues_list_count(1) - expect_filtered_search_input('bug report with everything') + expect_filtered_search_input('bug report foo') end it 'filters issues by searched text, author, assignee, label and milestone' do @@ -715,10 +715,10 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by searched text, author, text, assignee, text, label, text, milestone and text' do - input_filtered_search("bug author:@#{user.username} report assignee:@#{user.username} with label:~#{bug_label.title} everything milestone:%#{milestone.title} you") + input_filtered_search("bug author:@#{user.username} assignee:@#{user.username} report label:~#{bug_label.title} milestone:%#{milestone.title} foo") expect_issues_list_count(1) - expect_filtered_search_input('bug report with everything you') + expect_filtered_search_input('bug report foo') end it 'filters issues by searched text, author, assignee, multiple labels and milestone' do @@ -729,10 +729,10 @@ describe 'Filter issues', js: true, feature: true do end it 'filters issues by searched text, author, text, assignee, text, label1, text, label2, text, milestone and text' do - input_filtered_search("bug author:@#{user.username} report assignee:@#{user.username} with label:~#{bug_label.title} everything label:~#{caps_sensitive_label.title} you milestone:%#{milestone.title} thought") + input_filtered_search("bug author:@#{user.username} assignee:@#{user.username} report label:~#{bug_label.title} label:~#{caps_sensitive_label.title} milestone:%#{milestone.title} foo") expect_issues_list_count(1) - expect_filtered_search_input('bug report with everything you thought') + expect_filtered_search_input('bug report foo') end end diff --git a/spec/features/profiles/personal_access_tokens_spec.rb b/spec/features/profiles/personal_access_tokens_spec.rb index 0917d4dc3ef..99fba594651 100644 --- a/spec/features/profiles/personal_access_tokens_spec.rb +++ b/spec/features/profiles/personal_access_tokens_spec.rb @@ -27,7 +27,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do describe "token creation" do it "allows creation of a personal access token" do - name = FFaker::Product.brand + name = 'My PAT' visit profile_personal_access_tokens_path fill_in "Name", with: name @@ -52,7 +52,7 @@ describe 'Profile > Personal Access Tokens', feature: true, js: true do it "displays an error message" do disallow_personal_access_token_saves! visit profile_personal_access_tokens_path - fill_in "Name", with: FFaker::Product.brand + fill_in "Name", with: 'My PAT' expect { click_on "Create Personal Access Token" }.not_to change { PersonalAccessToken.count } expect(page).to have_content("Name cannot be nil") diff --git a/spec/features/projects/blobs/user_create_spec.rb b/spec/features/projects/blobs/user_create_spec.rb index 5686868a0c4..d214a531138 100644 --- a/spec/features/projects/blobs/user_create_spec.rb +++ b/spec/features/projects/blobs/user_create_spec.rb @@ -88,7 +88,7 @@ feature 'New blob creation', feature: true, js: true do scenario 'shows error message' do expect(page).to have_content('Your changes could not be committed because a file with the same name already exists') - expect(page).to have_content('New File') + expect(page).to have_content('New file') expect(page).to have_content('NextFeature') end end diff --git a/spec/features/projects/files/project_owner_creates_license_file_spec.rb b/spec/features/projects/files/project_owner_creates_license_file_spec.rb index ccadc936567..6b281e6d21d 100644 --- a/spec/features/projects/files/project_owner_creates_license_file_spec.rb +++ b/spec/features/projects/files/project_owner_creates_license_file_spec.rb @@ -40,7 +40,7 @@ feature 'project owner creates a license file', feature: true, js: true do scenario 'project master creates a license file from the "Add license" link' do click_link 'Add License' - expect(page).to have_content('New File') + expect(page).to have_content('New file') expect(current_path).to eq( namespace_project_new_blob_path(project.namespace, project, 'master')) expect(find('#file_name').value).to eq('LICENSE') @@ -63,7 +63,7 @@ feature 'project owner creates a license file', feature: true, js: true do def select_template(template) page.within('.js-license-selector-wrap') do - click_button 'Choose a License template' + click_button 'Apply a License template' click_link template wait_for_ajax end 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 420db962318..87322ac2584 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 @@ -14,7 +14,7 @@ feature 'project owner sees a link to create a license file in empty project', f visit namespace_project_path(project.namespace, project) click_link 'Create empty bare repository' click_on 'LICENSE' - expect(page).to have_content('New File') + expect(page).to have_content('New file') expect(current_path).to eq( namespace_project_new_blob_path(project.namespace, project, 'master')) @@ -40,7 +40,7 @@ feature 'project owner sees a link to create a license file in empty project', f def select_template(template) page.within('.js-license-selector-wrap') do - click_button 'Choose a License template' + click_button 'Apply a License template' click_link template wait_for_ajax end diff --git a/spec/features/projects/files/template_type_dropdown_spec.rb b/spec/features/projects/files/template_type_dropdown_spec.rb new file mode 100644 index 00000000000..5ee5e5b4c4e --- /dev/null +++ b/spec/features/projects/files/template_type_dropdown_spec.rb @@ -0,0 +1,135 @@ +require 'spec_helper' + +feature 'Template type dropdown selector', js: true do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + project.team << [user, :master] + login_as user + end + + context 'editing a non-matching file' do + before do + create_and_edit_file('.random-file.js') + end + + scenario 'not displayed' do + check_type_selector_display(false) + end + + scenario 'selects every template type correctly' do + fill_in 'file_path', with: '.gitignore' + try_selecting_all_types + end + + scenario 'updates toggle value when input matches' do + fill_in 'file_path', with: '.gitignore' + check_type_selector_toggle_text('.gitignore') + end + end + + context 'editing a matching file' do + before do + visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, 'LICENSE')) + end + + scenario 'displayed' do + check_type_selector_display(true) + end + + scenario 'is displayed when input matches' do + check_type_selector_display(true) + end + + scenario 'selects every template type correctly' do + try_selecting_all_types + end + + context 'user previews changes' do + before do + click_link 'Preview Changes' + end + + scenario 'type selector is hidden and shown correctly' do + check_type_selector_display(false) + click_link 'Write' + check_type_selector_display(true) + end + end + end + + context 'creating a matching file' do + before do + visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: '.gitignore') + end + + scenario 'is displayed' do + check_type_selector_display(true) + end + + scenario 'toggle is set to the correct value' do + check_type_selector_toggle_text('.gitignore') + end + + scenario 'selects every template type correctly' do + try_selecting_all_types + end + end + + context 'creating a file' do + before do + visit namespace_project_new_blob_path(project.namespace, project, project.default_branch) + end + + scenario 'type selector is shown' do + check_type_selector_display(true) + end + + scenario 'toggle is set to the proper value' do + check_type_selector_toggle_text('Choose type') + end + + scenario 'selects every template type correctly' do + try_selecting_all_types + end + end +end + +def check_type_selector_display(is_visible) + count = is_visible ? 1 : 0 + expect(page).to have_css('.js-template-type-selector', count: count) +end + +def try_selecting_all_types + try_selecting_template_type('LICENSE', 'Apply a License template') + try_selecting_template_type('Dockerfile', 'Apply a Dockerfile template') + try_selecting_template_type('.gitlab-ci.yml', 'Apply a GitLab CI Yaml template') + try_selecting_template_type('.gitignore', 'Apply a .gitignore template') +end + +def try_selecting_template_type(template_type, selector_label) + select_template_type(template_type) + check_template_selector_display(selector_label) + check_type_selector_toggle_text(template_type) +end + +def select_template_type(template_type) + find('.js-template-type-selector').click + find('.dropdown-content li', text: template_type).click +end + +def check_template_selector_display(content) + expect(page).to have_content(content) +end + +def check_type_selector_toggle_text(template_type) + dropdown_toggle_button = find('.template-type-selector .dropdown-toggle-text') + expect(dropdown_toggle_button).to have_content(template_type) +end + +def create_and_edit_file(file_name) + visit namespace_project_new_blob_path(project.namespace, project, 'master', file_name: file_name) + click_button "Commit Changes" + visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, file_name)) +end diff --git a/spec/features/projects/files/undo_template_spec.rb b/spec/features/projects/files/undo_template_spec.rb new file mode 100644 index 00000000000..5479ea34610 --- /dev/null +++ b/spec/features/projects/files/undo_template_spec.rb @@ -0,0 +1,67 @@ +require 'spec_helper' +include WaitForAjax + +feature 'Template Undo Button', js: true do + let(:project) { create(:project) } + let(:user) { create(:user) } + + before do + project.team << [user, :master] + login_as user + end + + context 'editing a matching file and applying a template' do + before do + visit namespace_project_edit_blob_path(project.namespace, project, File.join(project.default_branch, "LICENSE")) + select_file_template('.js-license-selector', 'Apache License 2.0') + end + + scenario 'reverts template application' do + try_template_undo('http://www.apache.org/licenses/', 'Apply a License template') + end + end + + context 'creating a non-matching file' do + before do + visit namespace_project_new_blob_path(project.namespace, project, 'master') + select_file_template_type('LICENSE') + select_file_template('.js-license-selector', 'Apache License 2.0') + end + + scenario 'reverts template application' do + try_template_undo('http://www.apache.org/licenses/', 'Apply a License template') + end + end +end + +def try_template_undo(template_content, toggle_text) + check_undo_button_display + check_content_reverted(template_content) + check_toggle_text_set(toggle_text) +end + +def check_toggle_text_set(neutral_toggle_text) + expect(page).to have_content(neutral_toggle_text) +end + +def check_undo_button_display + expect(page).to have_content('Template applied') + expect(page).to have_css('.template-selectors-undo-menu .btn-info') +end + +def check_content_reverted(template_content) + find('.template-selectors-undo-menu .btn-info').click + expect(page).not_to have_content(template_content) + expect(find('.template-type-selector .dropdown-toggle-text')).to have_content() +end + +def select_file_template(template_selector_selector, template_name) + find(template_selector_selector).click + find('.dropdown-content li', text: template_name).click + wait_for_ajax +end + +def select_file_template_type(template_type) + find('.js-template-type-selector').click + find('.dropdown-content li', text: template_type).click +end diff --git a/spec/features/u2f_spec.rb b/spec/features/u2f_spec.rb index a8d00bb8e5a..28373098123 100644 --- a/spec/features/u2f_spec.rb +++ b/spec/features/u2f_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: true, js: true do +feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', :js do include WaitForAjax before { allow_any_instance_of(U2fHelper).to receive(:inject_u2f_api?).and_return(true) } @@ -11,8 +11,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: wait_for_ajax end - def register_u2f_device(u2f_device = nil) - name = FFaker::Name.first_name + def register_u2f_device(u2f_device = nil, name: 'My device') u2f_device ||= FakeU2fDevice.new(page, name) u2f_device.respond_to_u2f_registration click_on 'Setup New U2F Device' @@ -62,7 +61,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: expect(page).to have_content('Your U2F device was registered') # Second device - second_device = register_u2f_device + second_device = register_u2f_device(name: 'My other device') expect(page).to have_content('Your U2F device was registered') expect(page).to have_content(first_device.name) @@ -76,7 +75,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: expect(page).to have_content("You've already enabled two-factor authentication using mobile") first_u2f_device = register_u2f_device - second_u2f_device = register_u2f_device + second_u2f_device = register_u2f_device(name: 'My other device') click_on "Delete", match: :first @@ -99,7 +98,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: user.update_attribute(:otp_required_for_login, true) visit profile_account_path manage_two_factor_authentication - register_u2f_device(u2f_device) + register_u2f_device(u2f_device, name: 'My other device') expect(page).to have_content('Your U2F device was registered') expect(U2fRegistration.count).to eq(2) @@ -198,7 +197,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: current_user.update_attribute(:otp_required_for_login, true) visit profile_account_path manage_two_factor_authentication - register_u2f_device + register_u2f_device(name: 'My other device') logout # Try authenticating user with the old U2F device @@ -231,7 +230,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: describe "when a given U2F device has not been registered" do it "does not allow logging in with that particular device" do - unregistered_device = FakeU2fDevice.new(page, FFaker::Name.first_name) + unregistered_device = FakeU2fDevice.new(page, 'My device') login_as(user) unregistered_device.respond_to_u2f_authentication expect(page).to have_content('We heard back from your U2F device') @@ -252,7 +251,7 @@ feature 'Using U2F (Universal 2nd Factor) Devices for Authentication', feature: # Register second device visit profile_two_factor_auth_path expect(page).to have_content("Your U2F device needs to be set up.") - second_device = register_u2f_device + second_device = register_u2f_device(name: 'My other device') logout # Authenticate as both devices diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb index ee52dc65175..231fd85c464 100644 --- a/spec/finders/issues_finder_spec.rb +++ b/spec/finders/issues_finder_spec.rb @@ -9,7 +9,7 @@ describe IssuesFinder do let(:label) { create(:label, project: project2) } let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone, title: 'gitlab') } let(:issue2) { create(:issue, author: user, assignee: user, project: project2, description: 'gitlab') } - let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) } + let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2, title: 'tanuki', description: 'tanuki') } describe '#execute' do let(:closed_issue) { create(:issue, author: user2, assignee: user2, project: project2, state: 'closed') } diff --git a/spec/initializers/trusted_proxies_spec.rb b/spec/initializers/trusted_proxies_spec.rb index ff8b8daa347..70a18f31744 100644 --- a/spec/initializers/trusted_proxies_spec.rb +++ b/spec/initializers/trusted_proxies_spec.rb @@ -56,7 +56,7 @@ describe 'trusted_proxies', lib: true do end def stub_request(headers = {}) - ActionDispatch::RemoteIp.new(Proc.new { }, false, Rails.application.config.action_dispatch.trusted_proxies).call(headers) + ActionDispatch::RemoteIp.new(proc { }, false, Rails.application.config.action_dispatch.trusted_proxies).call(headers) ActionDispatch::Request.new(headers) end diff --git a/spec/javascripts/environments/environment_spec.js b/spec/javascripts/environments/environment_spec.js index 9601575577e..9bcf617fcd8 100644 --- a/spec/javascripts/environments/environment_spec.js +++ b/spec/javascripts/environments/environment_spec.js @@ -91,6 +91,10 @@ describe('Environment', () => { }); describe('pagination', () => { + afterEach(() => { + window.history.pushState({}, null, ''); + }); + it('should render pagination', (done) => { setTimeout(() => { expect( diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 7cf39d37181..5a93d479c1f 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -46,6 +46,10 @@ require('~/lib/utils/common_utils'); spyOn(window.document, 'getElementById').and.callThrough(); }); + afterEach(() => { + window.history.pushState({}, null, ''); + }); + function expectGetElementIdToHaveBeenCalledWith(elementId) { expect(window.document.getElementById).toHaveBeenCalledWith(elementId); } @@ -75,11 +79,56 @@ require('~/lib/utils/common_utils'); }); }); + describe('gl.utils.setParamInURL', () => { + afterEach(() => { + window.history.pushState({}, null, ''); + }); + + it('should return the parameter', () => { + window.history.replaceState({}, null, ''); + + expect(gl.utils.setParamInURL('page', 156)).toBe('?page=156'); + expect(gl.utils.setParamInURL('page', '156')).toBe('?page=156'); + }); + + it('should update the existing parameter when its a number', () => { + window.history.pushState({}, null, '?page=15'); + + expect(gl.utils.setParamInURL('page', 16)).toBe('?page=16'); + expect(gl.utils.setParamInURL('page', '16')).toBe('?page=16'); + expect(gl.utils.setParamInURL('page', true)).toBe('?page=true'); + }); + + it('should update the existing parameter when its a string', () => { + window.history.pushState({}, null, '?scope=all'); + + expect(gl.utils.setParamInURL('scope', 'finished')).toBe('?scope=finished'); + }); + + it('should update the existing parameter when more than one parameter exists', () => { + window.history.pushState({}, null, '?scope=all&page=15'); + + expect(gl.utils.setParamInURL('scope', 'finished')).toBe('?scope=finished&page=15'); + }); + + it('should add a new parameter to the end of the existing ones', () => { + window.history.pushState({}, null, '?scope=all'); + + expect(gl.utils.setParamInURL('page', 16)).toBe('?scope=all&page=16'); + expect(gl.utils.setParamInURL('page', '16')).toBe('?scope=all&page=16'); + expect(gl.utils.setParamInURL('page', true)).toBe('?scope=all&page=true'); + }); + }); + describe('gl.utils.getParameterByName', () => { beforeEach(() => { window.history.pushState({}, null, '?scope=all&p=2'); }); + afterEach(() => { + window.history.replaceState({}, null, null); + }); + it('should return valid parameter', () => { const value = gl.utils.getParameterByName('scope'); expect(value).toBe('all'); diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js b/spec/javascripts/vue_shared/components/table_pagination_spec.js index d1640ffed99..96038718191 100644 --- a/spec/javascripts/vue_shared/components/table_pagination_spec.js +++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js @@ -124,6 +124,10 @@ describe('Pagination component', () => { }); describe('paramHelper', () => { + afterEach(() => { + window.history.pushState({}, null, ''); + }); + it('can parse url parameters correctly', () => { window.history.pushState({}, null, '?scope=all&p=2'); diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb index 8b5bfc4dbb0..6ec4360adc2 100644 --- a/spec/lib/gitlab/etag_caching/middleware_spec.rb +++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb @@ -99,6 +99,19 @@ describe Gitlab::EtagCaching::Middleware do middleware.call(build_env(path, if_none_match)) end + + context 'when polling is disabled' do + before do + allow(Gitlab::PollingInterval).to receive(:polling_enabled?). + and_return(false) + end + + it 'returns status code 429' do + status, _, _ = middleware.call(build_env(path, if_none_match)) + + expect(status).to eq 429 + end + end end context 'when If-None-Match header does not match ETag in store' do diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb index 83d2ff8f9b3..82685712b5b 100644 --- a/spec/lib/gitlab/git/tree_spec.rb +++ b/spec/lib/gitlab/git/tree_spec.rb @@ -19,6 +19,7 @@ describe Gitlab::Git::Tree, seed_helper: true do it { expect(dir.commit_id).to eq(SeedRepo::Commit::ID) } it { expect(dir.name).to eq('encoding') } it { expect(dir.path).to eq('encoding') } + it { expect(dir.mode).to eq('40000') } context :subdir do let(:subdir) { Gitlab::Git::Tree.where(repository, SeedRepo::Commit::ID, 'files').first } diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index 48f7754bed8..703b41f95ac 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -183,7 +183,7 @@ describe Gitlab::GitAccess, lib: true do describe '#check_push_access!' do before { merge_into_protected_branch } - let(:unprotected_branch) { FFaker::Internet.user_name } + let(:unprotected_branch) { 'unprotected_branch' } let(:changes) do { push_new_branch: "#{Gitlab::Git::BLANK_SHA} 570e7b2ab refs/heads/wow", @@ -211,9 +211,9 @@ describe Gitlab::GitAccess, lib: true do target_branch = project.repository.lookup('feature') source_branch = project.repository.create_file( user, - FFaker::InternetSE.login_user_name, - FFaker::HipsterIpsum.paragraph, - message: FFaker::HipsterIpsum.sentence, + 'John Doe', + 'This is the file content', + message: 'This is a good commit message', branch_name: unprotected_branch) rugged = project.repository.rugged author = { email: "email@example.com", time: Time.now, name: "Example Git User" } diff --git a/spec/lib/gitlab/git_spec.rb b/spec/lib/gitlab/git_spec.rb index 8eaf7aac264..36f0e6507c8 100644 --- a/spec/lib/gitlab/git_spec.rb +++ b/spec/lib/gitlab/git_spec.rb @@ -1,21 +1,8 @@ require 'spec_helper' describe Gitlab::Git, lib: true do - let(:committer_email) { FFaker::Internet.email } - - # I have to remove periods from the end of the name - # This happened when the user's name had a suffix (i.e. "Sr.") - # This seems to be what git does under the hood. For example, this commit: - # - # $ git commit --author='Foo Sr. <foo@example.com>' -m 'Where's my trailing period?' - # - # results in this: - # - # $ git show --pretty - # ... - # Author: Foo Sr <foo@example.com> - # ... - let(:committer_name) { FFaker::Name.name.chomp("\.") } + let(:committer_email) { 'user@example.org' } + let(:committer_name) { 'John Doe' } describe 'committer_hash' do it "returns a hash containing the given email and name" do diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb new file mode 100644 index 00000000000..55fcf91fb6e --- /dev/null +++ b/spec/lib/gitlab/gitaly_client_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe Gitlab::GitalyClient, lib: true do + describe '.new_channel' do + context 'when passed a UNIX socket address' do + it 'passes the address as-is to GRPC::Core::Channel initializer' do + address = 'unix:/tmp/gitaly.sock' + + expect(GRPC::Core::Channel).to receive(:new).with(address, any_args) + + described_class.new_channel(address) + end + end + + context 'when passed a TCP address' do + it 'strips tcp:// prefix before passing it to GRPC::Core::Channel initializer' do + address = 'localhost:9876' + prefixed_address = "tcp://#{address}" + + expect(GRPC::Core::Channel).to receive(:new).with(address, any_args) + + described_class.new_channel(prefixed_address) + end + end + end +end diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb index 8b867fbe322..9d5e20841b5 100644 --- a/spec/lib/gitlab/github_import/importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -215,9 +215,9 @@ describe Gitlab::GithubImport::Importer, lib: true do let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } let(:repository) { double(id: 1, fork: false) } let(:source_sha) { create(:commit, project: project).id } - let(:source_branch) { double(ref: 'branch-merged', repo: repository, sha: source_sha) } + let(:source_branch) { double(ref: 'branch-merged', repo: repository, sha: source_sha, user: octocat) } let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id } - let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) } + let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha, user: octocat) } let(:pull_request) do double( number: 1347, diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb index 44423917944..b7c59918a76 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -4,15 +4,18 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do let(:client) { double } let(:project) { create(:project, :repository) } let(:source_sha) { create(:commit, project: project).id } - let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id } + let(:target_commit) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit) } + let(:target_sha) { target_commit.id } + let(:target_short_sha) { target_commit.id.to_s[0..7] } let(:repository) { double(id: 1, fork: false) } let(:source_repo) { repository } let(:source_branch) { double(ref: 'branch-merged', repo: source_repo, sha: source_sha) } let(:forked_source_repo) { double(id: 2, fork: true, name: 'otherproject', full_name: 'company/otherproject') } let(:target_repo) { repository } - let(:target_branch) { double(ref: 'master', repo: target_repo, sha: target_sha) } - let(:removed_branch) { double(ref: 'removed-branch', repo: source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b') } - let(:forked_branch) { double(ref: 'master', repo: forked_source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b') } + let(:target_branch) { double(ref: 'master', repo: target_repo, sha: target_sha, user: octocat) } + let(:removed_branch) { double(ref: 'removed-branch', repo: source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) } + let(:forked_branch) { double(ref: 'master', repo: forked_source_repo, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: octocat) } + let(:branch_deleted_repo) { double(ref: 'master', repo: nil, sha: '2e5d3239642f9161dcbbc4b70a211a68e5e45e2b', user: 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') } @@ -61,7 +64,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do author_id: project.creator_id, assignee_id: nil, created_at: created_at, - updated_at: updated_at + updated_at: updated_at, + imported: true } expect(pull_request.attributes).to eq(expected) @@ -87,7 +91,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do author_id: project.creator_id, assignee_id: nil, created_at: created_at, - updated_at: updated_at + updated_at: updated_at, + imported: true } expect(pull_request.attributes).to eq(expected) @@ -114,7 +119,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do author_id: project.creator_id, assignee_id: nil, created_at: created_at, - updated_at: updated_at + updated_at: updated_at, + imported: true } expect(pull_request.attributes).to eq(expected) @@ -203,16 +209,24 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do context 'when source branch does not exist' do let(:raw_data) { double(base_data.merge(head: removed_branch)) } - it 'prefixes branch name with pull request number' do - expect(pull_request.source_branch_name).to eq 'pull/1347/removed-branch' + it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do + expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/removed-branch" end end context 'when source branch is from a fork' do let(:raw_data) { double(base_data.merge(head: forked_branch)) } - it 'prefixes branch name with pull request number and project with namespace to avoid collision' do - expect(pull_request.source_branch_name).to eq 'pull/1347/company/otherproject/master' + it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do + expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/master" + end + end + + context 'when source branch is from a deleted fork' do + let(:raw_data) { double(base_data.merge(head: branch_deleted_repo)) } + + it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do + expect(pull_request.source_branch_name).to eq "gh-#{target_short_sha}/1347/octocat/master" end end end @@ -229,8 +243,8 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do context 'when target branch does not exist' do let(:raw_data) { double(base_data.merge(base: removed_branch)) } - it 'prefixes branch name with pull request number' do - expect(pull_request.target_branch_name).to eq 'pull/1347/removed-branch' + it 'prefixes branch name with gh-:short_sha/:number/:user pattern to avoid collision' do + expect(pull_request.target_branch_name).to eq 'gl-2e5d3239/1347/octocat/removed-branch' end end end @@ -290,6 +304,14 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end end + context 'when source repository does not exist anymore' do + let(:raw_data) { double(base_data.merge(head: branch_deleted_repo)) } + + it 'returns true' do + expect(pull_request.cross_project?).to eq true + end + end + context 'when source and target repositories are the same' do let(:raw_data) { double(base_data.merge(head: source_branch)) } @@ -299,6 +321,14 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end end + describe '#source_branch_exists?' do + let(:raw_data) { double(base_data.merge(head: forked_branch)) } + + it 'returns false when is a cross_project' do + expect(pull_request.source_branch_exists?).to eq false + end + end + describe '#url' do let(:raw_data) { double(base_data) } diff --git a/spec/lib/gitlab/polling_interval_spec.rb b/spec/lib/gitlab/polling_interval_spec.rb new file mode 100644 index 00000000000..56c2847e26a --- /dev/null +++ b/spec/lib/gitlab/polling_interval_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe Gitlab::PollingInterval, lib: true do + let(:polling_interval) { described_class } + + describe '.set_header' do + let(:headers) { {} } + let(:response) { double(headers: headers) } + + context 'when polling is disabled' do + before do + stub_application_setting(polling_interval_multiplier: 0) + end + + it 'sets value to -1' do + polling_interval.set_header(response, interval: 10_000) + + expect(headers['Poll-Interval']).to eq(-1) + end + end + + context 'when polling is enabled' do + before do + stub_application_setting(polling_interval_multiplier: 0.33333) + end + + it 'applies modifier to base interval' do + polling_interval.set_header(response, interval: 10_000) + + expect(headers['Poll-Interval']).to eq(3333) + end + end + end +end diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index 535c96eeee9..3bd2a3238fe 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -179,19 +179,69 @@ describe Gitlab::Workhorse, lib: true do describe '.git_http_ok' do let(:user) { create(:user) } + let(:repo_path) { repository.path_to_repo } + let(:action) { 'info_refs' } - subject { described_class.git_http_ok(repository, user) } + subject { described_class.git_http_ok(repository, user, action) } - it { expect(subject).to eq({ GL_ID: "user-#{user.id}", RepoPath: repository.path_to_repo }) } + it { expect(subject).to include({ GL_ID: "user-#{user.id}", RepoPath: repo_path }) } context 'when Gitaly is enabled' do + let(:gitaly_params) do + { + GitalySocketPath: URI(Gitlab::GitalyClient.get_address('default')).path, + } + end + before do allow(Gitlab.config.gitaly).to receive(:enabled).and_return(true) end - it 'includes Gitaly params in the returned value' do - gitaly_socket_path = URI(Gitlab::GitalyClient.get_address('default')).path - expect(subject).to include({ GitalySocketPath: gitaly_socket_path }) + it 'includes a Repository param' do + repo_param = { Repository: { + path: repo_path, + storage_name: 'default', + relative_path: project.full_path + '.git', + } } + + expect(subject).to include(repo_param) + end + + { + git_receive_pack: :post_receive_pack, + git_upload_pack: :post_upload_pack + }.each do |action_name, feature_flag| + context "when #{action_name} action is passed" do + let(:action) { action_name } + + context 'when action is enabled by feature flag' do + it 'includes Gitaly params in the returned value' do + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag).and_return(true) + + expect(subject).to include(gitaly_params) + end + end + + context 'when action is not enabled by feature flag' do + it 'does not include Gitaly params in the returned value' do + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(feature_flag).and_return(false) + + expect(subject).not_to include(gitaly_params) + end + end + end + end + + context "when info_refs action is passed" do + let(:action) { 'info_refs' } + + it { expect(subject).to include(gitaly_params) } + end + + context 'when action passed is not supported by Gitaly' do + let(:action) { 'download' } + + it { expect { subject }.to raise_exception('Unsupported action: download') } end end end diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index f60c5ffb32a..6a89b007f96 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -37,7 +37,7 @@ describe Notify do context 'for issues' do let(:issue) { create(:issue, author: current_user, assignee: assignee, project: project) } - let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: FFaker::Lorem.sentence) } + let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: 'My awesome description') } describe 'that are new' do subject { Notify.new_issue_email(issue.assignee_id, issue.id) } @@ -187,7 +187,7 @@ describe Notify do let(:project) { create(:project, :repository) } let(:merge_author) { create(:user) } let(:merge_request) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project) } - let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: FFaker::Lorem.sentence) } + let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: 'My awesome description') } describe 'that are new' do subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 53282b999dc..e4a24fd63c2 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1055,10 +1055,13 @@ describe Ci::Pipeline, models: true do end before do - reset_delivered_emails! - project.team << [pipeline.user, Gitlab::Access::DEVELOPER] + 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/cycle_analytics/plan_spec.rb b/spec/models/cycle_analytics/plan_spec.rb index 55483fc876a..4f33f3c6d69 100644 --- a/spec/models/cycle_analytics/plan_spec.rb +++ b/spec/models/cycle_analytics/plan_spec.rb @@ -13,7 +13,7 @@ describe 'CycleAnalytics#plan', feature: true do data_fn: -> (context) do { issue: context.create(:issue, project: context.project), - branch_name: context.random_git_name + branch_name: context.generate(:branch) } end, start_time_conditions: [["issue associated with a milestone", @@ -35,7 +35,7 @@ describe 'CycleAnalytics#plan', feature: true do context "when a regular label (instead of a list label) is added to the issue" do it "returns nil" do - branch_name = random_git_name + branch_name = generate(:branch) label = create(:label) issue = create(:issue, project: project) issue.update(label_ids: [label.id]) diff --git a/spec/models/cycle_analytics/production_spec.rb b/spec/models/cycle_analytics/production_spec.rb index e6a826a9418..4744b9e05ea 100644 --- a/spec/models/cycle_analytics/production_spec.rb +++ b/spec/models/cycle_analytics/production_spec.rb @@ -23,7 +23,7 @@ describe 'CycleAnalytics#production', feature: true do # Make other changes on master sha = context.project.repository.create_file( context.user, - context.random_git_name, + context.generate(:branch), 'content', message: 'commit message', branch_name: 'master') diff --git a/spec/models/cycle_analytics/staging_spec.rb b/spec/models/cycle_analytics/staging_spec.rb index 3a02ed81adb..f78d7a23105 100644 --- a/spec/models/cycle_analytics/staging_spec.rb +++ b/spec/models/cycle_analytics/staging_spec.rb @@ -28,7 +28,7 @@ describe 'CycleAnalytics#staging', feature: true do # Make other changes on master sha = context.project.repository.create_file( context.user, - context.random_git_name, + context.generate(:branch), 'content', message: 'commit message', branch_name: 'master') diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index df742ee8084..d805e65b3c6 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -24,21 +24,8 @@ describe Repository, models: true do repository.commit(merge_commit_id) end - let(:author_email) { FFaker::Internet.email } - - # I have to remove periods from the end of the name - # This happened when the user's name had a suffix (i.e. "Sr.") - # This seems to be what git does under the hood. For example, this commit: - # - # $ git commit --author='Foo Sr. <foo@example.com>' -m 'Where's my trailing period?' - # - # results in this: - # - # $ git show --pretty - # ... - # Author: Foo Sr <foo@example.com> - # ... - let(:author_name) { FFaker::Name.name.chomp("\.") } + let(:author_email) { 'user@example.org' } + let(:author_name) { 'John Doe' } describe '#branch_names_contains' do subject { repository.branch_names_contains(sample_commit.id) } @@ -1293,14 +1280,6 @@ describe Repository, models: true do end end - describe '#before_import' do - it 'flushes the repository caches' do - expect(repository).to receive(:expire_content_cache) - - repository.before_import - end - end - describe '#after_import' do it 'flushes and builds the cache' do expect(repository).to receive(:expire_content_cache) diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index a7fad7f0bdb..8012530f139 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -11,21 +11,8 @@ describe API::Files, api: true do ref: 'master' } end - let(:author_email) { FFaker::Internet.email } - - # I have to remove periods from the end of the name - # This happened when the user's name had a suffix (i.e. "Sr.") - # This seems to be what git does under the hood. For example, this commit: - # - # $ git commit --author='Foo Sr. <foo@example.com>' -m 'Where's my trailing period?' - # - # results in this: - # - # $ git show --pretty - # ... - # Author: Foo Sr <foo@example.com> - # ... - let(:author_name) { FFaker::Name.name.chomp("\.") } + let(:author_email) { 'user@example.org' } + let(:author_name) { 'John Doe' } before { project.team << [user, :developer] } diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 91d6fb83c0b..4729adba11c 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -19,7 +19,7 @@ describe API::Issues, api: true do project: project, state: :closed, milestone: milestone, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 3.hours.ago end let!(:confidential_issue) do @@ -28,7 +28,7 @@ describe API::Issues, api: true do project: project, author: author, assignee: assignee, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 2.hours.ago end let!(:issue) do @@ -37,7 +37,7 @@ describe API::Issues, api: true do assignee: user, project: project, milestone: milestone, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 1.hour.ago end let!(:label) do diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index 2d37d026a39..84dca51801f 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::Members, api: true do include ApiHelpers - let(:master) { create(:user) } + let(:master) { create(:user, username: 'master_user') } let(:developer) { create(:user) } let(:access_requester) { create(:user) } let(:stranger) { create(:user) } diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index a3de4702ad0..2e291eb3cea 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -341,7 +341,6 @@ describe API::Projects, :api do it "assigns attributes to project" do project = attributes_for(:project, { path: 'camelCasePath', - description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, @@ -475,7 +474,6 @@ describe API::Projects, :api do it 'assigns attributes to project' do project = attributes_for(:project, { - description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 04e7837fd7a..f793c0db2f3 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -676,7 +676,7 @@ describe API::Users, api: true do before { admin } it "deletes user" do - delete api("/users/#{user.id}", admin) + Sidekiq::Testing.inline! { delete api("/users/#{user.id}", admin) } expect(response).to have_http_status(204) expect { User.find(user.id) }.to raise_error ActiveRecord::RecordNotFound @@ -684,23 +684,23 @@ describe API::Users, api: true do end it "does not delete for unauthenticated user" do - delete api("/users/#{user.id}") + Sidekiq::Testing.inline! { delete api("/users/#{user.id}") } expect(response).to have_http_status(401) end it "is not available for non admin users" do - delete api("/users/#{user.id}", user) + Sidekiq::Testing.inline! { delete api("/users/#{user.id}", user) } expect(response).to have_http_status(403) end it "returns 404 for non-existing user" do - delete api("/users/999999", admin) + Sidekiq::Testing.inline! { delete api("/users/999999", admin) } expect(response).to have_http_status(404) expect(json_response['message']).to eq('404 User Not Found') end it "returns a 404 for invalid ID" do - delete api("/users/ASDF", admin) + Sidekiq::Testing.inline! { delete api("/users/ASDF", admin) } expect(response).to have_http_status(404) end diff --git a/spec/requests/api/v3/files_spec.rb b/spec/requests/api/v3/files_spec.rb index 3b61139a2cd..349fd6b3415 100644 --- a/spec/requests/api/v3/files_spec.rb +++ b/spec/requests/api/v3/files_spec.rb @@ -26,8 +26,8 @@ describe API::V3::Files, api: true do ref: 'master' } end - let(:author_email) { FFaker::Internet.email } - let(:author_name) { FFaker::Name.name.chomp("\.") } + let(:author_email) { 'user@example.org' } + let(:author_name) { 'John Doe' } before { project.team << [user, :developer] } diff --git a/spec/requests/api/v3/issues_spec.rb b/spec/requests/api/v3/issues_spec.rb index 383871d5c38..b1b398a897e 100644 --- a/spec/requests/api/v3/issues_spec.rb +++ b/spec/requests/api/v3/issues_spec.rb @@ -19,7 +19,7 @@ describe API::V3::Issues, api: true do project: project, state: :closed, milestone: milestone, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 3.hours.ago end let!(:confidential_issue) do @@ -28,7 +28,7 @@ describe API::V3::Issues, api: true do project: project, author: author, assignee: assignee, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 2.hours.ago end let!(:issue) do @@ -37,7 +37,7 @@ describe API::V3::Issues, api: true do assignee: user, project: project, milestone: milestone, - created_at: generate(:issue_created_at), + created_at: generate(:past_time), updated_at: 1.hour.ago end let!(:label) do diff --git a/spec/requests/api/v3/members_spec.rb b/spec/requests/api/v3/members_spec.rb index 13814ed10c3..af1c5cff67f 100644 --- a/spec/requests/api/v3/members_spec.rb +++ b/spec/requests/api/v3/members_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::V3::Members, api: true do include ApiHelpers - let(:master) { create(:user) } + let(:master) { create(:user, username: 'master_user') } let(:developer) { create(:user) } let(:access_requester) { create(:user) } let(:stranger) { create(:user) } diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb index b1aa793ec00..40531fe7545 100644 --- a/spec/requests/api/v3/projects_spec.rb +++ b/spec/requests/api/v3/projects_spec.rb @@ -356,7 +356,6 @@ describe API::V3::Projects, api: true do it "assigns attributes to project" do project = attributes_for(:project, { path: 'camelCasePath', - description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, @@ -501,7 +500,6 @@ describe API::V3::Projects, api: true do it 'assigns attributes to project' do project = attributes_for(:project, { - description: FFaker::Lorem.sentence, issues_enabled: false, merge_requests_enabled: false, wiki_enabled: false, diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index d93616c4f50..bb98fb37a90 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -418,65 +418,6 @@ describe Ci::ProcessPipelineService, '#execute', :services do end end - context 'when there are builds that are not created yet' do - let(:pipeline) do - create(:ci_pipeline, config: config) - end - - let(:config) do - { rspec: { stage: 'test', script: 'rspec' }, - deploy: { stage: 'deploy', script: 'rsync' } } - end - - before do - create_build('linux', stage: 'build', stage_idx: 0) - create_build('mac', stage: 'build', stage_idx: 0) - end - - it 'processes the pipeline' do - # Currently we have five builds with state created - # - expect(builds.count).to eq(0) - expect(all_builds.count).to eq(2) - - # Process builds service will enqueue builds from the first stage. - # - process_pipeline - - expect(builds.count).to eq(2) - expect(all_builds.count).to eq(2) - - # When builds succeed we will enqueue remaining builds. - # - # We will have 2 succeeded, 1 pending (from stage test), total 4 (two - # additional build from `.gitlab-ci.yml`). - # - succeed_pending - process_pipeline - - expect(builds.success.count).to eq(2) - expect(builds.pending.count).to eq(1) - expect(all_builds.count).to eq(4) - - # When pending merge_when_pipeline_succeeds in stage test, we enqueue deploy stage. - # - succeed_pending - process_pipeline - - expect(builds.pending.count).to eq(1) - expect(builds.success.count).to eq(3) - expect(all_builds.count).to eq(4) - - # When the last one succeeds we have 4 successful builds. - # - succeed_pending - process_pipeline - - expect(builds.success.count).to eq(4) - expect(all_builds.count).to eq(4) - end - end - def process_pipeline described_class.new(pipeline.project, user).execute(pipeline) end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 5c841843b40..e3146a56495 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -113,7 +113,7 @@ describe NotificationService, services: true do project.add_master(issue.assignee) project.add_master(note.author) create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@subscribed_participant cc this guy') - update_custom_notification(:new_note, @u_guest_custom, project) + update_custom_notification(:new_note, @u_guest_custom, resource: project) update_custom_notification(:new_note, @u_custom_global) end @@ -379,7 +379,7 @@ describe NotificationService, services: true do build_team(note.project) reset_delivered_emails! allow_any_instance_of(Commit).to receive(:author).and_return(@u_committer) - update_custom_notification(:new_note, @u_guest_custom, project) + update_custom_notification(:new_note, @u_guest_custom, resource: project) update_custom_notification(:new_note, @u_custom_global) end @@ -457,7 +457,7 @@ describe NotificationService, services: true do add_users_with_subscription(issue.project, issue) reset_delivered_emails! - update_custom_notification(:new_issue, @u_guest_custom, project) + update_custom_notification(:new_issue, @u_guest_custom, resource: project) update_custom_notification(:new_issue, @u_custom_global) end @@ -567,7 +567,7 @@ describe NotificationService, services: true do describe '#reassigned_issue' do before do - update_custom_notification(:reassign_issue, @u_guest_custom, project) + update_custom_notification(:reassign_issue, @u_guest_custom, resource: project) update_custom_notification(:reassign_issue, @u_custom_global) end @@ -760,7 +760,7 @@ describe NotificationService, services: true do describe '#close_issue' do before do - update_custom_notification(:close_issue, @u_guest_custom, project) + update_custom_notification(:close_issue, @u_guest_custom, resource: project) update_custom_notification(:close_issue, @u_custom_global) end @@ -791,7 +791,7 @@ describe NotificationService, services: true do describe '#reopen_issue' do before do - update_custom_notification(:reopen_issue, @u_guest_custom, project) + update_custom_notification(:reopen_issue, @u_guest_custom, resource: project) update_custom_notification(:reopen_issue, @u_custom_global) end @@ -856,14 +856,14 @@ describe NotificationService, services: true do before do build_team(merge_request.target_project) add_users_with_subscription(merge_request.target_project, merge_request) - update_custom_notification(:new_merge_request, @u_guest_custom, project) + update_custom_notification(:new_merge_request, @u_guest_custom, resource: project) update_custom_notification(:new_merge_request, @u_custom_global) reset_delivered_emails! end describe '#new_merge_request' do before do - update_custom_notification(:new_merge_request, @u_guest_custom, project) + update_custom_notification(:new_merge_request, @u_guest_custom, resource: project) update_custom_notification(:new_merge_request, @u_custom_global) end @@ -952,7 +952,7 @@ describe NotificationService, services: true do describe '#reassigned_merge_request' do before do - update_custom_notification(:reassign_merge_request, @u_guest_custom, project) + update_custom_notification(:reassign_merge_request, @u_guest_custom, resource: project) update_custom_notification(:reassign_merge_request, @u_custom_global) end @@ -1026,7 +1026,7 @@ describe NotificationService, services: true do describe '#closed_merge_request' do before do - update_custom_notification(:close_merge_request, @u_guest_custom, project) + update_custom_notification(:close_merge_request, @u_guest_custom, resource: project) update_custom_notification(:close_merge_request, @u_custom_global) end @@ -1056,7 +1056,7 @@ describe NotificationService, services: true do describe '#merged_merge_request' do before do - update_custom_notification(:merge_merge_request, @u_guest_custom, project) + update_custom_notification(:merge_merge_request, @u_guest_custom, resource: project) update_custom_notification(:merge_merge_request, @u_custom_global) end @@ -1108,7 +1108,7 @@ describe NotificationService, services: true do describe '#reopen_merge_request' do before do - update_custom_notification(:reopen_merge_request, @u_guest_custom, project) + update_custom_notification(:reopen_merge_request, @u_guest_custom, resource: project) update_custom_notification(:reopen_merge_request, @u_custom_global) end @@ -1281,40 +1281,172 @@ describe NotificationService, services: true do describe 'Pipelines' do describe '#pipeline_finished' do let(:project) { create(:project, :public, :repository) } - let(:current_user) { create(:user) } let(:u_member) { create(:user) } - let(:u_other) { create(:user) } + let(:u_watcher) { create_user_with_notification(:watch, 'watcher') } + + let(:u_custom_notification_unset) do + create_user_with_notification(:custom, 'custom_unset') + end + + let(:u_custom_notification_enabled) do + user = create_user_with_notification(:custom, 'custom_enabled') + update_custom_notification(:success_pipeline, user, resource: project) + update_custom_notification(:failed_pipeline, user, resource: project) + user + end + + let(:u_custom_notification_disabled) do + user = create_user_with_notification(:custom, 'custom_disabled') + update_custom_notification(:success_pipeline, user, resource: project, value: false) + update_custom_notification(:failed_pipeline, user, resource: project, value: false) + user + end let(:commit) { project.commit } - let(:pipeline) do - create(:ci_pipeline, :success, + + def create_pipeline(user, status) + create(:ci_pipeline, status, project: project, - user: current_user, + user: user, ref: 'refs/heads/master', sha: commit.id, before_sha: '00000000') end before do - project.add_master(current_user) project.add_master(u_member) + project.add_master(u_watcher) + project.add_master(u_custom_notification_unset) + project.add_master(u_custom_notification_enabled) + project.add_master(u_custom_notification_disabled) + reset_delivered_emails! end - context 'without custom recipients' do - it 'notifies the pipeline user' do - notification.pipeline_finished(pipeline) + context 'with a successful pipeline' do + context 'when the creator has default settings' do + before do + pipeline = create_pipeline(u_member, :success) + notification.pipeline_finished(pipeline) + end + + it 'notifies nobody' do + should_not_email_anyone + end + end + + context 'when the creator has watch set' do + before do + pipeline = create_pipeline(u_watcher, :success) + notification.pipeline_finished(pipeline) + end + + it 'notifies nobody' do + should_not_email_anyone + end + end + + context 'when the creator has custom notifications, but without any set' do + before do + pipeline = create_pipeline(u_custom_notification_unset, :success) + notification.pipeline_finished(pipeline) + end + + it 'notifies nobody' do + should_not_email_anyone + end + end + + context 'when the creator has custom notifications disabled' do + before do + pipeline = create_pipeline(u_custom_notification_disabled, :success) + notification.pipeline_finished(pipeline) + end + + it 'notifies nobody' do + should_not_email_anyone + end + end + + context 'when the creator has custom notifications enabled' do + before do + pipeline = create_pipeline(u_custom_notification_enabled, :success) + notification.pipeline_finished(pipeline) + end - should_only_email(current_user, kind: :bcc) + it 'emails only the creator' do + should_only_email(u_custom_notification_enabled, kind: :bcc) + end end end - context 'with custom recipients' do - it 'notifies the custom recipients' do - users = [u_member, u_other] - notification.pipeline_finished(pipeline, users.map(&:notification_email)) + context 'with a failed pipeline' do + context 'when the creator has no custom notification set' do + before do + pipeline = create_pipeline(u_member, :failed) + notification.pipeline_finished(pipeline) + end + + it 'emails only the creator' do + should_only_email(u_member, kind: :bcc) + end + end + + context 'when the creator has watch set' do + before do + pipeline = create_pipeline(u_watcher, :failed) + notification.pipeline_finished(pipeline) + end + + it 'emails only the creator' do + should_only_email(u_watcher, kind: :bcc) + end + end + + context 'when the creator has custom notifications, but without any set' do + before do + pipeline = create_pipeline(u_custom_notification_unset, :failed) + notification.pipeline_finished(pipeline) + end + + it 'emails only the creator' do + should_only_email(u_custom_notification_unset, kind: :bcc) + end + end + + context 'when the creator has custom notifications disabled' do + before do + pipeline = create_pipeline(u_custom_notification_disabled, :failed) + notification.pipeline_finished(pipeline) + end - should_only_email(*users, kind: :bcc) + it 'notifies nobody' do + should_not_email_anyone + end + end + + context 'when the creator has custom notifications set' do + before do + pipeline = create_pipeline(u_custom_notification_enabled, :failed) + notification.pipeline_finished(pipeline) + end + + it 'emails only the creator' do + should_only_email(u_custom_notification_enabled, kind: :bcc) + end + end + + context 'when the creator has no read_build access' do + before do + pipeline = create_pipeline(u_member, :failed) + project.update(public_builds: false) + project.team.truncate + notification.pipeline_finished(pipeline) + end + + it 'does not send emails' do + should_not_email_anyone + end end end end @@ -1385,9 +1517,9 @@ describe NotificationService, services: true do # Create custom notifications # When resource is nil it means global notification - def update_custom_notification(event, user, resource = nil) + def update_custom_notification(event, user, resource: nil, value: true) setting = user.notification_settings_for(resource) - setting.events[event] = true + setting.events[event] = value setting.save end diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index e5917bb0b7a..09cfa36b3b9 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -26,30 +26,59 @@ describe Projects::ImportService, services: true do result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq 'The repository could not be created.' + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The repository could not be created." end end context 'with known url' do before do project.import_url = 'https://github.com/vim/vim.git' + project.import_type = 'github' end - it 'succeeds if repository import is successfully' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) + 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) - result = subject.execute + result = subject.execute - expect(result[:status]).to eq :success + expect(result[:status]).to eq :success + end + + it 'fails if repository import fails' do + expect_any_instance_of(Repository).to receive(:fetch_remote).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) + + 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 end - it 'fails if repository import fails' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) + context 'with a non Github repository' do + before do + project.import_url = 'https://bitbucket.org/vim/vim.git' + project.import_type = 'bitbucket' + end - result = subject.execute + it 'succeeds if repository import is successfully' do + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_return(true) + expect_any_instance_of(Gitlab::BitbucketImport::Importer).to receive(:execute).and_return(true) - 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" + result = subject.execute + + expect(result[:status]).to eq :success + end + + it 'fails if repository import fails' do + expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) + + 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 end end @@ -64,8 +93,8 @@ describe Projects::ImportService, services: true do end it 'succeeds if importer succeeds' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) - expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(true) + 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) result = subject.execute @@ -73,48 +102,42 @@ describe Projects::ImportService, services: true do end it 'flushes various caches' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository). - with(project.repository_storage_path, project.path_with_namespace, project.import_url). + allow_any_instance_of(Repository).to receive(:fetch_remote). and_return(true) - expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute). + allow_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute). and_return(true) - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches). - and_call_original - - expect_any_instance_of(Repository).to receive(:expire_exists_cache). - and_call_original + expect_any_instance_of(Repository).to receive(:expire_content_cache) subject.execute end it 'fails if importer fails' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) - expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_return(false) + 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) result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq 'The remote data could not be imported.' + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - The remote data could not be imported." end it 'fails if importer raise an error' do - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_return(true) - expect_any_instance_of(Gitlab::GithubImport::Importer).to receive(:execute).and_raise(Projects::ImportService::Error.new('Github: failed to connect API')) + 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')) result = subject.execute expect(result[:status]).to eq :error - expect(result[:message]).to eq 'Github: failed to connect API' + expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.path_with_namespace} - Github: failed to connect API" end - it 'expires existence cache after error' do + it 'expires content cache after error' do allow_any_instance_of(Project).to receive(:repository_exists?).and_return(false, true) - expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).with(project.repository_storage_path, project.path_with_namespace, project.import_url).and_raise(Gitlab::Shell::Error.new('Failed to import the repository')) - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches).and_call_original - expect_any_instance_of(Repository).to receive(:expire_exists_cache).and_call_original + 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(:expire_content_cache) subject.execute end diff --git a/spec/services/users/destroy_spec.rb b/spec/services/users/destroy_spec.rb index 9a28c03d968..66c61b7f8ff 100644 --- a/spec/services/users/destroy_spec.rb +++ b/spec/services/users/destroy_spec.rb @@ -17,13 +17,28 @@ describe Users::DestroyService, services: true do expect { Namespace.with_deleted.find(user.namespace.id) }.to raise_error(ActiveRecord::RecordNotFound) end - it 'will delete the project in the near future' do - expect_any_instance_of(Projects::DestroyService).to receive(:async_execute).once + it 'will delete the project' do + expect_any_instance_of(Projects::DestroyService).to receive(:execute).once service.execute(user) end end + context 'projects in pending_delete' do + before do + project.pending_delete = true + project.save + end + + it 'destroys a project in pending_delete' do + expect_any_instance_of(Projects::DestroyService).to receive(:execute).once + + service.execute(user) + + expect { Project.find(project.id) }.to raise_error(ActiveRecord::RecordNotFound) + end + end + context "a deleted user's issues" do let(:project) { create(:project) } diff --git a/spec/support/cycle_analytics_helpers.rb b/spec/support/cycle_analytics_helpers.rb index c864a705ca4..8ad042f5e3b 100644 --- a/spec/support/cycle_analytics_helpers.rb +++ b/spec/support/cycle_analytics_helpers.rb @@ -1,5 +1,5 @@ module CycleAnalyticsHelpers - def create_commit_referencing_issue(issue, branch_name: random_git_name) + def create_commit_referencing_issue(issue, branch_name: generate(:branch)) project.repository.add_branch(user, branch_name, 'master') create_commit("Commit for ##{issue.iid}", issue.project, user, branch_name) end @@ -7,9 +7,7 @@ module CycleAnalyticsHelpers def create_commit(message, project, user, branch_name, count: 1) oldrev = project.repository.commit(branch_name).sha commit_shas = Array.new(count) do |index| - filename = random_git_name - - commit_sha = project.repository.create_file(user, filename, "content", message: message, branch_name: branch_name) + commit_sha = project.repository.create_file(user, generate(:branch), "content", message: message, branch_name: branch_name) project.repository.commit(commit_sha) commit_sha @@ -24,13 +22,13 @@ module CycleAnalyticsHelpers def create_merge_request_closing_issue(issue, message: nil, source_branch: nil) if !source_branch || project.repository.commit(source_branch).blank? - source_branch = random_git_name + source_branch = generate(:branch) project.repository.add_branch(user, source_branch, 'master') end sha = project.repository.create_file( user, - random_git_name, + generate(:branch), 'content', message: 'commit message', branch_name: source_branch) diff --git a/spec/support/filter_spec_helper.rb b/spec/support/filter_spec_helper.rb index a8e454eb09e..b871b7ffc90 100644 --- a/spec/support/filter_spec_helper.rb +++ b/spec/support/filter_spec_helper.rb @@ -63,9 +63,9 @@ module FilterSpecHelper # # Returns a String def invalidate_reference(reference) - if reference =~ /\A(.+)?.\d+\z/ + if reference =~ /\A(.+)?[^\d]\d+\z/ # Integer-based reference with optional project prefix - reference.gsub(/\d+\z/) { |i| i.to_i + 1 } + reference.gsub(/\d+\z/) { |i| i.to_i + 10_000 } elsif reference =~ /\A(.+@)?(\h{7,40}\z)/ # SHA-based reference with optional prefix reference.gsub(/\h{7,40}\z/) { |v| v.reverse } diff --git a/spec/support/git_helpers.rb b/spec/support/git_helpers.rb deleted file mode 100644 index 93422390ef7..00000000000 --- a/spec/support/git_helpers.rb +++ /dev/null @@ -1,9 +0,0 @@ -module GitHelpers - def random_git_name - "#{FFaker::Product.brand}-#{FFaker::Product.brand}-#{rand(1000)}" - end -end - -RSpec.configure do |config| - config.include GitHelpers -end diff --git a/spec/support/issuables_list_metadata_shared_examples.rb b/spec/support/issuables_list_metadata_shared_examples.rb index 4c0f556e736..7ea4073ef2b 100644 --- a/spec/support/issuables_list_metadata_shared_examples.rb +++ b/spec/support/issuables_list_metadata_shared_examples.rb @@ -2,12 +2,12 @@ shared_examples 'issuables list meta-data' do |issuable_type, action = nil| before do @issuable_ids = [] - 2.times do + 2.times do |n| issuable = if issuable_type == :issue create(issuable_type, project: project) else - create(issuable_type, title: FFaker::Lorem.sentence, source_project: project, source_branch: FFaker::Name.name) + create(issuable_type, source_project: project, source_branch: "#{n}-feature") end @issuable_ids << issuable.id diff --git a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb index ee492daee30..9e9cdf3e48b 100644 --- a/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb +++ b/spec/support/services/issuable_create_service_slash_commands_shared_examples.rb @@ -7,7 +7,7 @@ shared_examples 'new issuable record that supports slash commands' do let(:assignee) { create(:user) } let!(:milestone) { create(:milestone, project: project) } let!(:labels) { create_list(:label, 3, project: project) } - let(:base_params) { { title: FFaker::Lorem.sentence(3) } } + let(:base_params) { { title: 'My issuable title' } } let(:params) { base_params.merge(defined?(default_params) ? default_params : {}).merge(example_params) } let(:issuable) { described_class.new(project, user, params).execute } diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index a19a35c2c0d..1b5cb71a6b0 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -131,8 +131,10 @@ module TestEnv set_repo_refs(repo_path, branch_sha) - # We must copy bare repositories because we will push to them. - system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare})) + unless File.directory?(repo_path_bare) + # We must copy bare repositories because we will push to them. + system(git_env, *%W(#{Gitlab.config.git.bin_path} clone -q --bare #{repo_path} #{repo_path_bare})) + end end def copy_repo(project) diff --git a/spec/workers/pipeline_notification_worker_spec.rb b/spec/workers/pipeline_notification_worker_spec.rb index 5a7ce2e08c4..139032d77bd 100644 --- a/spec/workers/pipeline_notification_worker_spec.rb +++ b/spec/workers/pipeline_notification_worker_spec.rb @@ -3,131 +3,19 @@ require 'spec_helper' describe PipelineNotificationWorker do include EmailHelpers - let(:pipeline) do - create(:ci_pipeline, - project: project, - sha: project.commit('master').sha, - user: pusher, - status: status) - end - - let(:project) { create(:project, :repository, public_builds: false) } - let(:user) { create(:user) } - let(:pusher) { user } - let(:watcher) { pusher } + let(:pipeline) { create(:ci_pipeline) } describe '#execute' do - before do - reset_delivered_emails! - pipeline.project.team << [pusher, Gitlab::Access::DEVELOPER] - end - - context 'when watcher has developer access' do - before do - pipeline.project.team << [watcher, Gitlab::Access::DEVELOPER] - end - - shared_examples 'sending emails' do - it 'sends emails' do - perform_enqueued_jobs do - subject.perform(pipeline.id) - end - - emails = ActionMailer::Base.deliveries - actual = emails.flat_map(&:bcc).sort - expected_receivers = receivers.map(&:email).uniq.sort - - expect(actual).to eq(expected_receivers) - expect(emails.size).to eq(1) - expect(emails.last.subject).to include(email_subject) - end - end - - context 'with success pipeline' do - let(:status) { 'success' } - let(:email_subject) { "Pipeline ##{pipeline.id} has succeeded" } - let(:receivers) { [pusher, watcher] } - - it_behaves_like 'sending emails' - - context 'with pipeline from someone else' do - let(:pusher) { create(:user) } - let(:watcher) { user } - - context 'with success pipeline notification on' do - before do - watcher.global_notification_setting. - update(level: 'custom', success_pipeline: true) - end - - it_behaves_like 'sending emails' - end - - context 'with success pipeline notification off' do - let(:receivers) { [pusher] } + it 'calls NotificationService#pipeline_finished when the pipeline exists' do + expect(NotificationService).to receive_message_chain(:new, :pipeline_finished) - before do - watcher.global_notification_setting. - update(level: 'custom', success_pipeline: false) - end - - it_behaves_like 'sending emails' - end - end - - context 'with failed pipeline' do - let(:status) { 'failed' } - let(:email_subject) { "Pipeline ##{pipeline.id} has failed" } - - it_behaves_like 'sending emails' - - context 'with pipeline from someone else' do - let(:pusher) { create(:user) } - let(:watcher) { user } - - context 'with failed pipeline notification on' do - before do - watcher.global_notification_setting. - update(level: 'custom', failed_pipeline: true) - end - - it_behaves_like 'sending emails' - end - - context 'with failed pipeline notification off' do - let(:receivers) { [pusher] } - - before do - watcher.global_notification_setting. - update(level: 'custom', failed_pipeline: false) - end - - it_behaves_like 'sending emails' - end - end - end - end + subject.perform(pipeline.id) end - context 'when watcher has no read_build access' do - let(:status) { 'failed' } - let(:email_subject) { "Pipeline ##{pipeline.id} has failed" } - let(:watcher) { create(:user) } - - before do - pipeline.project.team << [watcher, Gitlab::Access::GUEST] - - watcher.global_notification_setting. - update(level: 'custom', failed_pipeline: true) - - perform_enqueued_jobs do - subject.perform(pipeline.id) - end - end + it 'does nothing when the pipeline does not exist' do + expect(NotificationService).not_to receive(:new) - it 'does not send emails' do - should_only_email(pusher, kind: :bcc) - end + subject.perform(Ci::Pipeline.maximum(:id).to_i.succ) end end end |