summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorKamil Trzcinski <ayufan@ayufan.eu>2017-12-05 13:29:41 +0100
committerKamil Trzcinski <ayufan@ayufan.eu>2017-12-05 13:29:41 +0100
commit9429514e303bdceee0621b5c4bf02ad8ca0a7add (patch)
treea7bc5cc425601c4ea73ff9a9be90eebc21a93b17 /spec
parentb9d8d85e20af046c7dbe11c69fd3252f0486b9b2 (diff)
parent3138fcdcd70fd30fea74deff537b9836d6c94d21 (diff)
downloadgitlab-ce-9429514e303bdceee0621b5c4bf02ad8ca0a7add.tar.gz
Merge branch '35616-move-k8-to-cluster-page' into cluster-page-with-list-clusters
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/clusters/gcp_controller_spec.rb2
-rw-r--r--spec/controllers/projects/clusters/user_controller_spec.rb2
-rw-r--r--spec/controllers/projects/clusters_controller_spec.rb38
-rw-r--r--spec/controllers/projects_controller_spec.rb21
-rw-r--r--spec/features/projects/clusters/applications_spec.rb2
-rw-r--r--spec/features/projects/clusters/gcp_spec.rb8
-rw-r--r--spec/features/projects/clusters/user_spec.rb11
-rw-r--r--spec/features/projects/pipelines/pipeline_spec.rb30
-rw-r--r--spec/helpers/markup_helper_spec.rb2
-rw-r--r--spec/javascripts/boards/issue_spec.js6
-rw-r--r--spec/javascripts/notes/components/note_actions_spec.js (renamed from spec/javascripts/notes/components/issue_note_actions_spec.js)4
-rw-r--r--spec/javascripts/notes/components/note_attachment_spec.js (renamed from spec/javascripts/notes/components/issue_note_attachment_spec.js)4
-rw-r--r--spec/javascripts/notes/components/note_awards_list_spec.js (renamed from spec/javascripts/notes/components/issue_note_awards_list_spec.js)4
-rw-r--r--spec/javascripts/notes/components/note_edited_text_spec.js (renamed from spec/javascripts/notes/components/issue_note_edited_text_spec.js)6
-rw-r--r--spec/javascripts/notes/components/note_header_spec.js (renamed from spec/javascripts/notes/components/issue_note_header_spec.js)6
-rw-r--r--spec/javascripts/notes/components/note_signed_out_widget_spec.js (renamed from spec/javascripts/notes/components/issue_note_signed_out_widget_spec.js)6
-rw-r--r--spec/javascripts/pipelines/graph/job_component_spec.js65
-rw-r--r--spec/javascripts/sidebar/mock_data.js82
-rw-r--r--spec/javascripts/sidebar/sidebar_mediator_spec.js27
-rw-r--r--spec/javascripts/sidebar/sidebar_store_spec.js6
-rw-r--r--spec/lib/api/helpers/pagination_spec.rb21
-rw-r--r--spec/lib/gitlab/git/storage/circuit_breaker_spec.rb19
-rw-r--r--spec/lib/gitlab/git/storage/health_spec.rb1
-rw-r--r--spec/lib/gitlab/shell_spec.rb8
-rw-r--r--spec/lib/google_api/cloud_platform/client_spec.rb24
-rw-r--r--spec/mailers/notify_spec.rb4
-rw-r--r--spec/models/namespace_spec.rb10
-rw-r--r--spec/models/project_spec.rb6
-rw-r--r--spec/models/repository_spec.rb60
-rw-r--r--spec/requests/api/groups_spec.rb14
-rw-r--r--spec/services/notification_service_spec.rb28
-rw-r--r--spec/services/projects/count_service_spec.rb12
-rw-r--r--spec/support/query_recorder.rb19
-rw-r--r--spec/workers/repository_fork_worker_spec.rb77
34 files changed, 440 insertions, 195 deletions
diff --git a/spec/controllers/projects/clusters/gcp_controller_spec.rb b/spec/controllers/projects/clusters/gcp_controller_spec.rb
index e0fe291e724..bb5ef7bb365 100644
--- a/spec/controllers/projects/clusters/gcp_controller_spec.rb
+++ b/spec/controllers/projects/clusters/gcp_controller_spec.rb
@@ -16,7 +16,7 @@ describe Projects::Clusters::GcpController do
end
context 'when omniauth has been configured' do
- let(:key) { 'secere-key' }
+ let(:key) { 'secret-key' }
let(:session_key_for_redirect_uri) do
GoogleApi::CloudPlatform::Client.session_key_for_redirect_uri(key)
diff --git a/spec/controllers/projects/clusters/user_controller_spec.rb b/spec/controllers/projects/clusters/user_controller_spec.rb
index 06a9c50c5cc..22005e0dc66 100644
--- a/spec/controllers/projects/clusters/user_controller_spec.rb
+++ b/spec/controllers/projects/clusters/user_controller_spec.rb
@@ -58,7 +58,7 @@ describe Projects::Clusters::UserController do
project.add_master(user)
sign_in(user)
end
-
+
context 'when creates a cluster' do
it 'creates a new cluster' do
expect(ClusterProvisionWorker).to receive(:perform_async)
diff --git a/spec/controllers/projects/clusters_controller_spec.rb b/spec/controllers/projects/clusters_controller_spec.rb
index 9ff0b745073..806e33e0e4e 100644
--- a/spec/controllers/projects/clusters_controller_spec.rb
+++ b/spec/controllers/projects/clusters_controller_spec.rb
@@ -181,7 +181,7 @@ describe Projects::ClustersController do
end
describe 'PUT update' do
- context 'Managed' do
+ context 'when cluster is provided by GCP' do
let(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let(:user) { create(:user) }
@@ -207,7 +207,7 @@ describe Projects::ClustersController do
go
cluster.reload
- expect(response).to redirect_to(namespace_project_cluster_path(project.namespace, project, project.cluster))
+ expect(response).to redirect_to(project_cluster_path(project, project.cluster))
expect(flash[:notice]).to eq('Cluster was successfully updated.')
expect(cluster.enabled).to be_falsey
end
@@ -232,7 +232,7 @@ describe Projects::ClustersController do
end
end
- context 'User' do
+ context 'when cluster is provided by user' do
let(:cluster) { create(:cluster, :provided_by_user, projects: [project]) }
let(:user) { create(:user) }
@@ -317,7 +317,7 @@ describe Projects::ClustersController do
end
describe 'security' do
- set(:cluster) { create(:cluster, :providing_by_gcp, projects: [project]) }
+ set(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
let(:params) do
{ cluster: { enabled: false } }
@@ -335,8 +335,8 @@ describe Projects::ClustersController do
def go
put :update, params.merge(namespace_id: project.namespace,
- project_id: project,
- id: cluster)
+ project_id: project,
+ id: cluster)
end
def go_json
@@ -356,7 +356,7 @@ describe Projects::ClustersController do
sign_in(user)
end
- context 'GCP' do
+ context 'when cluster is provided by GCP' do
context 'when cluster is created' do
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
@@ -366,7 +366,7 @@ describe Projects::ClustersController do
.and change { Clusters::Platforms::Kubernetes.count }.by(-1)
.and change { Clusters::Providers::Gcp.count }.by(-1)
- expect(response).to redirect_to(namespace_project_clusters_path(project.namespace, project))
+ expect(response).to redirect_to(project_clusters_path(project))
expect(flash[:notice]).to eq('Cluster integration was successfully removed.')
end
end
@@ -379,25 +379,23 @@ describe Projects::ClustersController do
.to change { Clusters::Cluster.count }.by(-1)
.and change { Clusters::Providers::Gcp.count }.by(-1)
- expect(response).to redirect_to(namespace_project_clusters_path(project.namespace, project))
+ expect(response).to redirect_to(project_clusters_path(project))
expect(flash[:notice]).to eq('Cluster integration was successfully removed.')
end
end
end
- context 'User' do
- context 'when provider is user' do
- let!(:cluster) { create(:cluster, :provided_by_user, projects: [project]) }
+ context 'when cluster is provided by user' do
+ let!(:cluster) { create(:cluster, :provided_by_user, projects: [project]) }
- it "destroys and redirects back to clusters list" do
- expect { go }
- .to change { Clusters::Cluster.count }.by(-1)
- .and change { Clusters::Platforms::Kubernetes.count }.by(-1)
- .and change { Clusters::Providers::Gcp.count }.by(0)
+ it "destroys and redirects back to clusters list" do
+ expect { go }
+ .to change { Clusters::Cluster.count }.by(-1)
+ .and change { Clusters::Platforms::Kubernetes.count }.by(-1)
+ .and change { Clusters::Providers::Gcp.count }.by(0)
- expect(response).to redirect_to(namespace_project_clusters_path(project.namespace, project))
- expect(flash[:notice]).to eq('Cluster integration was successfully removed.')
- end
+ expect(response).to redirect_to(project_clusters_path(project))
+ expect(flash[:notice]).to eq('Cluster integration was successfully removed.')
end
end
end
diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index e7ab714c550..e4b2bbb7c51 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -261,6 +261,27 @@ describe ProjectsController do
expect(response).to redirect_to(namespace_project_path)
end
end
+
+ context 'when the project is forked and has a repository', :request_store do
+ let(:public_project) { create(:project, :public, :repository) }
+ let(:other_user) { create(:user) }
+
+ render_views
+
+ before do
+ # View the project as a user that does not have any rights
+ sign_in(other_user)
+
+ fork_project(public_project)
+ end
+
+ it 'does not increase the number of queries when the project is forked' do
+ expected_query = /#{public_project.fork_network.find_forks_in(other_user.namespace).to_sql}/
+
+ expect { get(:show, namespace_id: public_project.namespace, id: public_project) }
+ .not_to exceed_query_limit(1).for_query(expected_query)
+ end
+ end
end
describe "#update" do
diff --git a/spec/features/projects/clusters/applications_spec.rb b/spec/features/projects/clusters/applications_spec.rb
index 6104bad0125..b34cd061ec6 100644
--- a/spec/features/projects/clusters/applications_spec.rb
+++ b/spec/features/projects/clusters/applications_spec.rb
@@ -18,7 +18,7 @@ feature 'Clusters Applications', :js do
context 'when cluster is being created' do
let(:cluster) { create(:cluster, :providing_by_gcp, projects: [project])}
-
+
scenario 'user is unable to install applications' do
page.within('.js-cluster-application-row-helm') do
expect(page.find(:css, '.js-cluster-application-install-button')['disabled']).to eq('true')
diff --git a/spec/features/projects/clusters/gcp_spec.rb b/spec/features/projects/clusters/gcp_spec.rb
index 82f94dc4422..5a00b463960 100644
--- a/spec/features/projects/clusters/gcp_spec.rb
+++ b/spec/features/projects/clusters/gcp_spec.rb
@@ -90,18 +90,18 @@ feature 'Gcp Cluster', :js do
page.find(:css, '.js-toggle-cluster').click
click_button 'Save'
end
-
+
it 'user sees the successful message' do
expect(page).to have_content('Cluster was successfully updated.')
end
end
-
+
context 'when user changes cluster parameters' do
before do
fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace'
click_button 'Save changes'
end
-
+
it 'user sees the successful message' do
expect(page).to have_content('Cluster was successfully updated.')
expect(cluster.reload.platform_kubernetes.namespace).to eq('my-namespace')
@@ -114,7 +114,7 @@ feature 'Gcp Cluster', :js do
click_link 'Remove integration'
end
end
-
+
it 'user sees creation form with the successful message' do
expect(page).to have_content('Cluster integration was successfully removed.')
expect(page).to have_link('Add cluster')
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index c30f13c4682..414f4acba86 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -22,14 +22,19 @@ feature 'User Cluster', :js do
context 'when user filled form with valid parameters' do
before do
+ fill_in 'cluster_name', with: 'dev-cluster'
fill_in 'cluster_platform_kubernetes_attributes_api_url', with: 'http://example.com'
fill_in 'cluster_platform_kubernetes_attributes_token', with: 'my-token'
- fill_in 'cluster_name', with: 'dev-cluster'
click_button 'Add cluster'
end
- it 'user sees a cluster details page and creation status' do
- expect(page).to have_content('Cluster was successfully created on Google Container Engine')
+ it 'user sees a cluster details page' do
+ expect(page).to have_content('Enable cluster integration')
+ expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
+ expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
+ .to have_content('http://example.com')
+ expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
+ .to have_content('my-token')
end
end
diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb
index b8fa1a54c24..888e290292b 100644
--- a/spec/features/projects/pipelines/pipeline_spec.rb
+++ b/spec/features/projects/pipelines/pipeline_spec.rb
@@ -185,6 +185,36 @@ describe 'Pipeline', :js do
end
end
+ context 'when user does not have access to read jobs' do
+ before do
+ project.update(public_builds: false)
+ end
+
+ describe 'GET /:project/pipelines/:id' do
+ include_context 'pipeline builds'
+
+ let(:project) { create(:project, :repository) }
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id, user: user) }
+
+ before do
+ visit project_pipeline_path(project, pipeline)
+ end
+
+ it 'shows the pipeline graph' do
+ expect(page).to have_selector('.pipeline-visualization')
+ expect(page).to have_content('Build')
+ expect(page).to have_content('Test')
+ expect(page).to have_content('Deploy')
+ expect(page).to have_content('Retry')
+ expect(page).to have_content('Cancel running')
+ end
+
+ it 'should not link to job' do
+ expect(page).not_to have_selector('.js-pipeline-graph-job-link')
+ end
+ end
+ end
+
describe 'GET /:project/pipelines/:id/builds' do
include_context 'pipeline builds'
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index 62ea6d48542..ba0039f3a11 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -205,7 +205,7 @@ describe MarkupHelper do
it "uses Wiki pipeline for markdown files" do
allow(@wiki).to receive(:format).and_return(:markdown)
- expect(helper).to receive(:markdown_unsafe).with('wiki content', pipeline: :wiki, project: project, project_wiki: @wiki, page_slug: "nested/page")
+ expect(helper).to receive(:markdown_unsafe).with('wiki content', pipeline: :wiki, project: project, project_wiki: @wiki, page_slug: "nested/page", issuable_state_filter_enabled: true)
helper.render_wiki_content(@wiki)
end
diff --git a/spec/javascripts/boards/issue_spec.js b/spec/javascripts/boards/issue_spec.js
index ccde657789a..10b88878c2a 100644
--- a/spec/javascripts/boards/issue_spec.js
+++ b/spec/javascripts/boards/issue_spec.js
@@ -146,6 +146,12 @@ describe('Issue model', () => {
expect(issue.isFetching.subscriptions).toBe(false);
});
+ it('sets loading state', () => {
+ issue.setLoadingState('foo', true);
+
+ expect(issue.isLoading.foo).toBe(true);
+ });
+
describe('update', () => {
it('passes assignee ids when there are assignees', (done) => {
spyOn(Vue.http, 'patch').and.callFake((url, data) => {
diff --git a/spec/javascripts/notes/components/issue_note_actions_spec.js b/spec/javascripts/notes/components/note_actions_spec.js
index 7bcc061f167..ab81aabb992 100644
--- a/spec/javascripts/notes/components/issue_note_actions_spec.js
+++ b/spec/javascripts/notes/components/note_actions_spec.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import store from '~/notes/stores';
-import issueActions from '~/notes/components/issue_note_actions.vue';
+import noteActions from '~/notes/components/note_actions.vue';
import { userDataMock } from '../mock_data';
describe('issse_note_actions component', () => {
@@ -8,7 +8,7 @@ describe('issse_note_actions component', () => {
let Component;
beforeEach(() => {
- Component = Vue.extend(issueActions);
+ Component = Vue.extend(noteActions);
});
afterEach(() => {
diff --git a/spec/javascripts/notes/components/issue_note_attachment_spec.js b/spec/javascripts/notes/components/note_attachment_spec.js
index 8f33b874ad6..b14a518b622 100644
--- a/spec/javascripts/notes/components/issue_note_attachment_spec.js
+++ b/spec/javascripts/notes/components/note_attachment_spec.js
@@ -1,5 +1,5 @@
import Vue from 'vue';
-import issueNoteAttachment from '~/notes/components/issue_note_attachment.vue';
+import noteAttachment from '~/notes/components/note_attachment.vue';
describe('issue note attachment', () => {
it('should render properly', () => {
@@ -11,7 +11,7 @@ describe('issue note attachment', () => {
},
};
- const Component = Vue.extend(issueNoteAttachment);
+ const Component = Vue.extend(noteAttachment);
const vm = new Component({
propsData: props,
}).$mount();
diff --git a/spec/javascripts/notes/components/issue_note_awards_list_spec.js b/spec/javascripts/notes/components/note_awards_list_spec.js
index c689c452143..15995ec5a05 100644
--- a/spec/javascripts/notes/components/issue_note_awards_list_spec.js
+++ b/spec/javascripts/notes/components/note_awards_list_spec.js
@@ -1,9 +1,9 @@
import Vue from 'vue';
import store from '~/notes/stores';
-import awardsNote from '~/notes/components/issue_note_awards_list.vue';
+import awardsNote from '~/notes/components/note_awards_list.vue';
import { noteableDataMock, notesDataMock } from '../mock_data';
-describe('issue_note_awards_list component', () => {
+describe('note_awards_list component', () => {
let vm;
let awardsMock;
diff --git a/spec/javascripts/notes/components/issue_note_edited_text_spec.js b/spec/javascripts/notes/components/note_edited_text_spec.js
index 6603241eb64..e0b991c32ec 100644
--- a/spec/javascripts/notes/components/issue_note_edited_text_spec.js
+++ b/spec/javascripts/notes/components/note_edited_text_spec.js
@@ -1,12 +1,12 @@
import Vue from 'vue';
-import issueNoteEditedText from '~/notes/components/issue_note_edited_text.vue';
+import noteEditedText from '~/notes/components/note_edited_text.vue';
-describe('issue_note_edited_text', () => {
+describe('note_edited_text', () => {
let vm;
let props;
beforeEach(() => {
- const Component = Vue.extend(issueNoteEditedText);
+ const Component = Vue.extend(noteEditedText);
props = {
actionText: 'Edited',
className: 'foo-bar',
diff --git a/spec/javascripts/notes/components/issue_note_header_spec.js b/spec/javascripts/notes/components/note_header_spec.js
index 83ea18508ae..16a76b11321 100644
--- a/spec/javascripts/notes/components/issue_note_header_spec.js
+++ b/spec/javascripts/notes/components/note_header_spec.js
@@ -1,13 +1,13 @@
import Vue from 'vue';
-import issueNoteHeader from '~/notes/components/issue_note_header.vue';
+import noteHeader from '~/notes/components/note_header.vue';
import store from '~/notes/stores';
-describe('issue_note_header component', () => {
+describe('note_header component', () => {
let vm;
let Component;
beforeEach(() => {
- Component = Vue.extend(issueNoteHeader);
+ Component = Vue.extend(noteHeader);
});
afterEach(() => {
diff --git a/spec/javascripts/notes/components/issue_note_signed_out_widget_spec.js b/spec/javascripts/notes/components/note_signed_out_widget_spec.js
index f20d9ce9268..6cba8053888 100644
--- a/spec/javascripts/notes/components/issue_note_signed_out_widget_spec.js
+++ b/spec/javascripts/notes/components/note_signed_out_widget_spec.js
@@ -1,13 +1,13 @@
import Vue from 'vue';
-import issueNoteSignedOut from '~/notes/components/issue_note_signed_out_widget.vue';
+import noteSignedOut from '~/notes/components/note_signed_out_widget.vue';
import store from '~/notes/stores';
import { notesDataMock } from '../mock_data';
-describe('issue_note_signed_out_widget component', () => {
+describe('note_signed_out_widget component', () => {
let vm;
beforeEach(() => {
- const Component = Vue.extend(issueNoteSignedOut);
+ const Component = Vue.extend(noteSignedOut);
store.dispatch('setNotesData', notesDataMock);
vm = new Component({
diff --git a/spec/javascripts/pipelines/graph/job_component_spec.js b/spec/javascripts/pipelines/graph/job_component_spec.js
index 342ee6c1242..23c87610d83 100644
--- a/spec/javascripts/pipelines/graph/job_component_spec.js
+++ b/spec/javascripts/pipelines/graph/job_component_spec.js
@@ -1,8 +1,10 @@
import Vue from 'vue';
import jobComponent from '~/pipelines/components/graph/job_component.vue';
+import mountComponent from '../../helpers/vue_mount_component_helper';
describe('pipeline graph job component', () => {
let JobComponent;
+ let component;
const mockJob = {
id: 4256,
@@ -13,6 +15,7 @@ describe('pipeline graph job component', () => {
label: 'passed',
group: 'success',
details_path: '/root/ci-mock/builds/4256',
+ has_details: true,
action: {
icon: 'retry',
title: 'Retry',
@@ -26,13 +29,13 @@ describe('pipeline graph job component', () => {
JobComponent = Vue.extend(jobComponent);
});
+ afterEach(() => {
+ component.$destroy();
+ });
+
describe('name with link', () => {
it('should render the job name and status with a link', (done) => {
- const component = new JobComponent({
- propsData: {
- job: mockJob,
- },
- }).$mount();
+ component = mountComponent(JobComponent, { job: mockJob });
Vue.nextTick(() => {
const link = component.$el.querySelector('a');
@@ -56,23 +59,23 @@ describe('pipeline graph job component', () => {
describe('name without link', () => {
it('it should render status and name', () => {
- const component = new JobComponent({
- propsData: {
- job: {
- id: 4256,
- name: 'test',
- status: {
- icon: 'icon_status_success',
- text: 'passed',
- label: 'passed',
- group: 'success',
- details_path: '/root/ci-mock/builds/4256',
- },
+ component = mountComponent(JobComponent, {
+ job: {
+ id: 4256,
+ name: 'test',
+ status: {
+ icon: 'icon_status_success',
+ text: 'passed',
+ label: 'passed',
+ group: 'success',
+ details_path: '/root/ci-mock/builds/4256',
+ has_details: false,
},
},
- }).$mount();
+ });
expect(component.$el.querySelector('.js-status-icon-success')).toBeDefined();
+ expect(component.$el.querySelector('a')).toBeNull();
expect(
component.$el.querySelector('.ci-status-text').textContent.trim(),
@@ -82,11 +85,7 @@ describe('pipeline graph job component', () => {
describe('action icon', () => {
it('it should render the action icon', () => {
- const component = new JobComponent({
- propsData: {
- job: mockJob,
- },
- }).$mount();
+ component = mountComponent(JobComponent, { job: mockJob });
expect(component.$el.querySelector('a.ci-action-icon-container')).toBeDefined();
expect(component.$el.querySelector('i.ci-action-icon-wrapper')).toBeDefined();
@@ -95,24 +94,20 @@ describe('pipeline graph job component', () => {
describe('dropdown', () => {
it('should render the dropdown action icon', () => {
- const component = new JobComponent({
- propsData: {
- job: mockJob,
- isDropdown: true,
- },
- }).$mount();
+ component = mountComponent(JobComponent, {
+ job: mockJob,
+ isDropdown: true,
+ });
expect(component.$el.querySelector('a.ci-action-icon-wrapper')).toBeDefined();
});
});
it('should render provided class name', () => {
- const component = new JobComponent({
- propsData: {
- job: mockJob,
- cssClassJobName: 'css-class-job-name',
- },
- }).$mount();
+ component = mountComponent(JobComponent, {
+ job: mockJob,
+ cssClassJobName: 'css-class-job-name',
+ });
expect(
component.$el.querySelector('a').classList.contains('css-class-job-name'),
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index 0682b463043..3b094d20838 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -1,6 +1,6 @@
/* eslint-disable quote-props*/
-const sidebarMockData = {
+const RESPONSE_MAP = {
'GET': {
'/gitlab-org/gitlab-shell/issues/5.json': {
id: 45,
@@ -66,6 +66,65 @@ const sidebarMockData = {
},
labels: [],
},
+ '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar': {
+ assignees: [
+ {
+ name: 'User 0',
+ username: 'user0',
+ id: 22,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/user0',
+ },
+ {
+ name: 'Marguerite Bartell',
+ username: 'tajuana',
+ id: 18,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/tajuana',
+ },
+ {
+ name: 'Laureen Ritchie',
+ username: 'michaele.will',
+ id: 16,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/michaele.will',
+ },
+ ],
+ human_time_estimate: null,
+ human_total_time_spent: null,
+ participants: [
+ {
+ name: 'User 0',
+ username: 'user0',
+ id: 22,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/user0',
+ },
+ {
+ name: 'Marguerite Bartell',
+ username: 'tajuana',
+ id: 18,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/tajuana',
+ },
+ {
+ name: 'Laureen Ritchie',
+ username: 'michaele.will',
+ id: 16,
+ state: 'active',
+ avatar_url: 'http: //www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/michaele.will',
+ },
+ ],
+ subscribed: true,
+ time_estimate: 0,
+ total_time_spent: 0,
+ },
'/autocomplete/projects?project_id=15': [
{
'id': 0,
@@ -113,9 +172,10 @@ const sidebarMockData = {
},
};
-export default {
+const mockData = {
+ responseMap: RESPONSE_MAP,
mediator: {
- endpoint: '/gitlab-org/gitlab-shell/issues/5.json',
+ endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar',
toggleSubscriptionEndpoint: '/gitlab-org/gitlab-shell/issues/5/toggle_subscription',
moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move',
projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15',
@@ -141,12 +201,14 @@ export default {
name: 'Administrator',
username: 'root',
},
+};
- sidebarMockInterceptor(request, next) {
- const body = sidebarMockData[request.method.toUpperCase()][request.url];
+mockData.sidebarMockInterceptor = function (request, next) {
+ const body = this.responseMap[request.method.toUpperCase()][request.url];
- next(request.respondWith(JSON.stringify(body), {
- status: 200,
- }));
- },
-};
+ next(request.respondWith(JSON.stringify(body), {
+ status: 200,
+ }));
+}.bind(mockData);
+
+export default mockData;
diff --git a/spec/javascripts/sidebar/sidebar_mediator_spec.js b/spec/javascripts/sidebar/sidebar_mediator_spec.js
index 7deb1fd2118..14c34d5a78c 100644
--- a/spec/javascripts/sidebar/sidebar_mediator_spec.js
+++ b/spec/javascripts/sidebar/sidebar_mediator_spec.js
@@ -33,10 +33,29 @@ describe('Sidebar mediator', () => {
.catch(done.fail);
});
- it('fetches the data', () => {
- spyOn(this.mediator.service, 'get').and.callThrough();
- this.mediator.fetch();
- expect(this.mediator.service.get).toHaveBeenCalled();
+ it('fetches the data', (done) => {
+ const mockData = Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar'];
+ spyOn(this.mediator, 'processFetchedData').and.callThrough();
+
+ this.mediator.fetch()
+ .then(() => {
+ expect(this.mediator.processFetchedData).toHaveBeenCalledWith(mockData);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('processes fetched data', () => {
+ const mockData = Mock.responseMap.GET['/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar'];
+ this.mediator.processFetchedData(mockData);
+
+ expect(this.mediator.store.assignees).toEqual(mockData.assignees);
+ expect(this.mediator.store.humanTimeEstimate).toEqual(mockData.human_time_estimate);
+ expect(this.mediator.store.humanTotalTimeSpent).toEqual(mockData.human_total_time_spent);
+ expect(this.mediator.store.participants).toEqual(mockData.participants);
+ expect(this.mediator.store.subscribed).toEqual(mockData.subscribed);
+ expect(this.mediator.store.timeEstimate).toEqual(mockData.time_estimate);
+ expect(this.mediator.store.totalTimeSpent).toEqual(mockData.total_time_spent);
});
it('sets moveToProjectId', () => {
diff --git a/spec/javascripts/sidebar/sidebar_store_spec.js b/spec/javascripts/sidebar/sidebar_store_spec.js
index 51dee64fb93..ea4eae1e23f 100644
--- a/spec/javascripts/sidebar/sidebar_store_spec.js
+++ b/spec/javascripts/sidebar/sidebar_store_spec.js
@@ -120,6 +120,12 @@ describe('Sidebar store', () => {
expect(this.store.isFetching.participants).toEqual(false);
});
+ it('sets loading state', () => {
+ this.store.setLoadingState('assignees', true);
+
+ expect(this.store.isLoading.assignees).toEqual(true);
+ });
+
it('set time tracking data', () => {
this.store.setTimeTrackingData(Mock.time);
expect(this.store.timeEstimate).toEqual(Mock.time.time_estimate);
diff --git a/spec/lib/api/helpers/pagination_spec.rb b/spec/lib/api/helpers/pagination_spec.rb
index 59deca7757b..a547988d631 100644
--- a/spec/lib/api/helpers/pagination_spec.rb
+++ b/spec/lib/api/helpers/pagination_spec.rb
@@ -92,6 +92,27 @@ describe API::Helpers::Pagination do
subject.paginate(resource)
end
end
+
+ context 'if order' do
+ it 'is not present it adds default order(:id) if no order is present' do
+ resource.order_values = []
+
+ paginated_relation = subject.paginate(resource)
+
+ expect(resource.order_values).to be_empty
+ expect(paginated_relation.order_values).to be_present
+ expect(paginated_relation.order_values.first).to be_ascending
+ expect(paginated_relation.order_values.first.expr.name).to eq :id
+ end
+
+ it 'is present it does not add anything' do
+ paginated_relation = subject.paginate(resource.order(created_at: :desc))
+
+ expect(paginated_relation.order_values).to be_present
+ expect(paginated_relation.order_values.first).to be_descending
+ expect(paginated_relation.order_values.first.expr.name).to eq :created_at
+ end
+ end
end
context 'when resource empty' do
diff --git a/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb b/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb
index 72dabca793a..f34c9f09057 100644
--- a/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb
+++ b/spec/lib/gitlab/git/storage/circuit_breaker_spec.rb
@@ -27,6 +27,7 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state:
def set_in_redis(name, value)
Gitlab::Git::Storage.redis.with do |redis|
+ redis.zadd(Gitlab::Git::Storage::REDIS_KNOWN_KEYS, 0, cache_key)
redis.hmset(cache_key, name, value)
end.first
end
@@ -181,6 +182,24 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state:
expect(circuit_breaker.last_failure).to be_nil
end
+ it 'maintains known storage keys' do
+ Timecop.freeze do
+ # Insert an old key to expire
+ old_entry = Time.now.to_i - 3.days.to_i
+ Gitlab::Git::Storage.redis.with do |redis|
+ redis.zadd(Gitlab::Git::Storage::REDIS_KNOWN_KEYS, old_entry, 'to_be_removed')
+ end
+
+ circuit_breaker.perform { '' }
+
+ known_keys = Gitlab::Git::Storage.redis.with do |redis|
+ redis.zrange(Gitlab::Git::Storage::REDIS_KNOWN_KEYS, 0, -1)
+ end
+
+ expect(known_keys).to contain_exactly(cache_key)
+ end
+ end
+
it 'only performs the accessibility check once' do
expect(Gitlab::Git::Storage::ForkedStorageCheck)
.to receive(:storage_available?).once.and_call_original
diff --git a/spec/lib/gitlab/git/storage/health_spec.rb b/spec/lib/gitlab/git/storage/health_spec.rb
index 4a14a5201d1..d7a52a04fbb 100644
--- a/spec/lib/gitlab/git/storage/health_spec.rb
+++ b/spec/lib/gitlab/git/storage/health_spec.rb
@@ -6,6 +6,7 @@ describe Gitlab::Git::Storage::Health, clean_gitlab_redis_shared_state: true, br
def set_in_redis(cache_key, value)
Gitlab::Git::Storage.redis.with do |redis|
+ redis.zadd(Gitlab::Git::Storage::REDIS_KNOWN_KEYS, 0, cache_key)
redis.hmset(cache_key, :failure_count, value)
end.first
end
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 2158b2837e2..eec6858a5de 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -200,18 +200,18 @@ describe Gitlab::Shell do
describe '#fork_repository' do
it 'returns true when the command succeeds' do
expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
+ .with([projects_path, 'fork-repository', 'current/storage', 'project/path.git', 'new/storage', 'fork/path.git'],
nil, popen_vars).and_return([nil, 0])
- expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be true
+ expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'fork/path')).to be true
end
it 'return false when the command fails' do
expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'fork-project', 'current/storage', 'project/path.git', 'new/storage', 'new-namespace'],
+ .with([projects_path, 'fork-repository', 'current/storage', 'project/path.git', 'new/storage', 'fork/path.git'],
nil, popen_vars).and_return(["error", 1])
- expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'new-namespace')).to be false
+ expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'fork/path')).to be false
end
end
diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb
index fac23dce44d..ecb4034ec8b 100644
--- a/spec/lib/google_api/cloud_platform/client_spec.rb
+++ b/spec/lib/google_api/cloud_platform/client_spec.rb
@@ -3,6 +3,7 @@ require 'spec_helper'
describe GoogleApi::CloudPlatform::Client do
let(:token) { 'token' }
let(:client) { described_class.new(token, nil) }
+ let(:user_agent_options) { client.instance_eval { user_agent_header } }
describe '.session_key_for_redirect_uri' do
let(:state) { 'random_string' }
@@ -55,7 +56,8 @@ describe GoogleApi::CloudPlatform::Client do
before do
allow_any_instance_of(Google::Apis::ContainerV1::ContainerService)
- .to receive(:get_zone_cluster).and_return(gke_cluster)
+ .to receive(:get_zone_cluster).with(any_args, options: user_agent_options)
+ .and_return(gke_cluster)
end
it { is_expected.to eq(gke_cluster) }
@@ -74,7 +76,8 @@ describe GoogleApi::CloudPlatform::Client do
before do
allow_any_instance_of(Google::Apis::ContainerV1::ContainerService)
- .to receive(:create_cluster).and_return(operation)
+ .to receive(:create_cluster).with(any_args, options: user_agent_options)
+ .and_return(operation)
end
it { is_expected.to eq(operation) }
@@ -102,7 +105,8 @@ describe GoogleApi::CloudPlatform::Client do
before do
allow_any_instance_of(Google::Apis::ContainerV1::ContainerService)
- .to receive(:get_zone_operation).and_return(operation)
+ .to receive(:get_zone_operation).with(any_args, options: user_agent_options)
+ .and_return(operation)
end
it { is_expected.to eq(operation) }
@@ -125,4 +129,18 @@ describe GoogleApi::CloudPlatform::Client do
it { is_expected.to be_nil }
end
end
+
+ describe '#user_agent_header' do
+ subject { client.instance_eval { user_agent_header } }
+
+ it 'returns a RequestOptions object' do
+ expect(subject).to be_instance_of(Google::Apis::RequestOptions)
+ end
+
+ it 'has the correct GitLab version in User-Agent header' do
+ stub_const('Gitlab::VERSION', '10.3.0-pre')
+
+ expect(subject.header).to eq({ 'User-Agent': 'GitLab/10.3 (GPN:GitLab;)' })
+ end
+ end
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index f942a22b6d1..e1d71a9573b 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -602,7 +602,7 @@ describe Notify do
it 'has the correct subject and body' do
aggregate_failures do
- is_expected.to have_subject("Re: #{project.name} | #{commit.title.strip} (#{commit.short_id})")
+ is_expected.to have_subject("Re: #{project.name} | #{commit.title} (#{commit.short_id})")
is_expected.to have_body_text(commit.short_id)
end
end
@@ -712,7 +712,7 @@ describe Notify do
it_behaves_like 'a user cannot unsubscribe through footer link'
it 'has the correct subject' do
- is_expected.to have_subject "Re: #{project.name} | #{commit.title.strip} (#{commit.short_id})"
+ is_expected.to have_subject "Re: #{project.name} | #{commit.title} (#{commit.short_id})"
end
it 'contains a link to the commit' do
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 90b768f595e..3817f20bfe7 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -531,7 +531,7 @@ describe Namespace do
end
end
- describe '#has_forks_of?' do
+ describe '#find_fork_of?' do
let(:project) { create(:project, :public) }
let!(:forked_project) { fork_project(project, namespace.owner, namespace: namespace) }
@@ -550,5 +550,13 @@ describe Namespace do
expect(other_namespace.find_fork_of(project)).to eq(other_fork)
end
+
+ context 'with request store enabled', :request_store do
+ it 'only queries once' do
+ expect(project.fork_network).to receive(:find_forks_in).once.and_call_original
+
+ 2.times { namespace.find_fork_of(project) }
+ end
+ end
end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 521b7bd70ba..000d5b7126d 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -315,7 +315,6 @@ describe Project do
it { is_expected.to delegate_method(:empty_repo?).to(:repository) }
it { is_expected.to delegate_method(:members).to(:team).with_prefix(true) }
- it { is_expected.to delegate_method(:count).to(:forks).with_prefix(true) }
it { is_expected.to delegate_method(:name).to(:owner).with_prefix(true).with_arguments(allow_nil: true) }
end
@@ -1717,8 +1716,7 @@ describe Project do
expect(RepositoryForkWorker).to receive(:perform_async).with(
project.id,
forked_from_project.repository_storage_path,
- forked_from_project.disk_path,
- project.namespace.full_path).and_return(import_jid)
+ forked_from_project.disk_path).and_return(import_jid)
expect(project.add_import_job).to eq(import_jid)
end
@@ -2473,7 +2471,7 @@ describe Project do
it 'returns the number of forks' do
project = build(:project)
- allow(project.forks).to receive(:count).and_return(1)
+ expect_any_instance_of(Projects::ForksCountService).to receive(:count).and_return(1)
expect(project.forks_count).to eq(1)
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 27f0a99b2fa..af0c86abe86 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1408,42 +1408,52 @@ describe Repository do
end
describe '#cherry_pick' do
- let(:conflict_commit) { repository.commit('c642fe9b8b9f28f9225d7ea953fe14e74748d53b') }
- let(:pickable_commit) { repository.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
- let(:pickable_merge) { repository.commit('e56497bb5f03a90a51293fc6d516788730953899') }
- let(:message) { 'cherry-pick message' }
-
- context 'when there is a conflict' do
- it 'raises an error' do
- expect { repository.cherry_pick(user, conflict_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
+ shared_examples 'cherry-picking a commit' do
+ let(:conflict_commit) { repository.commit('c642fe9b8b9f28f9225d7ea953fe14e74748d53b') }
+ let(:pickable_commit) { repository.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
+ let(:pickable_merge) { repository.commit('e56497bb5f03a90a51293fc6d516788730953899') }
+ let(:message) { 'cherry-pick message' }
+
+ context 'when there is a conflict' do
+ it 'raises an error' do
+ expect { repository.cherry_pick(user, conflict_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
+ end
end
- end
- context 'when commit was already cherry-picked' do
- it 'raises an error' do
- repository.cherry_pick(user, pickable_commit, 'master', message)
+ context 'when commit was already cherry-picked' do
+ it 'raises an error' do
+ repository.cherry_pick(user, pickable_commit, 'master', message)
- expect { repository.cherry_pick(user, pickable_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
+ expect { repository.cherry_pick(user, pickable_commit, 'master', message) }.to raise_error(Gitlab::Git::Repository::CreateTreeError)
+ end
end
- end
- context 'when commit can be cherry-picked' do
- it 'cherry-picks the changes' do
- expect(repository.cherry_pick(user, pickable_commit, 'master', message)).to be_truthy
+ context 'when commit can be cherry-picked' do
+ it 'cherry-picks the changes' do
+ expect(repository.cherry_pick(user, pickable_commit, 'master', message)).to be_truthy
+ end
end
- end
- context 'cherry-picking a merge commit' do
- it 'cherry-picks the changes' do
- expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).to be_nil
+ context 'cherry-picking a merge commit' do
+ it 'cherry-picks the changes' do
+ expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).to be_nil
- cherry_pick_commit_sha = repository.cherry_pick(user, pickable_merge, 'improve/awesome', message)
- cherry_pick_commit_message = project.commit(cherry_pick_commit_sha).message
+ cherry_pick_commit_sha = repository.cherry_pick(user, pickable_merge, 'improve/awesome', message)
+ cherry_pick_commit_message = project.commit(cherry_pick_commit_sha).message
- expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).not_to be_nil
- expect(cherry_pick_commit_message).to eq(message)
+ expect(repository.blob_at_branch('improve/awesome', 'foo/bar/.gitkeep')).not_to be_nil
+ expect(cherry_pick_commit_message).to eq(message)
+ end
end
end
+
+ context 'when Gitaly cherry_pick feature is enabled' do
+ it_behaves_like 'cherry-picking a commit'
+ end
+
+ context 'when Gitaly cherry_pick feature is disabled', :disable_gitaly do
+ it_behaves_like 'cherry-picking a commit'
+ end
end
describe '#before_delete' do
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 04a658cd6c3..554723d6b1e 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -401,6 +401,20 @@ describe API::Groups do
expect(response).to have_gitlab_http_status(404)
end
+
+ it 'avoids N+1 queries' do
+ get api("/groups/#{group1.id}/projects", admin)
+
+ control_count = ActiveRecord::QueryRecorder.new do
+ get api("/groups/#{group1.id}/projects", admin)
+ end.count
+
+ create(:project, namespace: group1)
+
+ expect do
+ get api("/groups/#{group1.id}/projects", admin)
+ end.not_to exceed_query_limit(control_count)
+ end
end
context 'when using group path in URL' do
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index db5de572b6d..43e2643f709 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -12,6 +12,8 @@ describe NotificationService, :mailer do
shared_examples 'notifications for new mentions' do
def send_notifications(*new_mentions)
+ mentionable.description = new_mentions.map(&:to_reference).join(' ')
+
notification.send(notification_method, mentionable, new_mentions, @u_disabled)
end
@@ -20,13 +22,13 @@ describe NotificationService, :mailer do
should_not_email_anyone
end
- it 'emails new mentions with a watch level higher than participant' do
- send_notifications(@u_watcher, @u_participant_mentioned, @u_custom_global)
- should_only_email(@u_watcher, @u_participant_mentioned, @u_custom_global)
+ it 'emails new mentions with a watch level higher than mention' do
+ send_notifications(@u_watcher, @u_participant_mentioned, @u_custom_global, @u_mentioned)
+ should_only_email(@u_watcher, @u_participant_mentioned, @u_custom_global, @u_mentioned)
end
- it 'does not email new mentions with a watch level equal to or less than participant' do
- send_notifications(@u_participating, @u_mentioned)
+ it 'does not email new mentions with a watch level equal to or less than mention' do
+ send_notifications(@u_disabled)
should_not_email_anyone
end
end
@@ -509,6 +511,14 @@ describe NotificationService, :mailer do
should_not_email(issue.assignees.first)
end
+ it "emails any mentioned users with the mention level" do
+ issue.description = @u_mentioned.to_reference
+
+ notification.new_issue(issue, @u_disabled)
+
+ should_email(@u_mentioned)
+ end
+
it "emails the author if they've opted into notifications about their activity" do
issue.author.notified_of_own_activity = true
@@ -900,6 +910,14 @@ describe NotificationService, :mailer do
should_not_email(@u_lazy_participant)
end
+ it "emails any mentioned users with the mention level" do
+ merge_request.description = @u_mentioned.to_reference
+
+ notification.new_merge_request(merge_request, @u_disabled)
+
+ should_email(@u_mentioned)
+ end
+
it "emails the author if they've opted into notifications about their activity" do
merge_request.author.notified_of_own_activity = true
diff --git a/spec/services/projects/count_service_spec.rb b/spec/services/projects/count_service_spec.rb
index cc496501bad..183f6128c7b 100644
--- a/spec/services/projects/count_service_spec.rb
+++ b/spec/services/projects/count_service_spec.rb
@@ -4,9 +4,17 @@ describe Projects::CountService do
let(:project) { build(:project, id: 1) }
let(:service) { described_class.new(project) }
- describe '#relation_for_count' do
+ describe '.query' do
it 'raises NotImplementedError' do
- expect { service.relation_for_count }.to raise_error(NotImplementedError)
+ expect { described_class.query(project.id) }.to raise_error(NotImplementedError)
+ end
+ end
+
+ describe '#relation_for_count' do
+ it 'calls the class method query with the project id' do
+ expect(described_class).to receive(:query).with(project.id)
+
+ service.relation_for_count
end
end
diff --git a/spec/support/query_recorder.rb b/spec/support/query_recorder.rb
index 369775db462..8cf8f45a8b2 100644
--- a/spec/support/query_recorder.rb
+++ b/spec/support/query_recorder.rb
@@ -41,7 +41,8 @@ RSpec::Matchers.define :exceed_query_limit do |expected|
supports_block_expectations
match do |block|
- query_count(&block) > expected_count + threshold
+ @subject_block = block
+ actual_count > expected_count + threshold
end
failure_message_when_negated do |actual|
@@ -55,6 +56,11 @@ RSpec::Matchers.define :exceed_query_limit do |expected|
self
end
+ def for_query(query)
+ @query = query
+ self
+ end
+
def threshold
@threshold.to_i
end
@@ -68,12 +74,15 @@ RSpec::Matchers.define :exceed_query_limit do |expected|
end
def actual_count
- @recorder.count
+ @actual_count ||= if @query
+ recorder.log.select { |recorded| recorded =~ @query }.size
+ else
+ recorder.count
+ end
end
- def query_count(&block)
- @recorder = ActiveRecord::QueryRecorder.new(&block)
- @recorder.count
+ def recorder
+ @recorder ||= ActiveRecord::QueryRecorder.new(&@subject_block)
end
def count_queries(queries)
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index e881ec37ae5..74c85848b7e 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -1,8 +1,8 @@
require 'spec_helper'
describe RepositoryForkWorker do
- let(:project) { create(:project, :repository, :import_scheduled) }
- let(:fork_project) { create(:project, :repository, forked_from_project: project) }
+ let(:project) { create(:project, :repository) }
+ let(:fork_project) { create(:project, :repository, :import_scheduled, forked_from_project: project) }
let(:shell) { Gitlab::Shell.new }
subject { described_class.new }
@@ -12,50 +12,39 @@ describe RepositoryForkWorker do
end
describe "#perform" do
+ def perform!
+ subject.perform(fork_project.id, '/test/path', project.disk_path)
+ end
+
+ def expect_fork_repository
+ expect(shell).to receive(:fork_repository).with(
+ '/test/path',
+ project.disk_path,
+ fork_project.repository_storage_path,
+ fork_project.disk_path
+ )
+ end
+
describe 'when a worker was reset without cleanup' do
let(:jid) { '12345678' }
- let(:started_project) { create(:project, :repository, :import_started) }
it 'creates a new repository from a fork' do
allow(subject).to receive(:jid).and_return(jid)
- expect(shell).to receive(:fork_repository).with(
- '/test/path',
- project.full_path,
- project.repository_storage_path,
- fork_project.namespace.full_path
- ).and_return(true)
-
- subject.perform(
- project.id,
- '/test/path',
- project.full_path,
- fork_project.namespace.full_path)
+ expect_fork_repository.and_return(true)
+
+ perform!
end
end
it "creates a new repository from a fork" do
- expect(shell).to receive(:fork_repository).with(
- '/test/path',
- project.full_path,
- project.repository_storage_path,
- fork_project.namespace.full_path
- ).and_return(true)
+ expect_fork_repository.and_return(true)
- subject.perform(
- project.id,
- '/test/path',
- project.full_path,
- fork_project.namespace.full_path)
+ perform!
end
it 'flushes various caches' do
- expect(shell).to receive(:fork_repository).with(
- '/test/path',
- project.full_path,
- project.repository_storage_path,
- fork_project.namespace.full_path
- ).and_return(true)
+ expect_fork_repository.and_return(true)
expect_any_instance_of(Repository).to receive(:expire_emptiness_caches)
.and_call_original
@@ -63,32 +52,22 @@ describe RepositoryForkWorker do
expect_any_instance_of(Repository).to receive(:expire_exists_cache)
.and_call_original
- subject.perform(project.id, '/test/path', project.full_path,
- fork_project.namespace.full_path)
+ perform!
end
it "handles bad fork" do
- source_path = project.full_path
- target_path = fork_project.namespace.full_path
- error_message = "Unable to fork project #{project.id} for repository #{source_path} -> #{target_path}"
+ error_message = "Unable to fork project #{fork_project.id} for repository #{project.full_path} -> #{fork_project.full_path}"
- expect(shell).to receive(:fork_repository).and_return(false)
+ expect_fork_repository.and_return(false)
- expect do
- subject.perform(project.id, '/test/path', source_path, target_path)
- end.to raise_error(RepositoryForkWorker::ForkError, error_message)
+ expect { perform! }.to raise_error(RepositoryForkWorker::ForkError, error_message)
end
it 'handles unexpected error' do
- source_path = project.full_path
- target_path = fork_project.namespace.full_path
-
- allow_any_instance_of(Gitlab::Shell).to receive(:fork_repository).and_raise(RuntimeError)
+ expect_fork_repository.and_raise(RuntimeError)
- expect do
- subject.perform(project.id, '/test/path', source_path, target_path)
- end.to raise_error(RepositoryForkWorker::ForkError)
- expect(project.reload.import_status).to eq('failed')
+ expect { perform! }.to raise_error(RepositoryForkWorker::ForkError)
+ expect(fork_project.reload.import_status).to eq('failed')
end
end
end