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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-10-17 15:07:33 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2019-10-17 15:07:33 +0300
commit6b75320f525f841454f1ab162d141d3610f2e77b (patch)
tree4971c27759e4fbc18b85e71800c3b9c12346317e /spec
parent4226aca420920c1844e8eade4798a2dff188a6fc (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/groups/registry/repositories_controller_spec.rb90
-rw-r--r--spec/factories/boards.rb8
-rw-r--r--spec/factories/milestones.rb8
-rw-r--r--spec/features/groups/user_sees_package_sidebar_spec.rb47
-rw-r--r--spec/features/milestones/user_deletes_milestone_spec.rb6
-rw-r--r--spec/finders/boards/visits_finder_spec.rb8
-rw-r--r--spec/frontend/jobs/store/mutations_spec.js75
-rw-r--r--spec/frontend/jobs/store/utils_spec.js7
-rw-r--r--spec/frontend/registry/components/__snapshots__/group_empty_state_spec.js.snap61
-rw-r--r--spec/frontend/registry/components/__snapshots__/project_empty_state_spec.js.snap186
-rw-r--r--spec/frontend/registry/components/app_spec.js56
-rw-r--r--spec/frontend/registry/components/collapsible_container_spec.js42
-rw-r--r--spec/frontend/registry/components/group_empty_state_spec.js23
-rw-r--r--spec/frontend/registry/components/project_empty_state_spec.js27
-rw-r--r--spec/frontend/registry/components/table_registry_spec.js77
-rw-r--r--spec/frontend/registry/stores/actions_spec.js18
-rw-r--r--spec/frontend/registry/stores/getters_spec.js6
-rw-r--r--spec/frontend/registry/stores/mutations_spec.js11
-rw-r--r--spec/helpers/groups_helper_spec.rb35
-rw-r--r--spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb51
-rw-r--r--spec/lib/banzai/reference_parser/mentioned_users_by_group_parser_spec.rb46
-rw-r--r--spec/lib/banzai/reference_parser/mentioned_users_by_project_parser_spec.rb46
-rw-r--r--spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb112
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/stages_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb48
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb46
-rw-r--r--spec/lib/gitlab/data_builder/push_spec.rb8
-rw-r--r--spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb3
-rw-r--r--spec/lib/gitlab/gpg/commit_spec.rb28
-rw-r--r--spec/lib/gitlab/import/merge_request_creator_spec.rb7
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml1
-rw-r--r--spec/lib/gitlab/metrics/exporter/sidekiq_exporter_spec.rb65
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb3
-rw-r--r--spec/models/application_setting_spec.rb4
-rw-r--r--spec/models/gpg_signature_spec.rb12
-rw-r--r--spec/models/note_spec.rb4
-rw-r--r--spec/requests/api/events_spec.rb1
-rw-r--r--spec/requests/api/settings_spec.rb4
-rw-r--r--spec/serializers/container_repository_entity_spec.rb12
-rw-r--r--spec/services/boards/issues/create_service_spec.rb2
-rw-r--r--spec/services/boards/lists/update_service_spec.rb8
-rw-r--r--spec/services/boards/visits/create_service_spec.rb4
-rw-r--r--spec/services/bulk_push_event_payload_service_spec.rb27
-rw-r--r--spec/services/event_create_service_spec.rb78
-rw-r--r--spec/services/git/base_hooks_service_spec.rb48
-rw-r--r--spec/services/git/process_ref_changes_service_spec.rb48
-rw-r--r--spec/services/quick_actions/interpret_service_spec.rb12
-rw-r--r--spec/support/api/boards_shared_examples.rb2
-rw-r--r--spec/support/api/milestones_shared_examples.rb2
-rw-r--r--spec/support/shared_examples/services/boards/boards_create_service.rb2
-rw-r--r--spec/support/shared_examples/services/boards/boards_list_service.rb4
-rw-r--r--spec/views/events/event/_push.html.haml_spec.rb34
53 files changed, 1430 insertions, 137 deletions
diff --git a/spec/controllers/groups/registry/repositories_controller_spec.rb b/spec/controllers/groups/registry/repositories_controller_spec.rb
new file mode 100644
index 00000000000..4129891914d
--- /dev/null
+++ b/spec/controllers/groups/registry/repositories_controller_spec.rb
@@ -0,0 +1,90 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Groups::Registry::RepositoriesController do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:guest) { create(:user) }
+ let_it_be(:group, reload: true) { create(:group) }
+
+ before do
+ stub_container_registry_config(enabled: true)
+ group.add_owner(user)
+ group.add_guest(guest)
+ sign_in(user)
+ end
+
+ context 'GET #index' do
+ context 'when container registry is enabled' do
+ it 'show index page' do
+ get :index, params: {
+ group_id: group
+ }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'has the correct response schema' do
+ get :index, params: {
+ group_id: group,
+ format: :json
+ }
+
+ expect(response).to match_response_schema('registry/repositories')
+ end
+
+ it 'returns a list of projects for json format' do
+ project = create(:project, group: group)
+ repo = create(:container_repository, project: project)
+
+ get :index, params: {
+ group_id: group,
+ format: :json
+ }
+
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to be_kind_of(Array)
+ expect(json_response.first).to include(
+ 'id' => repo.id,
+ 'name' => repo.name
+ )
+ end
+
+ it 'tracks the event' do
+ expect(Gitlab::Tracking).to receive(:event).with(anything, 'list_repositories', {})
+
+ get :index, params: {
+ group_id: group
+ }
+ end
+ end
+
+ context 'container registry is disabled' do
+ before do
+ stub_container_registry_config(enabled: false)
+ end
+
+ it 'renders not found' do
+ get :index, params: {
+ group_id: group
+ }
+
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+
+ context 'user do not have acces to container registry' do
+ before do
+ sign_out(user)
+ sign_in(guest)
+ end
+
+ it 'renders not found' do
+ get :index, params: {
+ group_id: group
+ }
+ expect(response).to have_gitlab_http_status(:not_found)
+ end
+ end
+ end
+end
diff --git a/spec/factories/boards.rb b/spec/factories/boards.rb
index 29cfe8fb295..a201ca94380 100644
--- a/spec/factories/boards.rb
+++ b/spec/factories/boards.rb
@@ -7,7 +7,7 @@ FactoryBot.define do
group { nil }
project_id { nil }
group_id { nil }
- parent { nil }
+ resource_parent { nil }
end
after(:build, :stub) do |board, evaluator|
@@ -19,9 +19,9 @@ FactoryBot.define do
board.project = evaluator.project
elsif evaluator.project_id
board.project_id = evaluator.project_id
- elsif evaluator.parent
- id = evaluator.parent.id
- evaluator.parent.is_a?(Group) ? board.group_id = id : evaluator.project_id = id
+ elsif evaluator.resource_parent
+ id = evaluator.resource_parent.id
+ evaluator.resource_parent.is_a?(Group) ? board.group_id = id : evaluator.project_id = id
else
board.project = create(:project, :empty_repo)
end
diff --git a/spec/factories/milestones.rb b/spec/factories/milestones.rb
index 75ff925774a..32eee645f6a 100644
--- a/spec/factories/milestones.rb
+++ b/spec/factories/milestones.rb
@@ -9,7 +9,7 @@ FactoryBot.define do
group { nil }
project_id { nil }
group_id { nil }
- parent { nil }
+ resource_parent { nil }
end
trait :active do
@@ -34,9 +34,9 @@ FactoryBot.define do
milestone.project = evaluator.project
elsif evaluator.project_id
milestone.project_id = evaluator.project_id
- elsif evaluator.parent
- id = evaluator.parent.id
- evaluator.parent.is_a?(Group) ? evaluator.group_id = id : evaluator.project_id = id
+ elsif evaluator.resource_parent
+ id = evaluator.resource_parent.id
+ evaluator.resource_parent.is_a?(Group) ? evaluator.group_id = id : evaluator.project_id = id
else
milestone.project = create(:project)
end
diff --git a/spec/features/groups/user_sees_package_sidebar_spec.rb b/spec/features/groups/user_sees_package_sidebar_spec.rb
new file mode 100644
index 00000000000..f85b6841636
--- /dev/null
+++ b/spec/features/groups/user_sees_package_sidebar_spec.rb
@@ -0,0 +1,47 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Groups > sidebar' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+
+ before do
+ group.add_developer(user)
+ sign_in(user)
+ end
+
+ context 'Package menu' do
+ context 'when container registry is enabled' do
+ before do
+ stub_container_registry_config(enabled: true)
+ visit group_path(group)
+ end
+
+ it 'shows main menu' do
+ within '.nav-sidebar' do
+ expect(page).to have_link(_('Packages'))
+ end
+ end
+
+ it 'has container registry link' do
+ within '.nav-sidebar' do
+ expect(page).to have_link(_('Container Registry'))
+ end
+ end
+ end
+
+ context 'when container registry is disabled' do
+ before do
+ stub_container_registry_config(enabled: false)
+ visit group_path(group)
+ end
+
+ it 'does not have container registry link' do
+ within '.nav-sidebar' do
+ expect(page).not_to have_link(_('Container Registry'))
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/milestones/user_deletes_milestone_spec.rb b/spec/features/milestones/user_deletes_milestone_spec.rb
index 7c1d88f7798..fd72f2dfefa 100644
--- a/spec/features/milestones/user_deletes_milestone_spec.rb
+++ b/spec/features/milestones/user_deletes_milestone_spec.rb
@@ -12,7 +12,7 @@ describe "User deletes milestone", :js do
end
context "when milestone belongs to project" do
- let!(:milestone) { create(:milestone, parent: project, title: "project milestone") }
+ let!(:milestone) { create(:milestone, resource_parent: project, title: "project milestone") }
it "deletes milestone" do
project.add_developer(user)
@@ -30,8 +30,8 @@ describe "User deletes milestone", :js do
end
context "when milestone belongs to group" do
- let!(:milestone_to_be_deleted) { create(:milestone, parent: group, title: "group milestone 1") }
- let!(:milestone) { create(:milestone, parent: group, title: "group milestone 2") }
+ let!(:milestone_to_be_deleted) { create(:milestone, resource_parent: group, title: "group milestone 1") }
+ let!(:milestone) { create(:milestone, resource_parent: group, title: "group milestone 2") }
it "deletes milestone" do
group.add_developer(user)
diff --git a/spec/finders/boards/visits_finder_spec.rb b/spec/finders/boards/visits_finder_spec.rb
index 4d40f4826f8..7e3ad8aa9f0 100644
--- a/spec/finders/boards/visits_finder_spec.rb
+++ b/spec/finders/boards/visits_finder_spec.rb
@@ -10,7 +10,7 @@ describe Boards::VisitsFinder do
let(:project) { create(:project) }
let(:project_board) { create(:board, project: project) }
- subject(:finder) { described_class.new(project_board.parent, user) }
+ subject(:finder) { described_class.new(project_board.resource_parent, user) }
it 'returns nil when there is no user' do
finder.current_user = nil
@@ -27,7 +27,7 @@ describe Boards::VisitsFinder do
it 'queries for last N visits' do
expect(BoardProjectRecentVisit).to receive(:latest).with(user, project, count: 5).once
- described_class.new(project_board.parent, user).latest(5)
+ described_class.new(project_board.resource_parent, user).latest(5)
end
end
@@ -35,7 +35,7 @@ describe Boards::VisitsFinder do
let(:group) { create(:group) }
let(:group_board) { create(:board, group: group) }
- subject(:finder) { described_class.new(group_board.parent, user) }
+ subject(:finder) { described_class.new(group_board.resource_parent, user) }
it 'returns nil when there is no user' do
finder.current_user = nil
@@ -52,7 +52,7 @@ describe Boards::VisitsFinder do
it 'queries for last N visits' do
expect(BoardGroupRecentVisit).to receive(:latest).with(user, group, count: 5).once
- described_class.new(group_board.parent, user).latest(5)
+ described_class.new(group_board.resource_parent, user).latest(5)
end
end
end
diff --git a/spec/frontend/jobs/store/mutations_spec.js b/spec/frontend/jobs/store/mutations_spec.js
index 6576f3d1ff2..d1ab152330e 100644
--- a/spec/frontend/jobs/store/mutations_spec.js
+++ b/spec/frontend/jobs/store/mutations_spec.js
@@ -80,6 +80,81 @@ describe('Jobs Store Mutations', () => {
expect(stateCopy.traceSize).toEqual(511846);
expect(stateCopy.isTraceComplete).toEqual(true);
});
+
+ describe('with new job log', () => {
+ let stateWithNewLog;
+ beforeEach(() => {
+ gon.features = gon.features || {};
+ gon.features.jobLogJson = true;
+
+ stateWithNewLog = state();
+ });
+
+ afterEach(() => {
+ gon.features.jobLogJson = false;
+ });
+
+ describe('log.lines', () => {
+ describe('when append is true', () => {
+ it('sets the parsed log ', () => {
+ mutations[types.RECEIVE_TRACE_SUCCESS](stateWithNewLog, {
+ append: true,
+ size: 511846,
+ complete: true,
+ lines: [
+ {
+ offset: 1,
+ content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
+ },
+ ],
+ });
+
+ expect(stateWithNewLog.trace).toEqual([
+ {
+ offset: 1,
+ content: [{ text: 'Running with gitlab-runner 11.12.1 (5a147c92)' }],
+ lineNumber: 0,
+ },
+ ]);
+ });
+ });
+
+ describe('when it is defined', () => {
+ it('sets the parsed log ', () => {
+ mutations[types.RECEIVE_TRACE_SUCCESS](stateWithNewLog, {
+ append: false,
+ size: 511846,
+ complete: true,
+ lines: [
+ { offset: 0, content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }] },
+ ],
+ });
+
+ expect(stateWithNewLog.trace).toEqual([
+ {
+ offset: 0,
+ content: [{ text: 'Running with gitlab-runner 11.11.1 (5a147c92)' }],
+ lineNumber: 0,
+ },
+ ]);
+ });
+ });
+
+ describe('when it is null', () => {
+ it('sets the default value', () => {
+ mutations[types.RECEIVE_TRACE_SUCCESS](stateWithNewLog, {
+ append: true,
+ html,
+ size: 511846,
+ complete: false,
+ lines: null,
+ });
+
+ expect(stateWithNewLog.trace).toEqual([]);
+ });
+ });
+ });
+ });
});
describe('STOP_POLLING_TRACE', () => {
diff --git a/spec/frontend/jobs/store/utils_spec.js b/spec/frontend/jobs/store/utils_spec.js
index 9890e01460e..43dacfe622c 100644
--- a/spec/frontend/jobs/store/utils_spec.js
+++ b/spec/frontend/jobs/store/utils_spec.js
@@ -291,6 +291,13 @@ describe('Jobs Store Utils', () => {
});
});
});
+
+ describe('when no data is provided', () => {
+ it('returns an empty array', () => {
+ const result = findOffsetAndRemove();
+ expect(result).toEqual([]);
+ });
+ });
});
describe('getIncrementalLineNumber', () => {
diff --git a/spec/frontend/registry/components/__snapshots__/group_empty_state_spec.js.snap b/spec/frontend/registry/components/__snapshots__/group_empty_state_spec.js.snap
new file mode 100644
index 00000000000..3f13b7d4d76
--- /dev/null
+++ b/spec/frontend/registry/components/__snapshots__/group_empty_state_spec.js.snap
@@ -0,0 +1,61 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Registry Group Empty state to match the default snapshot 1`] = `
+<div
+ class="row container-message empty-state"
+>
+ <div
+ class="col-12"
+ >
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no container images available in this group"
+ class=""
+ src="imageUrl"
+ />
+ </div>
+ </div>
+
+ <div
+ class="col-12"
+ >
+ <div
+ class="text-content"
+ >
+ <h4
+ class="center"
+ style=""
+ >
+ There are no container images available in this group
+ </h4>
+
+ <p
+ class="center"
+ style=""
+ >
+ <p
+ class="js-no-container-images-text"
+ >
+ With the Container Registry, every project can have its own space to store its Docker images. Push at least one Docker image in one of this group's projects in order to show up here.
+ <a
+ href="help"
+ target="_blank"
+ >
+ More Information
+ </a>
+ </p>
+ </p>
+
+ <div
+ class="text-center"
+ >
+ <!---->
+
+ <!---->
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/registry/components/__snapshots__/project_empty_state_spec.js.snap b/spec/frontend/registry/components/__snapshots__/project_empty_state_spec.js.snap
new file mode 100644
index 00000000000..3084462f5ae
--- /dev/null
+++ b/spec/frontend/registry/components/__snapshots__/project_empty_state_spec.js.snap
@@ -0,0 +1,186 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Registry Project Empty state to match the default snapshot 1`] = `
+<div
+ class="row container-message empty-state"
+>
+ <div
+ class="col-12"
+ >
+ <div
+ class="svg-250 svg-content"
+ >
+ <img
+ alt="There are no container images stored for this project"
+ class=""
+ src="imageUrl"
+ />
+ </div>
+ </div>
+
+ <div
+ class="col-12"
+ >
+ <div
+ class="text-content"
+ >
+ <h4
+ class="center"
+ style=""
+ >
+ There are no container images stored for this project
+ </h4>
+
+ <p
+ class="center"
+ style=""
+ >
+ <p
+ class="js-no-container-images-text"
+ >
+ With the Container Registry, every project can have its own space to store its Docker images.
+ <a
+ href="help"
+ target="_blank"
+ >
+ More Information
+ </a>
+ </p>
+
+ <h5>
+ Quick Start
+ </h5>
+
+ <p
+ class="js-not-logged-in-to-registry-text"
+ >
+ If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have
+ <a
+ href="help_link"
+ target="_blank"
+ >
+ Two-Factor Authentication
+ </a>
+ enabled, use a
+ <a
+ href="personal_token"
+ target="_blank"
+ >
+ Personal Access Token
+ </a>
+ instead of a password.
+ </p>
+
+ <div
+ class="input-group append-bottom-10"
+ >
+ <input
+ class="form-control monospace"
+ readonly="readonly"
+ type="text"
+ />
+
+ <span
+ class="input-group-append"
+ >
+ <button
+ class="btn input-group-text btn-secondary btn-default"
+ data-clipboard-text="docker login host"
+ data-original-title="Copy login command"
+ title=""
+ type="button"
+ >
+ <svg
+ aria-hidden="true"
+ class="s16 ic-duplicate"
+ >
+ <use
+ xlink:href="#duplicate"
+ />
+ </svg>
+ </button>
+ </span>
+ </div>
+
+ <p />
+
+ <p>
+
+ You can add an image to this registry with the following commands:
+
+ </p>
+
+ <div
+ class="input-group append-bottom-10"
+ >
+ <input
+ class="form-control monospace"
+ readonly="readonly"
+ type="text"
+ />
+
+ <span
+ class="input-group-append"
+ >
+ <button
+ class="btn input-group-text btn-secondary btn-default"
+ data-clipboard-text="docker build -t url ."
+ data-original-title="Copy build command"
+ title=""
+ type="button"
+ >
+ <svg
+ aria-hidden="true"
+ class="s16 ic-duplicate"
+ >
+ <use
+ xlink:href="#duplicate"
+ />
+ </svg>
+ </button>
+ </span>
+ </div>
+
+ <div
+ class="input-group"
+ >
+ <input
+ class="form-control monospace"
+ readonly="readonly"
+ type="text"
+ />
+
+ <span
+ class="input-group-append"
+ >
+ <button
+ class="btn input-group-text btn-secondary btn-default"
+ data-clipboard-text="docker push url"
+ data-original-title="Copy push command"
+ title=""
+ type="button"
+ >
+ <svg
+ aria-hidden="true"
+ class="s16 ic-duplicate"
+ >
+ <use
+ xlink:href="#duplicate"
+ />
+ </svg>
+ </button>
+ </span>
+ </div>
+ </p>
+
+ <div
+ class="text-center"
+ >
+ <!---->
+
+ <!---->
+ </div>
+ </div>
+ </div>
+</div>
+`;
diff --git a/spec/frontend/registry/components/app_spec.js b/spec/frontend/registry/components/app_spec.js
index 5dcb61e03b5..a69c33c246d 100644
--- a/spec/frontend/registry/components/app_spec.js
+++ b/spec/frontend/registry/components/app_spec.js
@@ -1,3 +1,4 @@
+import Vue from 'vue';
import { mount } from '@vue/test-utils';
import registry from '~/registry/components/app.vue';
import { TEST_HOST } from '../../helpers/test_constants';
@@ -7,8 +8,8 @@ describe('Registry List', () => {
let wrapper;
const findCollapsibleContainer = w => w.findAll({ name: 'CollapsibeContainerRegisty' });
- const findNoContainerImagesText = w => w.find('.js-no-container-images-text');
- const findNotLoggedInToRegistryText = w => w.find('.js-not-logged-in-to-registry-text');
+ const findProjectEmptyState = w => w.find({ name: 'ProjectEmptyState' });
+ const findGroupEmptyState = w => w.find({ name: 'GroupEmptyState' });
const findSpinner = w => w.find('.gl-spinner');
const findCharacterErrorText = w => w.find('.js-character-error-text');
@@ -25,13 +26,18 @@ describe('Registry List', () => {
const setMainEndpoint = jest.fn();
const fetchRepos = jest.fn();
+ const setIsDeleteDisabled = jest.fn();
const methods = {
setMainEndpoint,
fetchRepos,
+ setIsDeleteDisabled,
};
beforeEach(() => {
+ // This is needed due to console.error called by vue to emit a warning that stop the tests.
+ // See https://github.com/vuejs/vue-test-utils/issues/532.
+ Vue.config.silent = true;
wrapper = mount(registry, {
propsData,
computed: {
@@ -43,6 +49,12 @@ describe('Registry List', () => {
});
});
+ afterEach(() => {
+ jest.clearAllMocks();
+ Vue.config.silent = false;
+ wrapper.destroy();
+ });
+
describe('with data', () => {
it('should render a list of CollapsibeContainerRegisty', () => {
const containers = findCollapsibleContainer(wrapper);
@@ -65,18 +77,9 @@ describe('Registry List', () => {
});
});
- it('should render empty message', () => {
- const noContainerImagesText = findNoContainerImagesText(localWrapper);
- expect(noContainerImagesText.text()).toEqual(
- 'With the Container Registry, every project can have its own space to store its Docker images. More Information',
- );
- });
-
- it('should render login help text', () => {
- const notLoggedInToRegistryText = findNotLoggedInToRegistryText(localWrapper);
- expect(notLoggedInToRegistryText.text()).toEqual(
- 'If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have Two-Factor Authentication enabled, use a Personal Access Token instead of a password.',
- );
+ it('should render project empty message', () => {
+ const projectEmptyState = findProjectEmptyState(localWrapper);
+ expect(projectEmptyState.exists()).toBe(true);
});
});
@@ -129,4 +132,29 @@ describe('Registry List', () => {
);
});
});
+
+ describe('with groupId set', () => {
+ const isGroupPage = true;
+
+ beforeEach(() => {
+ wrapper = mount(registry, {
+ propsData: {
+ ...propsData,
+ endpoint: null,
+ isGroupPage,
+ },
+ methods,
+ });
+ });
+
+ it('call the right vuex setters', () => {
+ expect(methods.setMainEndpoint).toHaveBeenLastCalledWith(null);
+ expect(methods.setIsDeleteDisabled).toHaveBeenLastCalledWith(true);
+ });
+
+ it('should render groups empty message', () => {
+ const groupEmptyState = findGroupEmptyState(wrapper);
+ expect(groupEmptyState.exists()).toBe(true);
+ });
+ });
});
diff --git a/spec/frontend/registry/components/collapsible_container_spec.js b/spec/frontend/registry/components/collapsible_container_spec.js
index 0fe4338f1ba..f93ebab1a4d 100644
--- a/spec/frontend/registry/components/collapsible_container_spec.js
+++ b/spec/frontend/registry/components/collapsible_container_spec.js
@@ -1,24 +1,40 @@
import Vue from 'vue';
-import { mount } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { mount, createLocalVue } from '@vue/test-utils';
import collapsibleComponent from '~/registry/components/collapsible_container.vue';
import { repoPropsData } from '../mock_data';
import createFlash from '~/flash';
+import * as getters from '~/registry/stores/getters';
jest.mock('~/flash.js');
+const localVue = createLocalVue();
+
+localVue.use(Vuex);
+
describe('collapsible registry container', () => {
let wrapper;
+ let store;
const findDeleteBtn = w => w.find('.js-remove-repo');
const findContainerImageTags = w => w.find('.container-image-tags');
const findToggleRepos = w => w.findAll('.js-toggle-repo');
+ const mountWithStore = config => mount(collapsibleComponent, { ...config, store, localVue });
+
beforeEach(() => {
createFlash.mockClear();
// This is needed due to console.error called by vue to emit a warning that stop the tests
// see https://github.com/vuejs/vue-test-utils/issues/532
Vue.config.silent = true;
- wrapper = mount(collapsibleComponent, {
+ store = new Vuex.Store({
+ state: {
+ isDeleteDisabled: false,
+ },
+ getters,
+ });
+
+ wrapper = mountWithStore({
propsData: {
repo: repoPropsData,
},
@@ -27,6 +43,7 @@ describe('collapsible registry container', () => {
afterEach(() => {
Vue.config.silent = false;
+ wrapper.destroy();
});
describe('toggle', () => {
@@ -86,4 +103,25 @@ describe('collapsible registry container', () => {
});
});
});
+
+ describe('disabled delete', () => {
+ beforeEach(() => {
+ store = new Vuex.Store({
+ state: {
+ isDeleteDisabled: true,
+ },
+ getters,
+ });
+ wrapper = mountWithStore({
+ propsData: {
+ repo: repoPropsData,
+ },
+ });
+ });
+
+ it('should not render delete button', () => {
+ const deleteBtn = findDeleteBtn(wrapper);
+ expect(deleteBtn.exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/registry/components/group_empty_state_spec.js b/spec/frontend/registry/components/group_empty_state_spec.js
new file mode 100644
index 00000000000..f71074b5154
--- /dev/null
+++ b/spec/frontend/registry/components/group_empty_state_spec.js
@@ -0,0 +1,23 @@
+import { mount } from '@vue/test-utils';
+import groupEmptyState from '~/registry/components/group_empty_state.vue';
+
+describe('Registry Group Empty state', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = mount(groupEmptyState, {
+ propsData: {
+ noContainersImage: 'imageUrl',
+ helpPagePath: 'help',
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('to match the default snapshot', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/registry/components/project_empty_state_spec.js b/spec/frontend/registry/components/project_empty_state_spec.js
new file mode 100644
index 00000000000..913524db3aa
--- /dev/null
+++ b/spec/frontend/registry/components/project_empty_state_spec.js
@@ -0,0 +1,27 @@
+import { mount } from '@vue/test-utils';
+import projectEmptyState from '~/registry/components/project_empty_state.vue';
+
+describe('Registry Project Empty state', () => {
+ let wrapper;
+
+ beforeEach(() => {
+ wrapper = mount(projectEmptyState, {
+ propsData: {
+ noContainersImage: 'imageUrl',
+ helpPagePath: 'help',
+ repositoryUrl: 'url',
+ twoFactorAuthHelpLink: 'help_link',
+ personalAccessTokensHelpLink: 'personal_token',
+ registryHostUrlWithPort: 'host',
+ },
+ });
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('to match the default snapshot', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+});
diff --git a/spec/frontend/registry/components/table_registry_spec.js b/spec/frontend/registry/components/table_registry_spec.js
index 021f13feeba..600a7a6ee87 100644
--- a/spec/frontend/registry/components/table_registry_spec.js
+++ b/spec/frontend/registry/components/table_registry_spec.js
@@ -1,12 +1,19 @@
import Vue from 'vue';
+import Vuex from 'vuex';
import tableRegistry from '~/registry/components/table_registry.vue';
-import { mount } from '@vue/test-utils';
+import { mount, createLocalVue } from '@vue/test-utils';
import { repoPropsData } from '../mock_data';
+import * as getters from '~/registry/stores/getters';
const [firstImage, secondImage] = repoPropsData.list;
+const localVue = createLocalVue();
+
+localVue.use(Vuex);
+
describe('table registry', () => {
let wrapper;
+ let store;
const findSelectAllCheckbox = w => w.find('.js-select-all-checkbox > input');
const findSelectCheckboxes = w => w.findAll('.js-select-checkbox > input');
@@ -15,19 +22,31 @@ describe('table registry', () => {
const findPagination = w => w.find('.js-registry-pagination');
const bulkDeletePath = 'path';
+ const mountWithStore = config => mount(tableRegistry, { ...config, store, localVue });
+
beforeEach(() => {
// This is needed due to console.error called by vue to emit a warning that stop the tests
// see https://github.com/vuejs/vue-test-utils/issues/532
Vue.config.silent = true;
- wrapper = mount(tableRegistry, {
+
+ store = new Vuex.Store({
+ state: {
+ isDeleteDisabled: false,
+ },
+ getters,
+ });
+
+ wrapper = mountWithStore({
propsData: {
repo: repoPropsData,
+ canDeleteRepo: true,
},
});
});
afterEach(() => {
Vue.config.silent = false;
+ wrapper.destroy();
});
describe('rendering', () => {
@@ -149,7 +168,6 @@ describe('table registry', () => {
});
describe('pagination', () => {
- let localWrapper = null;
const repo = {
repoPropsData,
pagination: {
@@ -160,7 +178,7 @@ describe('table registry', () => {
};
beforeEach(() => {
- localWrapper = mount(tableRegistry, {
+ wrapper = mount(tableRegistry, {
propsData: {
repo,
},
@@ -168,13 +186,13 @@ describe('table registry', () => {
});
it('should exist', () => {
- const pagination = findPagination(localWrapper);
+ const pagination = findPagination(wrapper);
expect(pagination.exists()).toBe(true);
});
it('should be visible when pagination is needed', () => {
- const pagination = findPagination(localWrapper);
+ const pagination = findPagination(wrapper);
expect(pagination.isVisible()).toBe(true);
- localWrapper.setProps({
+ wrapper.setProps({
repo: {
pagination: {
total: 0,
@@ -182,13 +200,13 @@ describe('table registry', () => {
},
},
});
- expect(localWrapper.vm.shouldRenderPagination).toBe(false);
+ expect(wrapper.vm.shouldRenderPagination).toBe(false);
});
it('should have a change function that update the list when run', () => {
const fetchList = jest.fn().mockResolvedValue();
- localWrapper.setMethods({ fetchList });
- localWrapper.vm.onPageChange(1);
- expect(localWrapper.vm.fetchList).toHaveBeenCalledWith({ repo, page: 1 });
+ wrapper.setMethods({ fetchList });
+ wrapper.vm.onPageChange(1);
+ expect(wrapper.vm.fetchList).toHaveBeenCalledWith({ repo, page: 1 });
});
});
@@ -208,4 +226,41 @@ describe('table registry', () => {
expect(wrapper.vm.modalDescription).toContain('<b>2</b> tags');
});
});
+
+ describe('disabled delete', () => {
+ beforeEach(() => {
+ store = new Vuex.Store({
+ state: {
+ isDeleteDisabled: true,
+ },
+ getters,
+ });
+ wrapper = mountWithStore({
+ propsData: {
+ repo: repoPropsData,
+ canDeleteRepo: false,
+ },
+ });
+ });
+
+ it('should not render select all', () => {
+ const selectAll = findSelectAllCheckbox(wrapper);
+ expect(selectAll.exists()).toBe(false);
+ });
+
+ it('should not render any select checkbox', () => {
+ const selects = findSelectCheckboxes(wrapper);
+ expect(selects.length).toBe(0);
+ });
+
+ it('should not render delete registry button', () => {
+ const deleteBtn = findDeleteButton(wrapper);
+ expect(deleteBtn.exists()).toBe(false);
+ });
+
+ it('should not render delete row button', () => {
+ const deleteBtns = findDeleteButtonsRow(wrapper);
+ expect(deleteBtns.length).toBe(0);
+ });
+ });
});
diff --git a/spec/frontend/registry/stores/actions_spec.js b/spec/frontend/registry/stores/actions_spec.js
index bf335904d23..7937fa82e80 100644
--- a/spec/frontend/registry/stores/actions_spec.js
+++ b/spec/frontend/registry/stores/actions_spec.js
@@ -34,7 +34,7 @@ describe('Actions Registry Store', () => {
mock.onGet(`${TEST_HOST}/endpoint.json`).replyOnce(200, reposServerResponse, {});
});
- it('should set receveived repos', done => {
+ it('should set received repos', done => {
testAction(
actions.fetchRepos,
null,
@@ -71,10 +71,10 @@ describe('Actions Registry Store', () => {
beforeEach(() => {
state.repos = parsedReposServerResponse;
[, repo] = state.repos;
- mock.onGet(repo.tagsPath).replyOnce(200, registryServerResponse, {});
});
it('should set received list', done => {
+ mock.onGet(repo.tagsPath).replyOnce(200, registryServerResponse, {});
testAction(
actions.fetchList,
{ repo },
@@ -97,6 +97,7 @@ describe('Actions Registry Store', () => {
});
it('should create flash on API error', done => {
+ mock.onGet(repo.tagsPath).replyOnce(400);
const updatedRepo = {
...repo,
tagsPath: null,
@@ -133,6 +134,19 @@ describe('Actions Registry Store', () => {
});
});
+ describe('setIsDeleteDisabled', () => {
+ it('should commit set is delete disabled', done => {
+ testAction(
+ actions.setIsDeleteDisabled,
+ true,
+ state,
+ [{ type: types.SET_IS_DELETE_DISABLED, payload: true }],
+ [],
+ done,
+ );
+ });
+ });
+
describe('toggleLoading', () => {
it('should commit toggle main loading', done => {
testAction(
diff --git a/spec/frontend/registry/stores/getters_spec.js b/spec/frontend/registry/stores/getters_spec.js
index 839aa718997..c16f520223b 100644
--- a/spec/frontend/registry/stores/getters_spec.js
+++ b/spec/frontend/registry/stores/getters_spec.js
@@ -7,6 +7,7 @@ describe('Getters Registry Store', () => {
state = {
isLoading: false,
endpoint: '/root/empty-project/container_registry.json',
+ isDeleteDisabled: false,
repos: [
{
canDelete: true,
@@ -43,4 +44,9 @@ describe('Getters Registry Store', () => {
expect(getters.repos(state)).toEqual(state.repos);
});
});
+ describe('isDeleteDisabled', () => {
+ it('should return isDeleteDisabled', () => {
+ expect(getters.isDeleteDisabled(state)).toEqual(state.isDeleteDisabled);
+ });
+ });
});
diff --git a/spec/frontend/registry/stores/mutations_spec.js b/spec/frontend/registry/stores/mutations_spec.js
index e19fe7a27cf..1d583028ca6 100644
--- a/spec/frontend/registry/stores/mutations_spec.js
+++ b/spec/frontend/registry/stores/mutations_spec.js
@@ -19,7 +19,16 @@ describe('Mutations Registry Store', () => {
const expectedState = Object.assign({}, mockState, { endpoint: 'foo' });
mutations[types.SET_MAIN_ENDPOINT](mockState, 'foo');
- expect(mockState).toEqual(expectedState);
+ expect(mockState.endpoint).toEqual(expectedState.endpoint);
+ });
+ });
+
+ describe('SET_IS_DELETE_DISABLED', () => {
+ it('should set the is delete disabled', () => {
+ const expectedState = Object.assign({}, mockState, { isDeleteDisabled: true });
+ mutations[types.SET_IS_DELETE_DISABLED](mockState, true);
+
+ expect(mockState.isDeleteDisabled).toEqual(expectedState.isDeleteDisabled);
});
});
diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb
index 98719697cea..8b33277ea18 100644
--- a/spec/helpers/groups_helper_spec.rb
+++ b/spec/helpers/groups_helper_spec.rb
@@ -191,6 +191,41 @@ describe GroupsHelper do
end
end
+ describe '#group_container_registry_nav' do
+ let(:group) { create(:group, :public) }
+ let(:user) { create(:user) }
+ before do
+ stub_container_registry_config(enabled: true)
+ allow(helper).to receive(:current_user) { user }
+ allow(helper).to receive(:can?).with(user, :read_container_image, group) { true }
+ helper.instance_variable_set(:@group, group)
+ end
+
+ subject { helper.group_container_registry_nav? }
+
+ context 'when container registry is enabled' do
+ it { is_expected.to be_truthy }
+
+ it 'is disabled for guest' do
+ allow(helper).to receive(:can?).with(user, :read_container_image, group) { false }
+ expect(subject).to be false
+ end
+ end
+
+ context 'when container registry is not enabled' do
+ before do
+ stub_container_registry_config(enabled: false)
+ end
+
+ it { is_expected.to be_falsy }
+
+ it 'is disabled for guests' do
+ allow(helper).to receive(:can?).with(user, :read_container_image, group) { false }
+ expect(subject).to be false
+ end
+ end
+ end
+
describe '#group_sidebar_links' do
let(:group) { create(:group, :public) }
let(:user) { create(:user) }
diff --git a/spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb b/spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb
new file mode 100644
index 00000000000..1be279375bd
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/mentioned_user_parser_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::MentionedUserParser do
+ include ReferenceParserHelpers
+
+ let(:group) { create(:group, :private) }
+ let(:user) { create(:user) }
+ let(:new_user) { create(:user) }
+ let(:project) { create(:project, group: group, creator: user) }
+ let(:link) { empty_html_link }
+
+ subject { described_class.new(Banzai::RenderContext.new(project, new_user)) }
+
+ describe '#gather_references' do
+ context 'when the link has a data-group attribute' do
+ context 'using an existing group ID' do
+ before do
+ link['data-group'] = project.group.id.to_s
+ group.add_developer(new_user)
+ end
+
+ it 'returns empty list of users' do
+ expect(subject.gather_references([link])).to eq([])
+ end
+ end
+ end
+
+ context 'when the link has a data-project attribute' do
+ context 'using an existing project ID' do
+ before do
+ link['data-project'] = project.id.to_s
+ project.add_developer(new_user)
+ end
+
+ it 'returns empty list of users' do
+ expect(subject.gather_references([link])).to eq([])
+ end
+ end
+ end
+
+ context 'when the link has a data-user attribute' do
+ it 'returns an Array of users' do
+ link['data-user'] = user.id.to_s
+
+ expect(subject.referenced_by([link])).to eq([user])
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/mentioned_users_by_group_parser_spec.rb b/spec/lib/banzai/reference_parser/mentioned_users_by_group_parser_spec.rb
new file mode 100644
index 00000000000..99d607629eb
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/mentioned_users_by_group_parser_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::MentionedUsersByGroupParser do
+ include ReferenceParserHelpers
+
+ let(:group) { create(:group, :private) }
+ let(:user) { create(:user) }
+ let(:new_user) { create(:user) }
+ let(:project) { create(:project, group: group, creator: user) }
+ let(:link) { empty_html_link }
+
+ subject { described_class.new(Banzai::RenderContext.new(project, new_user)) }
+
+ describe '#gather_references' do
+ context 'when the link has a data-group attribute' do
+ context 'using an existing group ID where user does not have access' do
+ it 'returns empty array' do
+ link['data-group'] = project.group.id.to_s
+
+ expect(subject.gather_references([link])).to eq([])
+ end
+ end
+
+ context 'using an existing group ID' do
+ before do
+ link['data-group'] = project.group.id.to_s
+ group.add_developer(new_user)
+ end
+
+ it 'returns groups' do
+ expect(subject.gather_references([link])).to eq([group])
+ end
+ end
+
+ context 'using a non-existing group ID' do
+ it 'returns an empty Array' do
+ link['data-group'] = 'test-non-existing'
+
+ expect(subject.gather_references([link])).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/banzai/reference_parser/mentioned_users_by_project_parser_spec.rb b/spec/lib/banzai/reference_parser/mentioned_users_by_project_parser_spec.rb
new file mode 100644
index 00000000000..155f2189d9e
--- /dev/null
+++ b/spec/lib/banzai/reference_parser/mentioned_users_by_project_parser_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Banzai::ReferenceParser::MentionedUsersByProjectParser do
+ include ReferenceParserHelpers
+
+ let(:group) { create(:group, :private) }
+ let(:user) { create(:user) }
+ let(:new_user) { create(:user) }
+ let(:project) { create(:project, group: group, creator: user) }
+ let(:link) { empty_html_link }
+
+ subject { described_class.new(Banzai::RenderContext.new(project, new_user)) }
+
+ describe '#gather_references' do
+ context 'when the link has a data-project attribute' do
+ context 'using an existing project ID where user does not have access' do
+ it 'returns empty Array' do
+ link['data-project'] = project.id.to_s
+
+ expect(subject.gather_references([link])).to eq([])
+ end
+ end
+
+ context 'using an existing project ID' do
+ before do
+ link['data-project'] = project.id.to_s
+ project.add_developer(new_user)
+ end
+
+ it 'returns an Array of referenced projects' do
+ expect(subject.gather_references([link])).to eq([project])
+ end
+ end
+
+ context 'using a non-existing project ID' do
+ it 'returns an empty Array' do
+ link['data-project'] = 'inexisting-project-id'
+
+ expect(subject.gather_references([link])).to eq([])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb b/spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb
new file mode 100644
index 00000000000..042f9b591b6
--- /dev/null
+++ b/spec/lib/gitlab/ci/config/edge_stages_injector_spec.rb
@@ -0,0 +1,112 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+
+describe Gitlab::Ci::Config::EdgeStagesInjector do
+ describe '#call' do
+ subject { described_class.new(config).to_hash }
+
+ context 'without stages' do
+ let(:config) do
+ {
+ test: { script: 'test' }
+ }
+ end
+
+ it { is_expected.to match config }
+ end
+
+ context 'with values' do
+ let(:config) do
+ {
+ stages: %w[stage1 stage2],
+ test: { script: 'test' }
+ }
+ end
+
+ let(:expected_stages) do
+ %w[.pre stage1 stage2 .post]
+ end
+
+ it { is_expected.to match(config.merge(stages: expected_stages)) }
+ end
+
+ context 'with bad values' do
+ let(:config) do
+ {
+ stages: 'stage1',
+ test: { script: 'test' }
+ }
+ end
+
+ it { is_expected.to match(config) }
+ end
+
+ context 'with collision values' do
+ let(:config) do
+ {
+ stages: %w[.post stage1 .pre .post stage2],
+ test: { script: 'test' }
+ }
+ end
+
+ let(:expected_stages) do
+ %w[.pre stage1 stage2 .post]
+ end
+
+ it { is_expected.to match(config.merge(stages: expected_stages)) }
+ end
+
+ context 'with types' do
+ let(:config) do
+ {
+ types: %w[stage1 stage2],
+ test: { script: 'test' }
+ }
+ end
+
+ let(:expected_config) do
+ {
+ types: %w[.pre stage1 stage2 .post],
+ test: { script: 'test' }
+ }
+ end
+
+ it { is_expected.to match expected_config }
+ end
+
+ context 'with types' do
+ let(:config) do
+ {
+ types: %w[.post stage1 .pre .post stage2],
+ test: { script: 'test' }
+ }
+ end
+
+ let(:expected_config) do
+ {
+ types: %w[.pre stage1 stage2 .post],
+ test: { script: 'test' }
+ }
+ end
+
+ it { is_expected.to match expected_config }
+ end
+ end
+
+ describe '.wrap_stages' do
+ subject { described_class.wrap_stages(stages) }
+
+ context 'with empty value' do
+ let(:stages) {}
+
+ it { is_expected.to eq %w[.pre .post] }
+ end
+
+ context 'with values' do
+ let(:stages) { %w[s1 .pre] }
+
+ it { is_expected.to eq %w[.pre s1 .post] }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index 968dbb9c7f2..7e1a80414d4 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -215,7 +215,7 @@ describe Gitlab::Ci::Config::Entry::Root do
describe '#stages_value' do
it 'returns an array of root stages' do
- expect(root.stages_value).to eq %w[build test deploy]
+ expect(root.stages_value).to eq %w[.pre build test deploy .post]
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/stages_spec.rb b/spec/lib/gitlab/ci/config/entry/stages_spec.rb
index 97970522104..3e6ff8eca28 100644
--- a/spec/lib/gitlab/ci/config/entry/stages_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/stages_spec.rb
@@ -42,7 +42,7 @@ describe Gitlab::Ci::Config::Entry::Stages do
describe '.default' do
it 'returns default stages' do
- expect(described_class.default).to eq %w[build test deploy]
+ expect(described_class.default).to eq %w[.pre build test deploy .post]
end
end
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 68c38644b5c..b254f9af2f1 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -51,6 +51,54 @@ describe Gitlab::Ci::Config do
end
end
end
+
+ describe '#stages' do
+ subject(:subject) { config.stages }
+
+ context 'with default stages' do
+ let(:default_stages) do
+ %w[.pre build test deploy .post]
+ end
+
+ it { is_expected.to eq default_stages }
+ end
+
+ context 'with custom stages' do
+ let(:yml) do
+ <<-EOS
+ stages:
+ - stage1
+ - stage2
+ job1:
+ stage: stage1
+ script:
+ - ls
+ EOS
+ end
+
+ it { is_expected.to eq %w[.pre stage1 stage2 .post] }
+ end
+
+ context 'with feature disabled' do
+ before do
+ stub_feature_flags(ci_pre_post_pipeline_stages: false)
+ end
+
+ let(:yml) do
+ <<-EOS
+ stages:
+ - stage1
+ - stage2
+ job1:
+ stage: stage1
+ script:
+ - ls
+ EOS
+ end
+
+ it { is_expected.to eq %w[stage1 stage2] }
+ end
+ end
end
context 'when using extendable hash' do
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index d43eb4e4b4a..cb5ebde16d7 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -26,7 +26,7 @@ module Gitlab
it 'returns valid build attributes' do
expect(subject).to eq({
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "rspec",
options: {
before_script: ["pwd"],
@@ -56,7 +56,7 @@ module Gitlab
it 'returns valid build attributes' do
expect(subject).to eq({
stage: 'test',
- stage_idx: 1,
+ stage_idx: 2,
name: 'rspec',
options: { script: ['rspec'] },
rules: [
@@ -209,13 +209,16 @@ module Gitlab
end
let(:attributes) do
- [{ name: "build",
+ [{ name: ".pre",
index: 0,
builds: [] },
- { name: "test",
+ { name: "build",
index: 1,
+ builds: [] },
+ { name: "test",
+ index: 2,
builds:
- [{ stage_idx: 1,
+ [{ stage_idx: 2,
stage: "test",
name: "rspec",
allow_failure: false,
@@ -225,9 +228,9 @@ module Gitlab
only: { refs: ["branches"] },
except: {} }] },
{ name: "deploy",
- index: 2,
+ index: 3,
builds:
- [{ stage_idx: 2,
+ [{ stage_idx: 3,
stage: "deploy",
name: "prod",
allow_failure: false,
@@ -235,7 +238,10 @@ module Gitlab
yaml_variables: [],
options: { script: ["cap prod"] },
only: { refs: ["tags"] },
- except: {} }] }]
+ except: {} }] },
+ { name: ".post",
+ index: 4,
+ builds: [] }]
end
it 'returns stages seed attributes' do
@@ -425,7 +431,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "rspec",
options: {
before_script: ["pwd"],
@@ -456,7 +462,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "rspec",
options: {
before_script: ["pwd"],
@@ -485,7 +491,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "rspec",
options: {
before_script: ["pwd"],
@@ -510,7 +516,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "rspec",
options: {
before_script: ["pwd"],
@@ -977,7 +983,7 @@ module Gitlab
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "rspec",
options: {
before_script: ["pwd"],
@@ -1272,7 +1278,7 @@ module Gitlab
expect(subject.builds.size).to eq(5)
expect(subject.builds[0]).to eq(
stage: "build",
- stage_idx: 0,
+ stage_idx: 1,
name: "build1",
options: {
script: ["test"]
@@ -1283,7 +1289,7 @@ module Gitlab
)
expect(subject.builds[2]).to eq(
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "test1",
options: {
script: ["test"],
@@ -1398,7 +1404,7 @@ module Gitlab
expect(subject.size).to eq(1)
expect(subject.first).to eq({
stage: "test",
- stage_idx: 1,
+ stage_idx: 2,
name: "normal_job",
options: {
script: ["test"]
@@ -1442,7 +1448,7 @@ module Gitlab
expect(subject.size).to eq(2)
expect(subject.first).to eq({
stage: "build",
- stage_idx: 0,
+ stage_idx: 1,
name: "job1",
options: {
script: ["execute-script-for-job"]
@@ -1453,7 +1459,7 @@ module Gitlab
})
expect(subject.second).to eq({
stage: "build",
- stage_idx: 0,
+ stage_idx: 1,
name: "job2",
options: {
script: ["execute-script-for-job"]
@@ -1665,14 +1671,14 @@ module Gitlab
config = YAML.dump({ rspec: { script: "test", type: "acceptance" } })
expect do
Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy")
+ end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be .pre, build, test, deploy, .post")
end
it "returns errors if job stage is not a defined stage" do
config = YAML.dump({ types: %w(build test), rspec: { script: "test", type: "acceptance" } })
expect do
Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be build, test")
+ end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: stage parameter should be .pre, build, test, .post")
end
it "returns errors if stages is not an array" do
diff --git a/spec/lib/gitlab/data_builder/push_spec.rb b/spec/lib/gitlab/data_builder/push_spec.rb
index e8a9f0b06a8..58509b69463 100644
--- a/spec/lib/gitlab/data_builder/push_spec.rb
+++ b/spec/lib/gitlab/data_builder/push_spec.rb
@@ -90,4 +90,12 @@ describe Gitlab::DataBuilder::Push do
.not_to raise_error
end
end
+
+ describe '.build_bulk' do
+ subject do
+ described_class.build_bulk(action: :created, ref_type: :branch, changes: [double, double])
+ end
+
+ it { is_expected.to eq(action: :created, ref_count: 2, ref_type: :branch) }
+ end
end
diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
index 6d614c6527a..8331f0b6bc7 100644
--- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb
@@ -311,10 +311,11 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi
end
end
- it 'creates the merge request diffs' do
+ it 'creates a merge request diff and sets it as the latest' do
mr = insert_git_data
expect(mr.merge_request_diffs.exists?).to eq(true)
+ expect(mr.reload.latest_merge_request_diff_id).to eq(mr.merge_request_diffs.first.id)
end
it 'creates the merge request diff commits' do
diff --git a/spec/lib/gitlab/gpg/commit_spec.rb b/spec/lib/gitlab/gpg/commit_spec.rb
index fa47cfd519b..8401b683fd5 100644
--- a/spec/lib/gitlab/gpg/commit_spec.rb
+++ b/spec/lib/gitlab/gpg/commit_spec.rb
@@ -370,5 +370,33 @@ describe Gitlab::Gpg::Commit do
it_behaves_like 'returns the cached signature on second call'
end
+
+ context 'multiple commits with signatures' do
+ let(:first_signature) { create(:gpg_signature) }
+
+ let(:gpg_key) { create(:gpg_key, key: GpgHelpers::User2.public_key) }
+ let(:second_signature) { create(:gpg_signature, gpg_key: gpg_key) }
+
+ let!(:first_commit) { create(:commit, project: project, sha: first_signature.commit_sha) }
+ let!(:second_commit) { create(:commit, project: project, sha: second_signature.commit_sha) }
+
+ let(:commits) do
+ [first_commit, second_commit].map do |commit|
+ gpg_commit = described_class.new(commit)
+
+ allow(gpg_commit).to receive(:has_signature?).and_return(true)
+
+ gpg_commit
+ end
+ end
+
+ it 'does an aggregated sql request instead of 2 separate ones' do
+ recorder = ActiveRecord::QueryRecorder.new do
+ commits.each(&:signature)
+ end
+
+ expect(recorder.count).to eq(1)
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/import/merge_request_creator_spec.rb b/spec/lib/gitlab/import/merge_request_creator_spec.rb
index 7c73e9b39f7..ff2c3032dbf 100644
--- a/spec/lib/gitlab/import/merge_request_creator_spec.rb
+++ b/spec/lib/gitlab/import/merge_request_creator_spec.rb
@@ -21,8 +21,11 @@ describe Gitlab::Import::MergeRequestCreator do
subject.execute(attributes)
- expect(merge_request.reload.merge_request_diffs.count).to eq(1)
- expect(merge_request.reload.merge_request_diffs.first.commits.count).to eq(commits_count)
+ merge_request.reload
+
+ expect(merge_request.merge_request_diffs.count).to eq(1)
+ expect(merge_request.merge_request_diffs.first.commits.count).to eq(commits_count)
+ expect(merge_request.latest_merge_request_diff_id).to eq(merge_request.merge_request_diffs.first.id)
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 d3b51a53ede..ebc5d9d1f56 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -47,6 +47,7 @@ PushEventPayload:
- commit_to
- ref
- commit_title
+- ref_count
Note:
- id
- note
diff --git a/spec/lib/gitlab/metrics/exporter/sidekiq_exporter_spec.rb b/spec/lib/gitlab/metrics/exporter/sidekiq_exporter_spec.rb
new file mode 100644
index 00000000000..a415b6407d5
--- /dev/null
+++ b/spec/lib/gitlab/metrics/exporter/sidekiq_exporter_spec.rb
@@ -0,0 +1,65 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Metrics::Exporter::SidekiqExporter do
+ let(:exporter) { described_class.new }
+
+ after do
+ exporter.stop
+ end
+
+ context 'with valid config' do
+ before do
+ stub_config(
+ monitoring: {
+ sidekiq_exporter: {
+ enabled: true,
+ port: 0,
+ address: '127.0.0.1'
+ }
+ }
+ )
+ end
+
+ it 'does start thread' do
+ expect(exporter.start).not_to be_nil
+ end
+ end
+
+ context 'when port is already taken' do
+ let(:first_exporter) { described_class.new }
+
+ before do
+ stub_config(
+ monitoring: {
+ sidekiq_exporter: {
+ enabled: true,
+ port: 9992,
+ address: '127.0.0.1'
+ }
+ }
+ )
+
+ first_exporter.start
+ end
+
+ after do
+ first_exporter.stop
+ end
+
+ it 'does print error message' do
+ expect(Sidekiq.logger).to receive(:error)
+ .with(
+ class: described_class.to_s,
+ message: 'Cannot start sidekiq_exporter',
+ exception: anything)
+
+ exporter.start
+ end
+
+ it 'does not start thread' do
+ expect(exporter.start).to be_nil
+ end
+ end
+end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 7513dbeeb6f..f6ace0d8bf5 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -265,7 +265,8 @@ describe Gitlab::ReferenceExtractor do
describe 'referables prefixes' do
def prefixes
described_class::REFERABLES.each_with_object({}) do |referable, result|
- klass = referable.to_s.camelize.constantize
+ class_name = referable.to_s.camelize
+ klass = class_name.constantize if Object.const_defined?(class_name)
next unless klass.respond_to?(:reference_prefix)
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index 702a6fab0e6..7bef3d30064 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -60,6 +60,10 @@ describe ApplicationSetting do
it { is_expected.not_to allow_value('three').for(:push_event_hooks_limit) }
it { is_expected.not_to allow_value(nil).for(:push_event_hooks_limit) }
+ it { is_expected.to allow_value(3).for(:push_event_activities_limit) }
+ it { is_expected.not_to allow_value('three').for(:push_event_activities_limit) }
+ it { is_expected.not_to allow_value(nil).for(:push_event_activities_limit) }
+
context "when user accepted let's encrypt terms of service" do
before do
setting.update(lets_encrypt_terms_of_service_accepted: true)
diff --git a/spec/models/gpg_signature_spec.rb b/spec/models/gpg_signature_spec.rb
index 4911375c962..dd18c8842ab 100644
--- a/spec/models/gpg_signature_spec.rb
+++ b/spec/models/gpg_signature_spec.rb
@@ -60,6 +60,18 @@ RSpec.describe GpgSignature do
end
end
+ describe '.by_commit_sha scope' do
+ let(:gpg_key) { create(:gpg_key, key: GpgHelpers::User2.public_key) }
+ let!(:another_gpg_signature) { create(:gpg_signature, gpg_key: gpg_key) }
+
+ it 'returns all gpg signatures by sha' do
+ expect(described_class.by_commit_sha(commit_sha)).to eq([gpg_signature])
+ expect(
+ described_class.by_commit_sha([commit_sha, another_gpg_signature.commit_sha])
+ ).to contain_exactly(gpg_signature, another_gpg_signature)
+ end
+ end
+
describe '#commit' do
it 'fetches the commit through the project' do
expect_any_instance_of(Project).to receive(:commit).with(commit_sha).and_return(commit)
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 83c7464757f..8a47b8c206b 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -972,13 +972,13 @@ describe Note do
project = create(:project)
note = create(:note_on_issue, project: project)
- expect(note.parent).to eq(project)
+ expect(note.resource_parent).to eq(project)
end
it 'returns nil for personal snippet note' do
note = create(:note_on_personal_snippet)
- expect(note.parent).to be_nil
+ expect(note.resource_parent).to be_nil
end
end
diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb
index 2fc772b12af..992fd5e9c66 100644
--- a/spec/requests/api/events_spec.rb
+++ b/spec/requests/api/events_spec.rb
@@ -122,6 +122,7 @@ describe API::Events do
expect(payload_hash['action']).to eq(payload.action)
expect(payload_hash['ref_type']).to eq(payload.ref_type)
expect(payload_hash['commit_to']).to eq(payload.commit_to)
+ expect(payload_hash['ref_count']).to eq(payload.ref_count)
end
end
diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb
index af1cf80e9d3..f3bfb258029 100644
--- a/spec/requests/api/settings_spec.rb
+++ b/spec/requests/api/settings_spec.rb
@@ -73,7 +73,8 @@ describe API::Settings, 'Settings' do
local_markdown_version: 3,
allow_local_requests_from_web_hooks_and_services: true,
allow_local_requests_from_system_hooks: false,
- push_event_hooks_limit: 2
+ push_event_hooks_limit: 2,
+ push_event_activities_limit: 2
}
expect(response).to have_gitlab_http_status(200)
@@ -104,6 +105,7 @@ describe API::Settings, 'Settings' do
expect(json_response['allow_local_requests_from_web_hooks_and_services']).to eq(true)
expect(json_response['allow_local_requests_from_system_hooks']).to eq(false)
expect(json_response['push_event_hooks_limit']).to eq(2)
+ expect(json_response['push_event_activities_limit']).to eq(2)
end
end
diff --git a/spec/serializers/container_repository_entity_spec.rb b/spec/serializers/container_repository_entity_spec.rb
index 5848dd64c3b..799a8d5c122 100644
--- a/spec/serializers/container_repository_entity_spec.rb
+++ b/spec/serializers/container_repository_entity_spec.rb
@@ -25,6 +25,18 @@ describe ContainerRepositoryEntity do
expect(subject).to include(:id, :path, :location, :tags_path)
end
+ context 'when project is not preset in the request' do
+ before do
+ allow(request).to receive(:respond_to?).and_return(false)
+ allow(request).to receive(:project).and_return(nil)
+ end
+
+ it 'uses project from the object' do
+ expect(request.project).not_to equal(project)
+ expect(subject).to include(:tags_path)
+ end
+ end
+
context 'when user can manage repositories' do
before do
project.add_developer(user)
diff --git a/spec/services/boards/issues/create_service_spec.rb b/spec/services/boards/issues/create_service_spec.rb
index 33637419f83..ef7b7fdbaac 100644
--- a/spec/services/boards/issues/create_service_spec.rb
+++ b/spec/services/boards/issues/create_service_spec.rb
@@ -10,7 +10,7 @@ describe Boards::Issues::CreateService do
let(:label) { create(:label, project: project, name: 'in-progress') }
let!(:list) { create(:list, board: board, label: label, position: 0) }
- subject(:service) { described_class.new(board.parent, project, user, board_id: board.id, list_id: list.id, title: 'New issue') }
+ subject(:service) { described_class.new(board.resource_parent, project, user, board_id: board.id, list_id: list.id, title: 'New issue') }
before do
project.add_developer(user)
diff --git a/spec/services/boards/lists/update_service_spec.rb b/spec/services/boards/lists/update_service_spec.rb
index a5411a2fb3a..243e0fc50ad 100644
--- a/spec/services/boards/lists/update_service_spec.rb
+++ b/spec/services/boards/lists/update_service_spec.rb
@@ -9,9 +9,9 @@ describe Boards::Lists::UpdateService do
shared_examples 'moving list' do
context 'when user can admin list' do
it 'calls Lists::MoveService to update list position' do
- board.parent.add_developer(user)
+ board.resource_parent.add_developer(user)
- expect(Boards::Lists::MoveService).to receive(:new).with(board.parent, user, params).and_call_original
+ expect(Boards::Lists::MoveService).to receive(:new).with(board.resource_parent, user, params).and_call_original
expect_any_instance_of(Boards::Lists::MoveService).to receive(:execute).with(list)
service.execute(list)
@@ -30,7 +30,7 @@ describe Boards::Lists::UpdateService do
shared_examples 'updating list preferences' do
context 'when user can read list' do
it 'updates list preference for user' do
- board.parent.add_guest(user)
+ board.resource_parent.add_guest(user)
service.execute(list)
@@ -48,7 +48,7 @@ describe Boards::Lists::UpdateService do
end
describe '#execute' do
- let(:service) { described_class.new(board.parent, user, params) }
+ let(:service) { described_class.new(board.resource_parent, user, params) }
context 'when position parameter is present' do
let(:params) { { position: 1 } }
diff --git a/spec/services/boards/visits/create_service_spec.rb b/spec/services/boards/visits/create_service_spec.rb
index 6baf7ac9deb..203c287f396 100644
--- a/spec/services/boards/visits/create_service_spec.rb
+++ b/spec/services/boards/visits/create_service_spec.rb
@@ -10,7 +10,7 @@ describe Boards::Visits::CreateService do
let(:project) { create(:project) }
let(:project_board) { create(:board, project: project) }
- subject(:service) { described_class.new(project_board.parent, user) }
+ subject(:service) { described_class.new(project_board.resource_parent, user) }
it 'returns nil when there is no user' do
service.current_user = nil
@@ -35,7 +35,7 @@ describe Boards::Visits::CreateService do
let(:group) { create(:group) }
let(:group_board) { create(:board, group: group) }
- subject(:service) { described_class.new(group_board.parent, user) }
+ subject(:service) { described_class.new(group_board.resource_parent, user) }
it 'returns nil when there is no user' do
service.current_user = nil
diff --git a/spec/services/bulk_push_event_payload_service_spec.rb b/spec/services/bulk_push_event_payload_service_spec.rb
new file mode 100644
index 00000000000..661c3540aa0
--- /dev/null
+++ b/spec/services/bulk_push_event_payload_service_spec.rb
@@ -0,0 +1,27 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe BulkPushEventPayloadService do
+ let(:event) { create(:push_event) }
+
+ let(:push_data) do
+ {
+ action: :created,
+ ref_count: 4,
+ ref_type: :branch
+ }
+ end
+
+ subject { described_class.new(event, push_data) }
+
+ it 'creates a PushEventPayload' do
+ push_event_payload = subject.execute
+
+ expect(push_event_payload).to be_persisted
+ expect(push_event_payload.action).to eq(push_data[:action].to_s)
+ expect(push_event_payload.commit_count).to eq(0)
+ expect(push_event_payload.ref_count).to eq(push_data[:ref_count])
+ expect(push_event_payload.ref_type).to eq(push_data[:ref_type].to_s)
+ end
+end
diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb
index 9f2c3fec62c..eb738ac80b1 100644
--- a/spec/services/event_create_service_spec.rb
+++ b/spec/services/event_create_service_spec.rb
@@ -113,40 +113,21 @@ describe EventCreateService do
end
end
- describe '#push', :clean_gitlab_redis_shared_state do
- let(:project) { create(:project) }
- let(:user) { create(:user) }
-
- let(:push_data) do
- {
- commits: [
- {
- id: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
- message: 'This is a commit'
- }
- ],
- before: '0000000000000000000000000000000000000000',
- after: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
- total_commits_count: 1,
- ref: 'refs/heads/my-branch'
- }
- end
-
+ shared_examples_for 'service for creating a push event' do |service_class|
it 'creates a new event' do
- expect { service.push(project, user, push_data) }.to change { Event.count }
+ expect { subject }.to change { Event.count }
end
it 'creates the push event payload' do
- expect(PushEventPayloadService).to receive(:new)
+ expect(service_class).to receive(:new)
.with(an_instance_of(PushEvent), push_data)
.and_call_original
- service.push(project, user, push_data)
+ subject
end
it 'updates user last activity' do
- expect { service.push(project, user, push_data) }
- .to change { user.last_activity_on }.to(Date.today)
+ expect { subject }.to change { user.last_activity_on }.to(Date.today)
end
it 'caches the last push event for the user' do
@@ -154,7 +135,7 @@ describe EventCreateService do
.to receive(:cache_last_push_event)
.with(an_instance_of(PushEvent))
- service.push(project, user, push_data)
+ subject
end
it 'does not create any event data when an error is raised' do
@@ -163,17 +144,56 @@ describe EventCreateService do
allow(payload_service).to receive(:execute)
.and_raise(RuntimeError)
- allow(PushEventPayloadService).to receive(:new)
+ allow(service_class).to receive(:new)
.and_return(payload_service)
- expect { service.push(project, user, push_data) }
- .to raise_error(RuntimeError)
-
+ expect { subject }.to raise_error(RuntimeError)
expect(Event.count).to eq(0)
expect(PushEventPayload.count).to eq(0)
end
end
+ describe '#push', :clean_gitlab_redis_shared_state do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ let(:push_data) do
+ {
+ commits: [
+ {
+ id: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
+ message: 'This is a commit'
+ }
+ ],
+ before: '0000000000000000000000000000000000000000',
+ after: '1cf19a015df3523caf0a1f9d40c98a267d6a2fc2',
+ total_commits_count: 1,
+ ref: 'refs/heads/my-branch'
+ }
+ end
+
+ subject { service.push(project, user, push_data) }
+
+ it_behaves_like 'service for creating a push event', PushEventPayloadService
+ end
+
+ describe '#bulk_push', :clean_gitlab_redis_shared_state do
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ let(:push_data) do
+ {
+ action: :created,
+ ref_count: 4,
+ ref_type: :branch
+ }
+ end
+
+ subject { service.bulk_push(project, user, push_data) }
+
+ it_behaves_like 'service for creating a push event', BulkPushEventPayloadService
+ end
+
describe 'Project' do
let(:user) { create :user }
let(:project) { create(:project) }
diff --git a/spec/services/git/base_hooks_service_spec.rb b/spec/services/git/base_hooks_service_spec.rb
index 90b3eb38469..f3f6b36a18d 100644
--- a/spec/services/git/base_hooks_service_spec.rb
+++ b/spec/services/git/base_hooks_service_spec.rb
@@ -12,8 +12,8 @@ describe Git::BaseHooksService do
let(:newrev) { "8a2a6eb295bb170b34c24c76c49ed0e9b2eaf34b" } # gitlab-test: git rev-parse refs/tags/v1.1.0
let(:ref) { 'refs/tags/v1.1.0' }
- describe '#execute_project_hooks' do
- class TestService < described_class
+ let(:test_service) do
+ Class.new(described_class) do
def hook_name
:push_hooks
end
@@ -22,22 +22,44 @@ describe Git::BaseHooksService do
[]
end
end
+ end
- let(:project) { create(:project, :repository) }
+ subject { test_service.new(project, user, params) }
- let(:params) do
- {
- change: {
- oldrev: oldrev,
- newrev: newrev,
- ref: ref
- }
+ let(:params) do
+ {
+ change: {
+ oldrev: oldrev,
+ newrev: newrev,
+ ref: ref
}
+ }
+ end
+
+ describe 'push event' do
+ it 'creates push event' do
+ expect_next_instance_of(EventCreateService) do |service|
+ expect(service).to receive(:push)
+ end
+
+ subject.execute
end
- subject { TestService.new(project, user, params) }
+ context 'create_push_event is set to false' do
+ before do
+ params[:create_push_event] = false
+ end
+
+ it 'does not create push event' do
+ expect(EventCreateService).not_to receive(:new)
+
+ subject.execute
+ end
+ end
+ end
- context '#execute_hooks' do
+ describe 'project hooks and services' do
+ context 'hooks' do
before do
expect(project).to receive(:has_active_hooks?).and_return(active)
end
@@ -65,7 +87,7 @@ describe Git::BaseHooksService do
end
end
- context '#execute_services' do
+ context 'services' do
before do
expect(project).to receive(:has_active_services?).and_return(active)
end
diff --git a/spec/services/git/process_ref_changes_service_spec.rb b/spec/services/git/process_ref_changes_service_spec.rb
index eeb395f6c7b..35ddf95b5f6 100644
--- a/spec/services/git/process_ref_changes_service_spec.rb
+++ b/spec/services/git/process_ref_changes_service_spec.rb
@@ -13,6 +13,12 @@ describe Git::ProcessRefChangesService do
let(:service) { double(execute: true) }
let(:git_changes) { double(branch_changes: [], tag_changes: []) }
+ def multiple_changes(change, count)
+ Array.new(count).map.with_index do |n, index|
+ { index: index, oldrev: change[:oldrev], newrev: change[:newrev], ref: "#{change[:ref]}#{n}" }
+ end
+ end
+
let(:changes) do
[
{ index: 0, oldrev: Gitlab::Git::BLANK_SHA, newrev: '789012', ref: "#{ref_prefix}/create" },
@@ -28,7 +34,7 @@ describe Git::ProcessRefChangesService do
it "calls #{push_service_class}" do
expect(push_service_class)
.to receive(:new)
- .with(project, project.owner, hash_including(execute_project_hooks: true))
+ .with(project, project.owner, hash_including(execute_project_hooks: true, create_push_event: true))
.exactly(changes.count).times
.and_return(service)
@@ -36,12 +42,6 @@ describe Git::ProcessRefChangesService do
end
context 'changes exceed push_event_hooks_limit' do
- def multiple_changes(change, count)
- Array.new(count).map.with_index do |n, index|
- { index: index, oldrev: change[:oldrev], newrev: change[:newrev], ref: "#{change[:ref]}#{n}" }
- end
- end
-
let(:push_event_hooks_limit) { 3 }
let(:changes) do
@@ -88,6 +88,40 @@ describe Git::ProcessRefChangesService do
end
end
+ context 'changes exceed push_event_activities_limit per action' do
+ let(:push_event_activities_limit) { 3 }
+
+ let(:changes) do
+ [
+ { oldrev: Gitlab::Git::BLANK_SHA, newrev: '789012', ref: "#{ref_prefix}/create" },
+ { oldrev: '123456', newrev: '789012', ref: "#{ref_prefix}/update" },
+ { oldrev: '123456', newrev: Gitlab::Git::BLANK_SHA, ref: "#{ref_prefix}/delete" }
+ ].map do |change|
+ multiple_changes(change, push_event_activities_limit + 1)
+ end.flatten
+ end
+
+ before do
+ stub_application_setting(push_event_activities_limit: push_event_activities_limit)
+ end
+
+ it "calls #{push_service_class} with create_push_event set to false" do
+ expect(push_service_class)
+ .to receive(:new)
+ .with(project, project.owner, hash_including(create_push_event: false))
+ .exactly(changes.count).times
+ .and_return(service)
+
+ subject.execute
+ end
+
+ it 'creates events per action' do
+ allow(push_service_class).to receive(:new).and_return(service)
+
+ expect { subject.execute }.to change { Event.count }.by(3)
+ end
+ end
+
context 'pipeline creation' do
context 'with valid .gitlab-ci.yml' do
before do
diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb
index ec68e1a8cf9..788f83cc233 100644
--- a/spec/services/quick_actions/interpret_service_spec.rb
+++ b/spec/services/quick_actions/interpret_service_spec.rb
@@ -1545,12 +1545,20 @@ describe QuickActions::InterpretService do
end
it 'limits to commands passed ' do
- content = "/shrug\n/close"
+ content = "/shrug test\n/close"
text, commands = service.execute(content, issue, only: [:shrug])
expect(commands).to be_empty
- expect(text).to eq("#{described_class::SHRUG}\n/close")
+ expect(text).to eq("test #{described_class::SHRUG}\n/close")
+ end
+
+ it 'preserves leading whitespace ' do
+ content = " - list\n\n/close\n\ntest\n\n"
+
+ text, _ = service.execute(content, issue)
+
+ expect(text).to eq(" - list\n\ntest")
end
context '/create_merge_request command' do
diff --git a/spec/support/api/boards_shared_examples.rb b/spec/support/api/boards_shared_examples.rb
index b7aff32460d..d41490f33e4 100644
--- a/spec/support/api/boards_shared_examples.rb
+++ b/spec/support/api/boards_shared_examples.rb
@@ -171,7 +171,7 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false|
if board_parent.try(:namespace)
board_parent.update(namespace: owner.namespace)
else
- board.parent.add_owner(owner)
+ board.resource_parent.add_owner(owner)
end
end
diff --git a/spec/support/api/milestones_shared_examples.rb b/spec/support/api/milestones_shared_examples.rb
index d6439f77408..ce8c2140e99 100644
--- a/spec/support/api/milestones_shared_examples.rb
+++ b/spec/support/api/milestones_shared_examples.rb
@@ -205,7 +205,7 @@ shared_examples_for 'group and project milestones' do |route_definition|
describe "DELETE #{route_definition}/:milestone_id" do
it "rejects a member with reporter access from deleting a milestone" do
reporter = create(:user)
- milestone.parent.add_reporter(reporter)
+ milestone.resource_parent.add_reporter(reporter)
delete api(resource_route, reporter)
diff --git a/spec/support/shared_examples/services/boards/boards_create_service.rb b/spec/support/shared_examples/services/boards/boards_create_service.rb
index 19818a6091b..7fd69354c2d 100644
--- a/spec/support/shared_examples/services/boards/boards_create_service.rb
+++ b/spec/support/shared_examples/services/boards/boards_create_service.rb
@@ -17,7 +17,7 @@ shared_examples 'boards create service' do
context 'when parent has a board' do
before do
- create(:board, parent: parent)
+ create(:board, resource_parent: parent)
end
it 'does not create a new board' do
diff --git a/spec/support/shared_examples/services/boards/boards_list_service.rb b/spec/support/shared_examples/services/boards/boards_list_service.rb
index 566e5050f8e..25dc2e04942 100644
--- a/spec/support/shared_examples/services/boards/boards_list_service.rb
+++ b/spec/support/shared_examples/services/boards/boards_list_service.rb
@@ -15,7 +15,7 @@ shared_examples 'boards list service' do
context 'when parent has a board' do
before do
- create(:board, parent: parent)
+ create(:board, resource_parent: parent)
end
it 'does not create a new board' do
@@ -24,7 +24,7 @@ shared_examples 'boards list service' do
end
it 'returns parent boards' do
- board = create(:board, parent: parent)
+ board = create(:board, resource_parent: parent)
expect(service.execute).to eq [board]
end
diff --git a/spec/views/events/event/_push.html.haml_spec.rb b/spec/views/events/event/_push.html.haml_spec.rb
index e43e37188a3..d33a8aa86fc 100644
--- a/spec/views/events/event/_push.html.haml_spec.rb
+++ b/spec/views/events/event/_push.html.haml_spec.rb
@@ -28,6 +28,23 @@ describe 'events/event/_push.html.haml' do
expect(rendered).not_to have_link(event.ref_name)
end
end
+
+ context 'ref_count is more than 1' do
+ let(:payload) do
+ build_stubbed(
+ :push_event_payload,
+ event: event,
+ ref_count: 4,
+ ref_type: :branch
+ )
+ end
+
+ it 'includes the count in the text' do
+ render partial: 'events/event/push', locals: { event: event }
+
+ expect(rendered).to include('4 branches')
+ end
+ end
end
context 'with a tag' do
@@ -53,5 +70,22 @@ describe 'events/event/_push.html.haml' do
expect(rendered).not_to have_link(event.ref_name)
end
end
+
+ context 'ref_count is more than 1' do
+ let(:payload) do
+ build_stubbed(
+ :push_event_payload,
+ event: event,
+ ref_count: 4,
+ ref_type: :tag
+ )
+ end
+
+ it 'includes the count in the text' do
+ render partial: 'events/event/push', locals: { event: event }
+
+ expect(rendered).to include('4 tags')
+ end
+ end
end
end