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:
authorDouglas Barbosa Alexandre <dbalexandre@gmail.com>2019-09-10 23:03:14 +0300
committerDouglas Barbosa Alexandre <dbalexandre@gmail.com>2019-09-10 23:03:14 +0300
commitcfe77ce4a3494b9c1516fe7e915f76b21a68e763 (patch)
treecef43c4d6c2fdee57ad19ab6815e41617eace2f2 /spec
parent934d4925d85f22c67e7ad57f607e8fe430a9ea92 (diff)
parent95d16dc007f3fe8831f2baa511bbb7bd708baff0 (diff)
Merge remote-tracking branch 'origin/master' into camilstaps/gitlab-ce-new-66023-public-private-fork-counts
Diffstat (limited to 'spec')
-rw-r--r--spec/fixtures/api/schemas/public_api/v4/tag.json3
-rw-r--r--spec/fixtures/valid.po5
-rw-r--r--spec/helpers/events_helper_spec.rb2
-rw-r--r--spec/helpers/releases_helper_spec.rb46
-rw-r--r--spec/javascripts/monitoring/components/graph_group_spec.js47
-rw-r--r--spec/javascripts/sidebar/mock_data.js10
-rw-r--r--spec/javascripts/sidebar/sidebar_assignees_spec.js4
-rw-r--r--spec/javascripts/sidebar/sidebar_mediator_spec.js33
-rw-r--r--spec/javascripts/sidebar/sidebar_move_issue_spec.js13
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml1
-rw-r--r--spec/lib/gitlab/repository_cache_adapter_spec.rb7
-rw-r--r--spec/lib/gitlab/repository_set_cache_spec.rb75
-rw-r--r--spec/lib/gitlab/sidekiq_daemon/monitor_spec.rb (renamed from spec/lib/gitlab/sidekiq_monitor_spec.rb)4
-rw-r--r--spec/lib/gitlab/sidekiq_middleware/monitor_spec.rb6
-rw-r--r--spec/lib/gitlab/utils/strong_memoize_spec.rb16
-rw-r--r--spec/presenters/event_presenter_spec.rb41
-rw-r--r--spec/routing/project_routing_spec.rb70
-rw-r--r--spec/rubocop/cop/scalability/file_uploads_spec.rb54
-rw-r--r--spec/services/ci/retry_build_service_spec.rb2
-rw-r--r--spec/services/merge_requests/build_service_spec.rb108
-rw-r--r--spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb54
21 files changed, 478 insertions, 123 deletions
diff --git a/spec/fixtures/api/schemas/public_api/v4/tag.json b/spec/fixtures/api/schemas/public_api/v4/tag.json
index 5713ea1f526..bb0190955f0 100644
--- a/spec/fixtures/api/schemas/public_api/v4/tag.json
+++ b/spec/fixtures/api/schemas/public_api/v4/tag.json
@@ -16,7 +16,8 @@
{ "type": "null" },
{ "$ref": "release/tag_release.json" }
]
- }
+ },
+ "protected": { "type": "boolean" }
},
"additionalProperties": false
}
diff --git a/spec/fixtures/valid.po b/spec/fixtures/valid.po
index 155b6cbb95d..28826f05595 100644
--- a/spec/fixtures/valid.po
+++ b/spec/fixtures/valid.po
@@ -1128,3 +1128,8 @@ msgid "parent"
msgid_plural "parents"
msgstr[0] "padre"
msgstr[1] "padres"
+
+msgid "CycleAnalytics|%{stageName}"
+msgid_plural "CycleAnalytics|%d stages selected"
+msgstr[0] "%{stageName}"
+msgstr[1] "%d stages selected"
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index 3d15306d4d2..e062c841717 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -27,7 +27,7 @@ describe EventsHelper do
end
describe '#event_feed_url' do
- let(:event) { create(:event) }
+ let(:event) { create(:event).present }
let(:project) { create(:project, :public, :repository) }
context 'issue' do
diff --git a/spec/helpers/releases_helper_spec.rb b/spec/helpers/releases_helper_spec.rb
new file mode 100644
index 00000000000..ff820b3cc95
--- /dev/null
+++ b/spec/helpers/releases_helper_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe ReleasesHelper do
+ describe '#illustration' do
+ it 'returns the correct image path' do
+ expect(helper.illustration).to match(/illustrations\/releases-(\w+)\.svg/)
+ end
+ end
+
+ describe '#help_page' do
+ it 'returns the correct link to the help page' do
+ expect(helper.help_page).to include('user/project/releases/index')
+ end
+ end
+
+ context 'url helpers' do
+ let(:project) { build(:project, namespace: create(:group)) }
+
+ before do
+ helper.instance_variable_set(:@project, project)
+ end
+
+ describe '#url_for_merge_requests' do
+ it 'returns the the correct link with the correct parameters' do
+ path = "#{project.group.path}/#{project.path}/merge_requests?scope=all&state=opened"
+ expect(helper.url_for_merge_requests).to include(path)
+ end
+ end
+
+ describe '#url_for_issues' do
+ it 'returns the the correct link with the correct parameters' do
+ path = "#{project.group.path}/#{project.path}/issues?scope=all&state=opened"
+ expect(helper.url_for_issues).to include(path)
+ end
+ end
+
+ describe '#data_for_releases_page' do
+ it 'has the needed data to display release blocks' do
+ keys = %i(project_id illustration_path documentation_path merge_requests_url issues_url)
+ expect(helper.data_for_releases_page.keys).to eq(keys)
+ end
+ end
+ end
+end
diff --git a/spec/javascripts/monitoring/components/graph_group_spec.js b/spec/javascripts/monitoring/components/graph_group_spec.js
new file mode 100644
index 00000000000..068c4b5302c
--- /dev/null
+++ b/spec/javascripts/monitoring/components/graph_group_spec.js
@@ -0,0 +1,47 @@
+import { shallowMount } from '@vue/test-utils';
+import GraphGroup from '~/monitoring/components/graph_group.vue';
+
+describe('Graph group component', () => {
+ let graphGroup;
+
+ afterEach(() => {
+ graphGroup.destroy();
+ });
+
+ describe('When groups can be collapsed', () => {
+ beforeEach(() => {
+ graphGroup = shallowMount(GraphGroup, {
+ propsData: {
+ name: 'panel',
+ collapseGroup: true,
+ },
+ });
+ });
+
+ it('should show the angle-down caret icon when collapseGroup is true', () => {
+ expect(graphGroup.vm.caretIcon).toBe('angle-down');
+ });
+
+ it('should show the angle-right caret icon when collapseGroup is false', () => {
+ graphGroup.vm.collapse();
+
+ expect(graphGroup.vm.caretIcon).toBe('angle-right');
+ });
+ });
+
+ describe('When groups can not be collapsed', () => {
+ beforeEach(() => {
+ graphGroup = shallowMount(GraphGroup, {
+ propsData: {
+ name: 'panel',
+ collapseGroup: true,
+ showPanels: false,
+ },
+ });
+ });
+
+ it('should not contain a prometheus-graph-group container when showPanels is false', () => {
+ expect(graphGroup.vm.$el.querySelector('.prometheus-graph-group')).toBe(null);
+ });
+ });
+});
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index 7f20b0da991..3ee97b978fd 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -210,14 +210,4 @@ const mockData = {
},
};
-mockData.sidebarMockInterceptor = function(request, next) {
- const body = this.responseMap[request.method.toUpperCase()][request.url];
-
- next(
- request.respondWith(JSON.stringify(body), {
- status: 200,
- }),
- );
-}.bind(mockData);
-
export default mockData;
diff --git a/spec/javascripts/sidebar/sidebar_assignees_spec.js b/spec/javascripts/sidebar/sidebar_assignees_spec.js
index 016f5e033a5..e808f4003ff 100644
--- a/spec/javascripts/sidebar/sidebar_assignees_spec.js
+++ b/spec/javascripts/sidebar/sidebar_assignees_spec.js
@@ -1,4 +1,3 @@
-import _ from 'underscore';
import Vue from 'vue';
import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees.vue';
import SidebarMediator from '~/sidebar/sidebar_mediator';
@@ -14,8 +13,6 @@ describe('sidebar assignees', () => {
preloadFixtures('issues/open-issue.html');
beforeEach(() => {
- Vue.http.interceptors.push(Mock.sidebarMockInterceptor);
-
loadFixtures('issues/open-issue.html');
mediator = new SidebarMediator(Mock.mediator);
@@ -38,7 +35,6 @@ describe('sidebar assignees', () => {
SidebarService.singleton = null;
SidebarStore.singleton = null;
SidebarMediator.singleton = null;
- Vue.http.interceptors = _.without(Vue.http.interceptors, Mock.sidebarMockInterceptor);
});
it('calls the mediator when saves the assignees', () => {
diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js
index 6c69c08e733..b0412105e3f 100644
--- a/spec/javascripts/sidebar/sidebar_mediator_spec.js
+++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js
@@ -1,31 +1,37 @@
-import _ from 'underscore';
-import Vue from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarStore from '~/sidebar/stores/sidebar_store';
import SidebarService from '~/sidebar/services/sidebar_service';
import Mock from './mock_data';
+const { mediator: mediatorMockData } = Mock;
+
describe('Sidebar mediator', function() {
+ let mock;
+
beforeEach(() => {
- Vue.http.interceptors.push(Mock.sidebarMockInterceptor);
- this.mediator = new SidebarMediator(Mock.mediator);
+ mock = new MockAdapter(axios);
+
+ this.mediator = new SidebarMediator(mediatorMockData);
});
afterEach(() => {
SidebarService.singleton = null;
SidebarStore.singleton = null;
SidebarMediator.singleton = null;
- Vue.http.interceptors = _.without(Vue.http.interceptors, Mock.sidebarMockInterceptor);
+ mock.restore();
});
it('assigns yourself ', () => {
this.mediator.assignYourself();
- expect(this.mediator.store.currentUser).toEqual(Mock.mediator.currentUser);
- expect(this.mediator.store.assignees[0]).toEqual(Mock.mediator.currentUser);
+ expect(this.mediator.store.currentUser).toEqual(mediatorMockData.currentUser);
+ expect(this.mediator.store.assignees[0]).toEqual(mediatorMockData.currentUser);
});
it('saves assignees', done => {
+ mock.onPut(mediatorMockData.endpoint).reply(200, {});
this.mediator
.saveAssignees('issue[assignee_ids]')
.then(resp => {
@@ -36,8 +42,8 @@ describe('Sidebar mediator', function() {
});
it('fetches the data', done => {
- const mockData =
- Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras'];
+ const mockData = Mock.responseMap.GET[mediatorMockData.endpoint];
+ mock.onGet(mediatorMockData.endpoint).reply(200, mockData);
spyOn(this.mediator, 'processFetchedData').and.callThrough();
this.mediator
@@ -50,8 +56,7 @@ describe('Sidebar mediator', function() {
});
it('processes fetched data', () => {
- const mockData =
- Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras'];
+ const mockData = Mock.responseMap.GET[mediatorMockData.endpoint];
this.mediator.processFetchedData(mockData);
expect(this.mediator.store.assignees).toEqual(mockData.assignees);
@@ -74,6 +79,7 @@ describe('Sidebar mediator', function() {
it('fetches autocomplete projects', done => {
const searchTerm = 'foo';
+ mock.onGet(mediatorMockData.projectsAutocompleteEndpoint).reply(200, {});
spyOn(this.mediator.service, 'getProjectsAutocomplete').and.callThrough();
spyOn(this.mediator.store, 'setAutocompleteProjects').and.callThrough();
@@ -88,7 +94,9 @@ describe('Sidebar mediator', function() {
});
it('moves issue', done => {
+ const mockData = Mock.responseMap.POST[mediatorMockData.moveIssueEndpoint];
const moveToProjectId = 7;
+ mock.onPost(mediatorMockData.moveIssueEndpoint).reply(200, mockData);
this.mediator.store.setMoveToProjectId(moveToProjectId);
spyOn(this.mediator.service, 'moveIssue').and.callThrough();
const visitUrl = spyOnDependency(SidebarMediator, 'visitUrl');
@@ -97,7 +105,7 @@ describe('Sidebar mediator', function() {
.moveIssue()
.then(() => {
expect(this.mediator.service.moveIssue).toHaveBeenCalledWith(moveToProjectId);
- expect(visitUrl).toHaveBeenCalledWith('/root/some-project/issues/5');
+ expect(visitUrl).toHaveBeenCalledWith(mockData.web_url);
})
.then(done)
.catch(done.fail);
@@ -105,6 +113,7 @@ describe('Sidebar mediator', function() {
it('toggle subscription', done => {
this.mediator.store.setSubscribedState(false);
+ mock.onPost(mediatorMockData.toggleSubscriptionEndpoint).reply(200, {});
spyOn(this.mediator.service, 'toggleSubscription').and.callThrough();
this.mediator
diff --git a/spec/javascripts/sidebar/sidebar_move_issue_spec.js b/spec/javascripts/sidebar/sidebar_move_issue_spec.js
index 230e0a933a9..ec712450f2e 100644
--- a/spec/javascripts/sidebar/sidebar_move_issue_spec.js
+++ b/spec/javascripts/sidebar/sidebar_move_issue_spec.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
-import _ from 'underscore';
-import Vue from 'vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from '~/lib/utils/axios_utils';
import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarStore from '~/sidebar/stores/sidebar_store';
import SidebarService from '~/sidebar/services/sidebar_service';
@@ -8,8 +8,12 @@ import SidebarMoveIssue from '~/sidebar/lib/sidebar_move_issue';
import Mock from './mock_data';
describe('SidebarMoveIssue', function() {
+ let mock;
+
beforeEach(() => {
- Vue.http.interceptors.push(Mock.sidebarMockInterceptor);
+ mock = new MockAdapter(axios);
+ const mockData = Mock.responseMap.GET['/autocomplete/projects?project_id=15'];
+ mock.onGet('/autocomplete/projects?project_id=15').reply(200, mockData);
this.mediator = new SidebarMediator(Mock.mediator);
this.$content = $(`
<div class="dropdown">
@@ -37,8 +41,7 @@ describe('SidebarMoveIssue', function() {
SidebarMediator.singleton = null;
this.sidebarMoveIssue.destroy();
-
- Vue.http.interceptors = _.without(Vue.http.interceptors, Mock.sidebarMockInterceptor);
+ mock.restore();
});
describe('init', () => {
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index dafa4243145..e496ab4cd35 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -376,6 +376,7 @@ project:
- index_status
- feature_usage
- approval_rules
+- approval_merge_request_rules
- approvers
- approver_users
- pages_domains
diff --git a/spec/lib/gitlab/repository_cache_adapter_spec.rb b/spec/lib/gitlab/repository_cache_adapter_spec.rb
index 808eb865a21..fd1338b55a6 100644
--- a/spec/lib/gitlab/repository_cache_adapter_spec.rb
+++ b/spec/lib/gitlab/repository_cache_adapter_spec.rb
@@ -6,6 +6,7 @@ describe Gitlab::RepositoryCacheAdapter do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:cache) { repository.send(:cache) }
+ let(:redis_set_cache) { repository.send(:redis_set_cache) }
describe '#cache_method_output', :use_clean_rails_memory_store_caching do
let(:fallback) { 10 }
@@ -208,9 +209,11 @@ describe Gitlab::RepositoryCacheAdapter do
describe '#expire_method_caches' do
it 'expires the caches of the given methods' do
expect(cache).to receive(:expire).with(:rendered_readme)
- expect(cache).to receive(:expire).with(:gitignore)
+ expect(cache).to receive(:expire).with(:branch_names)
+ expect(redis_set_cache).to receive(:expire).with(:rendered_readme)
+ expect(redis_set_cache).to receive(:expire).with(:branch_names)
- repository.expire_method_caches(%i(rendered_readme gitignore))
+ repository.expire_method_caches(%i(rendered_readme branch_names))
end
it 'does not expire caches for non-existent methods' do
diff --git a/spec/lib/gitlab/repository_set_cache_spec.rb b/spec/lib/gitlab/repository_set_cache_spec.rb
new file mode 100644
index 00000000000..87e51f801e5
--- /dev/null
+++ b/spec/lib/gitlab/repository_set_cache_spec.rb
@@ -0,0 +1,75 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::RepositorySetCache, :clean_gitlab_redis_cache do
+ let(:project) { create(:project) }
+ let(:repository) { project.repository }
+ let(:namespace) { "#{repository.full_path}:#{project.id}" }
+ let(:cache) { described_class.new(repository) }
+
+ describe '#cache_key' do
+ subject { cache.cache_key(:foo) }
+
+ it 'includes the namespace' do
+ is_expected.to eq("foo:#{namespace}:set")
+ end
+
+ context 'with a given namespace' do
+ let(:extra_namespace) { 'my:data' }
+ let(:cache) { described_class.new(repository, extra_namespace: extra_namespace) }
+
+ it 'includes the full namespace' do
+ is_expected.to eq("foo:#{namespace}:#{extra_namespace}:set")
+ end
+ end
+ end
+
+ describe '#expire' do
+ it 'expires the given key from the cache' do
+ cache.write(:foo, ['value'])
+
+ expect(cache.read(:foo)).to contain_exactly('value')
+ expect(cache.expire(:foo)).to eq(1)
+ expect(cache.read(:foo)).to be_empty
+ end
+ end
+
+ describe '#exist?' do
+ it 'checks whether the key exists' do
+ expect(cache.exist?(:foo)).to be(false)
+
+ cache.write(:foo, ['value'])
+
+ expect(cache.exist?(:foo)).to be(true)
+ end
+ end
+
+ describe '#fetch' do
+ let(:blk) { -> { ['block value'] } }
+
+ subject { cache.fetch(:foo, &blk) }
+
+ it 'fetches the key from the cache when filled' do
+ cache.write(:foo, ['value'])
+
+ is_expected.to contain_exactly('value')
+ end
+
+ it 'writes the value of the provided block when empty' do
+ cache.expire(:foo)
+
+ is_expected.to contain_exactly('block value')
+ expect(cache.read(:foo)).to contain_exactly('block value')
+ end
+ end
+
+ describe '#include?' do
+ it 'checks inclusion in the Redis set' do
+ cache.write(:foo, ['value'])
+
+ expect(cache.include?(:foo, 'value')).to be(true)
+ expect(cache.include?(:foo, 'bar')).to be(false)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_monitor_spec.rb b/spec/lib/gitlab/sidekiq_daemon/monitor_spec.rb
index bbd7bf90217..acbb09e3542 100644
--- a/spec/lib/gitlab/sidekiq_monitor_spec.rb
+++ b/spec/lib/gitlab/sidekiq_daemon/monitor_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe Gitlab::SidekiqMonitor do
+describe Gitlab::SidekiqDaemon::Monitor do
let(:monitor) { described_class.new }
describe '#within_job' do
@@ -43,7 +43,7 @@ describe Gitlab::SidekiqMonitor do
before do
# we want to run at most once cycle
# we toggle `enabled?` flag after the first call
- stub_const('Gitlab::SidekiqMonitor::RECONNECT_TIME', 0)
+ stub_const('Gitlab::SidekiqDaemon::Monitor::RECONNECT_TIME', 0)
allow(monitor).to receive(:enabled?).and_return(true, false)
allow(Sidekiq.logger).to receive(:info)
diff --git a/spec/lib/gitlab/sidekiq_middleware/monitor_spec.rb b/spec/lib/gitlab/sidekiq_middleware/monitor_spec.rb
index 7319cdc2399..023df1a6391 100644
--- a/spec/lib/gitlab/sidekiq_middleware/monitor_spec.rb
+++ b/spec/lib/gitlab/sidekiq_middleware/monitor_spec.rb
@@ -10,8 +10,8 @@ describe Gitlab::SidekiqMiddleware::Monitor do
let(:job) { { 'jid' => 'job-id' } }
let(:queue) { 'my-queue' }
- it 'calls SidekiqMonitor' do
- expect(Gitlab::SidekiqMonitor.instance).to receive(:within_job)
+ it 'calls Gitlab::SidekiqDaemon::Monitor' do
+ expect(Gitlab::SidekiqDaemon::Monitor.instance).to receive(:within_job)
.with('job-id', 'my-queue')
.and_call_original
@@ -29,7 +29,7 @@ describe Gitlab::SidekiqMiddleware::Monitor do
context 'when cancel happens' do
subject do
monitor.call(worker, job, queue) do
- raise Gitlab::SidekiqMonitor::CancelledError
+ raise Gitlab::SidekiqDaemon::Monitor::CancelledError
end
end
diff --git a/spec/lib/gitlab/utils/strong_memoize_spec.rb b/spec/lib/gitlab/utils/strong_memoize_spec.rb
index 26baaf873a8..624e799c5e9 100644
--- a/spec/lib/gitlab/utils/strong_memoize_spec.rb
+++ b/spec/lib/gitlab/utils/strong_memoize_spec.rb
@@ -52,6 +52,22 @@ describe Gitlab::Utils::StrongMemoize do
end
end
+ describe '#strong_memoized?' do
+ let(:value) { :anything }
+
+ subject { object.strong_memoized?(:method_name) }
+
+ it 'returns false if the value is uncached' do
+ is_expected.to be(false)
+ end
+
+ it 'returns true if the value is cached' do
+ object.method_name
+
+ is_expected.to be(true)
+ end
+ end
+
describe '#clear_memoization' do
let(:value) { 'mepmep' }
diff --git a/spec/presenters/event_presenter_spec.rb b/spec/presenters/event_presenter_spec.rb
new file mode 100644
index 00000000000..79f5e359141
--- /dev/null
+++ b/spec/presenters/event_presenter_spec.rb
@@ -0,0 +1,41 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe EventPresenter do
+ include Gitlab::Routing.url_helpers
+
+ set(:group) { create(:group) }
+ set(:project) { create(:project, group: group) }
+ set(:target) { create(:milestone, project: project) }
+ set(:group_event) { create(:event, :created, project: nil, group: group, target: target) }
+ set(:project_event) { create(:event, :created, project: project, target: target) }
+
+ describe '#resource_parent_name' do
+ context 'with group event' do
+ subject { group_event.present.resource_parent_name }
+
+ it { is_expected.to eq(group.full_name) }
+ end
+
+ context 'with project label' do
+ subject { project_event.present.resource_parent_name }
+
+ it { is_expected.to eq(project.full_name) }
+ end
+ end
+
+ describe '#target_link_options' do
+ context 'with group event' do
+ subject { group_event.present.target_link_options }
+
+ it { is_expected.to eq([group, target]) }
+ end
+
+ context 'with project label' do
+ subject { project_event.present.target_link_options }
+
+ it { is_expected.to eq([group.becomes(Namespace), project, target]) }
+ end
+ end
+end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 8a3de2a52fc..7e2d70d6eb5 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -530,15 +530,22 @@ describe 'project routing' do
end
end
- # project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /.+/, project_id: /[^\/]+/}
+ # project_blame GET /:project_id/blame/:id(.:format) blame#show {id: /[^\0]+/, project_id: /[^\/]+/}
describe Projects::BlameController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/blame/master/app/models/project.rb')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
expect(get('/gitlab/gitlabhq/blame/master/files.scss')).to route_to('projects/blame#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/blame/master/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blame', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/#{newline_file}" })
end
end
- # project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /.+/, project_id: /[^\/]+/}
+ # project_blob GET /:project_id/blob/:id(.:format) blob#show {id: /[^\0]+/, project_id: /[^\/]+/}
describe Projects::BlobController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/blob/master/app/models/project.rb')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
@@ -547,28 +554,56 @@ describe 'project routing' do
expect(get('/gitlab/gitlabhq/blob/master/files.scss')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
expect(get('/gitlab/gitlabhq/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/blob/index.js')
expect(get('/gitlab/gitlabhq/blob/blob/master/blob/index.js')).to route_to('projects/blob#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'blob/master/blob/index.js')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/blob/blob/master/blob/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blob', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "blob/master/blob/#{newline_file}" })
end
end
- # project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /.+/, project_id: /[^\/]+/}
+ # project_tree GET /:project_id/tree/:id(.:format) tree#show {id: /[^\0]+/, project_id: /[^\/]+/}
describe Projects::TreeController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/tree/master/app/models/project.rb')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/app/models/project.rb')
expect(get('/gitlab/gitlabhq/tree/master/files.scss')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/files.scss')
expect(get('/gitlab/gitlabhq/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master/tree/files')
expect(get('/gitlab/gitlabhq/tree/tree/master/tree/files')).to route_to('projects/tree#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'tree/master/tree/files')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/tree/master/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/tree', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/#{newline_file}" })
end
end
- # project_find_file GET /:namespace_id/:project_id/find_file/*id(.:format) projects/find_file#show {:id=>/.+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/html/}
+ # project_find_file GET /:namespace_id/:project_id/find_file/*id(.:format) projects/find_file#show {:id=>/[^\0]+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/html/}
# project_files GET /:namespace_id/:project_id/files/*id(.:format) projects/find_file#list {:id=>/(?:[^.]|\.(?!json$))+/, :namespace_id=>/[a-zA-Z.0-9_\-]+/, :project_id=>/[a-zA-Z.0-9_\-]+(?<!\.atom)/, :format=>/json/}
describe Projects::FindFileController, 'routing' do
it 'to #show' do
expect(get('/gitlab/gitlabhq/find_file/master')).to route_to('projects/find_file#show', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/find_file/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/find_file', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "#{newline_file}" })
end
it 'to #list' do
expect(get('/gitlab/gitlabhq/files/master.json')).to route_to('projects/find_file#list', namespace_id: 'gitlab', project_id: 'gitlabhq', id: 'master.json')
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/files/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/find_file', action: 'list',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "#{newline_file}" })
end
end
@@ -578,6 +613,13 @@ describe 'project routing' do
route_to('projects/blob#edit',
namespace_id: 'gitlab', project_id: 'gitlabhq',
id: 'master/app/models/project.rb'))
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/edit/master/docs/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blob', action: 'edit',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/docs/#{newline_file}" })
end
it 'to #preview' do
@@ -585,6 +627,26 @@ describe 'project routing' do
route_to('projects/blob#preview',
namespace_id: 'gitlab', project_id: 'gitlabhq',
id: 'master/app/models/project.rb'))
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/edit/master/docs/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/blob', action: 'edit',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/docs/#{newline_file}" })
+ end
+ end
+
+ # project_raw GET /:project_id/raw/:id(.:format) raw#show {id: /[^\0]+/, project_id: /[^\/]+/}
+ describe Projects::RawController, 'routing' do
+ it 'to #show' do
+ newline_file = "new\n\nline.txt"
+ url_encoded_newline_file = ERB::Util.url_encode(newline_file)
+ assert_routing({ path: "/gitlab/gitlabhq/raw/master/#{url_encoded_newline_file}",
+ method: :get },
+ { controller: 'projects/raw', action: 'show',
+ namespace_id: 'gitlab', project_id: 'gitlabhq',
+ id: "master/#{newline_file}" })
end
end
diff --git a/spec/rubocop/cop/scalability/file_uploads_spec.rb b/spec/rubocop/cop/scalability/file_uploads_spec.rb
new file mode 100644
index 00000000000..2a94fde5ba2
--- /dev/null
+++ b/spec/rubocop/cop/scalability/file_uploads_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'fast_spec_helper'
+require 'rubocop'
+require_relative '../../../support/helpers/expect_offense'
+require_relative '../../../../rubocop/cop/scalability/file_uploads'
+
+describe RuboCop::Cop::Scalability::FileUploads do
+ include CopHelper
+ include ExpectOffense
+
+ subject(:cop) { described_class.new }
+ let(:message) { 'Do not upload files without workhorse acceleration. Please refer to https://docs.gitlab.com/ee/development/uploads.html' }
+
+ context 'with required params' do
+ it 'detects File in types array' do
+ expect_offense(<<~PATTERN.strip_indent)
+ params do
+ requires :certificate, allow_blank: false, types: [String, File]
+ ^^^^ #{message}
+ end
+ PATTERN
+ end
+
+ it 'detects File as type argument' do
+ expect_offense(<<~PATTERN.strip_indent)
+ params do
+ requires :attachment, type: File
+ ^^^^ #{message}
+ end
+ PATTERN
+ end
+ end
+
+ context 'with optional params' do
+ it 'detects File in types array' do
+ expect_offense(<<~PATTERN.strip_indent)
+ params do
+ optional :certificate, allow_blank: false, types: [String, File]
+ ^^^^ #{message}
+ end
+ PATTERN
+ end
+
+ it 'detects File as type argument' do
+ expect_offense(<<~PATTERN.strip_indent)
+ params do
+ optional :attachment, type: File
+ ^^^^ #{message}
+ end
+ PATTERN
+ end
+ end
+end
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index fe7c6fe4700..281c7438eee 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -40,7 +40,7 @@ describe Ci::RetryBuildService do
user_id auto_canceled_by_id retried failure_reason
sourced_pipelines artifacts_file_store artifacts_metadata_store
metadata runner_session trace_chunks upstream_pipeline_id
- artifacts_file artifacts_metadata artifacts_size].freeze
+ artifacts_file artifacts_metadata artifacts_size commands].freeze
shared_examples 'build duplication' do
let(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index f18239f6d39..d546a092680 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -49,6 +49,22 @@ describe MergeRequests::BuildService do
allow(project).to receive(:commit).and_return(commit_2)
end
+ shared_examples 'allows the merge request to be created' do
+ it do
+ expect(merge_request.can_be_created).to eq(true)
+ end
+ end
+
+ shared_examples 'forbids the merge request from being created' do
+ it 'returns that the merge request cannot be created' do
+ expect(merge_request.can_be_created).to eq(false)
+ end
+
+ it 'adds an error message to the merge request' do
+ expect(merge_request.errors).to contain_exactly(*Array(error_message))
+ end
+ end
+
describe '#execute' do
it 'calls the compare service with the correct arguments' do
allow_any_instance_of(described_class).to receive(:projects_and_branches_valid?).and_return(true)
@@ -79,12 +95,8 @@ describe MergeRequests::BuildService do
context 'missing source branch' do
let(:source_branch) { '' }
- it 'forbids the merge request from being created' do
- expect(merge_request.can_be_created).to eq(false)
- end
-
- it 'adds an error message to the merge request' do
- expect(merge_request.errors).to contain_exactly('You must select source and target branch')
+ it_behaves_like 'forbids the merge request from being created' do
+ let(:error_message) { 'You must select source and target branch' }
end
end
@@ -96,25 +108,44 @@ describe MergeRequests::BuildService do
stub_compare
end
- it 'creates compare object with target branch as default branch' do
- expect(merge_request.compare).to be_present
- expect(merge_request.target_branch).to eq(project.default_branch)
- end
+ context 'when source branch' do
+ context 'is not the repository default branch' do
+ it 'creates compare object with target branch as default branch' do
+ expect(merge_request.compare).to be_present
+ expect(merge_request.target_branch).to eq(project.default_branch)
+ end
+
+ it_behaves_like 'allows the merge request to be created'
+ end
+
+ context 'the repository default branch' do
+ let(:source_branch) { 'master' }
+
+ it_behaves_like 'forbids the merge request from being created' do
+ let(:error_message) { 'You must select source and target branch' }
+ end
- it 'allows the merge request to be created' do
- expect(merge_request.can_be_created).to eq(true)
+ context 'when source project is different from the target project' do
+ let(:target_project) { create(:project, :public, :repository) }
+ let!(:project) { fork_project(target_project, user, namespace: user.namespace, repository: true) }
+ let(:source_project) { project }
+
+ it 'creates compare object with target branch as default branch' do
+ expect(merge_request.compare).to be_present
+ expect(merge_request.target_branch).to eq(project.default_branch)
+ end
+
+ it_behaves_like 'allows the merge request to be created'
+ end
+ end
end
end
context 'same source and target branch' do
let(:source_branch) { 'master' }
- it 'forbids the merge request from being created' do
- expect(merge_request.can_be_created).to eq(false)
- end
-
- it 'adds an error message to the merge request' do
- expect(merge_request.errors).to contain_exactly('You must select different branches')
+ it_behaves_like 'forbids the merge request from being created' do
+ let(:error_message) { 'You must select different branches' }
end
end
@@ -125,9 +156,7 @@ describe MergeRequests::BuildService do
stub_compare
end
- it 'allows the merge request to be created' do
- expect(merge_request.can_be_created).to eq(true)
- end
+ it_behaves_like 'allows the merge request to be created'
it 'adds a WIP prefix to the merge request title' do
expect(merge_request.title).to eq('WIP: Feature branch')
@@ -142,9 +171,7 @@ describe MergeRequests::BuildService do
stub_compare
end
- it 'allows the merge request to be created' do
- expect(merge_request.can_be_created).to eq(true)
- end
+ it_behaves_like 'allows the merge request to be created'
it 'uses the title of the commit as the title of the merge request' do
expect(merge_request.title).to eq(commit_1.safe_message.split("\n").first)
@@ -254,9 +281,7 @@ describe MergeRequests::BuildService do
stub_compare
end
- it 'allows the merge request to be created' do
- expect(merge_request.can_be_created).to eq(true)
- end
+ it_behaves_like 'allows the merge request to be created'
it 'uses the title of the branch as the merge request title' do
expect(merge_request.title).to eq('Feature branch')
@@ -340,12 +365,8 @@ describe MergeRequests::BuildService do
allow(project).to receive(:commit).with(target_branch).and_return(commit_1)
end
- it 'forbids the merge request from being created' do
- expect(merge_request.can_be_created).to eq(false)
- end
-
- it 'adds an error message to the merge request' do
- expect(merge_request.errors).to contain_exactly('Source branch "feature-branch" does not exist')
+ it_behaves_like 'forbids the merge request from being created' do
+ let(:error_message) { 'Source branch "feature-branch" does not exist' }
end
end
@@ -355,12 +376,8 @@ describe MergeRequests::BuildService do
allow(project).to receive(:commit).with(target_branch).and_return(nil)
end
- it 'forbids the merge request from being created' do
- expect(merge_request.can_be_created).to eq(false)
- end
-
- it 'adds an error message to the merge request' do
- expect(merge_request.errors).to contain_exactly('Target branch "master" does not exist')
+ it_behaves_like 'forbids the merge request from being created' do
+ let(:error_message) { 'Target branch "master" does not exist' }
end
end
@@ -369,15 +386,10 @@ describe MergeRequests::BuildService do
allow(project).to receive(:commit).and_return(nil)
end
- it 'forbids the merge request from being created' do
- expect(merge_request.can_be_created).to eq(false)
- end
-
- it 'adds both error messages to the merge request' do
- expect(merge_request.errors).to contain_exactly(
- 'Source branch "feature-branch" does not exist',
- 'Target branch "master" does not exist'
- )
+ it_behaves_like 'forbids the merge request from being created' do
+ let(:error_message) do
+ ['Source branch "feature-branch" does not exist', 'Target branch "master" does not exist']
+ end
end
end
diff --git a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
index 76d82649c5f..f2f31e1b7f2 100644
--- a/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
+++ b/spec/support/shared_examples/boards/multiple_issue_boards_shared_examples.rb
@@ -1,8 +1,6 @@
# frozen_string_literal: true
shared_examples_for 'multiple issue boards' do
- dropdown_selector = '.js-boards-selector .dropdown-menu'
-
context 'authorized user' do
before do
parent.add_maintainer(user)
@@ -20,18 +18,14 @@ shared_examples_for 'multiple issue boards' do
end
it 'shows a list of boards' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
expect(page).to have_content(board.name)
expect(page).to have_content(board2.name)
end
end
it 'switches current board' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_link board2.name
end
@@ -43,9 +37,7 @@ shared_examples_for 'multiple issue boards' do
end
it 'creates new board without detailed configuration' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_button 'Create new board'
end
@@ -57,28 +49,23 @@ shared_examples_for 'multiple issue boards' do
end
it 'deletes board' do
- click_button board.name
-
- wait_for_requests
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_button 'Delete board'
end
expect(page).to have_content('Are you sure you want to delete this board?')
click_button 'Delete'
- click_button board2.name
- page.within(dropdown_selector) do
+ wait_for_requests
+
+ in_boards_switcher_dropdown do
expect(page).not_to have_content(board.name)
expect(page).to have_content(board2.name)
end
end
it 'adds a list to the none default board' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_link board2.name
end
@@ -100,9 +87,7 @@ shared_examples_for 'multiple issue boards' do
expect(page).to have_selector('.board', count: 3)
- click_button board2.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
click_link board.name
end
@@ -114,9 +99,9 @@ shared_examples_for 'multiple issue boards' do
it 'maintains sidebar state over board switch' do
assert_boards_nav_active
- find('.boards-switcher').click
- wait_for_requests
- click_link board2.name
+ in_boards_switcher_dropdown do
+ click_link board2.name
+ end
assert_boards_nav_active
end
@@ -129,15 +114,24 @@ shared_examples_for 'multiple issue boards' do
end
it 'does not show action links' do
- click_button board.name
-
- page.within(dropdown_selector) do
+ in_boards_switcher_dropdown do
expect(page).not_to have_content('Create new board')
expect(page).not_to have_content('Delete board')
end
end
end
+ def in_boards_switcher_dropdown
+ find('.boards-switcher').click
+
+ wait_for_requests
+
+ dropdown_selector = '.js-boards-selector .dropdown-menu'
+ page.within(dropdown_selector) do
+ yield
+ end
+ end
+
def assert_boards_nav_active
expect(find('.nav-sidebar .active .active')).to have_selector('a', text: 'Boards')
end