summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorAlessio Caiazza <acaiazza@gitlab.com>2018-06-04 13:57:51 +0200
committerAlessio Caiazza <acaiazza@gitlab.com>2018-06-04 13:57:51 +0200
commit8ffcaf3b85fdf716ffeacf4e9d4c89b922de50b9 (patch)
tree2e6acfa369e3e659ef4c6afb9290ad122a8fea5c /spec
parent1841da16abe864b3dae19636fee9e9bbe9a01b56 (diff)
parent23ae072ba2d601a3639a32f5a29302c430106bb8 (diff)
downloadgitlab-ce-8ffcaf3b85fdf716ffeacf4e9d4c89b922de50b9.tar.gz
Merge branch 'master' into 11-0-stable-prepare-rc211-0-stable-prepare-rc2
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/groups/runners_controller_spec.rb3
-rw-r--r--spec/controllers/projects/mirrors_controller_spec.rb2
-rw-r--r--spec/controllers/projects/runners_controller_spec.rb3
-rw-r--r--spec/controllers/projects/services_controller_spec.rb2
-rw-r--r--spec/controllers/projects/settings/ci_cd_controller_spec.rb8
-rw-r--r--spec/factories/ci/runner_projects.rb2
-rw-r--r--spec/factories/ci/runners.rb31
-rw-r--r--spec/factories/issues.rb1
-rw-r--r--spec/features/admin/admin_runners_spec.rb19
-rw-r--r--spec/features/runners_spec.rb27
-rw-r--r--spec/finders/runner_jobs_finder_spec.rb2
-rw-r--r--spec/fixtures/api/schemas/entities/issue.json2
-rw-r--r--spec/javascripts/ide/helpers.js2
-rw-r--r--spec/javascripts/ide/mock_data.js10
-rw-r--r--spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js182
-rw-r--r--spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js55
-rw-r--r--spec/javascripts/integrations/integration_settings_form_spec.js23
-rw-r--r--spec/lib/backup/repository_spec.rb2
-rw-r--r--spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb12
-rw-r--r--spec/lib/gitlab/checks/lfs_integrity_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb65
-rw-r--r--spec/lib/gitlab/conflict/file_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/usage_data_spec.rb19
-rw-r--r--spec/lib/gitlab/file_finder_spec.rb24
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb133
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml1
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb82
-rw-r--r--spec/lib/gitlab/url_blocker_spec.rb10
-rw-r--r--spec/lib/gitlab/wiki_file_finder_spec.rb20
-rw-r--r--spec/lib/omni_auth/strategies/jwt_spec.rb6
-rw-r--r--spec/models/ci/build_spec.rb11
-rw-r--r--spec/models/ci/pipeline_spec.rb15
-rw-r--r--spec/models/ci/runner_spec.rb199
-rw-r--r--spec/models/concerns/issuable_spec.rb5
-rw-r--r--spec/models/concerns/reactive_caching_spec.rb1
-rw-r--r--spec/models/deployment_spec.rb1
-rw-r--r--spec/models/issue_spec.rb1
-rw-r--r--spec/models/merge_request_spec.rb1
-rw-r--r--spec/models/milestone_spec.rb2
-rw-r--r--spec/models/project_spec.rb14
-rw-r--r--spec/models/remote_mirror_spec.rb2
-rw-r--r--spec/models/timelog_spec.rb3
-rw-r--r--spec/models/user_spec.rb40
-rw-r--r--spec/requests/api/commit_statuses_spec.rb2
-rw-r--r--spec/requests/api/issues_spec.rb14
-rw-r--r--spec/requests/api/runner_spec.rb18
-rw-r--r--spec/requests/api/runners_spec.rb81
-rw-r--r--spec/serializers/runner_entity_spec.rb4
-rw-r--r--spec/services/ci/register_job_service_spec.rb42
-rw-r--r--spec/services/ci/update_build_queue_service_spec.rb17
-rw-r--r--spec/services/issues/update_service_spec.rb8
-rw-r--r--spec/services/merge_requests/update_service_spec.rb8
-rw-r--r--spec/support/gitaly.rb5
-rw-r--r--spec/support/helpers/cycle_analytics_helpers.rb24
-rw-r--r--spec/support/shared_examples/file_finder.rb21
-rw-r--r--spec/support/shared_examples/models/atomic_internal_id_spec.rb29
-rw-r--r--spec/support/shared_examples/url_validator_examples.rb42
-rw-r--r--spec/validators/public_url_validator_spec.rb28
-rw-r--r--spec/validators/url_placeholder_validator_spec.rb39
-rw-r--r--spec/validators/url_validator_spec.rb68
60 files changed, 1002 insertions, 497 deletions
diff --git a/spec/controllers/groups/runners_controller_spec.rb b/spec/controllers/groups/runners_controller_spec.rb
index 6d31b0ce959..5770d15557c 100644
--- a/spec/controllers/groups/runners_controller_spec.rb
+++ b/spec/controllers/groups/runners_controller_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Groups::RunnersController do
let(:user) { create(:user) }
let(:group) { create(:group) }
- let(:runner) { create(:ci_runner) }
+ let(:runner) { create(:ci_runner, :group, groups: [group]) }
let(:params) do
{
@@ -15,7 +15,6 @@ describe Groups::RunnersController do
before do
sign_in(user)
group.add_master(user)
- group.runners << runner
end
describe '#update' do
diff --git a/spec/controllers/projects/mirrors_controller_spec.rb b/spec/controllers/projects/mirrors_controller_spec.rb
index 45c1218a39c..5d64f362252 100644
--- a/spec/controllers/projects/mirrors_controller_spec.rb
+++ b/spec/controllers/projects/mirrors_controller_spec.rb
@@ -54,7 +54,7 @@ describe Projects::MirrorsController do
do_put(project, remote_mirrors_attributes: remote_mirror_attributes)
expect(response).to redirect_to(project_settings_repository_path(project))
- expect(flash[:alert]).to match(/must be a valid URL/)
+ expect(flash[:alert]).to match(/Only allowed protocols are/)
end
it 'should not create a RemoteMirror object' do
diff --git a/spec/controllers/projects/runners_controller_spec.rb b/spec/controllers/projects/runners_controller_spec.rb
index 89a13f3c976..2082dd2cff0 100644
--- a/spec/controllers/projects/runners_controller_spec.rb
+++ b/spec/controllers/projects/runners_controller_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Projects::RunnersController do
let(:user) { create(:user) }
let(:project) { create(:project) }
- let(:runner) { create(:ci_runner) }
+ let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:params) do
{
@@ -16,7 +16,6 @@ describe Projects::RunnersController do
before do
sign_in(user)
project.add_master(user)
- project.runners << runner
end
describe '#update' do
diff --git a/spec/controllers/projects/services_controller_spec.rb b/spec/controllers/projects/services_controller_spec.rb
index e4dc61b3a68..61f35cf325b 100644
--- a/spec/controllers/projects/services_controller_spec.rb
+++ b/spec/controllers/projects/services_controller_spec.rb
@@ -102,7 +102,7 @@ describe Projects::ServicesController do
expect(response.status).to eq(200)
expect(JSON.parse(response.body))
- .to eq('error' => true, 'message' => 'Test failed.', 'service_response' => 'Bad test')
+ .to eq('error' => true, 'message' => 'Test failed.', 'service_response' => 'Bad test', 'test_failed' => true)
end
end
end
diff --git a/spec/controllers/projects/settings/ci_cd_controller_spec.rb b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
index f1810763d2d..d53fe9bf734 100644
--- a/spec/controllers/projects/settings/ci_cd_controller_spec.rb
+++ b/spec/controllers/projects/settings/ci_cd_controller_spec.rb
@@ -19,12 +19,12 @@ describe Projects::Settings::CiCdController do
end
context 'with group runners' do
- let(:group_runner) { create(:ci_runner, runner_type: :group_type) }
let(:parent_group) { create(:group) }
- let(:group) { create(:group, runners: [group_runner], parent: parent_group) }
+ let(:group) { create(:group, parent: parent_group) }
+ let(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let(:other_project) { create(:project, group: group) }
- let!(:project_runner) { create(:ci_runner, projects: [other_project], runner_type: :project_type) }
- let!(:shared_runner) { create(:ci_runner, :shared) }
+ let!(:project_runner) { create(:ci_runner, :project, projects: [other_project]) }
+ let!(:shared_runner) { create(:ci_runner, :instance) }
it 'sets assignable project runners only' do
group.add_master(user)
diff --git a/spec/factories/ci/runner_projects.rb b/spec/factories/ci/runner_projects.rb
index f605e90ceed..ec15972c423 100644
--- a/spec/factories/ci/runner_projects.rb
+++ b/spec/factories/ci/runner_projects.rb
@@ -1,6 +1,6 @@
FactoryBot.define do
factory :ci_runner_project, class: Ci::RunnerProject do
- runner factory: :ci_runner
+ runner factory: [:ci_runner, :project]
project
end
end
diff --git a/spec/factories/ci/runners.rb b/spec/factories/ci/runners.rb
index cdc170b9ccb..6fb621b5e51 100644
--- a/spec/factories/ci/runners.rb
+++ b/spec/factories/ci/runners.rb
@@ -3,22 +3,45 @@ FactoryBot.define do
sequence(:description) { |n| "My runner#{n}" }
platform "darwin"
- is_shared false
active true
access_level :not_protected
- runner_type :project_type
+
+ is_shared true
+ runner_type :instance_type
trait :online do
contacted_at Time.now
end
- trait :shared do
+ trait :instance do
is_shared true
runner_type :instance_type
end
- trait :specific do
+ trait :group do
+ is_shared false
+ runner_type :group_type
+
+ after(:build) do |runner, evaluator|
+ runner.groups << build(:group) if runner.groups.empty?
+ end
+ end
+
+ trait :project do
is_shared false
+ runner_type :project_type
+
+ after(:build) do |runner, evaluator|
+ runner.projects << build(:project) if runner.projects.empty?
+ end
+ end
+
+ trait :without_projects do
+ # we use that to create invalid runner:
+ # the one without projects
+ after(:create) do |runner, evaluator|
+ runner.runner_projects.delete_all
+ end
end
trait :inactive do
diff --git a/spec/factories/issues.rb b/spec/factories/issues.rb
index 998080a3dd5..3a35bdd25de 100644
--- a/spec/factories/issues.rb
+++ b/spec/factories/issues.rb
@@ -3,6 +3,7 @@ FactoryBot.define do
title { generate(:title) }
project
author { project.creator }
+ updated_by { author }
trait :confidential do
confidential true
diff --git a/spec/features/admin/admin_runners_spec.rb b/spec/features/admin/admin_runners_spec.rb
index c33014cbb31..be8754a5315 100644
--- a/spec/features/admin/admin_runners_spec.rb
+++ b/spec/features/admin/admin_runners_spec.rb
@@ -62,7 +62,7 @@ describe "Admin Runners" do
context 'group runner' do
let(:group) { create(:group) }
- let!(:runner) { create(:ci_runner, groups: [group], runner_type: :group_type) }
+ let!(:runner) { create(:ci_runner, :group, groups: [group]) }
it 'shows the label and does not show the project count' do
visit admin_runners_path
@@ -76,7 +76,7 @@ describe "Admin Runners" do
context 'shared runner' do
it 'shows the label and does not show the project count' do
- runner = create :ci_runner, :shared
+ runner = create :ci_runner, :instance
visit admin_runners_path
@@ -90,7 +90,7 @@ describe "Admin Runners" do
context 'specific runner' do
it 'shows the label and the project count' do
project = create :project
- runner = create :ci_runner, projects: [project]
+ runner = create :ci_runner, :project, projects: [project]
visit admin_runners_path
@@ -149,8 +149,9 @@ describe "Admin Runners" do
end
context 'with specific runner' do
+ let(:runner) { create(:ci_runner, :project, projects: [@project1]) }
+
before do
- @project1.runners << runner
visit admin_runner_path(runner)
end
@@ -158,9 +159,9 @@ describe "Admin Runners" do
end
context 'with locked runner' do
+ let(:runner) { create(:ci_runner, :project, projects: [@project1], locked: true) }
+
before do
- runner.update(locked: true)
- @project1.runners << runner
visit admin_runner_path(runner)
end
@@ -168,9 +169,10 @@ describe "Admin Runners" do
end
context 'with shared runner' do
+ let(:runner) { create(:ci_runner, :instance) }
+
before do
@project1.destroy
- runner.update(is_shared: true)
visit admin_runner_path(runner)
end
@@ -179,8 +181,9 @@ describe "Admin Runners" do
end
describe 'disable/destroy' do
+ let(:runner) { create(:ci_runner, :project, projects: [@project1]) }
+
before do
- @project1.runners << runner
visit admin_runner_path(runner)
end
diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb
index e0cd963fe39..9ce7d538004 100644
--- a/spec/features/runners_spec.rb
+++ b/spec/features/runners_spec.rb
@@ -28,12 +28,8 @@ feature 'Runners' do
project.add_master(user)
end
- context 'when a specific runner is activated on the project' do
- given(:specific_runner) { create(:ci_runner, :specific) }
-
- background do
- project.runners << specific_runner
- end
+ context 'when a project_type runner is activated on the project' do
+ given!(:specific_runner) { create(:ci_runner, :project, projects: [project]) }
scenario 'user sees the specific runner' do
visit project_runners_path(project)
@@ -114,7 +110,7 @@ feature 'Runners' do
end
context 'when a shared runner is activated on the project' do
- given!(:shared_runner) { create(:ci_runner, :shared) }
+ given!(:shared_runner) { create(:ci_runner, :instance) }
scenario 'user sees CI/CD setting page' do
visit project_runners_path(project)
@@ -126,11 +122,10 @@ feature 'Runners' do
context 'when a specific runner exists in another project' do
given(:another_project) { create(:project) }
- given(:specific_runner) { create(:ci_runner, :specific) }
+ given!(:specific_runner) { create(:ci_runner, :project, projects: [another_project]) }
background do
another_project.add_master(user)
- another_project.runners << specific_runner
end
scenario 'user enables and disables a specific runner' do
@@ -220,8 +215,8 @@ feature 'Runners' do
end
context 'project with a group but no group runner' do
- given(:group) { create :group }
- given(:project) { create :project, group: group }
+ given(:group) { create(:group) }
+ given(:project) { create(:project, group: group) }
scenario 'group runners are not available' do
visit project_runners_path(project)
@@ -234,9 +229,9 @@ feature 'Runners' do
end
context 'project with a group and a group runner' do
- given(:group) { create :group }
- given(:project) { create :project, group: group }
- given!(:ci_runner) { create :ci_runner, groups: [group], description: 'group-runner' }
+ given(:group) { create(:group) }
+ given(:project) { create(:project, group: group) }
+ given!(:ci_runner) { create(:ci_runner, :group, groups: [group], description: 'group-runner') }
scenario 'group runners are available' do
visit project_runners_path(project)
@@ -263,7 +258,7 @@ feature 'Runners' do
end
context 'group runners in group settings' do
- given(:group) { create :group }
+ given(:group) { create(:group) }
background do
group.add_master(user)
end
@@ -277,7 +272,7 @@ feature 'Runners' do
end
context 'group with a runner' do
- let!(:runner) { create :ci_runner, groups: [group], description: 'group-runner' }
+ let!(:runner) { create(:ci_runner, :group, groups: [group], description: 'group-runner') }
scenario 'the runner is visible' do
visit group_settings_ci_cd_path(group)
diff --git a/spec/finders/runner_jobs_finder_spec.rb b/spec/finders/runner_jobs_finder_spec.rb
index 4275b1a7ff1..97304170c4e 100644
--- a/spec/finders/runner_jobs_finder_spec.rb
+++ b/spec/finders/runner_jobs_finder_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe RunnerJobsFinder do
let(:project) { create(:project) }
- let(:runner) { create(:ci_runner, :shared) }
+ let(:runner) { create(:ci_runner, :instance) }
subject { described_class.new(runner, params).execute }
diff --git a/spec/fixtures/api/schemas/entities/issue.json b/spec/fixtures/api/schemas/entities/issue.json
index 38467b4ca20..00abe73ec8a 100644
--- a/spec/fixtures/api/schemas/entities/issue.json
+++ b/spec/fixtures/api/schemas/entities/issue.json
@@ -27,7 +27,7 @@
"due_date": { "type": "date" },
"confidential": { "type": "boolean" },
"discussion_locked": { "type": ["boolean", "null"] },
- "updated_by_id": { "type": ["string", "null"] },
+ "updated_by_id": { "type": ["integer", "null"] },
"time_estimate": { "type": "integer" },
"total_time_spent": { "type": "integer" },
"human_time_estimate": { "type": ["integer", "null"] },
diff --git a/spec/javascripts/ide/helpers.js b/spec/javascripts/ide/helpers.js
index 5c7e2db0e96..9312e17704e 100644
--- a/spec/javascripts/ide/helpers.js
+++ b/spec/javascripts/ide/helpers.js
@@ -1,12 +1,14 @@
import { decorateData } from '~/ide/stores/utils';
import state from '~/ide/stores/state';
import commitState from '~/ide/stores/modules/commit/state';
+import mergeRequestsState from '~/ide/stores/modules/merge_requests/state';
import pipelinesState from '~/ide/stores/modules/pipelines/state';
export const resetStore = store => {
const newState = {
...state(),
commit: commitState(),
+ mergeRequests: mergeRequestsState(),
pipelines: pipelinesState(),
};
store.replaceState(newState);
diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js
index 8ad51e122b6..dcf857f7e04 100644
--- a/spec/javascripts/ide/mock_data.js
+++ b/spec/javascripts/ide/mock_data.js
@@ -147,3 +147,13 @@ export const fullPipelinesResponse = {
],
},
};
+
+export const mergeRequests = [
+ {
+ id: 1,
+ iid: 1,
+ title: 'Test merge request',
+ project_id: 1,
+ web_url: `${gl.TEST_HOST}/namespace/project-path/merge_requests/1`,
+ },
+];
diff --git a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js
new file mode 100644
index 00000000000..b571cfb963a
--- /dev/null
+++ b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js
@@ -0,0 +1,182 @@
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
+import state from '~/ide/stores/modules/merge_requests/state';
+import * as types from '~/ide/stores/modules/merge_requests/mutation_types';
+import actions, {
+ requestMergeRequests,
+ receiveMergeRequestsError,
+ receiveMergeRequestsSuccess,
+ fetchMergeRequests,
+ resetMergeRequests,
+} from '~/ide/stores/modules/merge_requests/actions';
+import { mergeRequests } from '../../../mock_data';
+import testAction from '../../../../helpers/vuex_action_helper';
+
+describe('IDE merge requests actions', () => {
+ let mockedState;
+ let mock;
+
+ beforeEach(() => {
+ mockedState = state();
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('requestMergeRequests', () => {
+ it('should should commit request', done => {
+ testAction(
+ requestMergeRequests,
+ null,
+ mockedState,
+ [{ type: types.REQUEST_MERGE_REQUESTS }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('receiveMergeRequestsError', () => {
+ let flashSpy;
+
+ beforeEach(() => {
+ flashSpy = spyOnDependency(actions, 'flash');
+ });
+
+ it('should should commit error', done => {
+ testAction(
+ receiveMergeRequestsError,
+ null,
+ mockedState,
+ [{ type: types.RECEIVE_MERGE_REQUESTS_ERROR }],
+ [],
+ done,
+ );
+ });
+
+ it('creates flash message', () => {
+ receiveMergeRequestsError({ commit() {} });
+
+ expect(flashSpy).toHaveBeenCalled();
+ });
+ });
+
+ describe('receiveMergeRequestsSuccess', () => {
+ it('should commit received data', done => {
+ testAction(
+ receiveMergeRequestsSuccess,
+ 'data',
+ mockedState,
+ [{ type: types.RECEIVE_MERGE_REQUESTS_SUCCESS, payload: 'data' }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('fetchMergeRequests', () => {
+ beforeEach(() => {
+ gon.api_version = 'v4';
+ });
+
+ describe('success', () => {
+ beforeEach(() => {
+ mock.onGet(/\/api\/v4\/merge_requests(.*)$/).replyOnce(200, mergeRequests);
+ });
+
+ it('calls API with params from state', () => {
+ const apiSpy = spyOn(axios, 'get').and.callThrough();
+
+ fetchMergeRequests({ dispatch() {}, state: mockedState });
+
+ expect(apiSpy).toHaveBeenCalledWith(jasmine.anything(), {
+ params: {
+ scope: 'assigned-to-me',
+ state: 'opened',
+ search: '',
+ },
+ });
+ });
+
+ it('calls API with search', () => {
+ const apiSpy = spyOn(axios, 'get').and.callThrough();
+
+ fetchMergeRequests({ dispatch() {}, state: mockedState }, 'testing search');
+
+ expect(apiSpy).toHaveBeenCalledWith(jasmine.anything(), {
+ params: {
+ scope: 'assigned-to-me',
+ state: 'opened',
+ search: 'testing search',
+ },
+ });
+ });
+
+ it('dispatches request', done => {
+ testAction(
+ fetchMergeRequests,
+ null,
+ mockedState,
+ [],
+ [
+ { type: 'requestMergeRequests' },
+ { type: 'resetMergeRequests' },
+ { type: 'receiveMergeRequestsSuccess' },
+ ],
+ done,
+ );
+ });
+
+ it('dispatches success with received data', done => {
+ testAction(
+ fetchMergeRequests,
+ null,
+ mockedState,
+ [],
+ [
+ { type: 'requestMergeRequests' },
+ { type: 'resetMergeRequests' },
+ { type: 'receiveMergeRequestsSuccess', payload: mergeRequests },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('error', () => {
+ beforeEach(() => {
+ mock.onGet(/\/api\/v4\/merge_requests(.*)$/).replyOnce(500);
+ });
+
+ it('dispatches error', done => {
+ testAction(
+ fetchMergeRequests,
+ null,
+ mockedState,
+ [],
+ [
+ { type: 'requestMergeRequests' },
+ { type: 'resetMergeRequests' },
+ { type: 'receiveMergeRequestsError' },
+ ],
+ done,
+ );
+ });
+ });
+ });
+
+ describe('resetMergeRequests', () => {
+ it('commits reset', done => {
+ testAction(
+ resetMergeRequests,
+ null,
+ mockedState,
+ [{ type: types.RESET_MERGE_REQUESTS }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js
new file mode 100644
index 00000000000..664d3914564
--- /dev/null
+++ b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js
@@ -0,0 +1,55 @@
+import state from '~/ide/stores/modules/merge_requests/state';
+import mutations from '~/ide/stores/modules/merge_requests/mutations';
+import * as types from '~/ide/stores/modules/merge_requests/mutation_types';
+import { mergeRequests } from '../../../mock_data';
+
+describe('IDE merge requests mutations', () => {
+ let mockedState;
+
+ beforeEach(() => {
+ mockedState = state();
+ });
+
+ describe(types.REQUEST_MERGE_REQUESTS, () => {
+ it('sets loading to true', () => {
+ mutations[types.REQUEST_MERGE_REQUESTS](mockedState);
+
+ expect(mockedState.isLoading).toBe(true);
+ });
+ });
+
+ describe(types.RECEIVE_MERGE_REQUESTS_ERROR, () => {
+ it('sets loading to false', () => {
+ mutations[types.RECEIVE_MERGE_REQUESTS_ERROR](mockedState);
+
+ expect(mockedState.isLoading).toBe(false);
+ });
+ });
+
+ describe(types.RECEIVE_MERGE_REQUESTS_SUCCESS, () => {
+ it('sets merge requests', () => {
+ gon.gitlab_url = gl.TEST_HOST;
+ mutations[types.RECEIVE_MERGE_REQUESTS_SUCCESS](mockedState, mergeRequests);
+
+ expect(mockedState.mergeRequests).toEqual([
+ {
+ id: 1,
+ iid: 1,
+ title: 'Test merge request',
+ projectId: 1,
+ projectPathWithNamespace: 'namespace/project-path',
+ },
+ ]);
+ });
+ });
+
+ describe(types.RESET_MERGE_REQUESTS, () => {
+ it('clears merge request array', () => {
+ mockedState.mergeRequests = ['test'];
+
+ mutations[types.RESET_MERGE_REQUESTS](mockedState);
+
+ expect(mockedState.mergeRequests).toEqual([]);
+ });
+ });
+});
diff --git a/spec/javascripts/integrations/integration_settings_form_spec.js b/spec/javascripts/integrations/integration_settings_form_spec.js
index 050b1f2074e..e07343810d2 100644
--- a/spec/javascripts/integrations/integration_settings_form_spec.js
+++ b/spec/javascripts/integrations/integration_settings_form_spec.js
@@ -143,6 +143,7 @@ describe('IntegrationSettingsForm', () => {
error: true,
message: errorMessage,
service_response: 'some error',
+ test_failed: true,
});
integrationSettingsForm.testSettings(formData)
@@ -157,6 +158,27 @@ describe('IntegrationSettingsForm', () => {
.catch(done.fail);
});
+ it('should not show error Flash with `Save anyway` action if ajax request responds with error in validation', (done) => {
+ const errorMessage = 'Validations failed.';
+ mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
+ error: true,
+ message: errorMessage,
+ service_response: 'some error',
+ test_failed: false,
+ });
+
+ integrationSettingsForm.testSettings(formData)
+ .then(() => {
+ const $flashContainer = $('.flash-container');
+ expect($flashContainer.find('.flash-text').text().trim()).toEqual('Validations failed. some error');
+ expect($flashContainer.find('.flash-action')).toBeDefined();
+ expect($flashContainer.find('.flash-action').text().trim()).toEqual('');
+
+ done();
+ })
+ .catch(done.fail);
+ });
+
it('should submit form if ajax request responds without any error in test', (done) => {
spyOn(integrationSettingsForm.$form, 'submit');
@@ -180,6 +202,7 @@ describe('IntegrationSettingsForm', () => {
mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
error: true,
message: errorMessage,
+ test_failed: true,
});
integrationSettingsForm.testSettings(formData)
diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb
index 023bedaaebb..f583b2021a2 100644
--- a/spec/lib/backup/repository_spec.rb
+++ b/spec/lib/backup/repository_spec.rb
@@ -92,7 +92,7 @@ describe Backup::Repository do
end
def list_repositories
- Dir[SEED_STORAGE_PATH + '/*.git']
+ Dir[File.join(SEED_STORAGE_PATH, '*.git')]
end
end
diff --git a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
index 007e93c1db6..211e3aaa94b 100644
--- a/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
+++ b/spec/lib/gitlab/background_migration/deserialize_merge_request_diffs_and_commits_spec.rb
@@ -299,7 +299,11 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m
let(:commits) { merge_request_diff.commits.map(&:to_hash) }
let(:first_commit) { project.repository.commit(merge_request_diff.head_commit_sha) }
let(:expected_commits) { commits }
- let(:diffs) { first_commit.rugged_diff_from_parent.patches }
+ let(:diffs) do
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ first_commit.rugged_diff_from_parent.patches
+ end
+ end
let(:expected_diffs) { [] }
include_examples 'updated MR diff'
@@ -309,7 +313,11 @@ describe Gitlab::BackgroundMigration::DeserializeMergeRequestDiffsAndCommits, :m
let(:commits) { merge_request_diff.commits.map(&:to_hash) }
let(:first_commit) { project.repository.commit(merge_request_diff.head_commit_sha) }
let(:expected_commits) { commits }
- let(:diffs) { first_commit.rugged_diff_from_parent.deltas }
+ let(:diffs) do
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ first_commit.rugged_diff_from_parent.deltas
+ end
+ end
let(:expected_diffs) { [] }
include_examples 'updated MR diff'
diff --git a/spec/lib/gitlab/checks/lfs_integrity_spec.rb b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
index 7201e4f7bf6..ec22e3a198e 100644
--- a/spec/lib/gitlab/checks/lfs_integrity_spec.rb
+++ b/spec/lib/gitlab/checks/lfs_integrity_spec.rb
@@ -6,7 +6,9 @@ describe Gitlab::Checks::LfsIntegrity do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:newrev) do
- operations = BareRepoOperations.new(repository.path)
+ operations = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ BareRepoOperations.new(repository.path)
+ end
# Create a commit not pointed at by any ref to emulate being in the
# pre-receive hook so that `--not --all` returns some objects
diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 4d7d6951a51..c5a4d9b4778 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -42,6 +42,10 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
it 'correctly assigns user' do
expect(pipeline.builds).to all(have_attributes(user: user))
end
+
+ it 'has pipeline iid' do
+ expect(pipeline.iid).to be > 0
+ end
end
context 'when pipeline is empty' do
@@ -68,6 +72,10 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
expect(pipeline.errors.to_a)
.to include 'No stages / jobs for this pipeline.'
end
+
+ it 'wastes pipeline iid' do
+ expect(InternalId.ci_pipelines.where(project_id: project.id).last.last_value).to be > 0
+ end
end
context 'when pipeline has validation errors' do
@@ -87,6 +95,10 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
expect(pipeline.errors.to_a)
.to include 'Failed to build the pipeline!'
end
+
+ it 'wastes pipeline iid' do
+ expect(InternalId.ci_pipelines.where(project_id: project.id).last.last_value).to be > 0
+ end
end
context 'when there is a seed blocks present' do
@@ -111,6 +123,12 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
expect(pipeline.variables.first.key).to eq 'VAR'
expect(pipeline.variables.first.value).to eq '123'
end
+
+ it 'has pipeline iid' do
+ step.perform!
+
+ expect(pipeline.iid).to be > 0
+ end
end
context 'when seeds block tries to persist some resources' do
@@ -121,6 +139,12 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
it 'raises exception' do
expect { step.perform! }.to raise_error(ActiveRecord::RecordNotSaved)
end
+
+ it 'wastes pipeline iid' do
+ expect { step.perform! }.to raise_error
+
+ expect(InternalId.ci_pipelines.where(project_id: project.id).last.last_value).to be > 0
+ end
end
end
@@ -132,22 +156,39 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
end
end
- context 'when using only/except build policies' do
- let(:config) do
- { rspec: { script: 'rspec', stage: 'test', only: ['master'] },
- prod: { script: 'cap prod', stage: 'deploy', only: ['tags'] } }
- end
+ context 'when variables policy is specified' do
+ shared_examples_for 'a correct pipeline' do
+ it 'populates pipeline according to used policies' do
+ step.perform!
- let(:pipeline) do
- build(:ci_pipeline, ref: 'master', config: config)
+ expect(pipeline.stages.size).to eq 1
+ expect(pipeline.stages.first.builds.size).to eq 1
+ expect(pipeline.stages.first.builds.first.name).to eq 'rspec'
+ end
end
- it 'populates pipeline according to used policies' do
- step.perform!
+ context 'when using only/except build policies' do
+ let(:config) do
+ { rspec: { script: 'rspec', stage: 'test', only: ['master'] },
+ prod: { script: 'cap prod', stage: 'deploy', only: ['tags'] } }
+ end
+
+ let(:pipeline) do
+ build(:ci_pipeline, ref: 'master', config: config)
+ end
- expect(pipeline.stages.size).to eq 1
- expect(pipeline.stages.first.builds.size).to eq 1
- expect(pipeline.stages.first.builds.first.name).to eq 'rspec'
+ it_behaves_like 'a correct pipeline'
+
+ context 'when variables expression is specified' do
+ context 'when pipeline iid is the subject' do
+ let(:config) do
+ { rspec: { script: 'rspec', only: { variables: ["$CI_PIPELINE_IID == '1'"] } },
+ prod: { script: 'cap prod', only: { variables: ["$CI_PIPELINE_IID == '1000'"] } } }
+ end
+
+ it_behaves_like 'a correct pipeline'
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/conflict/file_spec.rb b/spec/lib/gitlab/conflict/file_spec.rb
index 92792144429..5b343920429 100644
--- a/spec/lib/gitlab/conflict/file_spec.rb
+++ b/spec/lib/gitlab/conflict/file_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::Conflict::File do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
- let(:rugged) { repository.rugged }
+ let(:rugged) { Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.rugged } }
let(:their_commit) { rugged.branches['conflict-start'].target }
let(:our_commit) { rugged.branches['conflict-resolvable'].target }
let(:merge_request) { create(:merge_request, source_branch: 'conflict-resolvable', target_branch: 'conflict-start', source_project: project) }
diff --git a/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb b/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb
index 56a316318cb..a785b17f682 100644
--- a/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/usage_data_spec.rb
@@ -3,7 +3,12 @@ require 'spec_helper'
describe Gitlab::CycleAnalytics::UsageData do
describe '#to_json' do
before do
- Timecop.freeze do
+ # Since git commits only have second precision, round up to the
+ # nearest second to ensure we have accurate median and standard
+ # deviation calculations.
+ current_time = Time.at(Time.now.to_i)
+
+ Timecop.freeze(current_time) do
user = create(:user, :admin)
projects = create_list(:project, 2, :repository)
@@ -37,13 +42,7 @@ describe Gitlab::CycleAnalytics::UsageData do
expected_values.each_pair do |op, value|
expect(stage_values).to have_key(op)
-
- if op == :missing
- expect(stage_values[op]).to eq(value)
- else
- # delta is used because of git timings that Timecop does not stub
- expect(stage_values[op].to_i).to be_within(5).of(value.to_i)
- end
+ expect(stage_values[op]).to eq(value)
end
end
end
@@ -58,8 +57,8 @@ describe Gitlab::CycleAnalytics::UsageData do
missing: 0
},
plan: {
- average: 2,
- sd: 2,
+ average: 1,
+ sd: 0,
missing: 0
},
code: {
diff --git a/spec/lib/gitlab/file_finder_spec.rb b/spec/lib/gitlab/file_finder_spec.rb
index 07cb10e563e..d6d9e4001a3 100644
--- a/spec/lib/gitlab/file_finder_spec.rb
+++ b/spec/lib/gitlab/file_finder_spec.rb
@@ -3,27 +3,11 @@ require 'spec_helper'
describe Gitlab::FileFinder do
describe '#find' do
let(:project) { create(:project, :public, :repository) }
- let(:finder) { described_class.new(project, project.default_branch) }
- it 'finds by name' do
- results = finder.find('files')
-
- filename, blob = results.find { |_, blob| blob.filename == 'files/images/wm.svg' }
- expect(filename).to eq('files/images/wm.svg')
- expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
- expect(blob.ref).to eq(finder.ref)
- expect(blob.data).not_to be_empty
- end
-
- it 'finds by content' do
- results = finder.find('files')
-
- filename, blob = results.find { |_, blob| blob.filename == 'CHANGELOG' }
-
- expect(filename).to eq('CHANGELOG')
- expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
- expect(blob.ref).to eq(finder.ref)
- expect(blob.data).not_to be_empty
+ it_behaves_like 'file finder' do
+ subject { described_class.new(project, project.default_branch) }
+ let(:expected_file_by_name) { 'files/images/wm.svg' }
+ let(:expected_file_by_content) { 'CHANGELOG' }
end
end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index dd5c498706d..7a9621d9c78 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -114,7 +114,9 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'raises a no repository exception when there is no repo' do
broken_repo = described_class.new('default', 'a/path.git', '')
- expect { broken_repo.rugged }.to raise_error(Gitlab::Git::Repository::NoRepository)
+ expect do
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access { broken_repo.rugged }
+ end.to raise_error(Gitlab::Git::Repository::NoRepository)
end
describe 'alternates keyword argument' do
@@ -124,9 +126,9 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
it "is passed an empty array" do
- expect(Rugged::Repository).to receive(:new).with(repository.path, alternates: [])
+ expect(Rugged::Repository).to receive(:new).with(repository_path, alternates: [])
- repository.rugged
+ repository_rugged
end
end
@@ -142,10 +144,10 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
it "is passed the relative object dir envvars after being converted to absolute ones" do
- alternates = %w[foo bar baz].map { |d| File.join(repository.path, './objects', d) }
- expect(Rugged::Repository).to receive(:new).with(repository.path, alternates: alternates)
+ alternates = %w[foo bar baz].map { |d| File.join(repository_path, './objects', d) }
+ expect(Rugged::Repository).to receive(:new).with(repository_path, alternates: alternates)
- repository.rugged
+ repository_rugged
end
end
end
@@ -156,16 +158,22 @@ describe Gitlab::Git::Repository, seed_helper: true do
let(:feature) { 'feature' }
let(:feature2) { 'feature2' }
+ around do |example|
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ example.run
+ end
+ end
+
it "returns 'master' when master exists" do
expect(repository).to receive(:branch_names).at_least(:once).and_return([feature, master])
expect(repository.discover_default_branch).to eq('master')
end
it "returns non-master when master exists but default branch is set to something else" do
- File.write(File.join(repository.path, 'HEAD'), 'ref: refs/heads/feature')
+ File.write(File.join(repository_path, 'HEAD'), 'ref: refs/heads/feature')
expect(repository).to receive(:branch_names).at_least(:once).and_return([feature, master])
expect(repository.discover_default_branch).to eq('feature')
- File.write(File.join(repository.path, 'HEAD'), 'ref: refs/heads/master')
+ File.write(File.join(repository_path, 'HEAD'), 'ref: refs/heads/master')
end
it "returns a non-master branch when only one exists" do
@@ -364,6 +372,12 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
context '#submodules' do
+ around do |example|
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ example.run
+ end
+ end
+
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
context 'where repo has submodules' do
@@ -474,8 +488,8 @@ describe Gitlab::Git::Repository, seed_helper: true do
# Sanity check
expect(repository.has_local_branches?).to eq(true)
- FileUtils.rm_rf(File.join(repository.path, 'packed-refs'))
- heads_dir = File.join(repository.path, 'refs/heads')
+ FileUtils.rm_rf(File.join(repository_path, 'packed-refs'))
+ heads_dir = File.join(repository_path, 'refs/heads')
FileUtils.rm_rf(heads_dir)
FileUtils.mkdir_p(heads_dir)
@@ -516,10 +530,10 @@ describe Gitlab::Git::Repository, seed_helper: true do
branch_name = "to-be-deleted-soon"
repository.create_branch(branch_name)
- expect(repository.rugged.branches[branch_name]).not_to be_nil
+ expect(repository_rugged.branches[branch_name]).not_to be_nil
repository.delete_branch(branch_name)
- expect(repository.rugged.branches[branch_name]).to be_nil
+ expect(repository_rugged.branches[branch_name]).to be_nil
end
context "when branch does not exist" do
@@ -577,6 +591,12 @@ describe Gitlab::Git::Repository, seed_helper: true do
shared_examples 'deleting refs' do
let(:repo) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
+ def repo_rugged
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ repo.rugged
+ end
+ end
+
after do
ensure_seeds
end
@@ -584,7 +604,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'deletes the ref' do
repo.delete_refs('refs/heads/feature')
- expect(repo.rugged.references['refs/heads/feature']).to be_nil
+ expect(repo_rugged.references['refs/heads/feature']).to be_nil
end
it 'deletes all refs' do
@@ -592,7 +612,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
repo.delete_refs(*refs)
refs.each do |ref|
- expect(repo.rugged.references[ref]).to be_nil
+ expect(repo_rugged.references[ref]).to be_nil
end
end
@@ -615,7 +635,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe '#branch_names_contains_sha' do
- let(:head_id) { repository.rugged.head.target.oid }
+ let(:head_id) { repository_rugged.head.target.oid }
let(:new_branch) { head_id }
let(:utf8_branch) { 'branch-é' }
@@ -699,7 +719,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'fetches a repository as a mirror remote' do
subject
- expect(refs(new_repository.path)).to eq(refs(repository.path))
+ expect(refs(new_repository_path)).to eq(refs(repository_path))
end
context 'with keep-around refs' do
@@ -708,15 +728,15 @@ describe Gitlab::Git::Repository, seed_helper: true do
let(:tmp_ref) { "refs/tmp/#{SecureRandom.hex}" }
before do
- repository.rugged.references.create(keep_around_ref, sha, force: true)
- repository.rugged.references.create(tmp_ref, sha, force: true)
+ repository_rugged.references.create(keep_around_ref, sha, force: true)
+ repository_rugged.references.create(tmp_ref, sha, force: true)
end
it 'includes the temporary and keep-around refs' do
subject
- expect(refs(new_repository.path)).to include(keep_around_ref)
- expect(refs(new_repository.path)).to include(tmp_ref)
+ expect(refs(new_repository_path)).to include(keep_around_ref)
+ expect(refs(new_repository_path)).to include(tmp_ref)
end
end
end
@@ -728,6 +748,12 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'with gitaly enabled', :skip_gitaly_mock do
it_behaves_like 'repository mirror fecthing'
end
+
+ def new_repository_path
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ new_repository.path
+ end
+ end
end
describe '#remote_tags' do
@@ -739,10 +765,17 @@ describe Gitlab::Git::Repository, seed_helper: true do
Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
end
+ around do |example|
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ example.run
+ end
+ end
+
subject { repository.remote_tags(remote_name) }
before do
- repository.add_remote(remote_name, remote_repository.path)
+ remote_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { remote_repository.path }
+ repository.add_remote(remote_name, remote_repository_path)
remote_repository.add_tag(tag_name, user: user, target: target_commit_id)
end
@@ -975,8 +1008,10 @@ describe Gitlab::Git::Repository, seed_helper: true do
let(:options) { { ref: 'master', path: ['PROCESS.md', 'README.md'] } }
def commit_files(commit)
- commit.rugged_diff_from_parent.deltas.flat_map do |delta|
- [delta.old_file[:path], delta.new_file[:path]].uniq.compact
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ commit.rugged_diff_from_parent.deltas.flat_map do |delta|
+ [delta.old_file[:path], delta.new_file[:path]].uniq.compact
+ end
end
end
@@ -1019,6 +1054,12 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe "#rugged_commits_between" do
+ around do |example|
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ example.run
+ end
+ end
+
context 'two SHAs' do
let(:first_sha) { 'b0e52af38d7ea43cf41d8a6f2471351ac036d6c9' }
let(:second_sha) { '0e50ec4d3c7ce42ab74dda1d422cb2cbffe1e326' }
@@ -1363,7 +1404,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
allow(ref).to receive(:target) { raise Rugged::ReferenceError }
branches = double()
allow(branches).to receive(:each) { [ref].each }
- allow(repository.rugged).to receive(:branches) { branches }
+ allow(repository_rugged).to receive(:branches) { branches }
expect(subject).to be_empty
end
@@ -1661,6 +1702,12 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe '#batch_existence' do
let(:refs) { ['deadbeef', SeedRepo::RubyBlob::ID, '909e6157199'] }
+ around do |example|
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ example.run
+ end
+ end
+
it 'returns existing refs back' do
result = repository.batch_existence(refs)
@@ -1840,7 +1887,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'when the branch exists' do
context 'when the commit does not exist locally' do
let(:source_branch) { 'new-branch-for-fetch-source-branch' }
- let(:source_rugged) { source_repository.rugged }
+ let(:source_rugged) { Gitlab::GitalyClient::StorageSettings.allow_disk_access { source_repository.rugged } }
let(:new_oid) { new_commit_edit_old_file(source_rugged).oid }
before do
@@ -1898,7 +1945,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it "removes the branch from the repo" do
repository.rm_branch(branch_name, user: user)
- expect(repository.rugged.branches[branch_name]).to be_nil
+ expect(repository_rugged.branches[branch_name]).to be_nil
end
end
@@ -1930,7 +1977,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe '#write_config' do
before do
- repository.rugged.config["gitlab.fullpath"] = repository.path
+ repository_rugged.config["gitlab.fullpath"] = repository_path
end
shared_examples 'writing repo config' do
@@ -1938,7 +1985,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'writes it to disk' do
repository.write_config(full_path: "not-the/real-path.git")
- config = File.read(File.join(repository.path, "config"))
+ config = File.read(File.join(repository_path, "config"))
expect(config).to include("[gitlab]")
expect(config).to include("fullpath = not-the/real-path.git")
@@ -1949,10 +1996,10 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'does not write it to disk' do
repository.write_config(full_path: "")
- config = File.read(File.join(repository.path, "config"))
+ config = File.read(File.join(repository_path, "config"))
expect(config).to include("[gitlab]")
- expect(config).to include("fullpath = #{repository.path}")
+ expect(config).to include("fullpath = #{repository_path}")
end
end
end
@@ -2173,7 +2220,11 @@ describe Gitlab::Git::Repository, seed_helper: true do
describe '#gitlab_projects' do
subject { repository.gitlab_projects }
- it { expect(subject.shard_path).to eq(storage_path) }
+ it do
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ expect(subject.shard_path).to eq(storage_path)
+ end
+ end
it { expect(subject.repository_relative_path).to eq(repository.relative_path) }
end
@@ -2189,7 +2240,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
repository.bundle_to_disk(save_path)
success = system(
- *%W(#{Gitlab.config.git.bin_path} -C #{repository.path} bundle verify #{save_path}),
+ *%W(#{Gitlab.config.git.bin_path} -C #{repository_path} bundle verify #{save_path}),
[:out, :err] => '/dev/null'
)
expect(success).to be true
@@ -2231,7 +2282,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
it 'creates a symlink to the global hooks dir' do
imported_repo.create_from_bundle(bundle_path)
- hooks_path = File.join(imported_repo.path, 'hooks')
+ hooks_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { File.join(imported_repo.path, 'hooks') }
expect(File.readlink(hooks_path)).to eq(Gitlab.config.gitlab_shell.hooks_path)
end
@@ -2360,7 +2411,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe '#clean_stale_repository_files' do
- let(:worktree_path) { File.join(repository.path, 'worktrees', 'delete-me') }
+ let(:worktree_path) { File.join(repository_path, 'worktrees', 'delete-me') }
it 'cleans up the files' do
repository.with_worktree(worktree_path, 'master', env: ENV) do
@@ -2507,7 +2558,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
- rugged = repository.rugged
+ rugged = repository_rugged
rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", source_branch.dereferenced_target.sha)
end
@@ -2586,4 +2637,16 @@ describe Gitlab::Git::Repository, seed_helper: true do
line.split("\t").last
end
end
+
+ def repository_rugged
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ repository.rugged
+ end
+ end
+
+ def repository_path
+ Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+ repository.path
+ end
+ end
end
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 74e7a45fd6c..2aebdc57f7c 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -242,6 +242,7 @@ Ci::Pipeline:
- config_source
- failure_reason
- protected
+- iid
Ci::Stage:
- id
- name
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index e3f705d2299..50224bde722 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -22,47 +22,57 @@ describe Gitlab::ProjectSearchResults do
it { expect(results.query).to eq('hello world') }
end
- describe 'blob search' do
- let(:project) { create(:project, :public, :repository) }
-
- subject(:results) { described_class.new(user, project, 'files').objects('blobs') }
-
- context 'when repository is disabled' do
- let(:project) { create(:project, :public, :repository, :repository_disabled) }
+ shared_examples 'general blob search' do |entity_type, blob_kind|
+ let(:query) { 'files' }
+ subject(:results) { described_class.new(user, project, query).objects(blob_type) }
- it 'hides blobs from members' do
+ context "when #{entity_type} is disabled" do
+ let(:project) { disabled_project }
+ it "hides #{blob_kind} from members" do
project.add_reporter(user)
is_expected.to be_empty
end
- it 'hides blobs from non-members' do
+ it "hides #{blob_kind} from non-members" do
is_expected.to be_empty
end
end
- context 'when repository is internal' do
- let(:project) { create(:project, :public, :repository, :repository_private) }
+ context "when #{entity_type} is internal" do
+ let(:project) { private_project }
- it 'finds blobs for members' do
+ it "finds #{blob_kind} for members" do
project.add_reporter(user)
is_expected.not_to be_empty
end
- it 'hides blobs from non-members' do
+ it "hides #{blob_kind} from non-members" do
is_expected.to be_empty
end
end
it 'finds by name' do
- expect(results.map(&:first)).to include('files/images/wm.svg')
+ expect(results.map(&:first)).to include(expected_file_by_name)
end
it 'finds by content' do
- blob = results.select { |result| result.first == "CHANGELOG" }.flatten.last
+ blob = results.select { |result| result.first == expected_file_by_content }.flatten.last
- expect(blob.filename).to eq("CHANGELOG")
+ expect(blob.filename).to eq(expected_file_by_content)
+ end
+ end
+
+ describe 'blob search' do
+ let(:project) { create(:project, :public, :repository) }
+
+ it_behaves_like 'general blob search', 'repository', 'blobs' do
+ let(:blob_type) { 'blobs' }
+ let(:disabled_project) { create(:project, :public, :repository, :repository_disabled) }
+ let(:private_project) { create(:project, :public, :repository, :repository_private) }
+ let(:expected_file_by_name) { 'files/images/wm.svg' }
+ let(:expected_file_by_content) { 'CHANGELOG' }
end
describe 'parsing results' do
@@ -189,40 +199,18 @@ describe Gitlab::ProjectSearchResults do
describe 'wiki search' do
let(:project) { create(:project, :public, :wiki_repo) }
let(:wiki) { build(:project_wiki, project: project) }
- let!(:wiki_page) { wiki.create_page('Title', 'Content') }
-
- subject(:results) { described_class.new(user, project, 'Content').objects('wiki_blobs') }
-
- context 'when wiki is disabled' do
- let(:project) { create(:project, :public, :wiki_repo, :wiki_disabled) }
- it 'hides wiki blobs from members' do
- project.add_reporter(user)
-
- is_expected.to be_empty
- end
-
- it 'hides wiki blobs from non-members' do
- is_expected.to be_empty
- end
- end
-
- context 'when wiki is internal' do
- let(:project) { create(:project, :public, :wiki_repo, :wiki_private) }
-
- it 'finds wiki blobs for guest' do
- project.add_guest(user)
-
- is_expected.not_to be_empty
- end
-
- it 'hides wiki blobs from non-members' do
- is_expected.to be_empty
- end
+ before do
+ wiki.create_page('Files/Title', 'Content')
+ wiki.create_page('CHANGELOG', 'Files example')
end
- it 'finds by content' do
- expect(results).to include("master:Title.md\x001\x00Content\n")
+ it_behaves_like 'general blob search', 'wiki', 'wiki blobs' do
+ let(:blob_type) { 'wiki_blobs' }
+ let(:disabled_project) { create(:project, :public, :wiki_repo, :wiki_disabled) }
+ let(:private_project) { create(:project, :public, :wiki_repo, :wiki_private) }
+ let(:expected_file_by_name) { 'Files/Title.md' }
+ let(:expected_file_by_content) { 'CHANGELOG.md' }
end
end
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb
index a3b3dc3be6d..81dbbb962dd 100644
--- a/spec/lib/gitlab/url_blocker_spec.rb
+++ b/spec/lib/gitlab/url_blocker_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe Gitlab::UrlBlocker do
describe '#blocked_url?' do
- let(:valid_ports) { Project::VALID_IMPORT_PORTS }
+ let(:ports) { Project::VALID_IMPORT_PORTS }
it 'allows imports from configured web host and port' do
import_url = "http://#{Gitlab.config.gitlab.host}:#{Gitlab.config.gitlab.port}/t.git"
@@ -19,7 +19,13 @@ describe Gitlab::UrlBlocker do
end
it 'returns true for bad port' do
- expect(described_class.blocked_url?('https://gitlab.com:25/foo/foo.git', valid_ports: valid_ports)).to be true
+ expect(described_class.blocked_url?('https://gitlab.com:25/foo/foo.git', ports: ports)).to be true
+ end
+
+ it 'returns true for bad protocol' do
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git', protocols: ['https'])).to be false
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git')).to be false
+ expect(described_class.blocked_url?('https://gitlab.com/foo/foo.git', protocols: ['http'])).to be true
end
it 'returns true for alternative version of 127.0.0.1 (0177.1)' do
diff --git a/spec/lib/gitlab/wiki_file_finder_spec.rb b/spec/lib/gitlab/wiki_file_finder_spec.rb
new file mode 100644
index 00000000000..025d1203dc5
--- /dev/null
+++ b/spec/lib/gitlab/wiki_file_finder_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Gitlab::WikiFileFinder do
+ describe '#find' do
+ let(:project) { create(:project, :public, :wiki_repo) }
+ let(:wiki) { build(:project_wiki, project: project) }
+
+ before do
+ wiki.create_page('Files/Title', 'Content')
+ wiki.create_page('CHANGELOG', 'Files example')
+ end
+
+ it_behaves_like 'file finder' do
+ subject { described_class.new(project, project.wiki.default_branch) }
+
+ let(:expected_file_by_name) { 'Files/Title.md' }
+ let(:expected_file_by_content) { 'CHANGELOG.md' }
+ end
+ end
+end
diff --git a/spec/lib/omni_auth/strategies/jwt_spec.rb b/spec/lib/omni_auth/strategies/jwt_spec.rb
index 23485fbcb18..88d6d0b559a 100644
--- a/spec/lib/omni_auth/strategies/jwt_spec.rb
+++ b/spec/lib/omni_auth/strategies/jwt_spec.rb
@@ -43,7 +43,7 @@ describe OmniAuth::Strategies::Jwt do
end
it 'raises error' do
- expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::JWT::ClaimInvalid)
+ expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
end
end
@@ -61,7 +61,7 @@ describe OmniAuth::Strategies::Jwt do
end
it 'raises error' do
- expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::JWT::ClaimInvalid)
+ expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
end
end
@@ -80,7 +80,7 @@ describe OmniAuth::Strategies::Jwt do
end
it 'raises error' do
- expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::JWT::ClaimInvalid)
+ expect { strategy.decoded }.to raise_error(OmniAuth::Strategies::Jwt::ClaimInvalid)
end
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 77179028ede..66c9708b4cf 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -148,10 +148,9 @@ describe Ci::Build do
end
context 'when there are runners' do
- let(:runner) { create(:ci_runner) }
+ let(:runner) { create(:ci_runner, :project, projects: [build.project]) }
before do
- build.project.runners << runner
runner.update_attributes(contacted_at: 1.second.ago)
end
@@ -1388,12 +1387,7 @@ describe Ci::Build do
it { is_expected.to be_truthy }
context "and there are specific runner" do
- let(:runner) { create(:ci_runner, contacted_at: 1.second.ago) }
-
- before do
- build.project.runners << runner
- runner.save
- end
+ let!(:runner) { create(:ci_runner, :project, projects: [build.project], contacted_at: 1.second.ago) }
it { is_expected.to be_falsey }
end
@@ -1565,6 +1559,7 @@ describe Ci::Build do
{ key: 'CI_PROJECT_NAMESPACE', value: project.namespace.full_path, public: true },
{ key: 'CI_PROJECT_URL', value: project.web_url, public: true },
{ key: 'CI_PROJECT_VISIBILITY', value: 'private', public: true },
+ { key: 'CI_PIPELINE_IID', value: pipeline.iid.to_s, public: true },
{ key: 'CI_CONFIG_PATH', value: pipeline.ci_yaml_file_path, public: true },
{ key: 'CI_PIPELINE_SOURCE', value: pipeline.source, public: true },
{ key: 'CI_COMMIT_MESSAGE', value: pipeline.git_commit_message, public: true },
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index e4f4c62bd22..24692ebb9a3 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -35,6 +35,16 @@ describe Ci::Pipeline, :mailer do
end
end
+ describe 'modules' do
+ it_behaves_like 'AtomicInternalId', validate_presence: false do
+ let(:internal_id_attribute) { :iid }
+ let(:instance) { build(:ci_pipeline) }
+ let(:scope) { :project }
+ let(:scope_attrs) { { project: instance.project } }
+ let(:usage) { :ci_pipelines }
+ end
+ end
+
describe '#source' do
context 'when creating new pipeline' do
let(:pipeline) do
@@ -195,7 +205,8 @@ describe Ci::Pipeline, :mailer do
it 'includes all predefined variables in a valid order' do
keys = subject.map { |variable| variable[:key] }
- expect(keys).to eq %w[CI_CONFIG_PATH
+ expect(keys).to eq %w[CI_PIPELINE_IID
+ CI_CONFIG_PATH
CI_PIPELINE_SOURCE
CI_COMMIT_MESSAGE
CI_COMMIT_TITLE
@@ -1589,7 +1600,7 @@ describe Ci::Pipeline, :mailer do
context 'when pipeline is not stuck' do
before do
- create(:ci_runner, :shared, :online)
+ create(:ci_runner, :instance, :online)
end
it 'is not stuck' do
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 0fbc934f669..0f072aa1719 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -21,60 +21,58 @@ describe Ci::Runner do
end
end
- context 'either_projects_or_group' do
+ context '#exactly_one_group' do
let(:group) { create(:group) }
+ let(:runner) { create(:ci_runner, :group, groups: [group]) }
- it 'disallows assigning to a group if already assigned to a group' do
- runner = create(:ci_runner, groups: [group])
-
+ it 'disallows assigning group if already assigned to a group' do
runner.groups << build(:group)
expect(runner).not_to be_valid
- expect(runner.errors.full_messages).to eq ['Runner can only be assigned to one group']
+ expect(runner.errors.full_messages).to include('Runner needs to be assigned to exactly one group')
end
+ end
- it 'disallows assigning to a group if already assigned to a project' do
- project = create(:project)
- runner = create(:ci_runner, projects: [project])
+ context 'runner_type validations' do
+ set(:group) { create(:group) }
+ set(:project) { create(:project) }
+ let(:group_runner) { create(:ci_runner, :group, groups: [group]) }
+ let(:project_runner) { create(:ci_runner, :project, projects: [project]) }
+ let(:instance_runner) { create(:ci_runner, :instance) }
- runner.groups << build(:group)
+ it 'disallows assigning group to project_type runner' do
+ project_runner.groups << build(:group)
- expect(runner).not_to be_valid
- expect(runner.errors.full_messages).to eq ['Runner can only be assigned either to projects or to a group']
+ expect(project_runner).not_to be_valid
+ expect(project_runner.errors.full_messages).to include('Runner cannot have groups assigned')
end
- it 'disallows assigning to a project if already assigned to a group' do
- runner = create(:ci_runner, groups: [group])
-
- runner.projects << build(:project)
+ it 'disallows assigning group to instance_type runner' do
+ instance_runner.groups << build(:group)
- expect(runner).not_to be_valid
- expect(runner.errors.full_messages).to eq ['Runner can only be assigned either to projects or to a group']
+ expect(instance_runner).not_to be_valid
+ expect(instance_runner.errors.full_messages).to include('Runner cannot have groups assigned')
end
- it 'allows assigning to a group if not assigned to a group nor a project' do
- runner = create(:ci_runner)
-
- runner.groups << build(:group)
+ it 'disallows assigning project to group_type runner' do
+ group_runner.projects << build(:project)
- expect(runner).to be_valid
+ expect(group_runner).not_to be_valid
+ expect(group_runner.errors.full_messages).to include('Runner cannot have projects assigned')
end
- it 'allows assigning to a project if not assigned to a group nor a project' do
- runner = create(:ci_runner)
-
- runner.projects << build(:project)
+ it 'disallows assigning project to instance_type runner' do
+ instance_runner.projects << build(:project)
- expect(runner).to be_valid
+ expect(instance_runner).not_to be_valid
+ expect(instance_runner.errors.full_messages).to include('Runner cannot have projects assigned')
end
- it 'allows assigning to a project if already assigned to a project' do
- project = create(:project)
- runner = create(:ci_runner, projects: [project])
-
- runner.projects << build(:project)
+ it 'should fail to save a group assigned to a project runner even if the runner is already saved' do
+ group_runner
- expect(runner).to be_valid
+ expect { create(:group, runners: [project_runner]) }
+ .to raise_error(ActiveRecord::RecordInvalid)
end
end
end
@@ -110,17 +108,12 @@ describe Ci::Runner do
describe '.shared' do
let(:group) { create(:group) }
let(:project) { create(:project) }
+ let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
+ let!(:project_runner) { create(:ci_runner, :project, projects: [project]) }
+ let!(:shared_runner) { create(:ci_runner, :instance) }
- it 'returns the shared group runner' do
- runner = create(:ci_runner, :shared, groups: [group])
-
- expect(described_class.shared).to eq [runner]
- end
-
- it 'returns the shared project runner' do
- runner = create(:ci_runner, :shared, projects: [project])
-
- expect(described_class.shared).to eq [runner]
+ it 'returns only shared runners' do
+ expect(described_class.shared).to contain_exactly(shared_runner)
end
end
@@ -128,11 +121,11 @@ describe Ci::Runner do
it 'returns the specific project runner' do
# own
specific_project = create(:project)
- specific_runner = create(:ci_runner, :specific, projects: [specific_project])
+ specific_runner = create(:ci_runner, :project, projects: [specific_project])
# other
other_project = create(:project)
- create(:ci_runner, :specific, projects: [other_project])
+ create(:ci_runner, :project, projects: [other_project])
expect(described_class.belonging_to_project(specific_project.id)).to eq [specific_runner]
end
@@ -141,17 +134,17 @@ describe Ci::Runner do
describe '.belonging_to_parent_group_of_project' do
let(:project) { create(:project, group: group) }
let(:group) { create(:group) }
- let(:runner) { create(:ci_runner, :specific, groups: [group]) }
+ let(:runner) { create(:ci_runner, :group, groups: [group]) }
let!(:unrelated_group) { create(:group) }
let!(:unrelated_project) { create(:project, group: unrelated_group) }
- let!(:unrelated_runner) { create(:ci_runner, :specific, groups: [unrelated_group]) }
+ let!(:unrelated_runner) { create(:ci_runner, :group, groups: [unrelated_group]) }
it 'returns the specific group runner' do
expect(described_class.belonging_to_parent_group_of_project(project.id)).to contain_exactly(runner)
end
context 'with a parent group with a runner', :nested_groups do
- let(:runner) { create(:ci_runner, :specific, groups: [parent_group]) }
+ let(:runner) { create(:ci_runner, :group, groups: [parent_group]) }
let(:project) { create(:project, group: group) }
let(:group) { create(:group, parent: parent_group) }
let(:parent_group) { create(:group) }
@@ -167,13 +160,13 @@ describe Ci::Runner do
# group specific
group = create(:group)
project = create(:project, group: group)
- group_runner = create(:ci_runner, :specific, groups: [group])
+ group_runner = create(:ci_runner, :group, groups: [group])
# project specific
- project_runner = create(:ci_runner, :specific, projects: [project])
+ project_runner = create(:ci_runner, :project, projects: [project])
# globally shared
- shared_runner = create(:ci_runner, :shared)
+ shared_runner = create(:ci_runner, :instance)
expect(described_class.owned_or_shared(project.id)).to contain_exactly(
group_runner, project_runner, shared_runner
@@ -183,31 +176,32 @@ describe Ci::Runner do
describe '#display_name' do
it 'returns the description if it has a value' do
- runner = FactoryBot.build(:ci_runner, description: 'Linux/Ruby-1.9.3-p448')
+ runner = build(:ci_runner, description: 'Linux/Ruby-1.9.3-p448')
expect(runner.display_name).to eq 'Linux/Ruby-1.9.3-p448'
end
it 'returns the token if it does not have a description' do
- runner = FactoryBot.create(:ci_runner)
+ runner = create(:ci_runner)
expect(runner.display_name).to eq runner.description
end
it 'returns the token if the description is an empty string' do
- runner = FactoryBot.build(:ci_runner, description: '', token: 'token')
+ runner = build(:ci_runner, description: '', token: 'token')
expect(runner.display_name).to eq runner.token
end
end
describe '#assign_to' do
- let!(:project) { FactoryBot.create(:project) }
+ let(:project) { create(:project) }
subject { runner.assign_to(project) }
context 'with shared_runner' do
- let!(:runner) { FactoryBot.create(:ci_runner, :shared) }
+ let(:runner) { create(:ci_runner, :instance) }
it 'transitions shared runner to project runner and assigns project' do
- subject
+ expect(subject).to be_truthy
+
expect(runner).to be_specific
expect(runner).to be_project_type
expect(runner.projects).to eq([project])
@@ -216,7 +210,8 @@ describe Ci::Runner do
end
context 'with group runner' do
- let!(:runner) { FactoryBot.create(:ci_runner, runner_type: :group_type) }
+ let(:group) { create(:group) }
+ let(:runner) { create(:ci_runner, :group, groups: [group]) }
it 'raises an error' do
expect { subject }
@@ -229,15 +224,15 @@ describe Ci::Runner do
subject { described_class.online }
before do
- @runner1 = FactoryBot.create(:ci_runner, :shared, contacted_at: 1.year.ago)
- @runner2 = FactoryBot.create(:ci_runner, :shared, contacted_at: 1.second.ago)
+ @runner1 = create(:ci_runner, :instance, contacted_at: 1.year.ago)
+ @runner2 = create(:ci_runner, :instance, contacted_at: 1.second.ago)
end
it { is_expected.to eq([@runner2])}
end
describe '#online?' do
- let(:runner) { FactoryBot.create(:ci_runner, :shared) }
+ let(:runner) { create(:ci_runner, :instance) }
subject { runner.online? }
@@ -307,21 +302,20 @@ describe Ci::Runner do
end
describe '#can_pick?' do
- let(:pipeline) { create(:ci_pipeline) }
+ set(:pipeline) { create(:ci_pipeline) }
let(:build) { create(:ci_build, pipeline: pipeline) }
- let(:runner) { create(:ci_runner, tag_list: tag_list, run_untagged: run_untagged) }
+ let(:runner_project) { build.project }
+ let(:runner) { create(:ci_runner, :project, projects: [runner_project], tag_list: tag_list, run_untagged: run_untagged) }
let(:tag_list) { [] }
let(:run_untagged) { true }
subject { runner.can_pick?(build) }
- before do
- build.project.runners << runner
- end
-
context 'a different runner' do
+ let(:other_project) { create(:project) }
+ let(:other_runner) { create(:ci_runner, :project, projects: [other_project], tag_list: tag_list, run_untagged: run_untagged) }
+
it 'cannot handle builds' do
- other_runner = create(:ci_runner)
expect(other_runner.can_pick?(build)).to be_falsey
end
end
@@ -375,18 +369,14 @@ describe Ci::Runner do
end
context 'when runner is shared' do
- let(:runner) { create(:ci_runner, :shared) }
-
- before do
- build.project.runners = []
- end
+ let(:runner) { create(:ci_runner, :instance) }
it 'can handle builds' do
expect(runner.can_pick?(build)).to be_truthy
end
context 'when runner is locked' do
- let(:runner) { create(:ci_runner, :shared, locked: true) }
+ let(:runner) { create(:ci_runner, :instance, locked: true) }
it 'can handle builds' do
expect(runner.can_pick?(build)).to be_truthy
@@ -401,10 +391,8 @@ describe Ci::Runner do
end
end
- context 'when runner is not assigned to a project' do
- before do
- build.project.runners = []
- end
+ context 'when runner is assigned to another project' do
+ let(:runner_project) { create(:project) }
it 'cannot handle builds' do
expect(runner.can_pick?(build)).to be_falsey
@@ -412,10 +400,8 @@ describe Ci::Runner do
end
context 'when runner is assigned to a group' do
- before do
- build.project.runners = []
- runner.groups << create(:group, projects: [build.project])
- end
+ let(:group) { create(:group, projects: [build.project]) }
+ let(:runner) { create(:ci_runner, :group, tag_list: tag_list, run_untagged: run_untagged, groups: [group]) }
it 'can handle builds' do
expect(runner.can_pick?(build)).to be_truthy
@@ -469,7 +455,7 @@ describe Ci::Runner do
end
describe '#status' do
- let(:runner) { FactoryBot.create(:ci_runner, :shared, contacted_at: 1.second.ago) }
+ let(:runner) { create(:ci_runner, :instance, contacted_at: 1.second.ago) }
subject { runner.status }
@@ -626,12 +612,13 @@ describe Ci::Runner do
end
describe '.assignable_for' do
- let!(:unlocked_project_runner) { create(:ci_runner, runner_type: :project_type, projects: [project]) }
- let!(:locked_project_runner) { create(:ci_runner, runner_type: :project_type, locked: true, projects: [project]) }
- let!(:group_runner) { create(:ci_runner, runner_type: :group_type) }
- let!(:instance_runner) { create(:ci_runner, :shared) }
let(:project) { create(:project) }
+ let(:group) { create(:group) }
let(:another_project) { create(:project) }
+ let!(:unlocked_project_runner) { create(:ci_runner, :project, projects: [project]) }
+ let!(:locked_project_runner) { create(:ci_runner, :project, locked: true, projects: [project]) }
+ let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
+ let!(:instance_runner) { create(:ci_runner, :instance) }
context 'with already assigned project' do
subject { described_class.assignable_for(project) }
@@ -651,19 +638,16 @@ describe Ci::Runner do
describe "belongs_to_one_project?" do
it "returns false if there are two projects runner assigned to" do
- runner = FactoryBot.create(:ci_runner)
- project = FactoryBot.create(:project)
- project1 = FactoryBot.create(:project)
- project.runners << runner
- project1.runners << runner
+ project1 = create(:project)
+ project2 = create(:project)
+ runner = create(:ci_runner, :project, projects: [project1, project2])
expect(runner.belongs_to_one_project?).to be_falsey
end
it "returns true" do
- runner = FactoryBot.create(:ci_runner)
- project = FactoryBot.create(:project)
- project.runners << runner
+ project = create(:project)
+ runner = create(:ci_runner, :project, projects: [project])
expect(runner.belongs_to_one_project?).to be_truthy
end
@@ -713,21 +697,21 @@ describe Ci::Runner do
subject { runner.assigned_to_group? }
context 'when project runner' do
- let(:runner) { create(:ci_runner, description: 'Project runner', projects: [project]) }
+ let(:runner) { create(:ci_runner, :project, description: 'Project runner', projects: [project]) }
let(:project) { create(:project) }
it { is_expected.to be_falsey }
end
context 'when shared runner' do
- let(:runner) { create(:ci_runner, :shared, description: 'Shared runner') }
+ let(:runner) { create(:ci_runner, :instance, description: 'Shared runner') }
it { is_expected.to be_falsey }
end
context 'when group runner' do
let(:group) { create(:group) }
- let(:runner) { create(:ci_runner, description: 'Group runner', groups: [group]) }
+ let(:runner) { create(:ci_runner, :group, description: 'Group runner', groups: [group]) }
it { is_expected.to be_truthy }
end
@@ -737,18 +721,18 @@ describe Ci::Runner do
subject { runner.assigned_to_project? }
context 'when group runner' do
- let(:runner) { create(:ci_runner, description: 'Group runner', groups: [group]) }
+ let(:runner) { create(:ci_runner, :group, description: 'Group runner', groups: [group]) }
let(:group) { create(:group) }
it { is_expected.to be_falsey }
end
context 'when shared runner' do
- let(:runner) { create(:ci_runner, :shared, description: 'Shared runner') }
+ let(:runner) { create(:ci_runner, :instance, description: 'Shared runner') }
it { is_expected.to be_falsey }
end
context 'when project runner' do
- let(:runner) { create(:ci_runner, description: 'Group runner', projects: [project]) }
+ let(:runner) { create(:ci_runner, :project, description: 'Project runner', projects: [project]) }
let(:project) { create(:project) }
it { is_expected.to be_truthy }
@@ -780,4 +764,17 @@ describe Ci::Runner do
end
end
end
+
+ describe 'project runner without projects is destroyable' do
+ subject { create(:ci_runner, :project, :without_projects) }
+
+ it 'does not have projects' do
+ expect(subject.runner_projects).to be_empty
+ end
+
+ it 'can be destroyed' do
+ subject
+ expect { subject.destroy }.to change { described_class.count }.by(-1)
+ end
+ end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index bd6bf5b0712..1cfd526834c 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -12,6 +12,7 @@ describe Issuable do
it { is_expected.to belong_to(:author) }
it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:todos).dependent(:destroy) }
+ it { is_expected.to have_many(:labels) }
context 'Notes' do
let!(:note) { create(:note, noteable: issue, project: issue.project) }
@@ -274,8 +275,8 @@ describe Issuable do
it 'skips coercion for not Integer values' do
expect { issue.time_estimate = nil }.to change { issue.time_estimate }.to(nil)
- expect { issue.time_estimate = 'invalid time' }.not_to raise_error(StandardError)
- expect { issue.time_estimate = 22.33 }.not_to raise_error(StandardError)
+ expect { issue.time_estimate = 'invalid time' }.not_to raise_error
+ expect { issue.time_estimate = 22.33 }.not_to raise_error
end
end
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb
index 4570dbb1d8e..f2a3df50c1a 100644
--- a/spec/models/concerns/reactive_caching_spec.rb
+++ b/spec/models/concerns/reactive_caching_spec.rb
@@ -94,6 +94,7 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do
end
it { expect(instance.result).to be_nil }
+ it { expect(reactive_cache_alive?(instance)).to be_falsy }
end
describe '#exclusively_update_reactive_cache!' do
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index aee70bcfb29..e01906f4b6c 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -20,6 +20,7 @@ describe Deployment do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:deployment) }
+ let(:scope) { :project }
let(:scope_attrs) { { project: instance.project } }
let(:usage) { :deployments }
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index 128acf83686..e818fbeb9cf 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -17,6 +17,7 @@ describe Issue do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:issue) }
+ let(:scope) { :project }
let(:scope_attrs) { { project: instance.project } }
let(:usage) { :issues }
end
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 9ffa91fc265..65cc9372cbe 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -84,6 +84,7 @@ describe MergeRequest do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:merge_request) }
+ let(:scope) { :target_project }
let(:scope_attrs) { { project: instance.target_project } }
let(:usage) { :merge_requests }
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 4bb9717d33e..204d6b47832 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -6,6 +6,7 @@ describe Milestone do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:milestone, project: build(:project), group: nil) }
+ let(:scope) { :project }
let(:scope_attrs) { { project: instance.project } }
let(:usage) { :milestones }
end
@@ -15,6 +16,7 @@ describe Milestone do
it_behaves_like 'AtomicInternalId' do
let(:internal_id_attribute) { :iid }
let(:instance) { build(:milestone, project: nil, group: build(:group)) }
+ let(:scope) { :group }
let(:scope_attrs) { { namespace: instance.group } }
let(:usage) { :milestones }
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index af2240f4f89..9a76452a808 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -1177,8 +1177,8 @@ describe Project do
describe '#any_runners?' do
context 'shared runners' do
let(:project) { create(:project, shared_runners_enabled: shared_runners_enabled) }
- let(:specific_runner) { create(:ci_runner) }
- let(:shared_runner) { create(:ci_runner, :shared) }
+ let(:specific_runner) { create(:ci_runner, :project, projects: [project]) }
+ let(:shared_runner) { create(:ci_runner, :instance) }
context 'for shared runners disabled' do
let(:shared_runners_enabled) { false }
@@ -1188,7 +1188,7 @@ describe Project do
end
it 'has a specific runner' do
- project.runners << specific_runner
+ specific_runner
expect(project.any_runners?).to be_truthy
end
@@ -1200,13 +1200,13 @@ describe Project do
end
it 'checks the presence of specific runner' do
- project.runners << specific_runner
+ specific_runner
expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
end
it 'returns false if match cannot be found' do
- project.runners << specific_runner
+ specific_runner
expect(project.any_runners? { false }).to be_falsey
end
@@ -1238,7 +1238,7 @@ describe Project do
context 'group runners' do
let(:project) { create(:project, group_runners_enabled: group_runners_enabled) }
let(:group) { create(:group, projects: [project]) }
- let(:group_runner) { create(:ci_runner, groups: [group]) }
+ let(:group_runner) { create(:ci_runner, :group, groups: [group]) }
context 'for group runners disabled' do
let(:group_runners_enabled) { false }
@@ -1279,7 +1279,7 @@ describe Project do
end
describe '#shared_runners' do
- let!(:runner) { create(:ci_runner, :shared) }
+ let!(:runner) { create(:ci_runner, :instance) }
subject { project.shared_runners }
diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb
index a80800c6c92..1d94abe4195 100644
--- a/spec/models/remote_mirror_spec.rb
+++ b/spec/models/remote_mirror_spec.rb
@@ -12,8 +12,8 @@ describe RemoteMirror do
context 'with an invalid URL' do
it 'should not be valid' do
remote_mirror = build(:remote_mirror, url: 'ftp://invalid.invalid')
+
expect(remote_mirror).not_to be_valid
- expect(remote_mirror.errors[:url].size).to eq(2)
end
end
end
diff --git a/spec/models/timelog_spec.rb b/spec/models/timelog_spec.rb
index 6e30798356c..a0c93c531ea 100644
--- a/spec/models/timelog_spec.rb
+++ b/spec/models/timelog_spec.rb
@@ -5,6 +5,9 @@ RSpec.describe Timelog do
let(:issue) { create(:issue) }
let(:merge_request) { create(:merge_request) }
+ it { is_expected.to belong_to(:issue).touch(true) }
+ it { is_expected.to belong_to(:merge_request).touch(true) }
+
it { is_expected.to be_valid }
it { is_expected.to validate_presence_of(:time_spent) }
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 16b409844fa..09dfeae6377 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1858,13 +1858,10 @@ describe User do
describe '#ci_owned_runners' do
let(:user) { create(:user) }
- let(:runner_1) { create(:ci_runner) }
- let(:runner_2) { create(:ci_runner) }
+ let!(:project) { create(:project) }
+ let(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'without any projects nor groups' do
- let!(:project) { create(:project, runners: [runner_1]) }
- let!(:group) { create(:group) }
-
it 'does not load' do
expect(user.ci_owned_runners).to be_empty
end
@@ -1872,38 +1869,40 @@ describe User do
context 'with personal projects runners' do
let(:namespace) { create(:namespace, owner: user) }
- let!(:project) { create(:project, namespace: namespace, runners: [runner_1]) }
+ let!(:project) { create(:project, namespace: namespace) }
it 'loads' do
- expect(user.ci_owned_runners).to contain_exactly(runner_1)
+ expect(user.ci_owned_runners).to contain_exactly(runner)
end
end
context 'with personal group runner' do
- let!(:project) { create(:project, runners: [runner_1]) }
+ let!(:project) { create(:project) }
+ let(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:group) do
- create(:group, runners: [runner_2]).tap do |group|
+ create(:group).tap do |group|
group.add_owner(user)
end
end
it 'loads' do
- expect(user.ci_owned_runners).to contain_exactly(runner_2)
+ expect(user.ci_owned_runners).to contain_exactly(group_runner)
end
end
context 'with personal project and group runner' do
let(:namespace) { create(:namespace, owner: user) }
- let!(:project) { create(:project, namespace: namespace, runners: [runner_1]) }
+ let!(:project) { create(:project, namespace: namespace) }
+ let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:group) do
- create(:group, runners: [runner_2]).tap do |group|
+ create(:group).tap do |group|
group.add_owner(user)
end
end
it 'loads' do
- expect(user.ci_owned_runners).to contain_exactly(runner_1, runner_2)
+ expect(user.ci_owned_runners).to contain_exactly(runner, group_runner)
end
end
@@ -1914,7 +1913,7 @@ describe User do
end
it 'loads' do
- expect(user.ci_owned_runners).to contain_exactly(runner_1)
+ expect(user.ci_owned_runners).to contain_exactly(runner)
end
end
@@ -1931,7 +1930,7 @@ describe User do
context 'with groups projects runners' do
let(:group) { create(:group) }
- let!(:project) { create(:project, group: group, runners: [runner_1]) }
+ let!(:project) { create(:project, group: group) }
def add_user(access)
group.add_user(user, access)
@@ -1941,11 +1940,8 @@ describe User do
end
context 'with groups runners' do
- let!(:group) do
- create(:group, runners: [runner_1]).tap do |group|
- group.add_owner(user)
- end
- end
+ let!(:runner) { create(:ci_runner, :group, groups: [group]) }
+ let!(:group) { create(:group) }
def add_user(access)
group.add_user(user, access)
@@ -1955,7 +1951,7 @@ describe User do
end
context 'with other projects runners' do
- let!(:project) { create(:project, runners: [runner_1]) }
+ let!(:project) { create(:project) }
def add_user(access)
project.add_role(user, access)
@@ -1968,7 +1964,7 @@ describe User do
let(:group) { create(:group) }
let(:another_user) { create(:user) }
let(:subgroup) { create(:group, parent: group) }
- let!(:project) { create(:project, group: subgroup, runners: [runner_1]) }
+ let!(:project) { create(:project, group: subgroup) }
def add_user(access)
group.add_user(user, access)
diff --git a/spec/requests/api/commit_statuses_spec.rb b/spec/requests/api/commit_statuses_spec.rb
index f246bb79ab7..cd43bec35df 100644
--- a/spec/requests/api/commit_statuses_spec.rb
+++ b/spec/requests/api/commit_statuses_spec.rb
@@ -304,7 +304,7 @@ describe API::CommitStatuses do
it 'responds with bad request status and validation errors' do
expect(response).to have_gitlab_http_status(400)
expect(json_response['message']['target_url'])
- .to include 'must be a valid URL'
+ .to include 'is blocked: Only allowed protocols are http, https'
end
end
end
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index 3106083293f..4181f4ebbbe 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -1351,19 +1351,25 @@ describe API::Issues do
expect(json_response['labels']).to eq([label.title])
end
- it 'removes all labels' do
- put api("/projects/#{project.id}/issues/#{issue.iid}", user), labels: ''
+ it 'removes all labels and touches the record' do
+ Timecop.travel(1.minute.from_now) do
+ put api("/projects/#{project.id}/issues/#{issue.iid}", user), labels: ''
+ end
expect(response).to have_gitlab_http_status(200)
expect(json_response['labels']).to eq([])
+ expect(json_response['updated_at']).to be > Time.now
end
- it 'updates labels' do
- put api("/projects/#{project.id}/issues/#{issue.iid}", user),
+ it 'updates labels and touches the record' do
+ Timecop.travel(1.minute.from_now) do
+ put api("/projects/#{project.id}/issues/#{issue.iid}", user),
labels: 'foo,bar'
+ end
expect(response).to have_gitlab_http_status(200)
expect(json_response['labels']).to include 'foo'
expect(json_response['labels']).to include 'bar'
+ expect(json_response['updated_at']).to be > Time.now
end
it 'allows special label names' do
diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 6aadf839dbd..319ac389083 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -111,11 +111,13 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
context 'when tags are not provided' do
- it 'returns 404 error' do
+ it 'returns 400 error' do
post api('/runners'), token: registration_token,
run_untagged: false
- expect(response).to have_gitlab_http_status 404
+ expect(response).to have_gitlab_http_status 400
+ expect(json_response['message']).to include(
+ 'tags_list' => ['can not be empty when runner is not allowed to pick untagged jobs'])
end
end
end
@@ -262,16 +264,12 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
describe '/api/v4/jobs' do
let(:project) { create(:project, shared_runners_enabled: false) }
let(:pipeline) { create(:ci_pipeline_without_jobs, project: project, ref: 'master') }
- let(:runner) { create(:ci_runner) }
+ let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:job) do
create(:ci_build, :artifacts, :extended_options,
pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0, commands: "ls\ndate")
end
- before do
- project.runners << runner
- end
-
describe 'POST /api/v4/jobs/request' do
let!(:last_update) {}
let!(:new_update) { }
@@ -379,7 +377,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
context 'when shared runner requests job for project without shared_runners_enabled' do
- let(:runner) { create(:ci_runner, :shared) }
+ let(:runner) { create(:ci_runner, :instance) }
it_behaves_like 'no jobs available'
end
@@ -724,7 +722,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
context 'when runner specifies lower timeout' do
- let(:runner) { create(:ci_runner, maximum_timeout: 1000) }
+ let(:runner) { create(:ci_runner, :project, maximum_timeout: 1000, projects: [project]) }
it 'contains info about timeout overridden by runner' do
request_job
@@ -735,7 +733,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
context 'when runner specifies bigger timeout' do
- let(:runner) { create(:ci_runner, maximum_timeout: 2000) }
+ let(:runner) { create(:ci_runner, :project, maximum_timeout: 2000, projects: [project]) }
it 'contains info about timeout not overridden by runner' do
request_job
diff --git a/spec/requests/api/runners_spec.rb b/spec/requests/api/runners_spec.rb
index c7587c877fc..0c7937feed6 100644
--- a/spec/requests/api/runners_spec.rb
+++ b/spec/requests/api/runners_spec.rb
@@ -11,23 +11,10 @@ describe API::Runners do
let(:group) { create(:group).tap { |group| group.add_owner(user) } }
let(:group2) { create(:group).tap { |group| group.add_owner(user) } }
- let!(:shared_runner) { create(:ci_runner, :shared, description: 'Shared runner') }
- let!(:unused_project_runner) { create(:ci_runner) }
-
- let!(:project_runner) do
- create(:ci_runner, description: 'Project runner').tap do |runner|
- create(:ci_runner_project, runner: runner, project: project)
- end
- end
-
- let!(:two_projects_runner) do
- create(:ci_runner, description: 'Two projects runner').tap do |runner|
- create(:ci_runner_project, runner: runner, project: project)
- create(:ci_runner_project, runner: runner, project: project2)
- end
- end
-
- let!(:group_runner) { create(:ci_runner, description: 'Group runner', groups: [group], runner_type: :group_type) }
+ let!(:shared_runner) { create(:ci_runner, :instance, description: 'Shared runner') }
+ let!(:project_runner) { create(:ci_runner, :project, description: 'Project runner', projects: [project]) }
+ let!(:two_projects_runner) { create(:ci_runner, :project, description: 'Two projects runner', projects: [project, project2]) }
+ let!(:group_runner) { create(:ci_runner, :group, description: 'Group runner', groups: [group]) }
before do
# Set project access for users
@@ -141,6 +128,18 @@ describe API::Runners do
end
context 'when runner is not shared' do
+ context 'when unused runner is present' do
+ let!(:unused_project_runner) { create(:ci_runner, :project, :without_projects) }
+
+ it 'deletes unused runner' do
+ expect do
+ delete api("/runners/#{unused_project_runner.id}", admin)
+
+ expect(response).to have_gitlab_http_status(204)
+ end.to change { Ci::Runner.specific.count }.by(-1)
+ end
+ end
+
it "returns runner's details" do
get api("/runners/#{project_runner.id}", admin)
@@ -310,14 +309,6 @@ describe API::Runners do
end
context 'when runner is not shared' do
- it 'deletes unused runner' do
- expect do
- delete api("/runners/#{unused_project_runner.id}", admin)
-
- expect(response).to have_gitlab_http_status(204)
- end.to change { Ci::Runner.specific.count }.by(-1)
- end
-
it 'deletes used project runner' do
expect do
delete api("/runners/#{project_runner.id}", admin)
@@ -543,11 +534,7 @@ describe API::Runners do
describe 'POST /projects/:id/runners' do
context 'authorized user' do
- let(:project_runner2) do
- create(:ci_runner).tap do |runner|
- create(:ci_runner_project, runner: runner, project: project2)
- end
- end
+ let(:project_runner2) { create(:ci_runner, :project, projects: [project2]) }
it 'enables specific runner' do
expect do
@@ -560,7 +547,7 @@ describe API::Runners do
expect do
post api("/projects/#{project.id}/runners", user), runner_id: project_runner.id
end.to change { project.runners.count }.by(0)
- expect(response).to have_gitlab_http_status(409)
+ expect(response).to have_gitlab_http_status(400)
end
it 'does not enable locked runner' do
@@ -586,11 +573,15 @@ describe API::Runners do
end
context 'user is admin' do
- it 'enables any specific runner' do
- expect do
- post api("/projects/#{project.id}/runners", admin), runner_id: unused_project_runner.id
- end.to change { project.runners.count }.by(+1)
- expect(response).to have_gitlab_http_status(201)
+ context 'when project runner is used' do
+ let!(:new_project_runner) { create(:ci_runner, :project) }
+
+ it 'enables any specific runner' do
+ expect do
+ post api("/projects/#{project.id}/runners", admin), runner_id: new_project_runner.id
+ end.to change { project.runners.count }.by(+1)
+ expect(response).to have_gitlab_http_status(201)
+ end
end
it 'enables a shared runner' do
@@ -603,14 +594,6 @@ describe API::Runners do
end
end
- context 'user is not admin' do
- it 'does not enable runner without access to' do
- post api("/projects/#{project.id}/runners", user), runner_id: unused_project_runner.id
-
- expect(response).to have_gitlab_http_status(403)
- end
- end
-
it 'raises an error when no runner_id param is provided' do
post api("/projects/#{project.id}/runners", admin)
@@ -618,6 +601,16 @@ describe API::Runners do
end
end
+ context 'user is not admin' do
+ let!(:new_project_runner) { create(:ci_runner, :project) }
+
+ it 'does not enable runner without access to' do
+ post api("/projects/#{project.id}/runners", user), runner_id: new_project_runner.id
+
+ expect(response).to have_gitlab_http_status(403)
+ end
+ end
+
context 'authorized user without permissions' do
it 'does not enable runner' do
post api("/projects/#{project.id}/runners", user2)
diff --git a/spec/serializers/runner_entity_spec.rb b/spec/serializers/runner_entity_spec.rb
index 439ba2cbca2..ba99d568eba 100644
--- a/spec/serializers/runner_entity_spec.rb
+++ b/spec/serializers/runner_entity_spec.rb
@@ -1,10 +1,10 @@
require 'spec_helper'
describe RunnerEntity do
- let(:runner) { create(:ci_runner, :specific) }
+ let(:project) { create(:project) }
+ let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:entity) { described_class.new(runner, request: request, current_user: user) }
let(:request) { double('request') }
- let(:project) { create(:project) }
let(:user) { create(:admin) }
before do
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 8063bc7e1ac..3816bd0deb5 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -5,15 +5,11 @@ module Ci
set(:group) { create(:group) }
set(:project) { create(:project, group: group, shared_runners_enabled: false, group_runners_enabled: false) }
set(:pipeline) { create(:ci_pipeline, project: project) }
- let!(:shared_runner) { create(:ci_runner, is_shared: true) }
- let!(:specific_runner) { create(:ci_runner, is_shared: false) }
- let!(:group_runner) { create(:ci_runner, groups: [group], runner_type: :group_type) }
+ let!(:shared_runner) { create(:ci_runner, :instance) }
+ let!(:specific_runner) { create(:ci_runner, :project, projects: [project]) }
+ let!(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let!(:pending_job) { create(:ci_build, pipeline: pipeline) }
- before do
- specific_runner.assign_to(project)
- end
-
describe '#execute' do
context 'runner follow tag list' do
it "picks build with the same tag" do
@@ -181,24 +177,24 @@ module Ci
end
context 'for multiple builds' do
- let!(:project2) { create :project, group_runners_enabled: true, group: group }
- let!(:pipeline2) { create :ci_pipeline, project: project2 }
- let!(:project3) { create :project, group_runners_enabled: true, group: group }
- let!(:pipeline3) { create :ci_pipeline, project: project3 }
+ let!(:project2) { create(:project, group_runners_enabled: true, group: group) }
+ let!(:pipeline2) { create(:ci_pipeline, project: project2) }
+ let!(:project3) { create(:project, group_runners_enabled: true, group: group) }
+ let!(:pipeline3) { create(:ci_pipeline, project: project3) }
let!(:build1_project1) { pending_job }
- let!(:build2_project1) { create :ci_build, pipeline: pipeline }
- let!(:build3_project1) { create :ci_build, pipeline: pipeline }
- let!(:build1_project2) { create :ci_build, pipeline: pipeline2 }
- let!(:build2_project2) { create :ci_build, pipeline: pipeline2 }
- let!(:build1_project3) { create :ci_build, pipeline: pipeline3 }
+ let!(:build2_project1) { create(:ci_build, pipeline: pipeline) }
+ let!(:build3_project1) { create(:ci_build, pipeline: pipeline) }
+ let!(:build1_project2) { create(:ci_build, pipeline: pipeline2) }
+ let!(:build2_project2) { create(:ci_build, pipeline: pipeline2) }
+ let!(:build1_project3) { create(:ci_build, pipeline: pipeline3) }
# these shouldn't influence the scheduling
- let!(:unrelated_group) { create :group }
- let!(:unrelated_project) { create :project, group_runners_enabled: true, group: unrelated_group }
- let!(:unrelated_pipeline) { create :ci_pipeline, project: unrelated_project }
- let!(:build1_unrelated_project) { create :ci_build, pipeline: unrelated_pipeline }
- let!(:unrelated_group_runner) { create :ci_runner, groups: [unrelated_group] }
+ let!(:unrelated_group) { create(:group) }
+ let!(:unrelated_project) { create(:project, group_runners_enabled: true, group: unrelated_group) }
+ let!(:unrelated_pipeline) { create(:ci_pipeline, project: unrelated_project) }
+ let!(:build1_unrelated_project) { create(:ci_build, pipeline: unrelated_pipeline) }
+ let!(:unrelated_group_runner) { create(:ci_runner, :group, groups: [unrelated_group]) }
it 'does not consider builds from other group runners' do
expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 6
@@ -292,7 +288,7 @@ module Ci
end
context 'when access_level of runner is not_protected' do
- let!(:specific_runner) { create(:ci_runner, :specific) }
+ let!(:specific_runner) { create(:ci_runner, :project, projects: [project]) }
context 'when a job is protected' do
let!(:pending_job) { create(:ci_build, :protected, pipeline: pipeline) }
@@ -324,7 +320,7 @@ module Ci
end
context 'when access_level of runner is ref_protected' do
- let!(:specific_runner) { create(:ci_runner, :ref_protected, :specific) }
+ let!(:specific_runner) { create(:ci_runner, :project, :ref_protected, projects: [project]) }
context 'when a job is protected' do
let!(:pending_job) { create(:ci_build, :protected, pipeline: pipeline) }
diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb
index 74a23ed2a3f..ca0c6be5da6 100644
--- a/spec/services/ci/update_build_queue_service_spec.rb
+++ b/spec/services/ci/update_build_queue_service_spec.rb
@@ -6,19 +6,18 @@ describe Ci::UpdateBuildQueueService do
let(:pipeline) { create(:ci_pipeline, project: project) }
context 'when updating specific runners' do
- let(:runner) { create(:ci_runner) }
+ let(:runner) { create(:ci_runner, :project, projects: [project]) }
context 'when there is a runner that can pick build' do
- before do
- build.project.runners << runner
- end
-
it 'ticks runner queue value' do
expect { subject.execute(build) }.to change { runner.ensure_runner_queue_value }
end
end
context 'when there is no runner that can pick build' do
+ let(:another_project) { create(:project) }
+ let(:runner) { create(:ci_runner, :project, projects: [another_project]) }
+
it 'does not tick runner queue value' do
expect { subject.execute(build) }.not_to change { runner.ensure_runner_queue_value }
end
@@ -26,7 +25,7 @@ describe Ci::UpdateBuildQueueService do
end
context 'when updating shared runners' do
- let(:runner) { create(:ci_runner, :shared) }
+ let(:runner) { create(:ci_runner, :instance) }
context 'when there is no runner that can pick build' do
it 'ticks runner queue value' do
@@ -56,9 +55,9 @@ describe Ci::UpdateBuildQueueService do
end
context 'when updating group runners' do
- let(:group) { create :group }
- let(:project) { create :project, group: group }
- let(:runner) { create :ci_runner, groups: [group] }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, group: group) }
+ let(:runner) { create(:ci_runner, :group, groups: [group]) }
context 'when there is a runner that can pick build' do
it 'ticks runner queue value' do
diff --git a/spec/services/issues/update_service_spec.rb b/spec/services/issues/update_service_spec.rb
index 23b1134b5a3..158541d36e3 100644
--- a/spec/services/issues/update_service_spec.rb
+++ b/spec/services/issues/update_service_spec.rb
@@ -337,12 +337,18 @@ describe Issues::UpdateService, :mailer do
context 'when the labels change' do
before do
- update_issue(label_ids: [label.id])
+ Timecop.freeze(1.minute.from_now) do
+ update_issue(label_ids: [label.id])
+ end
end
it 'marks todos as done' do
expect(todo.reload.done?).to eq true
end
+
+ it 'updates updated_at' do
+ expect(issue.reload.updated_at).to be > Time.now
+ end
end
end
diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb
index 5279ea6164e..bd2e91f1f7a 100644
--- a/spec/services/merge_requests/update_service_spec.rb
+++ b/spec/services/merge_requests/update_service_spec.rb
@@ -326,12 +326,18 @@ describe MergeRequests::UpdateService, :mailer do
context 'when the labels change' do
before do
- update_merge_request({ label_ids: [label.id] })
+ Timecop.freeze(1.minute.from_now) do
+ update_merge_request({ label_ids: [label.id] })
+ end
end
it 'marks pending todos as done' do
expect(pending_todo.reload).to be_done
end
+
+ it 'updates updated_at' do
+ expect(merge_request.reload.updated_at).to be > Time.now
+ end
end
context 'when the assignee changes' do
diff --git a/spec/support/gitaly.rb b/spec/support/gitaly.rb
index 9cf541372b5..5a1dd44bc9d 100644
--- a/spec/support/gitaly.rb
+++ b/spec/support/gitaly.rb
@@ -7,7 +7,10 @@ RSpec.configure do |config|
next if example.metadata[:skip_gitaly_mock]
# Use 'and_wrap_original' to make sure the arguments are valid
- allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original { |m, *args| m.call(*args) || true }
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original do |m, *args|
+ m.call(*args)
+ !Gitlab::GitalyClient::EXPLICIT_OPT_IN_REQUIRED.include?(args.first)
+ end
end
end
end
diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb
index 55359d36597..06a76d53354 100644
--- a/spec/support/helpers/cycle_analytics_helpers.rb
+++ b/spec/support/helpers/cycle_analytics_helpers.rb
@@ -4,12 +4,12 @@ module CycleAnalyticsHelpers
create_commit("Commit for ##{issue.iid}", issue.project, user, branch_name)
end
- def create_commit(message, project, user, branch_name, count: 1)
+ def create_commit(message, project, user, branch_name, count: 1, commit_time: nil, skip_push_handler: false)
repository = project.repository
- oldrev = repository.commit(branch_name).sha
+ oldrev = repository.commit(branch_name)&.sha || Gitlab::Git::BLANK_SHA
if Timecop.frozen? && Gitlab::GitalyClient.feature_enabled?(:operation_user_commit_files)
- mock_gitaly_multi_action_dates(repository.raw)
+ mock_gitaly_multi_action_dates(repository.raw, commit_time)
end
commit_shas = Array.new(count) do |index|
@@ -19,6 +19,8 @@ module CycleAnalyticsHelpers
commit_sha
end
+ return if skip_push_handler
+
GitPushService.new(project,
user,
oldrev: oldrev,
@@ -44,13 +46,11 @@ module CycleAnalyticsHelpers
project.repository.add_branch(user, source_branch, 'master')
end
- sha = project.repository.create_file(
- user,
- generate(:branch),
- 'content',
- message: commit_message,
- branch_name: source_branch)
- project.repository.commit(sha)
+ # Cycle analytic specs often test with frozen times, which causes metrics to be
+ # pinned to the current time. For example, in the plan stage, we assume that an issue
+ # milestone has been created before any code has been written. We add a second
+ # to ensure that the plan time is positive.
+ create_commit(commit_message, project, user, source_branch, commit_time: Time.now + 1.second, skip_push_handler: true)
opts = {
title: 'Awesome merge_request',
@@ -116,9 +116,9 @@ module CycleAnalyticsHelpers
protected: false)
end
- def mock_gitaly_multi_action_dates(raw_repository)
+ def mock_gitaly_multi_action_dates(raw_repository, commit_time)
allow(raw_repository).to receive(:multi_action).and_wrap_original do |m, *args|
- new_date = Time.now
+ new_date = commit_time || Time.now
branch_update = m.call(*args)
if branch_update.newrev
diff --git a/spec/support/shared_examples/file_finder.rb b/spec/support/shared_examples/file_finder.rb
new file mode 100644
index 00000000000..ef144bdf61c
--- /dev/null
+++ b/spec/support/shared_examples/file_finder.rb
@@ -0,0 +1,21 @@
+shared_examples 'file finder' do
+ let(:query) { 'files' }
+ let(:search_results) { subject.find(query) }
+
+ it 'finds by name' do
+ filename, blob = search_results.find { |_, blob| blob.filename == expected_file_by_name }
+ expect(filename).to eq(expected_file_by_name)
+ expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
+ expect(blob.ref).to eq(subject.ref)
+ expect(blob.data).not_to be_empty
+ end
+
+ it 'finds by content' do
+ filename, blob = search_results.find { |_, blob| blob.filename == expected_file_by_content }
+
+ expect(filename).to eq(expected_file_by_content)
+ expect(blob).to be_a(Gitlab::SearchResults::FoundBlob)
+ expect(blob.ref).to eq(subject.ref)
+ expect(blob.data).not_to be_empty
+ end
+end
diff --git a/spec/support/shared_examples/models/atomic_internal_id_spec.rb b/spec/support/shared_examples/models/atomic_internal_id_spec.rb
index 6a6e13418a9..7ab1041d17c 100644
--- a/spec/support/shared_examples/models/atomic_internal_id_spec.rb
+++ b/spec/support/shared_examples/models/atomic_internal_id_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-shared_examples_for 'AtomicInternalId' do
+shared_examples_for 'AtomicInternalId' do |validate_presence: true|
describe '.has_internal_id' do
describe 'Module inclusion' do
subject { described_class }
@@ -9,14 +9,31 @@ shared_examples_for 'AtomicInternalId' do
end
describe 'Validation' do
- subject { instance }
-
before do
- allow(InternalId).to receive(:generate_next).and_return(nil)
+ allow_any_instance_of(described_class).to receive(:"ensure_#{scope}_#{internal_id_attribute}!")
+
+ instance.valid?
end
- it { is_expected.to validate_presence_of(internal_id_attribute) }
- it { is_expected.to validate_numericality_of(internal_id_attribute) }
+ context 'when presence validation is required' do
+ before do
+ skip unless validate_presence
+ end
+
+ it 'validates presence' do
+ expect(instance.errors[internal_id_attribute]).to include("can't be blank")
+ end
+ end
+
+ context 'when presence validation is not required' do
+ before do
+ skip if validate_presence
+ end
+
+ it 'does not validate presence' do
+ expect(instance.errors[internal_id_attribute]).to be_empty
+ end
+ end
end
describe 'Creating an instance' do
diff --git a/spec/support/shared_examples/url_validator_examples.rb b/spec/support/shared_examples/url_validator_examples.rb
new file mode 100644
index 00000000000..b4757a70984
--- /dev/null
+++ b/spec/support/shared_examples/url_validator_examples.rb
@@ -0,0 +1,42 @@
+RSpec.shared_examples 'url validator examples' do |protocols|
+ let(:validator) { described_class.new(attributes: [:link_url], **options) }
+ let!(:badge) { build(:badge, link_url: 'http://www.example.com') }
+
+ subject { validator.validate_each(badge, :link_url, badge.link_url) }
+
+ describe '#validates_each' do
+ context 'with no options' do
+ let(:options) { {} }
+
+ it "allows #{protocols.join(',')} protocols by default" do
+ expect(validator.send(:default_options)[:protocols]).to eq protocols
+ end
+
+ it 'checks that the url structure is valid' do
+ badge.link_url = "#{badge.link_url}:invalid_port"
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+ end
+
+ context 'with protocols' do
+ let(:options) { { protocols: %w[http] } }
+
+ it 'allows urls with the defined protocols' do
+ subject
+
+ expect(badge.errors.empty?).to be true
+ end
+
+ it 'add error if the url protocol does not match the selected ones' do
+ badge.link_url = 'https://www.example.com'
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+ end
+ end
+end
diff --git a/spec/validators/public_url_validator_spec.rb b/spec/validators/public_url_validator_spec.rb
new file mode 100644
index 00000000000..710dd3dc38e
--- /dev/null
+++ b/spec/validators/public_url_validator_spec.rb
@@ -0,0 +1,28 @@
+require 'spec_helper'
+
+describe PublicUrlValidator do
+ include_examples 'url validator examples', described_class::DEFAULT_PROTOCOLS
+
+ context 'by default' do
+ let(:validator) { described_class.new(attributes: [:link_url]) }
+ let!(:badge) { build(:badge, link_url: 'http://www.example.com') }
+
+ subject { validator.validate_each(badge, :link_url, badge.link_url) }
+
+ it 'blocks urls pointing to localhost' do
+ badge.link_url = 'https://127.0.0.1'
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+
+ it 'blocks urls pointing to the local network' do
+ badge.link_url = 'https://192.168.1.1'
+
+ subject
+
+ expect(badge.errors.empty?).to be false
+ end
+ end
+end
diff --git a/spec/validators/url_placeholder_validator_spec.rb b/spec/validators/url_placeholder_validator_spec.rb
deleted file mode 100644
index b76d8acdf88..00000000000
--- a/spec/validators/url_placeholder_validator_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'spec_helper'
-
-describe UrlPlaceholderValidator do
- let(:validator) { described_class.new(attributes: [:link_url], **options) }
- let!(:badge) { build(:badge) }
- let(:placeholder_url) { 'http://www.example.com/%{project_path}/%{project_id}/%{default_branch}/%{commit_sha}' }
-
- subject { validator.validate_each(badge, :link_url, badge.link_url) }
-
- describe '#validates_each' do
- context 'with no options' do
- let(:options) { {} }
-
- it 'allows http and https protocols by default' do
- expect(validator.send(:default_options)[:protocols]).to eq %w(http https)
- end
-
- it 'checks that the url structure is valid' do
- badge.link_url = placeholder_url
-
- subject
-
- expect(badge.errors.empty?).to be false
- end
- end
-
- context 'with placeholder regex' do
- let(:options) { { placeholder_regex: /(project_path|project_id|commit_sha|default_branch)/ } }
-
- it 'checks that the url is valid and obviate placeholders that match regex' do
- badge.link_url = placeholder_url
-
- subject
-
- expect(badge.errors.empty?).to be true
- end
- end
- end
-end
diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb
index 763dff181d2..2d719263fc8 100644
--- a/spec/validators/url_validator_spec.rb
+++ b/spec/validators/url_validator_spec.rb
@@ -1,46 +1,62 @@
require 'spec_helper'
describe UrlValidator do
- let(:validator) { described_class.new(attributes: [:link_url], **options) }
- let!(:badge) { build(:badge) }
-
+ let!(:badge) { build(:badge, link_url: 'http://www.example.com') }
subject { validator.validate_each(badge, :link_url, badge.link_url) }
- describe '#validates_each' do
- context 'with no options' do
- let(:options) { {} }
+ include_examples 'url validator examples', described_class::DEFAULT_PROTOCOLS
+
+ context 'by default' do
+ let(:validator) { described_class.new(attributes: [:link_url]) }
+
+ it 'does not block urls pointing to localhost' do
+ badge.link_url = 'https://127.0.0.1'
+
+ subject
+
+ expect(badge.errors.empty?).to be true
+ end
+
+ it 'does not block urls pointing to the local network' do
+ badge.link_url = 'https://192.168.1.1'
- it 'allows http and https protocols by default' do
- expect(validator.send(:default_options)[:protocols]).to eq %w(http https)
- end
+ subject
- it 'checks that the url structure is valid' do
- badge.link_url = 'http://www.google.es/%{whatever}'
+ expect(badge.errors.empty?).to be true
+ end
+ end
+
+ context 'when allow_localhost is set to false' do
+ let(:validator) { described_class.new(attributes: [:link_url], allow_localhost: false) }
+
+ it 'blocks urls pointing to localhost' do
+ badge.link_url = 'https://127.0.0.1'
- subject
+ subject
- expect(badge.errors.empty?).to be false
- end
+ expect(badge.errors.empty?).to be false
end
+ end
- context 'with protocols' do
- let(:options) { { protocols: %w(http) } }
+ context 'when allow_local_network is set to false' do
+ let(:validator) { described_class.new(attributes: [:link_url], allow_local_network: false) }
- it 'allows urls with the defined protocols' do
- badge.link_url = 'http://www.example.com'
+ it 'blocks urls pointing to the local network' do
+ badge.link_url = 'https://192.168.1.1'
- subject
+ subject
- expect(badge.errors.empty?).to be true
- end
+ expect(badge.errors.empty?).to be false
+ end
+ end
- it 'add error if the url protocol does not match the selected ones' do
- badge.link_url = 'https://www.example.com'
+ context 'when ports is set' do
+ let(:validator) { described_class.new(attributes: [:link_url], ports: [443]) }
- subject
+ it 'blocks urls with a different port' do
+ subject
- expect(badge.errors.empty?).to be false
- end
+ expect(badge.errors.empty?).to be false
end
end
end