diff options
author | Sean McGivern <sean@gitlab.com> | 2017-07-07 17:54:39 +0300 |
---|---|---|
committer | Sean McGivern <sean@gitlab.com> | 2017-07-07 17:54:39 +0300 |
commit | b8c4d5e0f552dc9986883bd9c8783c7f43f125ce (patch) | |
tree | 06478887ace997e9b5735f797ddd64b7f028dc6d /spec | |
parent | 97611c88fcbae6b025750e6ebf2061a3d87d9753 (diff) | |
parent | c88739ffa6ad99fbd5e20a6e8f2ee251996ea18b (diff) |
Merge branch 'master' into 33929-allow-to-enable-perf-bar-for-a-group
Diffstat (limited to 'spec')
53 files changed, 1154 insertions, 268 deletions
diff --git a/spec/controllers/groups/settings/ci_cd_controller_spec.rb b/spec/controllers/groups/settings/ci_cd_controller_spec.rb new file mode 100644 index 00000000000..2e0efb57c74 --- /dev/null +++ b/spec/controllers/groups/settings/ci_cd_controller_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe Groups::Settings::CiCdController do + let(:group) { create(:group) } + let(:user) { create(:user) } + + before do + group.add_master(user) + sign_in(user) + end + + describe 'GET #show' do + it 'renders show with 200 status code' do + get :show, group_id: group + + expect(response).to have_http_status(200) + expect(response).to render_template(:show) + end + end +end diff --git a/spec/controllers/groups/variables_controller_spec.rb b/spec/controllers/groups/variables_controller_spec.rb new file mode 100644 index 00000000000..02f2fa46047 --- /dev/null +++ b/spec/controllers/groups/variables_controller_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +describe Groups::VariablesController do + let(:group) { create(:group) } + let(:user) { create(:user) } + + before do + sign_in(user) + group.add_master(user) + end + + describe 'POST #create' do + context 'variable is valid' do + it 'shows a success flash message' do + post :create, group_id: group, variable: { key: "one", value: "two" } + + expect(flash[:notice]).to include 'Variable was successfully created.' + expect(response).to redirect_to(group_settings_ci_cd_path(group)) + end + end + + context 'variable is invalid' do + it 'renders show' do + post :create, group_id: group, variable: { key: "..one", value: "two" } + + expect(response).to render_template("groups/variables/show") + end + end + end + + describe 'POST #update' do + let(:variable) { create(:ci_group_variable) } + + context 'updating a variable with valid characters' do + before do + group.variables << variable + end + + it 'shows a success flash message' do + post :update, group_id: group, + id: variable.id, variable: { key: variable.key, value: 'two' } + + expect(flash[:notice]).to include 'Variable was successfully updated.' + expect(response).to redirect_to(group_variables_path(group)) + end + + it 'renders the action #show if the variable key is invalid' do + post :update, group_id: group, + id: variable.id, variable: { key: '?', value: variable.value } + + expect(response).to have_http_status(200) + expect(response).to render_template :show + end + end + end +end diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 9db8ff5bbaa..f88f50c3cc6 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -58,11 +58,9 @@ describe Projects::EnvironmentsController do expect(json_response['stopped_count']).to eq 1 end - it 'does not set the polling interval header' do - # TODO, this is a temporary fix, see follow up issue: - # https://gitlab.com/gitlab-org/gitlab-ee/issues/2677 + it 'sets the polling interval header' do expect(response).to have_http_status(:ok) - expect(response.headers['Poll-Interval']).to be_nil + expect(response.headers['Poll-Interval']).to eq("3000") end end diff --git a/spec/controllers/projects/variables_controller_spec.rb b/spec/controllers/projects/variables_controller_spec.rb index a0ecc756653..da06fcb7cfb 100644 --- a/spec/controllers/projects/variables_controller_spec.rb +++ b/spec/controllers/projects/variables_controller_spec.rb @@ -15,13 +15,13 @@ describe Projects::VariablesController do post :create, namespace_id: project.namespace.to_param, project_id: project, variable: { key: "one", value: "two" } - expect(flash[:notice]).to include 'Variables were successfully updated.' + expect(flash[:notice]).to include 'Variable was successfully created.' expect(response).to redirect_to(project_settings_ci_cd_path(project)) end end context 'variable is invalid' do - it 'shows an alert flash message' do + it 'renders show' do post :create, namespace_id: project.namespace.to_param, project_id: project, variable: { key: "..one", value: "two" } @@ -35,7 +35,6 @@ describe Projects::VariablesController do context 'updating a variable with valid characters' do before do - variable.project_id = project.id project.variables << variable end diff --git a/spec/factories/ci/group_variables.rb b/spec/factories/ci/group_variables.rb new file mode 100644 index 00000000000..565ced9eb1a --- /dev/null +++ b/spec/factories/ci/group_variables.rb @@ -0,0 +1,12 @@ +FactoryGirl.define do + factory :ci_group_variable, class: Ci::GroupVariable do + sequence(:key) { |n| "VARIABLE_#{n}" } + value 'VARIABLE_VALUE' + + trait(:protected) do + protected true + end + + group factory: :group + end +end diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb index 6712dd5d82e..33a17cf7ed5 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_id 1 - project_id 1 + runner factory: :ci_runner + project factory: :empty_project end end diff --git a/spec/features/group_variables_spec.rb b/spec/features/group_variables_spec.rb new file mode 100644 index 00000000000..37814ba6238 --- /dev/null +++ b/spec/features/group_variables_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' + +feature 'Group variables', js: true do + let(:user) { create(:user) } + let(:group) { create(:group) } + + background do + group.add_master(user) + gitlab_sign_in(user) + end + + context 'when user creates a new variable' do + background do + visit group_settings_ci_cd_path(group) + fill_in 'variable_key', with: 'AAA' + fill_in 'variable_value', with: 'AAA123' + find(:css, "#variable_protected").set(true) + click_on 'Add new variable' + end + + scenario 'user sees the created variable' do + page.within('.variables-table') do + expect(find(".variable-key")).to have_content('AAA') + expect(find(".variable-value")).to have_content('******') + expect(find(".variable-protected")).to have_content('Yes') + end + click_on 'Reveal Values' + page.within('.variables-table') do + expect(find(".variable-value")).to have_content('AAA123') + end + end + end + + context 'when user edits a variable' do + background do + create(:ci_group_variable, key: 'AAA', value: 'AAA123', protected: true, + group: group) + + visit group_settings_ci_cd_path(group) + + page.within('.variable-menu') do + click_on 'Update' + end + + fill_in 'variable_key', with: 'BBB' + fill_in 'variable_value', with: 'BBB123' + find(:css, "#variable_protected").set(false) + click_on 'Save variable' + end + + scenario 'user sees the updated variable' do + page.within('.variables-table') do + expect(find(".variable-key")).to have_content('BBB') + expect(find(".variable-value")).to have_content('******') + expect(find(".variable-protected")).to have_content('No') + end + end + end + + context 'when user deletes a variable' do + background do + create(:ci_group_variable, key: 'BBB', value: 'BBB123', protected: false, + group: group) + + visit group_settings_ci_cd_path(group) + + page.within('.variable-menu') do + page.accept_alert 'Are you sure?' do + click_on 'Remove' + end + end + end + + scenario 'user does not see the deleted variable' do + expect(page).to have_no_css('.variables-table') + end + end +end diff --git a/spec/features/oauth_login_spec.rb b/spec/features/oauth_login_spec.rb new file mode 100644 index 00000000000..1b6d1f3415f --- /dev/null +++ b/spec/features/oauth_login_spec.rb @@ -0,0 +1,112 @@ +require 'spec_helper' + +feature 'OAuth Login', js: true do + def enter_code(code) + fill_in 'user_otp_attempt', with: code + click_button 'Verify code' + end + + def stub_omniauth_config(provider) + OmniAuth.config.add_mock(provider, OmniAuth::AuthHash.new(provider: provider.to_s, uid: "12345")) + Rails.application.env_config['devise.mapping'] = Devise.mappings[:user] + Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[provider] + end + + providers = [:github, :twitter, :bitbucket, :gitlab, :google_oauth2, + :facebook, :cas3, :auth0] + + before(:all) do + # The OmniAuth `full_host` parameter doesn't get set correctly (it gets set to something like `http://localhost` + # here), and causes integration tests to fail with 404s. We set the `full_host` by removing the request path (and + # anything after it) from the request URI. + @omniauth_config_full_host = OmniAuth.config.full_host + OmniAuth.config.full_host = ->(request) { request['REQUEST_URI'].sub(/#{request['REQUEST_PATH']}.*/, '') } + end + + after(:all) do + OmniAuth.config.full_host = @omniauth_config_full_host + end + + providers.each do |provider| + context "when the user logs in using the #{provider} provider" do + context 'when two-factor authentication is disabled' do + it 'logs the user in' do + stub_omniauth_config(provider) + user = create(:omniauth_user, extern_uid: 'my-uid', provider: provider.to_s) + login_via(provider.to_s, user, 'my-uid') + + expect(current_path).to eq root_path + end + end + + context 'when two-factor authentication is enabled' do + it 'logs the user in' do + stub_omniauth_config(provider) + user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider.to_s) + login_via(provider.to_s, user, 'my-uid') + + enter_code(user.current_otp) + expect(current_path).to eq root_path + end + end + + context 'when "remember me" is checked' do + context 'when two-factor authentication is disabled' do + it 'remembers the user after a browser restart' do + stub_omniauth_config(provider) + user = create(:omniauth_user, extern_uid: 'my-uid', provider: provider.to_s) + login_via(provider.to_s, user, 'my-uid', remember_me: true) + + clear_browser_session + + visit(root_path) + expect(current_path).to eq root_path + end + end + + context 'when two-factor authentication is enabled' do + it 'remembers the user after a browser restart' do + stub_omniauth_config(provider) + user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider.to_s) + login_via(provider.to_s, user, 'my-uid', remember_me: true) + enter_code(user.current_otp) + + clear_browser_session + + visit(root_path) + expect(current_path).to eq root_path + end + end + end + + context 'when "remember me" is not checked' do + context 'when two-factor authentication is disabled' do + it 'does not remember the user after a browser restart' do + stub_omniauth_config(provider) + user = create(:omniauth_user, extern_uid: 'my-uid', provider: provider.to_s) + login_via(provider.to_s, user, 'my-uid', remember_me: false) + + clear_browser_session + + visit(root_path) + expect(current_path).to eq new_user_session_path + end + end + + context 'when two-factor authentication is enabled' do + it 'does not remember the user after a browser restart' do + stub_omniauth_config(provider) + user = create(:omniauth_user, :two_factor, extern_uid: 'my-uid', provider: provider.to_s) + login_via(provider.to_s, user, 'my-uid', remember_me: false) + enter_code(user.current_otp) + + clear_browser_session + + visit(root_path) + expect(current_path).to eq new_user_session_path + end + end + end + end + end +end diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb index 1a2dedf27eb..7acf7a089af 100644 --- a/spec/features/variables_spec.rb +++ b/spec/features/variables_spec.rb @@ -24,7 +24,7 @@ describe 'Project variables', js: true do fill_in('variable_value', with: 'key value') click_button('Add new variable') - expect(page).to have_content('Variables were successfully updated.') + expect(page).to have_content('Variable was successfully created.') page.within('.variables-table') do expect(page).to have_content('key') expect(page).to have_content('No') @@ -36,7 +36,7 @@ describe 'Project variables', js: true do fill_in('variable_value', with: '') click_button('Add new variable') - expect(page).to have_content('Variables were successfully updated.') + expect(page).to have_content('Variable was successfully created.') page.within('.variables-table') do expect(page).to have_content('new_key') end @@ -48,7 +48,7 @@ describe 'Project variables', js: true do check('Protected') click_button('Add new variable') - expect(page).to have_content('Variables were successfully updated.') + expect(page).to have_content('Variable was successfully created.') page.within('.variables-table') do expect(page).to have_content('key') expect(page).to have_content('Yes') @@ -82,7 +82,7 @@ describe 'Project variables', js: true do it 'deletes variable' do page.within('.variables-table') do - find('.btn-variable-delete').click + click_on 'Remove' end expect(page).not_to have_selector('variables-table') @@ -90,7 +90,7 @@ describe 'Project variables', js: true do it 'edits variable' do page.within('.variables-table') do - find('.btn-variable-edit').click + click_on 'Update' end expect(page).to have_content('Update variable') @@ -104,7 +104,7 @@ describe 'Project variables', js: true do it 'edits variable with empty value' do page.within('.variables-table') do - find('.btn-variable-edit').click + click_on 'Update' end expect(page).to have_content('Update variable') @@ -117,7 +117,7 @@ describe 'Project variables', js: true do it 'edits variable to be protected' do page.within('.variables-table') do - find('.btn-variable-edit').click + click_on 'Update' end expect(page).to have_content('Update variable') @@ -132,7 +132,7 @@ describe 'Project variables', js: true do project.variables.first.update(protected: true) page.within('.variables-table') do - find('.btn-variable-edit').click + click_on 'Update' end expect(page).to have_content('Update variable') diff --git a/spec/fixtures/config/kubeconfig-without-ca.yml b/spec/fixtures/config/kubeconfig-without-ca.yml new file mode 100644 index 00000000000..b2cb989d548 --- /dev/null +++ b/spec/fixtures/config/kubeconfig-without-ca.yml @@ -0,0 +1,18 @@ +--- +apiVersion: v1 +clusters: +- name: gitlab-deploy + cluster: + server: https://kube.domain.com +contexts: +- name: gitlab-deploy + context: + cluster: gitlab-deploy + namespace: NAMESPACE + user: gitlab-deploy +current-context: gitlab-deploy +kind: Config +users: +- name: gitlab-deploy + user: + token: TOKEN diff --git a/spec/fixtures/config/kubeconfig.yml b/spec/fixtures/config/kubeconfig.yml new file mode 100644 index 00000000000..c4e8e573c32 --- /dev/null +++ b/spec/fixtures/config/kubeconfig.yml @@ -0,0 +1,19 @@ +--- +apiVersion: v1 +clusters: +- name: gitlab-deploy + cluster: + server: https://kube.domain.com + certificate-authority-data: "UEVN\n" +contexts: +- name: gitlab-deploy + context: + cluster: gitlab-deploy + namespace: NAMESPACE + user: gitlab-deploy +current-context: gitlab-deploy +kind: Config +users: +- name: gitlab-deploy + user: + token: TOKEN diff --git a/spec/javascripts/fixtures/oauth_remember_me.html.haml b/spec/javascripts/fixtures/oauth_remember_me.html.haml new file mode 100644 index 00000000000..7886e995e57 --- /dev/null +++ b/spec/javascripts/fixtures/oauth_remember_me.html.haml @@ -0,0 +1,5 @@ +#oauth-container + %input#remember_me{ type: "checkbox" } + + %a.oauth-login.twitter{ href: "http://example.com/" } + %a.oauth-login.github{ href: "http://example.com/" } diff --git a/spec/javascripts/issue_show/components/description_spec.js b/spec/javascripts/issue_show/components/description_spec.js index f3fdbff01a6..360691a3546 100644 --- a/spec/javascripts/issue_show/components/description_spec.js +++ b/spec/javascripts/issue_show/components/description_spec.js @@ -44,32 +44,34 @@ describe('Description component', () => { }); }); - it('re-inits the TaskList when description changed', (done) => { - spyOn(gl, 'TaskList'); - vm.descriptionHtml = 'changed'; - - setTimeout(() => { - expect( - gl.TaskList, - ).toHaveBeenCalled(); - - done(); - }); - }); - - it('does not re-init the TaskList when canUpdate is false', (done) => { - spyOn(gl, 'TaskList'); - vm.canUpdate = false; - vm.descriptionHtml = 'changed'; - - setTimeout(() => { - expect( - gl.TaskList, - ).not.toHaveBeenCalled(); - - done(); - }); - }); + // TODO: gl.TaskList no longer exists. rewrite these tests once we have a way to rewire ES modules + + // it('re-inits the TaskList when description changed', (done) => { + // spyOn(gl, 'TaskList'); + // vm.descriptionHtml = 'changed'; + // + // setTimeout(() => { + // expect( + // gl.TaskList, + // ).toHaveBeenCalled(); + // + // done(); + // }); + // }); + + // it('does not re-init the TaskList when canUpdate is false', (done) => { + // spyOn(gl, 'TaskList'); + // vm.canUpdate = false; + // vm.descriptionHtml = 'changed'; + // + // setTimeout(() => { + // expect( + // gl.TaskList, + // ).not.toHaveBeenCalled(); + // + // done(); + // }); + // }); describe('taskStatus', () => { it('adds full taskStatus', (done) => { diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 49ef21f75de..dc40244c20e 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -6,7 +6,6 @@ import '~/commit/pipelines/pipelines_bundle'; import '~/breakpoints'; import '~/lib/utils/common_utils'; import '~/diff'; -import '~/single_file_diff'; import '~/files_comment_button'; import '~/notes'; import 'vendor/jquery.scrollTo'; diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js index 56d938e1fbe..b69f4eddffc 100644 --- a/spec/javascripts/monitoring/mock_data.js +++ b/spec/javascripts/monitoring/mock_data.js @@ -2481,6 +2481,7 @@ export const singleRowMetrics = [ 'queries': [ { 'query_range': 'avg(rate(container_cpu_usage_seconds_total{%{environment_filter}}[2m])) * 100', + 'label': 'Container CPU', 'result': [ { 'metric': { diff --git a/spec/javascripts/monitoring/monitoring_column_spec.js b/spec/javascripts/monitoring/monitoring_column_spec.js index b3bc97adc9f..c423024dce0 100644 --- a/spec/javascripts/monitoring/monitoring_column_spec.js +++ b/spec/javascripts/monitoring/monitoring_column_spec.js @@ -95,7 +95,7 @@ describe('MonitoringColumn', () => { }); }); - it('has a title for the y-axis that comes from the backend', () => { + it('has a title for the y-axis and the chart legend that comes from the backend', () => { const component = createComponent({ columnData: singleRowMetrics[0], classType: 'col-md-6', @@ -104,5 +104,6 @@ describe('MonitoringColumn', () => { }); expect(component.yAxisLabel).toEqual(component.columnData.y_label); + expect(component.legendTitle).toEqual(component.columnData.queries[0].label); }); }); diff --git a/spec/javascripts/oauth_remember_me_spec.js b/spec/javascripts/oauth_remember_me_spec.js new file mode 100644 index 00000000000..f90e0093d25 --- /dev/null +++ b/spec/javascripts/oauth_remember_me_spec.js @@ -0,0 +1,26 @@ +import OAuthRememberMe from '~/oauth_remember_me'; + +describe('OAuthRememberMe', () => { + preloadFixtures('static/oauth_remember_me.html.raw'); + + beforeEach(() => { + loadFixtures('static/oauth_remember_me.html.raw'); + + new OAuthRememberMe({ container: $('#oauth-container') }).bindEvents(); + }); + + it('adds the "remember_me" query parameter to all OAuth login buttons', () => { + $('#oauth-container #remember_me').click(); + + expect($('#oauth-container .oauth-login.twitter').attr('href')).toBe('http://example.com/?remember_me=1'); + expect($('#oauth-container .oauth-login.github').attr('href')).toBe('http://example.com/?remember_me=1'); + }); + + it('removes the "remember_me" query parameter from all OAuth login buttons', () => { + $('#oauth-container #remember_me').click(); + $('#oauth-container #remember_me').click(); + + expect($('#oauth-container .oauth-login.twitter').attr('href')).toBe('http://example.com/'); + expect($('#oauth-container .oauth-login.github').attr('href')).toBe('http://example.com/'); + }); +}); diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js b/spec/javascripts/signin_tabs_memoizer_spec.js index 0a32797c3e2..a53e8a94d89 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js +++ b/spec/javascripts/signin_tabs_memoizer_spec.js @@ -1,8 +1,7 @@ import AccessorUtilities from '~/lib/utils/accessor'; +import SigninTabsMemoizer from '~/signin_tabs_memoizer'; -import '~/signin_tabs_memoizer'; - -((global) => { +(() => { describe('SigninTabsMemoizer', () => { const fixtureTemplate = 'static/signin_tabs.html.raw'; const tabSelector = 'ul.nav-tabs'; @@ -10,7 +9,7 @@ import '~/signin_tabs_memoizer'; let memo; function createMemoizer() { - memo = new global.ActiveTabMemoizer({ + memo = new SigninTabsMemoizer({ currentTabKey, tabSelector, }); @@ -78,7 +77,7 @@ import '~/signin_tabs_memoizer'; beforeEach(function () { memo.isLocalStorageAvailable = false; - global.ActiveTabMemoizer.prototype.saveData.call(memo); + SigninTabsMemoizer.prototype.saveData.call(memo); }); it('should not call .setItem', () => { @@ -92,7 +91,7 @@ import '~/signin_tabs_memoizer'; beforeEach(function () { memo.isLocalStorageAvailable = true; - global.ActiveTabMemoizer.prototype.saveData.call(memo, value); + SigninTabsMemoizer.prototype.saveData.call(memo, value); }); it('should call .setItem', () => { @@ -117,7 +116,7 @@ import '~/signin_tabs_memoizer'; beforeEach(function () { memo.isLocalStorageAvailable = false; - readData = global.ActiveTabMemoizer.prototype.readData.call(memo); + readData = SigninTabsMemoizer.prototype.readData.call(memo); }); it('should not call .getItem and should return `null`', () => { @@ -130,7 +129,7 @@ import '~/signin_tabs_memoizer'; beforeEach(function () { memo.isLocalStorageAvailable = true; - readData = global.ActiveTabMemoizer.prototype.readData.call(memo); + readData = SigninTabsMemoizer.prototype.readData.call(memo); }); it('should call .getItem and return the localStorage value', () => { @@ -140,4 +139,4 @@ import '~/signin_tabs_memoizer'; }); }); }); -})(window); +})(); diff --git a/spec/javascripts/todos_spec.js b/spec/javascripts/todos_spec.js index cd74aba4a4e..fd492159081 100644 --- a/spec/javascripts/todos_spec.js +++ b/spec/javascripts/todos_spec.js @@ -1,4 +1,4 @@ -import '~/todos'; +import Todos from '~/todos'; import '~/lib/utils/common_utils'; describe('Todos', () => { @@ -9,7 +9,7 @@ describe('Todos', () => { loadFixtures('todos/todos.html.raw'); todoItem = document.querySelector('.todos-list .todo'); - return new gl.Todos(); + return new Todos(); }); describe('goToTodoUrl', () => { diff --git a/spec/javascripts/visibility_select_spec.js b/spec/javascripts/visibility_select_spec.js index c2eaea7c2ed..82714cb69bd 100644 --- a/spec/javascripts/visibility_select_spec.js +++ b/spec/javascripts/visibility_select_spec.js @@ -1,8 +1,6 @@ -import '~/visibility_select'; +import VisibilitySelect from '~/visibility_select'; (() => { - const VisibilitySelect = gl.VisibilitySelect; - describe('VisibilitySelect', function () { const lockedElement = document.createElement('div'); lockedElement.dataset.helpBlock = 'lockedHelpBlock'; 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 4b6f171c8d6..647b59520f8 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 @@ -76,28 +76,6 @@ describe('MRWidgetPipeline', () => { el = vm.$el; }); - afterEach(() => { - vm.$destroy(); - }); - - describe('without a pipeline', () => { - beforeEach(() => { - vm.mr = { pipeline: null }; - }); - - it('should render message with spinner', (done) => { - Vue.nextTick() - .then(() => { - expect(el.querySelector('.pipeline-id')).toBe(null); - expect(el.innerText.trim()).toBe('Waiting for pipeline...'); - expect(el.querySelectorAll('i.fa.fa-spinner.fa-spin').length).toBe(1); - done(); - }) - .then(done) - .catch(done.fail); - }); - }); - it('should render template elements correctly', () => { expect(el.classList.contains('mr-widget-heading')).toBeTruthy(); expect(el.querySelectorAll('.ci-status-icon.ci-status-icon-success').length).toEqual(1); @@ -115,47 +93,39 @@ describe('MRWidgetPipeline', () => { it('should list single stage', (done) => { pipeline.details.stages.splice(0, 1); - Vue.nextTick() - .then(() => { - expect(el.querySelectorAll('.stage-container button').length).toEqual(1); - expect(el.innerText).toContain('with stage'); - }) - .then(done) - .catch(done.fail); + Vue.nextTick(() => { + expect(el.querySelectorAll('.stage-container button').length).toEqual(1); + expect(el.innerText).toContain('with stage'); + done(); + }); }); it('should not have stages when there is no stage', (done) => { vm.mr.pipeline.details.stages = []; - Vue.nextTick() - .then(() => { - expect(el.querySelectorAll('.stage-container button').length).toEqual(0); - }) - .then(done) - .catch(done.fail); + Vue.nextTick(() => { + expect(el.querySelectorAll('.stage-container button').length).toEqual(0); + done(); + }); }); it('should not have coverage text when pipeline has no coverage info', (done) => { vm.mr.pipeline.coverage = null; - Vue.nextTick() - .then(() => { - expect(el.querySelector('.js-mr-coverage')).toEqual(null); - }) - .then(done) - .catch(done.fail); + Vue.nextTick(() => { + expect(el.querySelector('.js-mr-coverage')).toEqual(null); + done(); + }); }); it('should show CI error when there is a CI error', (done) => { vm.mr.ciStatus = null; - Vue.nextTick() - .then(() => { - expect(el.querySelectorAll('.js-ci-error').length).toEqual(1); - expect(el.innerText).toContain('Could not connect to the CI server'); - }) - .then(done) - .catch(done.fail); + Vue.nextTick(() => { + expect(el.querySelectorAll('.js-ci-error').length).toEqual(1); + expect(el.innerText).toContain('Could not connect to the CI server'); + done(); + }); }); }); }); diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index 4399c8b2025..a225b04c47e 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -1,9 +1,8 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle, no-return-assign, new-cap, max-len */ /* global Dropzone */ /* global Mousetrap */ -/* global ZenMode */ -import '~/zen_mode'; +import ZenMode from '~/zen_mode'; (function() { var enterZen, escapeKeydown, exitZen; diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index a5f09f1856e..562f0c2991c 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -88,7 +88,10 @@ merge_requests: - head_pipeline merge_request_diff: - merge_request +- merge_request_diff_commits - merge_request_diff_files +merge_request_diff_commits: +- merge_request_diff merge_request_diff_files: - merge_request_diff pipelines: diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 98c117b4cd8..469a014e4d2 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -2741,13 +2741,12 @@ "merge_request_diff": { "id": 27, "state": "collected", - "st_commits": [ + "merge_request_diff_commits": [ { - "id": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc", + "merge_request_diff_id": 27, + "relative_order": 0, + "sha": "bb5206fee213d983da88c47f9cf4cc6caf9c66dc", "message": "Feature conflcit added\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", - "parent_ids": [ - "5937ac0a7beb003549fc5fd26fc247adbce4a52e" - ], "authored_date": "2014-08-06T08:35:52.000+02:00", "author_name": "Dmitriy Zaporozhets", "author_email": "dmitriy.zaporozhets@gmail.com", @@ -2756,11 +2755,10 @@ "committer_email": "dmitriy.zaporozhets@gmail.com" }, { - "id": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", + "merge_request_diff_id": 27, + "relative_order": 1, + "sha": "5937ac0a7beb003549fc5fd26fc247adbce4a52e", "message": "Add submodule from gitlab.com\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", - "parent_ids": [ - "570e7b2abdd848b95f2f578043fc23bd6f6fd24d" - ], "authored_date": "2014-02-27T10:01:38.000+01:00", "author_name": "Dmitriy Zaporozhets", "author_email": "dmitriy.zaporozhets@gmail.com", @@ -2769,11 +2767,10 @@ "committer_email": "dmitriy.zaporozhets@gmail.com" }, { - "id": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", + "merge_request_diff_id": 27, + "relative_order": 2, + "sha": "570e7b2abdd848b95f2f578043fc23bd6f6fd24d", "message": "Change some files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", - "parent_ids": [ - "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9" - ], "authored_date": "2014-02-27T09:57:31.000+01:00", "author_name": "Dmitriy Zaporozhets", "author_email": "dmitriy.zaporozhets@gmail.com", @@ -2782,11 +2779,10 @@ "committer_email": "dmitriy.zaporozhets@gmail.com" }, { - "id": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9", + "merge_request_diff_id": 27, + "relative_order": 3, + "sha": "6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9", "message": "More submodules\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", - "parent_ids": [ - "d14d6c0abdd253381df51a723d58691b2ee1ab08" - ], "authored_date": "2014-02-27T09:54:21.000+01:00", "author_name": "Dmitriy Zaporozhets", "author_email": "dmitriy.zaporozhets@gmail.com", @@ -2795,11 +2791,10 @@ "committer_email": "dmitriy.zaporozhets@gmail.com" }, { - "id": "d14d6c0abdd253381df51a723d58691b2ee1ab08", + "merge_request_diff_id": 27, + "relative_order": 4, + "sha": "d14d6c0abdd253381df51a723d58691b2ee1ab08", "message": "Remove ds_store files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", - "parent_ids": [ - "c1acaa58bbcbc3eafe538cb8274ba387047b69f8" - ], "authored_date": "2014-02-27T09:49:50.000+01:00", "author_name": "Dmitriy Zaporozhets", "author_email": "dmitriy.zaporozhets@gmail.com", @@ -2808,11 +2803,10 @@ "committer_email": "dmitriy.zaporozhets@gmail.com" }, { - "id": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8", + "merge_request_diff_id": 27, + "relative_order": 5, + "sha": "c1acaa58bbcbc3eafe538cb8274ba387047b69f8", "message": "Ignore DS files\n\nSigned-off-by: Dmitriy Zaporozhets \u003cdmitriy.zaporozhets@gmail.com\u003e\n", - "parent_ids": [ - "ae73cb07c9eeaf35924a10f713b364d32b2dd34f" - ], "authored_date": "2014-02-27T09:48:32.000+01:00", "author_name": "Dmitriy Zaporozhets", "author_email": "dmitriy.zaporozhets@gmail.com", 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 c11b15a811b..d50d238ddcd 100644 --- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb @@ -95,6 +95,11 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do expect(MergeRequestDiffFile.where.not(diff: nil).count).to eq(9) end + it 'has the correct data for merge request diff commits in serialised and table formats' do + expect(MergeRequestDiff.where.not(st_commits: nil).count).to eq(7) + expect(MergeRequestDiffCommit.count).to eq(6) + end + it 'has the correct time for merge request st_commits' do st_commits = MergeRequestDiff.where.not(st_commits: nil).first.st_commits 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 e52f79513f1..22a65e24f26 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -87,6 +87,10 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_files']).not_to be_empty end + it 'has merge request diff commits' do + expect(saved_project_json['merge_requests'].first['merge_request_diff']['merge_request_diff_commits']).not_to be_empty + end + it 'has merge requests comments' do expect(saved_project_json['merge_requests'].first['notes']).not_to be_empty end diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 697ddf52af9..b4a7e956686 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -172,6 +172,17 @@ MergeRequestDiff: - real_size - head_commit_sha - start_commit_sha +MergeRequestDiffCommit: +- merge_request_diff_id +- relative_order +- sha +- authored_date +- committed_date +- author_name +- author_email +- committer_name +- committer_email +- message MergeRequestDiffFile: - merge_request_diff_id - relative_order diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb index e8c599a95ee..34b33772578 100644 --- a/spec/lib/gitlab/kubernetes_spec.rb +++ b/spec/lib/gitlab/kubernetes_spec.rb @@ -46,4 +46,28 @@ describe Gitlab::Kubernetes do expect(filter_by_label(items, app: 'foo')).to eq(matching_items) end end + + describe '#to_kubeconfig' do + subject do + to_kubeconfig( + url: 'https://kube.domain.com', + namespace: 'NAMESPACE', + token: 'TOKEN', + ca_pem: ca_pem) + end + + context 'when CA PEM is provided' do + let(:ca_pem) { 'PEM' } + let(:path) { expand_fixture_path('config/kubeconfig.yml') } + + it { is_expected.to eq(YAML.load_file(path)) } + end + + context 'when CA PEM is not provided' do + let(:ca_pem) { nil } + let(:path) { expand_fixture_path('config/kubeconfig-without-ca.yml') } + + it { is_expected.to eq(YAML.load_file(path)) } + end + end end diff --git a/spec/lib/gitlab/sql/glob_spec.rb b/spec/lib/gitlab/sql/glob_spec.rb new file mode 100644 index 00000000000..451c583310d --- /dev/null +++ b/spec/lib/gitlab/sql/glob_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe Gitlab::SQL::Glob, lib: true do + describe '.to_like' do + it 'matches * as %' do + expect(glob('apple', '*')).to be(true) + expect(glob('apple', 'app*')).to be(true) + expect(glob('apple', 'apple*')).to be(true) + expect(glob('apple', '*pple')).to be(true) + expect(glob('apple', 'ap*le')).to be(true) + + expect(glob('apple', '*a')).to be(false) + expect(glob('apple', 'app*a')).to be(false) + expect(glob('apple', 'ap*l')).to be(false) + end + + it 'matches % literally' do + expect(glob('100%', '100%')).to be(true) + + expect(glob('100%', '%')).to be(false) + end + + it 'matches _ literally' do + expect(glob('^_^', '^_^')).to be(true) + + expect(glob('^A^', '^_^')).to be(false) + end + end + + def glob(string, pattern) + match(string, subject.to_like(quote(pattern))) + end + + def match(string, pattern) + value = query("SELECT #{quote(string)} LIKE #{pattern}") + .rows.flatten.first + + case value + when 't', 1 + true + else + false + end + end + + def query(sql) + ActiveRecord::Base.connection.select_all(sql) + end + + def quote(string) + ActiveRecord::Base.connection.quote(string) + end +end diff --git a/spec/models/blob_viewer/readme_spec.rb b/spec/models/blob_viewer/readme_spec.rb new file mode 100644 index 00000000000..02679dbb544 --- /dev/null +++ b/spec/models/blob_viewer/readme_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe BlobViewer::Readme, model: true do + include FakeBlobHelpers + + let(:project) { create(:project, :repository) } + let(:blob) { fake_blob(path: 'README.md') } + subject { described_class.new(blob) } + + describe '#render_error' do + context 'when there is no wiki' do + it 'returns :no_wiki' do + expect(subject.render_error).to eq(:no_wiki) + end + end + + context 'when there is an external wiki' do + before do + project.has_external_wiki = true + end + + it 'returns nil' do + expect(subject.render_error).to be_nil + end + end + + context 'when there is a local wiki' do + before do + project.wiki_enabled = true + end + + context 'when the wiki is empty' do + it 'returns :no_wiki' do + expect(subject.render_error).to eq(:no_wiki) + end + end + + context 'when the wiki is not empty' do + before do + WikiPages::CreateService.new(project, project.owner, title: 'home', content: 'Home page').execute + end + + it 'returns nil' do + expect(subject.render_error).to be_nil + end + end + end + end +end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index a7ba3a7c43e..cf6d356c524 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -863,7 +863,7 @@ describe Ci::Build, :models do pipeline2 = create(:ci_pipeline, project: project) @build2 = create(:ci_build, pipeline: pipeline2) - allow(@merge_request).to receive(:commits_sha) + allow(@merge_request).to receive(:commit_shas) .and_return([pipeline.sha, pipeline2.sha]) allow(MergeRequest).to receive_message_chain(:includes, :where, :reorder).and_return([@merge_request]) end @@ -1356,6 +1356,59 @@ describe Ci::Build, :models do end end + context 'when group secret variable is defined' do + let(:secret_variable) do + { key: 'SECRET_KEY', value: 'secret_value', public: false } + end + + let(:group) { create(:group, :access_requestable) } + + before do + build.project.update(group: group) + + create(:ci_group_variable, + secret_variable.slice(:key, :value).merge(group: group)) + end + + it { is_expected.to include(secret_variable) } + end + + context 'when group protected variable is defined' do + let(:protected_variable) do + { key: 'PROTECTED_KEY', value: 'protected_value', public: false } + end + + let(:group) { create(:group, :access_requestable) } + + before do + build.project.update(group: group) + + create(:ci_group_variable, + :protected, + protected_variable.slice(:key, :value).merge(group: group)) + end + + context 'when the branch is protected' do + before do + create(:protected_branch, project: build.project, name: build.ref) + end + + it { is_expected.to include(protected_variable) } + end + + context 'when the tag is protected' do + before do + create(:protected_tag, project: build.project, name: build.ref) + end + + it { is_expected.to include(protected_variable) } + end + + context 'when the ref is not protected' do + it { is_expected.not_to include(protected_variable) } + end + end + context 'when build is for triggers' do let(:trigger) { create(:ci_trigger, project: project) } let(:trigger_request) { create(:ci_trigger_request_with_variables, pipeline: pipeline, trigger: trigger) } @@ -1496,9 +1549,10 @@ describe Ci::Build, :models do allow(pipeline).to receive(:predefined_variables) { [pipeline_pre_var] } allow(build).to receive(:yaml_variables) { [build_yaml_var] } - allow(project).to receive(:secret_variables_for).with(build.ref) do - [create(:ci_variable, key: 'secret', value: 'value')] - end + allow(project).to receive(:secret_variables_for) + .with(ref: 'master', environment: nil) do + [create(:ci_variable, key: 'secret', value: 'value')] + end end it do diff --git a/spec/models/ci/group_variable_spec.rb b/spec/models/ci/group_variable_spec.rb new file mode 100644 index 00000000000..24b914face9 --- /dev/null +++ b/spec/models/ci/group_variable_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe Ci::GroupVariable, models: true do + subject { build(:ci_group_variable) } + + it { is_expected.to include_module(HasVariable) } + it { is_expected.to include_module(Presentable) } + it { is_expected.to validate_uniqueness_of(:key).scoped_to(:group_id) } + + describe '.unprotected' do + subject { described_class.unprotected } + + context 'when variable is protected' do + before do + create(:ci_group_variable, :protected) + end + + it 'returns nothing' do + is_expected.to be_empty + end + end + + context 'when variable is not protected' do + let(:variable) { create(:ci_group_variable, protected: false) } + + it 'returns the variable' do + is_expected.to contain_exactly(variable) + end + end + end +end diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb index 50f7c029af8..890ffaae494 100644 --- a/spec/models/ci/variable_spec.rb +++ b/spec/models/ci/variable_spec.rb @@ -3,15 +3,10 @@ require 'spec_helper' describe Ci::Variable, models: true do subject { build(:ci_variable) } - let(:secret_value) { 'secret' } - describe 'validations' do it { is_expected.to include_module(HasVariable) } + it { is_expected.to include_module(Presentable) } it { is_expected.to validate_uniqueness_of(:key).scoped_to(:project_id, :environment_scope) } - it { is_expected.to validate_length_of(:key).is_at_most(255) } - it { is_expected.to allow_value('foo').for(:key) } - it { is_expected.not_to allow_value('foo bar').for(:key) } - it { is_expected.not_to allow_value('foo/bar').for(:key) } end describe '.unprotected' do diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index ac9303370ab..505039c9d88 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) { build_stubbed(:empty_project) } + let(:project) { create(:empty_project) } context "by milestone due date" do # Correct order is: diff --git a/spec/models/concerns/sha_attribute_spec.rb b/spec/models/concerns/sha_attribute_spec.rb index 9e37c2b20c4..610793ee557 100644 --- a/spec/models/concerns/sha_attribute_spec.rb +++ b/spec/models/concerns/sha_attribute_spec.rb @@ -13,15 +13,34 @@ describe ShaAttribute do end describe '#sha_attribute' do - it 'defines a SHA attribute for a binary column' do - expect(model).to receive(:attribute) - .with(:sha1, an_instance_of(Gitlab::Database::ShaAttribute)) + context' when the table exists' do + before do + allow(model).to receive(:table_exists?).and_return(true) + end - model.sha_attribute(:sha1) + it 'defines a SHA attribute for a binary column' do + expect(model).to receive(:attribute) + .with(:sha1, an_instance_of(Gitlab::Database::ShaAttribute)) + + model.sha_attribute(:sha1) + end + + it 'raises ArgumentError when the column type is not :binary' do + expect { model.sha_attribute(:name) }.to raise_error(ArgumentError) + end end - it 'raises ArgumentError when the column type is not :binary' do - expect { model.sha_attribute(:name) }.to raise_error(ArgumentError) + context' when the table does not exist' do + before do + allow(model).to receive(:table_exists?).and_return(false) + end + + it 'does nothing' do + expect(model).not_to receive(:columns) + expect(model).not_to receive(:attribute) + + model.sha_attribute(:name) + end end end end diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 5c13cf584f9..38fbdd2536a 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -42,7 +42,7 @@ describe ForkedProjectLink, "add link on fork" do describe '#forked?' do let(:project_to) { create(:project, forked_project_link: forked_project_link) } - let(:forked_project_link) { build(:forked_project_link) } + let(:forked_project_link) { create(:forked_project_link) } before do forked_project_link.forked_from_project = project_from @@ -59,9 +59,9 @@ describe ForkedProjectLink, "add link on fork" do end it "project_to.destroy destroys fork_link" do - expect(forked_project_link).to receive(:destroy) - project_to.destroy + + expect(ForkedProjectLink.exists?(id: forked_project_link.id)).to eq(false) end end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 4de1683b21c..399020953e8 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -13,6 +13,7 @@ describe Group, models: true do it { is_expected.to have_many(:shared_projects).through(:project_group_links) } it { is_expected.to have_many(:notification_settings).dependent(:destroy) } it { is_expected.to have_many(:labels).class_name('GroupLabel') } + it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') } it { is_expected.to have_many(:uploads).dependent(:destroy) } it { is_expected.to have_one(:chat_team) } @@ -418,4 +419,69 @@ describe Group, models: true do expect(calls).to eq 2 end end + + describe '#secret_variables_for' do + let(:project) { create(:empty_project, group: group) } + + let!(:secret_variable) do + create(:ci_group_variable, value: 'secret', group: group) + end + + let!(:protected_variable) do + create(:ci_group_variable, :protected, value: 'protected', group: group) + end + + subject { group.secret_variables_for('ref', project) } + + shared_examples 'ref is protected' do + it 'contains all the variables' do + is_expected.to contain_exactly(secret_variable, protected_variable) + end + end + + context 'when the ref is not protected' do + before do + stub_application_setting( + default_branch_protection: Gitlab::Access::PROTECTION_NONE) + end + + it 'contains only the secret variables' do + is_expected.to contain_exactly(secret_variable) + end + end + + context 'when the ref is a protected branch' do + before do + create(:protected_branch, name: 'ref', project: project) + end + + it_behaves_like 'ref is protected' + end + + context 'when the ref is a protected tag' do + before do + create(:protected_tag, name: 'ref', project: project) + end + + it_behaves_like 'ref is protected' + end + + context 'when group has children' do + let!(:group_child) { create(:group, parent: group) } + let!(:variable_child) { create(:ci_group_variable, group: group_child) } + let!(:group_child_3) { create(:group, parent: group_child_2) } + let!(:variable_child_3) { create(:ci_group_variable, group: group_child_3) } + let!(:group_child_2) { create(:group, parent: group_child) } + let!(:variable_child_2) { create(:ci_group_variable, group: group_child_2) } + + it 'returns all variables belong to the group and parent groups' do + expected_array1 = [protected_variable, secret_variable] + expected_array2 = [variable_child, variable_child_2, variable_child_3] + got_array = group_child_3.secret_variables_for('ref', project).to_a + + expect(got_array.shift(2)).to contain_exactly(*expected_array1) + expect(got_array).to eq(expected_array2) + end + end + end end diff --git a/spec/models/merge_request_diff_commit_spec.rb b/spec/models/merge_request_diff_commit_spec.rb new file mode 100644 index 00000000000..dbfd1526518 --- /dev/null +++ b/spec/models/merge_request_diff_commit_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +describe MergeRequestDiffCommit, type: :model do + let(:merge_request) { create(:merge_request) } + subject { merge_request.commits.first } + + describe '#to_hash' do + it 'returns the same results as Commit#to_hash, except for parent_ids' do + commit_from_repo = merge_request.project.repository.commit(subject.sha) + commit_from_repo_hash = commit_from_repo.to_hash.merge(parent_ids: []) + + expect(subject.to_hash).to eq(commit_from_repo_hash) + end + end +end diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index 4ad4abaa572..edc2f4bb9f0 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -98,7 +98,7 @@ describe MergeRequestDiff, models: true do end it 'saves empty state' do - allow_any_instance_of(MergeRequestDiff).to receive(:commits) + allow_any_instance_of(MergeRequestDiff).to receive_message_chain(:compare, :commits) .and_return([]) mr_diff = create(:merge_request).merge_request_diff @@ -107,14 +107,14 @@ describe MergeRequestDiff, models: true do end end - describe '#commits_sha' do + describe '#commit_shas' do it 'returns all commits SHA using serialized commits' do subject.st_commits = [ { id: 'sha1' }, { id: 'sha2' } ] - expect(subject.commits_sha).to eq(%w(sha1 sha2)) + expect(subject.commit_shas).to eq(%w(sha1 sha2)) end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 587d4b83cb4..ea405fabff0 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -10,7 +10,7 @@ describe MergeRequest, models: true do it { is_expected.to belong_to(:source_project).class_name('Project') } it { is_expected.to belong_to(:merge_user).class_name("User") } it { is_expected.to belong_to(:assignee) } - it { is_expected.to have_many(:merge_request_diffs).dependent(:destroy) } + it { is_expected.to have_many(:merge_request_diffs) } end describe 'modules' do @@ -720,14 +720,14 @@ describe MergeRequest, models: true do subject { create :merge_request, :simple } end - describe '#commits_sha' do + describe '#commit_shas' do before do - allow(subject.merge_request_diff).to receive(:commits_sha) + allow(subject.merge_request_diff).to receive(:commit_shas) .and_return(['sha1']) end it 'delegates to merge request diff' do - expect(subject.commits_sha).to eq ['sha1'] + expect(subject.commit_shas).to eq ['sha1'] end end @@ -752,7 +752,7 @@ describe MergeRequest, models: true do describe '#all_pipelines' do shared_examples 'returning pipelines with proper ordering' do let!(:all_pipelines) do - subject.all_commits_sha.map do |sha| + subject.all_commit_shas.map do |sha| create(:ci_empty_pipeline, project: subject.source_project, sha: sha, @@ -794,16 +794,16 @@ describe MergeRequest, models: true do end end - describe '#all_commits_sha' do + describe '#all_commit_shas' do context 'when merge request is persisted' do - let(:all_commits_sha) do + let(:all_commit_shas) do subject.merge_request_diffs.flat_map(&:commits).map(&:sha).uniq end shared_examples 'returning all SHA' do it 'returns all SHA from all merge_request_diffs' do expect(subject.merge_request_diffs.size).to eq(2) - expect(subject.all_commits_sha).to eq(all_commits_sha) + expect(subject.all_commit_shas).to eq(all_commit_shas) end end @@ -834,7 +834,7 @@ describe MergeRequest, models: true do end it 'returns commits from compare commits temporary data' do - expect(subject.all_commits_sha).to eq [commit, commit] + expect(subject.all_commit_shas).to eq [commit, commit] end end @@ -842,7 +842,7 @@ describe MergeRequest, models: true do subject { build(:merge_request) } it 'returns array with diff head sha element only' do - expect(subject.all_commits_sha).to eq [subject.diff_head_sha] + expect(subject.all_commit_shas).to eq [subject.diff_head_sha] end end end diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 858ad595dbf..5ba523a478a 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -129,7 +129,7 @@ describe KubernetesService, models: true, caching: true do it "returns the default namespace" do is_expected.to eq(service.send(:default_namespace)) end - + context 'when namespace is specified' do before do service.namespace = 'my-namespace' @@ -201,6 +201,22 @@ describe KubernetesService, models: true, caching: true do end describe '#predefined_variables' do + let(:kubeconfig) do + config = + YAML.load(File.read(expand_fixture_path('config/kubeconfig.yml'))) + + config.dig('users', 0, 'user')['token'] = + 'token' + + config.dig('clusters', 0, 'cluster')['certificate-authority-data'] = + Base64.encode64('CA PEM DATA') + + config.dig('contexts', 0, 'context')['namespace'] = + namespace + + YAML.dump(config) + end + before do subject.api_url = 'https://kube.domain.com' subject.token = 'token' @@ -208,32 +224,34 @@ describe KubernetesService, models: true, caching: true do subject.project = project end - context 'namespace is provided' do - before do - subject.namespace = 'my-project' - end - + shared_examples 'setting variables' do it 'sets the variables' do expect(subject.predefined_variables).to include( { key: 'KUBE_URL', value: 'https://kube.domain.com', public: true }, { key: 'KUBE_TOKEN', value: 'token', public: false }, - { key: 'KUBE_NAMESPACE', value: 'my-project', public: true }, + { key: 'KUBE_NAMESPACE', value: namespace, public: true }, + { key: 'KUBECONFIG', value: kubeconfig, public: false, file: true }, { key: 'KUBE_CA_PEM', value: 'CA PEM DATA', public: true }, { key: 'KUBE_CA_PEM_FILE', value: 'CA PEM DATA', public: true, file: true } ) end end - context 'no namespace provided' do - it 'sets the variables' do - expect(subject.predefined_variables).to include( - { key: 'KUBE_URL', value: 'https://kube.domain.com', public: true }, - { key: 'KUBE_TOKEN', value: 'token', public: false }, - { key: 'KUBE_CA_PEM', value: 'CA PEM DATA', public: true }, - { key: 'KUBE_CA_PEM_FILE', value: 'CA PEM DATA', public: true, file: true } - ) + context 'namespace is provided' do + let(:namespace) { 'my-project' } + + before do + subject.namespace = namespace end + it_behaves_like 'setting variables' + end + + context 'no namespace provided' do + let(:namespace) { subject.actual_namespace } + + it_behaves_like 'setting variables' + it 'sets the KUBE_NAMESPACE' do kube_namespace = subject.predefined_variables.find { |h| h[:key] == 'KUBE_NAMESPACE' } diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f50b4aea411..99bfab70088 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -7,50 +7,50 @@ describe Project, models: true do it { is_expected.to belong_to(:creator).class_name('User') } it { is_expected.to have_many(:users) } it { is_expected.to have_many(:services) } - it { is_expected.to have_many(:events).dependent(:destroy) } - it { is_expected.to have_many(:merge_requests).dependent(:destroy) } - it { is_expected.to have_many(:issues).dependent(:destroy) } - it { is_expected.to have_many(:milestones).dependent(:destroy) } - it { is_expected.to have_many(:project_members).dependent(:destroy) } + it { is_expected.to have_many(:events) } + it { is_expected.to have_many(:merge_requests) } + it { is_expected.to have_many(:issues) } + it { is_expected.to have_many(:milestones) } + it { is_expected.to have_many(:project_members).dependent(:delete_all) } it { is_expected.to have_many(:users).through(:project_members) } - it { is_expected.to have_many(:requesters).dependent(:destroy) } - it { is_expected.to have_many(:notes).dependent(:destroy) } - it { is_expected.to have_many(:snippets).class_name('ProjectSnippet').dependent(:destroy) } - it { is_expected.to have_many(:deploy_keys_projects).dependent(:destroy) } + it { is_expected.to have_many(:requesters).dependent(:delete_all) } + it { is_expected.to have_many(:notes) } + it { is_expected.to have_many(:snippets).class_name('ProjectSnippet') } + it { is_expected.to have_many(:deploy_keys_projects) } it { is_expected.to have_many(:deploy_keys) } - it { is_expected.to have_many(:hooks).dependent(:destroy) } - it { is_expected.to have_many(:protected_branches).dependent(:destroy) } - it { is_expected.to have_one(:forked_project_link).dependent(:destroy) } - it { is_expected.to have_one(:slack_service).dependent(:destroy) } - it { is_expected.to have_one(:microsoft_teams_service).dependent(:destroy) } - it { is_expected.to have_one(:mattermost_service).dependent(:destroy) } - it { is_expected.to have_one(:pushover_service).dependent(:destroy) } - it { is_expected.to have_one(:asana_service).dependent(:destroy) } - it { is_expected.to have_many(:boards).dependent(:destroy) } - it { is_expected.to have_one(:campfire_service).dependent(:destroy) } - it { is_expected.to have_one(:drone_ci_service).dependent(:destroy) } - it { is_expected.to have_one(:emails_on_push_service).dependent(:destroy) } - it { is_expected.to have_one(:pipelines_email_service).dependent(:destroy) } - it { is_expected.to have_one(:irker_service).dependent(:destroy) } - it { is_expected.to have_one(:pivotaltracker_service).dependent(:destroy) } - it { is_expected.to have_one(:hipchat_service).dependent(:destroy) } - it { is_expected.to have_one(:flowdock_service).dependent(:destroy) } - it { is_expected.to have_one(:assembla_service).dependent(:destroy) } - it { is_expected.to have_one(:slack_slash_commands_service).dependent(:destroy) } - it { is_expected.to have_one(:mattermost_slash_commands_service).dependent(:destroy) } - it { is_expected.to have_one(:gemnasium_service).dependent(:destroy) } - it { is_expected.to have_one(:buildkite_service).dependent(:destroy) } - it { is_expected.to have_one(:bamboo_service).dependent(:destroy) } - it { is_expected.to have_one(:teamcity_service).dependent(:destroy) } - it { is_expected.to have_one(:jira_service).dependent(:destroy) } - it { is_expected.to have_one(:redmine_service).dependent(:destroy) } - it { is_expected.to have_one(:custom_issue_tracker_service).dependent(:destroy) } - it { is_expected.to have_one(:bugzilla_service).dependent(:destroy) } - it { is_expected.to have_one(:gitlab_issue_tracker_service).dependent(:destroy) } - it { is_expected.to have_one(:external_wiki_service).dependent(:destroy) } - it { is_expected.to have_one(:project_feature).dependent(:destroy) } - it { is_expected.to have_one(:statistics).class_name('ProjectStatistics').dependent(:delete) } - it { is_expected.to have_one(:import_data).class_name('ProjectImportData').dependent(:delete) } + it { is_expected.to have_many(:hooks) } + it { is_expected.to have_many(:protected_branches) } + it { is_expected.to have_one(:forked_project_link) } + it { is_expected.to have_one(:slack_service) } + it { is_expected.to have_one(:microsoft_teams_service) } + it { is_expected.to have_one(:mattermost_service) } + it { is_expected.to have_one(:pushover_service) } + it { is_expected.to have_one(:asana_service) } + it { is_expected.to have_many(:boards) } + it { is_expected.to have_one(:campfire_service) } + it { is_expected.to have_one(:drone_ci_service) } + it { is_expected.to have_one(:emails_on_push_service) } + it { is_expected.to have_one(:pipelines_email_service) } + it { is_expected.to have_one(:irker_service) } + it { is_expected.to have_one(:pivotaltracker_service) } + it { is_expected.to have_one(:hipchat_service) } + it { is_expected.to have_one(:flowdock_service) } + it { is_expected.to have_one(:assembla_service) } + it { is_expected.to have_one(:slack_slash_commands_service) } + it { is_expected.to have_one(:mattermost_slash_commands_service) } + it { is_expected.to have_one(:gemnasium_service) } + it { is_expected.to have_one(:buildkite_service) } + it { is_expected.to have_one(:bamboo_service) } + it { is_expected.to have_one(:teamcity_service) } + it { is_expected.to have_one(:jira_service) } + it { is_expected.to have_one(:redmine_service) } + it { is_expected.to have_one(:custom_issue_tracker_service) } + it { is_expected.to have_one(:bugzilla_service) } + it { is_expected.to have_one(:gitlab_issue_tracker_service) } + it { is_expected.to have_one(:external_wiki_service) } + it { is_expected.to have_one(:project_feature) } + it { is_expected.to have_one(:statistics).class_name('ProjectStatistics') } + it { is_expected.to have_one(:import_data).class_name('ProjectImportData') } it { is_expected.to have_one(:last_event).class_name('Event') } it { is_expected.to have_one(:forked_from_project).through(:forked_project_link) } it { is_expected.to have_many(:commit_statuses) } @@ -62,18 +62,18 @@ describe Project, models: true do it { is_expected.to have_many(:variables) } it { is_expected.to have_many(:triggers) } it { is_expected.to have_many(:pages_domains) } - it { is_expected.to have_many(:labels).class_name('ProjectLabel').dependent(:destroy) } - it { is_expected.to have_many(:users_star_projects).dependent(:destroy) } - it { is_expected.to have_many(:environments).dependent(:destroy) } - it { is_expected.to have_many(:deployments).dependent(:destroy) } - it { is_expected.to have_many(:todos).dependent(:destroy) } - it { is_expected.to have_many(:releases).dependent(:destroy) } - it { is_expected.to have_many(:lfs_objects_projects).dependent(:destroy) } - it { is_expected.to have_many(:project_group_links).dependent(:destroy) } - it { is_expected.to have_many(:notification_settings).dependent(:destroy) } + it { is_expected.to have_many(:labels).class_name('ProjectLabel') } + it { is_expected.to have_many(:users_star_projects) } + it { is_expected.to have_many(:environments) } + it { is_expected.to have_many(:deployments) } + it { is_expected.to have_many(:todos) } + it { is_expected.to have_many(:releases) } + it { is_expected.to have_many(:lfs_objects_projects) } + it { is_expected.to have_many(:project_group_links) } + it { is_expected.to have_many(:notification_settings).dependent(:delete_all) } it { is_expected.to have_many(:forks).through(:forked_project_links) } it { is_expected.to have_many(:uploads).dependent(:destroy) } - it { is_expected.to have_many(:pipeline_schedules).dependent(:destroy) } + it { is_expected.to have_many(:pipeline_schedules) } context 'after initialized' do it "has a project_feature" do @@ -1875,7 +1875,12 @@ describe Project, models: true do create(:ci_variable, :protected, value: 'protected', project: project) end - subject { project.secret_variables_for('ref') } + subject { project.secret_variables_for(ref: 'ref') } + + before do + stub_application_setting( + default_branch_protection: Gitlab::Access::PROTECTION_NONE) + end shared_examples 'ref is protected' do it 'contains all the variables' do @@ -1884,11 +1889,6 @@ describe Project, models: true do end context 'when the ref is not protected' do - before do - stub_application_setting( - default_branch_protection: Gitlab::Access::PROTECTION_NONE) - end - it 'contains only the secret variables' do is_expected.to contain_exactly(secret_variable) end @@ -2199,4 +2199,21 @@ describe Project, models: true do end end end + + describe '#remove_private_deploy_keys' do + it 'removes the private deploy keys of a project' do + project = create(:empty_project) + + private_key = create(:deploy_key, public: false) + public_key = create(:deploy_key, public: true) + + create(:deploy_keys_project, deploy_key: private_key, project: project) + create(:deploy_keys_project, deploy_key: public_key, project: project) + + project.remove_private_deploy_keys + + expect(project.deploy_keys.where(public: false).any?).to eq(false) + expect(project.deploy_keys.where(public: true).any?).to eq(true) + end + end end diff --git a/spec/presenters/ci/build_presenter_spec.rb b/spec/presenters/ci/build_presenter_spec.rb index 518e97d17a1..f05d5c7fce5 100644 --- a/spec/presenters/ci/build_presenter_spec.rb +++ b/spec/presenters/ci/build_presenter_spec.rb @@ -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) { build_stubbed(:empty_project, public_builds: false) } + let(:project) { create(:empty_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) { build_stubbed(:empty_project, :public) } + let(:project) { create(:empty_project, :public) } it 'returns true' do expect(presenter.can?(nil, :read_build)).to be_truthy diff --git a/spec/presenters/ci/group_variable_presenter_spec.rb b/spec/presenters/ci/group_variable_presenter_spec.rb new file mode 100644 index 00000000000..d404028405b --- /dev/null +++ b/spec/presenters/ci/group_variable_presenter_spec.rb @@ -0,0 +1,63 @@ +require 'spec_helper' + +describe Ci::GroupVariablePresenter do + include Gitlab::Routing.url_helpers + + let(:group) { create(:group) } + let(:variable) { create(:ci_group_variable, group: group) } + + subject(:presenter) do + described_class.new(variable) + end + + it 'inherits from Gitlab::View::Presenter::Delegated' do + expect(described_class.superclass).to eq(Gitlab::View::Presenter::Delegated) + end + + describe '#initialize' do + it 'takes a variable and optional params' do + expect { presenter }.not_to raise_error + end + + it 'exposes variable' do + expect(presenter.variable).to eq(variable) + end + + it 'forwards missing methods to variable' do + expect(presenter.key).to eq(variable.key) + end + end + + describe '#placeholder' do + subject { described_class.new(variable).placeholder } + + it { is_expected.to eq('GROUP_VARIABLE') } + end + + describe '#form_path' do + context 'when variable is persisted' do + subject { described_class.new(variable).form_path } + + it { is_expected.to eq(group_variable_path(group, variable)) } + end + + context 'when variable is not persisted' do + let(:variable) { build(:ci_group_variable, group: group) } + subject { described_class.new(variable).form_path } + + it { is_expected.to eq(group_variables_path(group)) } + end + end + + describe '#edit_path' do + subject { described_class.new(variable).edit_path } + + it { is_expected.to eq(group_variable_path(group, variable)) } + end + + describe '#delete_path' do + subject { described_class.new(variable).delete_path } + + it { is_expected.to eq(group_variable_path(group, variable)) } + end +end diff --git a/spec/presenters/ci/variable_presenter_spec.rb b/spec/presenters/ci/variable_presenter_spec.rb new file mode 100644 index 00000000000..9e6aae7bcad --- /dev/null +++ b/spec/presenters/ci/variable_presenter_spec.rb @@ -0,0 +1,63 @@ +require 'spec_helper' + +describe Ci::VariablePresenter do + include Gitlab::Routing.url_helpers + + let(:project) { create(:empty_project) } + let(:variable) { create(:ci_variable, project: project) } + + subject(:presenter) do + described_class.new(variable) + end + + it 'inherits from Gitlab::View::Presenter::Delegated' do + expect(described_class.superclass).to eq(Gitlab::View::Presenter::Delegated) + end + + describe '#initialize' do + it 'takes a variable and optional params' do + expect { presenter }.not_to raise_error + end + + it 'exposes variable' do + expect(presenter.variable).to eq(variable) + end + + it 'forwards missing methods to variable' do + expect(presenter.key).to eq(variable.key) + end + end + + describe '#placeholder' do + subject { described_class.new(variable).placeholder } + + it { is_expected.to eq('PROJECT_VARIABLE') } + end + + describe '#form_path' do + context 'when variable is persisted' do + subject { described_class.new(variable).form_path } + + it { is_expected.to eq(project_variable_path(project, variable)) } + end + + context 'when variable is not persisted' do + let(:variable) { build(:ci_variable, project: project) } + subject { described_class.new(variable).form_path } + + it { is_expected.to eq(project_variables_path(project)) } + end + end + + describe '#edit_path' do + subject { described_class.new(variable).edit_path } + + it { is_expected.to eq(project_variable_path(project, variable)) } + end + + describe '#delete_path' do + subject { described_class.new(variable).delete_path } + + it { is_expected.to eq(project_variable_path(project, variable)) } + end +end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 8ac65ecccab..fa704f23857 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -52,6 +52,24 @@ describe API::Projects do end end + shared_examples_for 'projects response without N + 1 queries' do + it 'avoids N + 1 queries' do + control_count = ActiveRecord::QueryRecorder.new do + get api('/projects', current_user) + end.count + + if defined?(additional_project) + additional_project + else + create(:empty_project, :public) + end + + expect do + get api('/projects', current_user) + end.not_to exceed_query_limit(control_count + 8) + end + end + let!(:public_project) { create(:empty_project, :public, name: 'public_project') } before do project @@ -62,9 +80,13 @@ describe API::Projects do context 'when unauthenticated' do it_behaves_like 'projects response' do - let(:filter) { {} } + let(:filter) { { search: project.name } } + let(:current_user) { user } + let(:projects) { [project] } + end + + it_behaves_like 'projects response without N + 1 queries' do let(:current_user) { nil } - let(:projects) { [public_project] } end end @@ -75,6 +97,21 @@ describe API::Projects do let(:projects) { [public_project, project, project2, project3] } end + it_behaves_like 'projects response without N + 1 queries' do + let(:current_user) { user } + end + + context 'when some projects are in a group' do + before do + create(:empty_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)) } + end + end + it 'includes the project labels as the tag_list' do get api('/projects', user) @@ -476,6 +513,26 @@ describe API::Projects do end 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) } + + it 'returns error when user not found' do + get api('/users/9999/projects/') + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 User Not Found') + end + + it 'returns projects filtered by user' do + get api("/users/#{user4.id}/projects/", user) + + expect(response).to have_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(json_response.map { |project| project['id'] }).to contain_exactly(public_project.id) + end + end + describe 'POST /projects/user/:id' do before do expect(project).to be_persisted diff --git a/spec/rubocop/cop/active_record_dependent_spec.rb b/spec/rubocop/cop/active_record_dependent_spec.rb new file mode 100644 index 00000000000..599a032bfc5 --- /dev/null +++ b/spec/rubocop/cop/active_record_dependent_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require 'rubocop' +require 'rubocop/rspec/support' +require_relative '../../../rubocop/cop/active_record_dependent' + +describe RuboCop::Cop::ActiveRecordDependent do + include CopHelper + + subject(:cop) { described_class.new } + + context 'inside the app/models directory' do + it 'registers an offense when dependent: is used' do + allow(cop).to receive(:in_model?).and_return(true) + + inspect_source(cop, 'belongs_to :foo, dependent: :destroy') + + aggregate_failures do + expect(cop.offenses.size).to eq(1) + expect(cop.offenses.map(&:line)).to eq([1]) + end + end + end + + context 'outside the app/models directory' do + it 'does nothing' do + allow(cop).to receive(:in_model?).and_return(false) + + inspect_source(cop, 'belongs_to :foo, dependent: :destroy') + + expect(cop.offenses).to be_empty + end + end +end diff --git a/spec/rubocop/cop/activerecord_serialize_spec.rb b/spec/rubocop/cop/active_record_serialize_spec.rb index 5bd7e5fa926..b94b25cecd0 100644 --- a/spec/rubocop/cop/activerecord_serialize_spec.rb +++ b/spec/rubocop/cop/active_record_serialize_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' require 'rubocop' require 'rubocop/rspec/support' -require_relative '../../../rubocop/cop/activerecord_serialize' +require_relative '../../../rubocop/cop/active_record_serialize' -describe RuboCop::Cop::ActiverecordSerialize do +describe RuboCop::Cop::ActiveRecordSerialize do include CopHelper subject(:cop) { described_class.new } diff --git a/spec/support/capybara_helpers.rb b/spec/support/capybara_helpers.rb index b57a3493aff..3eb7bea3227 100644 --- a/spec/support/capybara_helpers.rb +++ b/spec/support/capybara_helpers.rb @@ -35,6 +35,11 @@ module CapybaraHelpers visit 'about:blank' visit url end + + # Simulate a browser restart by clearing the session cookie. + def clear_browser_session + page.driver.remove_cookie('_gitlab_session') + end end RSpec.configure do |config| diff --git a/spec/support/gitaly.rb b/spec/support/gitaly.rb index 2bf159002a0..89fb362cf14 100644 --- a/spec/support/gitaly.rb +++ b/spec/support/gitaly.rb @@ -1,8 +1,6 @@ -if Gitlab::GitalyClient.enabled? - RSpec.configure do |config| - config.before(:each) do |example| - next if example.metadata[:skip_gitaly_mock] - allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true) - end +RSpec.configure do |config| + config.before(:each) do |example| + next if example.metadata[:skip_gitaly_mock] + allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(true) end end diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 4c88958264b..99e7806353d 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -62,6 +62,16 @@ module LoginHelpers Thread.current[:current_user] = user end + def login_via(provider, user, uid, remember_me: false) + mock_auth_hash(provider, uid, user.email) + visit new_user_session_path + expect(page).to have_content('Sign in with') + + check 'Remember Me' if remember_me + + click_link "oauth-login-#{provider}" + end + def mock_auth_hash(provider, uid, email) # The mock_auth configuration allows you to set per-provider (or default) # authentication hashes to return during integration testing. @@ -108,6 +118,7 @@ module LoginHelpers end allow(Gitlab::OAuth::Provider).to receive_messages(providers: [:saml], config_for: mock_saml_config) stub_omniauth_setting(messages) - expect_any_instance_of(Object).to receive(:omniauth_authorize_path).with(:user, "saml").and_return('/users/auth/saml') + allow_any_instance_of(Object).to receive(:user_saml_omniauth_authorize_path).and_return('/users/auth/saml') + allow_any_instance_of(Object).to receive(:omniauth_authorize_path).with(:user, "saml").and_return('/users/auth/saml') end end diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 32546abcad4..0cae5620920 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -69,7 +69,7 @@ module TestEnv # Setup GitLab shell for test instance setup_gitlab_shell - setup_gitaly if Gitlab::GitalyClient.enabled? + setup_gitaly # Create repository for FactoryGirl.create(:project) setup_factory_repo diff --git a/spec/workers/expire_build_instance_artifacts_worker_spec.rb b/spec/workers/expire_build_instance_artifacts_worker_spec.rb index 1d8da68883b..bed5c5e2ecb 100644 --- a/spec/workers/expire_build_instance_artifacts_worker_spec.rb +++ b/spec/workers/expire_build_instance_artifacts_worker_spec.rb @@ -30,20 +30,6 @@ describe ExpireBuildInstanceArtifactsWorker do expect(build.reload.artifacts_file_identifier).to be_nil end end - - context 'when associated project was removed' do - let(:build) do - create(:ci_build, :artifacts, artifacts_expiry) do |build| - build.project.pending_delete = true - end - end - - it 'does not remove artifacts' do - expect do - build.reload.artifacts_file - end.not_to raise_error - end - end end context 'with not yet expired artifacts' do |