summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2019-12-03 18:06:49 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2019-12-03 18:06:49 +0000
commitab7cf450ba19cf80b9534f25dc707b33845e3014 (patch)
treebbfa6aba83c48aea68d79c4179ce576b6eec326d /spec
parent4204cf308596e0e26f578a6e2da88f49c0f4aad9 (diff)
downloadgitlab-ce-ab7cf450ba19cf80b9534f25dc707b33845e3014.tar.gz
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/application_controller_spec.rb14
-rw-r--r--spec/controllers/instance_statistics/dev_ops_score_controller_spec.rb (renamed from spec/controllers/instance_statistics/conversational_development_index_controller_spec.rb)2
-rw-r--r--spec/controllers/projects/branches_controller_spec.rb8
-rw-r--r--spec/controllers/uploads_controller_spec.rb24
-rw-r--r--spec/features/dashboard/milestones_spec.rb20
-rw-r--r--spec/features/instance_statistics/dev_ops_score_spec.rb (renamed from spec/features/instance_statistics/conversational_development_index_spec.rb)12
-rw-r--r--spec/features/merge_request/user_sees_deleted_target_branch_spec.rb2
-rw-r--r--spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb8
-rw-r--r--spec/features/milestones/user_views_milestones_spec.rb31
-rw-r--r--spec/frontend/environment.js1
-rw-r--r--spec/frontend/monitoring/mock_data.js175
-rw-r--r--spec/frontend/sidebar/assignees_spec.js200
-rw-r--r--spec/frontend/sidebar/mock_data.js213
-rw-r--r--spec/graphql/mutations/issues/set_confidential_spec.rb39
-rw-r--r--spec/javascripts/monitoring/mock_data.js229
-rw-r--r--spec/javascripts/sidebar/assignees_spec.js248
-rw-r--r--spec/javascripts/sidebar/mock_data.js214
-rw-r--r--spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb42
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb22
-rw-r--r--spec/models/ci/build_spec.rb74
-rw-r--r--spec/models/clusters/platforms/kubernetes_spec.rb20
-rw-r--r--spec/models/commit_spec.rb2
-rw-r--r--spec/models/milestone_spec.rb34
-rw-r--r--spec/models/project_spec.rb5
-rw-r--r--spec/requests/api/branches_spec.rb2
-rw-r--r--spec/requests/api/files_spec.rb4
-rw-r--r--spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb51
-rw-r--r--spec/requests/user_avatar_spec.rb36
-rw-r--r--spec/routing/instance_statistics_routing_spec.rb4
-rw-r--r--spec/services/branches/create_service_spec.rb (renamed from spec/services/create_branch_service_spec.rb)6
-rw-r--r--spec/services/branches/delete_merged_service_spec.rb (renamed from spec/services/delete_merged_branches_service_spec.rb)2
-rw-r--r--spec/services/branches/delete_service_spec.rb (renamed from spec/services/delete_branch_service_spec.rb)4
-rw-r--r--spec/services/branches/validate_new_service_spec.rb40
-rw-r--r--spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb4
-rw-r--r--spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb27
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb11
-rw-r--r--spec/services/merge_requests/merge_to_ref_service_spec.rb2
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb2
-rw-r--r--spec/services/todo_service_spec.rb24
-rw-r--r--spec/support/helpers/kubernetes_helpers.rb29
-rw-r--r--spec/support/helpers/position_tracer_helpers.rb2
-rw-r--r--spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb14
-rw-r--r--spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb10
-rw-r--r--spec/workers/delete_merged_branches_worker_spec.rb4
44 files changed, 1162 insertions, 755 deletions
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 4a10e7b5325..04bbffc587f 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -90,14 +90,6 @@ describe ApplicationController do
let(:format) { :html }
it_behaves_like 'setting gon variables'
-
- context 'for peek requests' do
- before do
- request.path = '/-/peek'
- end
-
- it_behaves_like 'not setting gon variables'
- end
end
context 'with json format' do
@@ -105,6 +97,12 @@ describe ApplicationController do
it_behaves_like 'not setting gon variables'
end
+
+ context 'with atom format' do
+ let(:format) { :atom }
+
+ it_behaves_like 'not setting gon variables'
+ end
end
describe 'session expiration' do
diff --git a/spec/controllers/instance_statistics/conversational_development_index_controller_spec.rb b/spec/controllers/instance_statistics/dev_ops_score_controller_spec.rb
index 4935cb265bf..5825c6295f6 100644
--- a/spec/controllers/instance_statistics/conversational_development_index_controller_spec.rb
+++ b/spec/controllers/instance_statistics/dev_ops_score_controller_spec.rb
@@ -2,6 +2,6 @@
require 'spec_helper'
-describe InstanceStatistics::ConversationalDevelopmentIndexController do
+describe InstanceStatistics::DevOpsScoreController do
it_behaves_like 'instance statistics availability'
end
diff --git a/spec/controllers/projects/branches_controller_spec.rb b/spec/controllers/projects/branches_controller_spec.rb
index affe0e0f970..4f8ab6a5def 100644
--- a/spec/controllers/projects/branches_controller_spec.rb
+++ b/spec/controllers/projects/branches_controller_spec.rb
@@ -178,7 +178,7 @@ describe Projects::BranchesController do
it 'redirects to newly created branch' do
result = { status: :success, branch: double(name: branch) }
- expect_any_instance_of(CreateBranchService).to receive(:execute).and_return(result)
+ expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result)
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true)
post :create,
@@ -200,7 +200,7 @@ describe Projects::BranchesController do
it 'redirects to autodeploy setup page' do
result = { status: :success, branch: double(name: branch) }
- expect_any_instance_of(CreateBranchService).to receive(:execute).and_return(result)
+ expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result)
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true)
post :create,
@@ -221,7 +221,7 @@ describe Projects::BranchesController do
create(:cluster, :provided_by_gcp, projects: [project])
- expect_any_instance_of(CreateBranchService).to receive(:execute).and_return(result)
+ expect_any_instance_of(::Branches::CreateService).to receive(:execute).and_return(result)
expect(SystemNoteService).to receive(:new_issue_branch).and_return(true)
post :create,
@@ -459,7 +459,7 @@ describe Projects::BranchesController do
end
it 'starts worker to delete merged branches' do
- expect_any_instance_of(DeleteMergedBranchesService).to receive(:async_execute)
+ expect_any_instance_of(::Branches::DeleteMergedService).to receive(:async_execute)
destroy_all_merged
end
diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index 1bcf3bb106b..f35babc1b56 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -228,10 +228,10 @@ describe UploadsController do
user.block
end
- it "redirects to the sign in page" do
+ it "responds with status 401" do
get :show, params: { model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" }
- expect(response).to redirect_to(new_user_session_path)
+ expect(response).to have_gitlab_http_status(401)
end
end
@@ -320,10 +320,10 @@ describe UploadsController do
end
context "when not signed in" do
- it "redirects to the sign in page" do
+ it "responds with status 401" do
get :show, params: { model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" }
- expect(response).to redirect_to(new_user_session_path)
+ expect(response).to have_gitlab_http_status(401)
end
end
@@ -343,10 +343,10 @@ describe UploadsController do
project.add_maintainer(user)
end
- it "redirects to the sign in page" do
+ it "responds with status 401" do
get :show, params: { model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" }
- expect(response).to redirect_to(new_user_session_path)
+ expect(response).to have_gitlab_http_status(401)
end
end
@@ -439,10 +439,10 @@ describe UploadsController do
user.block
end
- it "redirects to the sign in page" do
+ it "responds with status 401" do
get :show, params: { model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" }
- expect(response).to redirect_to(new_user_session_path)
+ expect(response).to have_gitlab_http_status(401)
end
end
@@ -526,10 +526,10 @@ describe UploadsController do
end
context "when not signed in" do
- it "redirects to the sign in page" do
+ it "responds with status 401" do
get :show, params: { model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" }
- expect(response).to redirect_to(new_user_session_path)
+ expect(response).to have_gitlab_http_status(401)
end
end
@@ -549,10 +549,10 @@ describe UploadsController do
project.add_maintainer(user)
end
- it "redirects to the sign in page" do
+ it "responds with status 401" do
get :show, params: { model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" }
- expect(response).to redirect_to(new_user_session_path)
+ expect(response).to have_gitlab_http_status(401)
end
end
diff --git a/spec/features/dashboard/milestones_spec.rb b/spec/features/dashboard/milestones_spec.rb
index c21bc922de7..4ad19710d90 100644
--- a/spec/features/dashboard/milestones_spec.rb
+++ b/spec/features/dashboard/milestones_spec.rb
@@ -30,6 +30,7 @@ describe 'Dashboard > Milestones' do
expect(current_path).to eq dashboard_milestones_path
expect(page).to have_content(milestone.title)
expect(page).to have_content(group.name)
+ expect(first('.milestone')).to have_content('Merge Requests')
end
describe 'new milestones dropdown', :js do
@@ -46,4 +47,23 @@ describe 'Dashboard > Milestones' do
end
end
end
+
+ describe 'with merge requests disabled' do
+ let(:user) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project) { create(:project, :merge_requests_disabled, namespace: user.namespace) }
+ let!(:milestone) { create(:milestone, project: project) }
+
+ before do
+ group.add_developer(user)
+ sign_in(user)
+ visit dashboard_milestones_path
+ end
+
+ it 'does not see milestones' do
+ expect(current_path).to eq dashboard_milestones_path
+ expect(page).to have_content(milestone.title)
+ expect(first('.milestone')).to have_no_content('Merge Requests')
+ end
+ end
end
diff --git a/spec/features/instance_statistics/conversational_development_index_spec.rb b/spec/features/instance_statistics/dev_ops_score_spec.rb
index 6d05682fcd5..c9e6ab67267 100644
--- a/spec/features/instance_statistics/conversational_development_index_spec.rb
+++ b/spec/features/instance_statistics/dev_ops_score_spec.rb
@@ -2,13 +2,13 @@
require 'spec_helper'
-describe 'Conversational Development Index' do
+describe 'Dev Ops Score' do
before do
sign_in(create(:admin))
end
it 'has dismissable intro callout', :js do
- visit instance_statistics_conversational_development_index_index_path
+ visit instance_statistics_dev_ops_score_index_path
expect(page).to have_content 'Introducing Your Conversational Development Index'
@@ -23,13 +23,13 @@ describe 'Conversational Development Index' do
end
it 'shows empty state' do
- visit instance_statistics_conversational_development_index_index_path
+ visit instance_statistics_dev_ops_score_index_path
expect(page).to have_content('Usage ping is not enabled')
end
it 'hides the intro callout' do
- visit instance_statistics_conversational_development_index_index_path
+ visit instance_statistics_dev_ops_score_index_path
expect(page).not_to have_content 'Introducing Your Conversational Development Index'
end
@@ -39,7 +39,7 @@ describe 'Conversational Development Index' do
it 'shows empty state' do
stub_application_setting(usage_ping_enabled: true)
- visit instance_statistics_conversational_development_index_index_path
+ visit instance_statistics_dev_ops_score_index_path
expect(page).to have_content('Data is still calculating')
end
@@ -50,7 +50,7 @@ describe 'Conversational Development Index' do
stub_application_setting(usage_ping_enabled: true)
create(:dev_ops_score_metric)
- visit instance_statistics_conversational_development_index_index_path
+ visit instance_statistics_dev_ops_score_index_path
expect(page).to have_content(
'Issues created per active user 1.2 You 9.3 Lead 13.3%'
diff --git a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
index 224261dec00..9ef6847f7f5 100644
--- a/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
+++ b/spec/features/merge_request/user_sees_deleted_target_branch_spec.rb
@@ -9,7 +9,7 @@ describe 'Merge request > User sees deleted target branch', :js do
before do
project.add_maintainer(user)
- DeleteBranchService.new(project, user).execute('feature')
+ ::Branches::DeleteService.new(project, user).execute('feature')
sign_in(user)
visit project_merge_request_path(project, merge_request)
end
diff --git a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
index c42eb8560a4..22b2ea81b32 100644
--- a/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
+++ b/spec/features/merge_request/user_selects_branches_for_new_mr_spec.rb
@@ -178,10 +178,11 @@ describe 'Merge request > User selects branches for new MR', :js do
end
context 'with special characters in branch names' do
+ let(:create_branch_service) { ::Branches::CreateService.new(project, user) }
+
it 'escapes quotes in branch names' do
special_branch_name = '"with-quotes"'
- CreateBranchService.new(project, user)
- .execute(special_branch_name, 'add-pdf-file')
+ create_branch_service.execute(special_branch_name, 'add-pdf-file')
visit project_new_merge_request_path(project)
select_source_branch(special_branch_name)
@@ -192,8 +193,7 @@ describe 'Merge request > User selects branches for new MR', :js do
it 'does not escape unicode in branch names' do
special_branch_name = 'ʕ•ᴥ•ʔ'
- CreateBranchService.new(project, user)
- .execute(special_branch_name, 'add-pdf-file')
+ create_branch_service.execute(special_branch_name, 'add-pdf-file')
visit project_new_merge_request_path(project)
select_source_branch(special_branch_name)
diff --git a/spec/features/milestones/user_views_milestones_spec.rb b/spec/features/milestones/user_views_milestones_spec.rb
index 09378cab5e3..c91fe95aa77 100644
--- a/spec/features/milestones/user_views_milestones_spec.rb
+++ b/spec/features/milestones/user_views_milestones_spec.rb
@@ -18,6 +18,7 @@ describe "User views milestones" do
expect(page).to have_content(milestone.title)
.and have_content(milestone.expires_at)
.and have_content("Issues")
+ .and have_content("Merge Requests")
end
context "with issues" do
@@ -32,6 +33,7 @@ describe "User views milestones" do
.and have_selector("#tab-issues li.issuable-row", count: 2)
.and have_content(issue.title)
.and have_content(closed_issue.title)
+ .and have_selector("#tab-merge-requests")
end
end
@@ -62,3 +64,32 @@ describe "User views milestones" do
end
end
end
+
+describe "User views milestones with no MR" do
+ set(:user) { create(:user) }
+ set(:project) { create(:project, :merge_requests_disabled) }
+ set(:milestone) { create(:milestone, project: project) }
+
+ before do
+ project.add_developer(user)
+ sign_in(user)
+
+ visit(project_milestones_path(project))
+ end
+
+ it "shows milestone" do
+ expect(page).to have_content(milestone.title)
+ .and have_content(milestone.expires_at)
+ .and have_content("Issues")
+ .and have_no_content("Merge Requests")
+ end
+
+ it "opens milestone" do
+ click_link(milestone.title)
+
+ expect(current_path).to eq(project_milestone_path(project, milestone))
+ expect(page).to have_content(milestone.title)
+ .and have_selector("#tab-issues")
+ .and have_no_selector("#tab-merge-requests")
+ end
+end
diff --git a/spec/frontend/environment.js b/spec/frontend/environment.js
index 3c6553f3547..cd4fae60049 100644
--- a/spec/frontend/environment.js
+++ b/spec/frontend/environment.js
@@ -31,6 +31,7 @@ class CustomEnvironment extends JSDOMEnvironment {
this.global.gon = {
ee: IS_EE,
};
+ this.global.IS_EE = IS_EE;
this.rejectedPromises = [];
diff --git a/spec/frontend/monitoring/mock_data.js b/spec/frontend/monitoring/mock_data.js
index 758e86235be..a184892773b 100644
--- a/spec/frontend/monitoring/mock_data.js
+++ b/spec/frontend/monitoring/mock_data.js
@@ -1,5 +1,10 @@
+// This import path needs to be relative for now because this mock data is used in
+// Karma specs too, where the helpers/test_constants alias can not be resolved
+import { TEST_HOST } from '../helpers/test_constants';
+
export const mockHost = 'http://test.host';
export const mockProjectDir = '/frontend-fixtures/environments-project';
+export const mockApiEndpoint = `${TEST_HOST}/monitoring/mock`;
export const anomalyDeploymentData = [
{
@@ -278,6 +283,49 @@ export const mockedQueryResultPayload = {
],
};
+export const mockedQueryResultPayloadCoresTotal = {
+ metricId: '13_system_metrics_kubernetes_container_cores_total',
+ result: [
+ {
+ metric: {},
+ values: [
+ [1563272065.589, '9.396484375'],
+ [1563272125.589, '9.333984375'],
+ [1563272185.589, '9.333984375'],
+ [1563272245.589, '9.333984375'],
+ [1563272305.589, '9.333984375'],
+ [1563272365.589, '9.333984375'],
+ [1563272425.589, '9.38671875'],
+ [1563272485.589, '9.333984375'],
+ [1563272545.589, '9.333984375'],
+ [1563272605.589, '9.333984375'],
+ [1563272665.589, '9.333984375'],
+ [1563272725.589, '9.333984375'],
+ [1563272785.589, '9.396484375'],
+ [1563272845.589, '9.333984375'],
+ [1563272905.589, '9.333984375'],
+ [1563272965.589, '9.3984375'],
+ [1563273025.589, '9.337890625'],
+ [1563273085.589, '9.34765625'],
+ [1563273145.589, '9.337890625'],
+ [1563273205.589, '9.337890625'],
+ [1563273265.589, '9.337890625'],
+ [1563273325.589, '9.337890625'],
+ [1563273385.589, '9.337890625'],
+ [1563273445.589, '9.337890625'],
+ [1563273505.589, '9.337890625'],
+ [1563273565.589, '9.337890625'],
+ [1563273625.589, '9.337890625'],
+ [1563273685.589, '9.337890625'],
+ [1563273745.589, '9.337890625'],
+ [1563273805.589, '9.337890625'],
+ [1563273865.589, '9.390625'],
+ [1563273925.589, '9.390625'],
+ ],
+ },
+ ],
+};
+
export const metricsGroupsAPIResponse = [
{
group: 'System metrics (Kubernetes)',
@@ -460,3 +508,130 @@ export const dashboardGitResponse = [
path: '.gitlab/dashboards/dashboard_2.yml',
},
];
+
+export const graphDataPrometheusQuery = {
+ title: 'Super Chart A2',
+ type: 'single-stat',
+ weight: 2,
+ metrics: [
+ {
+ id: 'metric_a1',
+ metricId: '2',
+ query: 'max(go_memstats_alloc_bytes{job="prometheus"}) by (job) /1024/1024',
+ unit: 'MB',
+ label: 'Total Consumption',
+ metric_id: 2,
+ prometheus_endpoint_path:
+ '/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
+ result: [
+ {
+ metric: { job: 'prometheus' },
+ value: ['2019-06-26T21:03:20.881Z', 91],
+ },
+ ],
+ },
+ ],
+};
+
+export const graphDataPrometheusQueryRange = {
+ title: 'Super Chart A1',
+ type: 'area-chart',
+ weight: 2,
+ metrics: [
+ {
+ id: 'metric_a1',
+ metricId: '2',
+ query_range:
+ 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024',
+ unit: 'MB',
+ label: 'Total Consumption',
+ metric_id: 2,
+ prometheus_endpoint_path:
+ '/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
+ result: [
+ {
+ metric: {},
+ values: [[1495700554.925, '8.0390625'], [1495700614.925, '8.0390625']],
+ },
+ ],
+ },
+ ],
+};
+
+export const graphDataPrometheusQueryRangeMultiTrack = {
+ title: 'Super Chart A3',
+ type: 'heatmap',
+ weight: 3,
+ x_label: 'Status Code',
+ y_label: 'Time',
+ metrics: [
+ {
+ metricId: '1',
+ id: 'response_metrics_nginx_ingress_throughput_status_code',
+ query_range:
+ 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[60m])) by (status_code)',
+ unit: 'req / sec',
+ label: 'Status Code',
+ metric_id: 1,
+ prometheus_endpoint_path:
+ '/root/rails_nodb/environments/3/prometheus/api/v1/query_range?query=sum%28rate%28nginx_upstream_responses_total%7Bupstream%3D~%22%25%7Bkube_namespace%7D-%25%7Bci_environment_slug%7D-.%2A%22%7D%5B2m%5D%29%29+by+%28status_code%29',
+ result: [
+ {
+ metric: { status_code: '1xx' },
+ values: [
+ ['2019-08-30T15:00:00.000Z', 0],
+ ['2019-08-30T16:00:00.000Z', 2],
+ ['2019-08-30T17:00:00.000Z', 0],
+ ['2019-08-30T18:00:00.000Z', 0],
+ ['2019-08-30T19:00:00.000Z', 0],
+ ['2019-08-30T20:00:00.000Z', 3],
+ ],
+ },
+ {
+ metric: { status_code: '2xx' },
+ values: [
+ ['2019-08-30T15:00:00.000Z', 1],
+ ['2019-08-30T16:00:00.000Z', 3],
+ ['2019-08-30T17:00:00.000Z', 6],
+ ['2019-08-30T18:00:00.000Z', 10],
+ ['2019-08-30T19:00:00.000Z', 8],
+ ['2019-08-30T20:00:00.000Z', 6],
+ ],
+ },
+ {
+ metric: { status_code: '3xx' },
+ values: [
+ ['2019-08-30T15:00:00.000Z', 1],
+ ['2019-08-30T16:00:00.000Z', 2],
+ ['2019-08-30T17:00:00.000Z', 3],
+ ['2019-08-30T18:00:00.000Z', 3],
+ ['2019-08-30T19:00:00.000Z', 2],
+ ['2019-08-30T20:00:00.000Z', 1],
+ ],
+ },
+ {
+ metric: { status_code: '4xx' },
+ values: [
+ ['2019-08-30T15:00:00.000Z', 2],
+ ['2019-08-30T16:00:00.000Z', 0],
+ ['2019-08-30T17:00:00.000Z', 0],
+ ['2019-08-30T18:00:00.000Z', 2],
+ ['2019-08-30T19:00:00.000Z', 0],
+ ['2019-08-30T20:00:00.000Z', 2],
+ ],
+ },
+ {
+ metric: { status_code: '5xx' },
+ values: [
+ ['2019-08-30T15:00:00.000Z', 0],
+ ['2019-08-30T16:00:00.000Z', 1],
+ ['2019-08-30T17:00:00.000Z', 0],
+ ['2019-08-30T18:00:00.000Z', 0],
+ ['2019-08-30T19:00:00.000Z', 0],
+ ['2019-08-30T20:00:00.000Z', 2],
+ ],
+ },
+ ],
+ },
+ ],
+};
diff --git a/spec/frontend/sidebar/assignees_spec.js b/spec/frontend/sidebar/assignees_spec.js
new file mode 100644
index 00000000000..14b6da10991
--- /dev/null
+++ b/spec/frontend/sidebar/assignees_spec.js
@@ -0,0 +1,200 @@
+import { mount } from '@vue/test-utils';
+import { trimText } from 'helpers/text_helper';
+import Assignee from '~/sidebar/components/assignees/assignees.vue';
+import UsersMock from './mock_data';
+import UsersMockHelper from '../helpers/user_mock_data_helper';
+
+describe('Assignee component', () => {
+ const getDefaultProps = () => ({
+ rootPath: 'http://localhost:3000',
+ users: [],
+ editable: false,
+ });
+ let wrapper;
+
+ const createWrapper = (propsData = getDefaultProps()) => {
+ wrapper = mount(Assignee, {
+ propsData,
+ sync: false,
+ attachToDocument: true,
+ });
+ };
+
+ const findComponentTextNoUsers = () => wrapper.find('.assign-yourself');
+ const findCollapsedChildren = () => wrapper.findAll('.sidebar-collapsed-icon > *');
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('No assignees/users', () => {
+ it('displays no assignee icon when collapsed', () => {
+ createWrapper();
+ const collapsedChildren = findCollapsedChildren();
+
+ expect(collapsedChildren.length).toBe(1);
+ expect(collapsedChildren.at(0).attributes('aria-label')).toBe('None');
+ expect(collapsedChildren.at(0).classes()).toContain('fa', 'fa-user');
+ });
+
+ it('displays only "None" when no users are assigned and the issue is read-only', () => {
+ createWrapper();
+ const componentTextNoUsers = trimText(findComponentTextNoUsers().text());
+
+ expect(componentTextNoUsers).toBe('None');
+ expect(componentTextNoUsers).not.toContain('assign yourself');
+ });
+
+ it('displays only "None" when no users are assigned and the issue can be edited', () => {
+ createWrapper({
+ ...getDefaultProps(),
+ editable: true,
+ });
+ const componentTextNoUsers = trimText(findComponentTextNoUsers().text());
+
+ expect(componentTextNoUsers).toContain('None');
+ expect(componentTextNoUsers).toContain('assign yourself');
+ });
+
+ it('emits the assign-self event when "assign yourself" is clicked', () => {
+ createWrapper({
+ ...getDefaultProps(),
+ editable: true,
+ });
+
+ jest.spyOn(wrapper.vm, '$emit');
+ wrapper.find('.assign-yourself .btn-link').trigger('click');
+
+ expect(wrapper.emitted('assign-self')).toBeTruthy();
+ });
+ });
+
+ describe('One assignee/user', () => {
+ it('displays one assignee icon when collapsed', () => {
+ createWrapper({
+ ...getDefaultProps(),
+ users: [UsersMock.user],
+ });
+
+ const collapsedChildren = findCollapsedChildren();
+ const assignee = collapsedChildren.at(0);
+
+ expect(collapsedChildren.length).toBe(1);
+ expect(assignee.find('.avatar').attributes('src')).toBe(UsersMock.user.avatar);
+ expect(assignee.find('.avatar').attributes('alt')).toBe(`${UsersMock.user.name}'s avatar`);
+
+ expect(trimText(assignee.find('.author').text())).toBe(UsersMock.user.name);
+ });
+ });
+
+ describe('Two or more assignees/users', () => {
+ it('displays two assignee icons when collapsed', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(2);
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const collapsedChildren = findCollapsedChildren();
+
+ expect(collapsedChildren.length).toBe(2);
+
+ const first = collapsedChildren.at(0);
+
+ expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar);
+ expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
+
+ expect(trimText(first.find('.author').text())).toBe(users[0].name);
+
+ const second = collapsedChildren.at(1);
+
+ expect(second.find('.avatar').attributes('src')).toBe(users[1].avatar);
+ expect(second.find('.avatar').attributes('alt')).toBe(`${users[1].name}'s avatar`);
+
+ expect(trimText(second.find('.author').text())).toBe(users[1].name);
+ });
+
+ it('displays one assignee icon and counter when collapsed', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const collapsedChildren = findCollapsedChildren();
+
+ expect(collapsedChildren.length).toBe(2);
+
+ const first = collapsedChildren.at(0);
+
+ expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar);
+ expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
+
+ expect(trimText(first.find('.author').text())).toBe(users[0].name);
+
+ const second = collapsedChildren.at(1);
+
+ expect(trimText(second.find('.avatar-counter').text())).toBe('+2');
+ });
+
+ it('Shows two assignees', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(2);
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ editable: true,
+ });
+
+ expect(wrapper.findAll('.user-item').length).toBe(users.length);
+ expect(wrapper.find('.user-list-more').exists()).toBe(false);
+ });
+
+ it('shows sorted assignee where "can merge" users are sorted first', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ users[0].can_merge = false;
+ users[1].can_merge = false;
+ users[2].can_merge = true;
+
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ editable: true,
+ });
+
+ expect(wrapper.vm.sortedAssigness[0].can_merge).toBe(true);
+ });
+
+ it('passes the sorted assignees to the uncollapsed-assignee-list', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ users[0].can_merge = false;
+ users[1].can_merge = false;
+ users[2].can_merge = true;
+
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const userItems = wrapper.findAll('.user-list .user-item a');
+
+ expect(userItems.length).toBe(3);
+ expect(userItems.at(0).attributes('data-original-title')).toBe(users[2].name);
+ });
+
+ it('passes the sorted assignees to the collapsed-assignee-list', () => {
+ const users = UsersMockHelper.createNumberRandomUsers(3);
+ users[0].can_merge = false;
+ users[1].can_merge = false;
+ users[2].can_merge = true;
+
+ createWrapper({
+ ...getDefaultProps(),
+ users,
+ });
+
+ const collapsedButton = wrapper.find('.sidebar-collapsed-user button');
+
+ expect(trimText(collapsedButton.text())).toBe(users[2].name);
+ });
+ });
+});
diff --git a/spec/frontend/sidebar/mock_data.js b/spec/frontend/sidebar/mock_data.js
new file mode 100644
index 00000000000..3ee97b978fd
--- /dev/null
+++ b/spec/frontend/sidebar/mock_data.js
@@ -0,0 +1,213 @@
+const RESPONSE_MAP = {
+ GET: {
+ '/gitlab-org/gitlab-shell/issues/5.json': {
+ id: 45,
+ iid: 5,
+ author_id: 23,
+ description: 'Nulla ullam commodi delectus adipisci quis sit.',
+ lock_version: null,
+ milestone_id: 21,
+ position: 0,
+ state: 'closed',
+ title: 'Vel et nulla voluptatibus corporis dolor iste saepe laborum.',
+ updated_by_id: 1,
+ created_at: '2017-02-02T21: 49: 49.664Z',
+ updated_at: '2017-05-03T22: 26: 03.760Z',
+ time_estimate: 0,
+ total_time_spent: 0,
+ human_time_estimate: null,
+ human_total_time_spent: null,
+ branch_name: null,
+ confidential: false,
+ assignees: [
+ {
+ name: 'User 0',
+ username: 'user0',
+ id: 22,
+ state: 'active',
+ avatar_url:
+ 'https://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:
+ 'https://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:
+ 'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
+ web_url: 'http: //localhost:3001/michaele.will',
+ },
+ ],
+ due_date: null,
+ moved_to_id: null,
+ project_id: 4,
+ weight: null,
+ milestone: {
+ id: 21,
+ iid: 1,
+ project_id: 4,
+ title: 'v0.0',
+ description: 'Molestiae commodi laboriosam odio sunt eaque reprehenderit.',
+ state: 'active',
+ created_at: '2017-02-02T21: 49: 30.530Z',
+ updated_at: '2017-02-02T21: 49: 30.530Z',
+ due_date: null,
+ start_date: null,
+ },
+ labels: [],
+ },
+ '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras': {
+ assignees: [
+ {
+ name: 'User 0',
+ username: 'user0',
+ id: 22,
+ state: 'active',
+ avatar_url:
+ 'https://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:
+ 'https://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:
+ 'https://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:
+ 'https://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:
+ 'https://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:
+ 'https://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,
+ name_with_namespace: 'No project',
+ },
+ {
+ id: 20,
+ name_with_namespace: '<img src=x onerror=alert(document.domain)> foo / bar',
+ },
+ ],
+ },
+ PUT: {
+ '/gitlab-org/gitlab-shell/issues/5.json': {
+ data: {},
+ },
+ },
+ POST: {
+ '/gitlab-org/gitlab-shell/issues/5/move': {
+ id: 123,
+ iid: 5,
+ author_id: 1,
+ description: 'some description',
+ lock_version: 5,
+ milestone_id: null,
+ state: 'opened',
+ title: 'some title',
+ updated_by_id: 1,
+ created_at: '2017-06-27T19:54:42.437Z',
+ updated_at: '2017-08-18T03:39:49.222Z',
+ time_estimate: 0,
+ total_time_spent: 0,
+ human_time_estimate: null,
+ human_total_time_spent: null,
+ branch_name: null,
+ confidential: false,
+ assignees: [],
+ due_date: null,
+ moved_to_id: null,
+ project_id: 7,
+ milestone: null,
+ labels: [],
+ web_url: '/root/some-project/issues/5',
+ },
+ '/gitlab-org/gitlab-shell/issues/5/toggle_subscription': {},
+ },
+};
+
+const mockData = {
+ responseMap: RESPONSE_MAP,
+ mediator: {
+ endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras',
+ toggleSubscriptionEndpoint: '/gitlab-org/gitlab-shell/issues/5/toggle_subscription',
+ moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move',
+ projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15',
+ editable: true,
+ currentUser: {
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ avatar_url:
+ 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ },
+ rootPath: '/',
+ fullPath: '/gitlab-org/gitlab-shell',
+ },
+ time: {
+ time_estimate: 3600,
+ total_time_spent: 0,
+ human_time_estimate: '1h',
+ human_total_time_spent: null,
+ },
+ user: {
+ avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
+ id: 1,
+ name: 'Administrator',
+ username: 'root',
+ },
+};
+
+export default mockData;
diff --git a/spec/graphql/mutations/issues/set_confidential_spec.rb b/spec/graphql/mutations/issues/set_confidential_spec.rb
new file mode 100644
index 00000000000..05b787eb5ca
--- /dev/null
+++ b/spec/graphql/mutations/issues/set_confidential_spec.rb
@@ -0,0 +1,39 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Mutations::Issues::SetConfidential do
+ let(:issue) { create(:issue) }
+ let(:user) { create(:user) }
+ subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) }
+
+ describe '#resolve' do
+ let(:confidential) { true }
+ let(:mutated_issue) { subject[:issue] }
+ subject { mutation.resolve(project_path: issue.project.full_path, iid: issue.iid, confidential: confidential) }
+
+ it 'raises an error if the resource is not accessible to the user' do
+ expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
+ end
+
+ context 'when the user can update the issue' do
+ before do
+ issue.project.add_developer(user)
+ end
+
+ it 'returns the issue as confidential' do
+ expect(mutated_issue).to eq(issue)
+ expect(mutated_issue.confidential).to be_truthy
+ expect(subject[:errors]).to be_empty
+ end
+
+ context 'when passing confidential as false' do
+ let(:confidential) { false }
+
+ it 'updates the issue confidentiality to false' do
+ expect(mutated_issue.confidential).to be_falsey
+ end
+ end
+ end
+ end
+end
diff --git a/spec/javascripts/monitoring/mock_data.js b/spec/javascripts/monitoring/mock_data.js
index f59c4ee4264..c80401e8c1d 100644
--- a/spec/javascripts/monitoring/mock_data.js
+++ b/spec/javascripts/monitoring/mock_data.js
@@ -1,226 +1,5 @@
-import {
- anomalyMockGraphData as importedAnomalyMockGraphData,
- metricsGroupsAPIResponse as importedMetricsGroupsAPIResponse,
- environmentData as importedEnvironmentData,
- dashboardGitResponse as importedDashboardGitResponse,
-} from '../../frontend/monitoring/mock_data';
+// No new code should be added to this file. Instead, modify the
+// file this one re-exports from. For more detail about why, see:
+// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/31349
-export const anomalyMockGraphData = importedAnomalyMockGraphData;
-export const metricsGroupsAPIResponse = importedMetricsGroupsAPIResponse;
-export const environmentData = importedEnvironmentData;
-export const dashboardGitResponse = importedDashboardGitResponse;
-
-export const mockApiEndpoint = `${gl.TEST_HOST}/monitoring/mock`;
-
-export const mockedQueryResultPayload = {
- metricId: '17_system_metrics_kubernetes_container_memory_average',
- result: [
- {
- metric: {},
- values: [
- [1563272065.589, '10.396484375'],
- [1563272125.589, '10.333984375'],
- [1563272185.589, '10.333984375'],
- [1563272245.589, '10.333984375'],
- [1563272305.589, '10.333984375'],
- [1563272365.589, '10.333984375'],
- [1563272425.589, '10.38671875'],
- [1563272485.589, '10.333984375'],
- [1563272545.589, '10.333984375'],
- [1563272605.589, '10.333984375'],
- [1563272665.589, '10.333984375'],
- [1563272725.589, '10.333984375'],
- [1563272785.589, '10.396484375'],
- [1563272845.589, '10.333984375'],
- [1563272905.589, '10.333984375'],
- [1563272965.589, '10.3984375'],
- [1563273025.589, '10.337890625'],
- [1563273085.589, '10.34765625'],
- [1563273145.589, '10.337890625'],
- [1563273205.589, '10.337890625'],
- [1563273265.589, '10.337890625'],
- [1563273325.589, '10.337890625'],
- [1563273385.589, '10.337890625'],
- [1563273445.589, '10.337890625'],
- [1563273505.589, '10.337890625'],
- [1563273565.589, '10.337890625'],
- [1563273625.589, '10.337890625'],
- [1563273685.589, '10.337890625'],
- [1563273745.589, '10.337890625'],
- [1563273805.589, '10.337890625'],
- [1563273865.589, '10.390625'],
- [1563273925.589, '10.390625'],
- ],
- },
- ],
-};
-
-export const mockedQueryResultPayloadCoresTotal = {
- metricId: '13_system_metrics_kubernetes_container_cores_total',
- result: [
- {
- metric: {},
- values: [
- [1563272065.589, '9.396484375'],
- [1563272125.589, '9.333984375'],
- [1563272185.589, '9.333984375'],
- [1563272245.589, '9.333984375'],
- [1563272305.589, '9.333984375'],
- [1563272365.589, '9.333984375'],
- [1563272425.589, '9.38671875'],
- [1563272485.589, '9.333984375'],
- [1563272545.589, '9.333984375'],
- [1563272605.589, '9.333984375'],
- [1563272665.589, '9.333984375'],
- [1563272725.589, '9.333984375'],
- [1563272785.589, '9.396484375'],
- [1563272845.589, '9.333984375'],
- [1563272905.589, '9.333984375'],
- [1563272965.589, '9.3984375'],
- [1563273025.589, '9.337890625'],
- [1563273085.589, '9.34765625'],
- [1563273145.589, '9.337890625'],
- [1563273205.589, '9.337890625'],
- [1563273265.589, '9.337890625'],
- [1563273325.589, '9.337890625'],
- [1563273385.589, '9.337890625'],
- [1563273445.589, '9.337890625'],
- [1563273505.589, '9.337890625'],
- [1563273565.589, '9.337890625'],
- [1563273625.589, '9.337890625'],
- [1563273685.589, '9.337890625'],
- [1563273745.589, '9.337890625'],
- [1563273805.589, '9.337890625'],
- [1563273865.589, '9.390625'],
- [1563273925.589, '9.390625'],
- ],
- },
- ],
-};
-
-export const graphDataPrometheusQuery = {
- title: 'Super Chart A2',
- type: 'single-stat',
- weight: 2,
- metrics: [
- {
- id: 'metric_a1',
- metricId: '2',
- query: 'max(go_memstats_alloc_bytes{job="prometheus"}) by (job) /1024/1024',
- unit: 'MB',
- label: 'Total Consumption',
- metric_id: 2,
- prometheus_endpoint_path:
- '/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
- result: [
- {
- metric: { job: 'prometheus' },
- value: ['2019-06-26T21:03:20.881Z', 91],
- },
- ],
- },
- ],
-};
-
-export const graphDataPrometheusQueryRange = {
- title: 'Super Chart A1',
- type: 'area-chart',
- weight: 2,
- metrics: [
- {
- id: 'metric_a1',
- metricId: '2',
- query_range:
- 'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024',
- unit: 'MB',
- label: 'Total Consumption',
- metric_id: 2,
- prometheus_endpoint_path:
- '/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
- result: [
- {
- metric: {},
- values: [[1495700554.925, '8.0390625'], [1495700614.925, '8.0390625']],
- },
- ],
- },
- ],
-};
-
-export const graphDataPrometheusQueryRangeMultiTrack = {
- title: 'Super Chart A3',
- type: 'heatmap',
- weight: 3,
- x_label: 'Status Code',
- y_label: 'Time',
- metrics: [
- {
- metricId: '1',
- id: 'response_metrics_nginx_ingress_throughput_status_code',
- query_range:
- 'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[60m])) by (status_code)',
- unit: 'req / sec',
- label: 'Status Code',
- metric_id: 1,
- prometheus_endpoint_path:
- '/root/rails_nodb/environments/3/prometheus/api/v1/query_range?query=sum%28rate%28nginx_upstream_responses_total%7Bupstream%3D~%22%25%7Bkube_namespace%7D-%25%7Bci_environment_slug%7D-.%2A%22%7D%5B2m%5D%29%29+by+%28status_code%29',
- result: [
- {
- metric: { status_code: '1xx' },
- values: [
- ['2019-08-30T15:00:00.000Z', 0],
- ['2019-08-30T16:00:00.000Z', 2],
- ['2019-08-30T17:00:00.000Z', 0],
- ['2019-08-30T18:00:00.000Z', 0],
- ['2019-08-30T19:00:00.000Z', 0],
- ['2019-08-30T20:00:00.000Z', 3],
- ],
- },
- {
- metric: { status_code: '2xx' },
- values: [
- ['2019-08-30T15:00:00.000Z', 1],
- ['2019-08-30T16:00:00.000Z', 3],
- ['2019-08-30T17:00:00.000Z', 6],
- ['2019-08-30T18:00:00.000Z', 10],
- ['2019-08-30T19:00:00.000Z', 8],
- ['2019-08-30T20:00:00.000Z', 6],
- ],
- },
- {
- metric: { status_code: '3xx' },
- values: [
- ['2019-08-30T15:00:00.000Z', 1],
- ['2019-08-30T16:00:00.000Z', 2],
- ['2019-08-30T17:00:00.000Z', 3],
- ['2019-08-30T18:00:00.000Z', 3],
- ['2019-08-30T19:00:00.000Z', 2],
- ['2019-08-30T20:00:00.000Z', 1],
- ],
- },
- {
- metric: { status_code: '4xx' },
- values: [
- ['2019-08-30T15:00:00.000Z', 2],
- ['2019-08-30T16:00:00.000Z', 0],
- ['2019-08-30T17:00:00.000Z', 0],
- ['2019-08-30T18:00:00.000Z', 2],
- ['2019-08-30T19:00:00.000Z', 0],
- ['2019-08-30T20:00:00.000Z', 2],
- ],
- },
- {
- metric: { status_code: '5xx' },
- values: [
- ['2019-08-30T15:00:00.000Z', 0],
- ['2019-08-30T16:00:00.000Z', 1],
- ['2019-08-30T17:00:00.000Z', 0],
- ['2019-08-30T18:00:00.000Z', 0],
- ['2019-08-30T19:00:00.000Z', 0],
- ['2019-08-30T20:00:00.000Z', 2],
- ],
- },
- ],
- },
- ],
-};
+export * from '../../frontend/monitoring/mock_data';
diff --git a/spec/javascripts/sidebar/assignees_spec.js b/spec/javascripts/sidebar/assignees_spec.js
deleted file mode 100644
index a1df5389a38..00000000000
--- a/spec/javascripts/sidebar/assignees_spec.js
+++ /dev/null
@@ -1,248 +0,0 @@
-import Vue from 'vue';
-import Assignee from '~/sidebar/components/assignees/assignees.vue';
-import UsersMock from './mock_data';
-import UsersMockHelper from '../helpers/user_mock_data_helper';
-
-describe('Assignee component', () => {
- let component;
- let AssigneeComponent;
-
- beforeEach(() => {
- AssigneeComponent = Vue.extend(Assignee);
- });
-
- describe('No assignees/users', () => {
- it('displays no assignee icon when collapsed', () => {
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users: [],
- editable: false,
- },
- }).$mount();
-
- const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
-
- expect(collapsed.childElementCount).toEqual(1);
- expect(collapsed.children[0].getAttribute('aria-label')).toEqual('None');
- expect(collapsed.children[0].classList.contains('fa')).toEqual(true);
- expect(collapsed.children[0].classList.contains('fa-user')).toEqual(true);
- });
-
- it('displays only "None" when no users are assigned and the issue is read-only', () => {
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users: [],
- editable: false,
- },
- }).$mount();
- const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();
-
- expect(componentTextNoUsers).toBe('None');
- expect(componentTextNoUsers.indexOf('assign yourself')).toEqual(-1);
- });
-
- it('displays only "None" when no users are assigned and the issue can be edited', () => {
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users: [],
- editable: true,
- },
- }).$mount();
- const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();
-
- expect(componentTextNoUsers.indexOf('None')).toEqual(0);
- expect(componentTextNoUsers.indexOf('assign yourself')).toBeGreaterThan(0);
- });
-
- it('emits the assign-self event when "assign yourself" is clicked', () => {
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users: [],
- editable: true,
- },
- }).$mount();
-
- spyOn(component, '$emit');
- component.$el.querySelector('.assign-yourself .btn-link').click();
-
- expect(component.$emit).toHaveBeenCalledWith('assign-self');
- });
- });
-
- describe('One assignee/user', () => {
- it('displays one assignee icon when collapsed', () => {
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users: [UsersMock.user],
- editable: false,
- },
- }).$mount();
-
- const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
- const assignee = collapsed.children[0];
-
- expect(collapsed.childElementCount).toEqual(1);
- expect(assignee.querySelector('.avatar').getAttribute('src')).toEqual(UsersMock.user.avatar);
- expect(assignee.querySelector('.avatar').getAttribute('alt')).toEqual(
- `${UsersMock.user.name}'s avatar`,
- );
-
- expect(assignee.querySelector('.author').innerText.trim()).toEqual(UsersMock.user.name);
- });
- });
-
- describe('Two or more assignees/users', () => {
- it('has no "cannot merge" tooltip when every user can merge', () => {
- const users = UsersMockHelper.createNumberRandomUsers(2);
- users[0].can_merge = true;
- users[1].can_merge = true;
-
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000/',
- users,
- editable: true,
- issuableType: 'merge_request',
- },
- }).$mount();
-
- expect(component.collapsedTooltipTitle).not.toContain('cannot merge');
- });
-
- it('displays two assignee icons when collapsed', () => {
- const users = UsersMockHelper.createNumberRandomUsers(2);
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users,
- editable: false,
- },
- }).$mount();
-
- const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
-
- expect(collapsed.childElementCount).toEqual(2);
-
- const first = collapsed.children[0];
-
- expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatar);
- expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(
- `${users[0].name}'s avatar`,
- );
-
- expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);
-
- const second = collapsed.children[1];
-
- expect(second.querySelector('.avatar').getAttribute('src')).toEqual(users[1].avatar);
- expect(second.querySelector('.avatar').getAttribute('alt')).toEqual(
- `${users[1].name}'s avatar`,
- );
-
- expect(second.querySelector('.author').innerText.trim()).toEqual(users[1].name);
- });
-
- it('displays one assignee icon and counter when collapsed', () => {
- const users = UsersMockHelper.createNumberRandomUsers(3);
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users,
- editable: false,
- },
- }).$mount();
-
- const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
-
- expect(collapsed.childElementCount).toEqual(2);
-
- const first = collapsed.children[0];
-
- expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatar);
- expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(
- `${users[0].name}'s avatar`,
- );
-
- expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);
-
- const second = collapsed.children[1];
-
- expect(second.querySelector('.avatar-counter').innerText.trim()).toEqual('+2');
- });
-
- it('Shows two assignees', () => {
- const users = UsersMockHelper.createNumberRandomUsers(2);
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users,
- editable: true,
- },
- }).$mount();
-
- expect(component.$el.querySelectorAll('.user-item').length).toEqual(users.length);
- expect(component.$el.querySelector('.user-list-more')).toBe(null);
- });
-
- it('shows sorted assignee where "can merge" users are sorted first', () => {
- const users = UsersMockHelper.createNumberRandomUsers(3);
- users[0].can_merge = false;
- users[1].can_merge = false;
- users[2].can_merge = true;
-
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users,
- editable: true,
- },
- }).$mount();
-
- expect(component.sortedAssigness[0].can_merge).toBe(true);
- });
-
- it('passes the sorted assignees to the uncollapsed-assignee-list', () => {
- const users = UsersMockHelper.createNumberRandomUsers(3);
- users[0].can_merge = false;
- users[1].can_merge = false;
- users[2].can_merge = true;
-
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users,
- editable: false,
- },
- }).$mount();
-
- const userItems = component.$el.querySelectorAll('.user-list .user-item a');
-
- expect(userItems.length).toBe(3);
- expect(userItems[0].dataset.originalTitle).toBe(users[2].name);
- });
-
- it('passes the sorted assignees to the collapsed-assignee-list', () => {
- const users = UsersMockHelper.createNumberRandomUsers(3);
- users[0].can_merge = false;
- users[1].can_merge = false;
- users[2].can_merge = true;
-
- component = new AssigneeComponent({
- propsData: {
- rootPath: 'http://localhost:3000',
- users,
- editable: false,
- },
- }).$mount();
-
- const collapsedButton = component.$el.querySelector('.sidebar-collapsed-user button');
-
- expect(collapsedButton.innerText.trim()).toBe(users[2].name);
- });
- });
-});
diff --git a/spec/javascripts/sidebar/mock_data.js b/spec/javascripts/sidebar/mock_data.js
index 3ee97b978fd..c869ff96933 100644
--- a/spec/javascripts/sidebar/mock_data.js
+++ b/spec/javascripts/sidebar/mock_data.js
@@ -1,213 +1,7 @@
-const RESPONSE_MAP = {
- GET: {
- '/gitlab-org/gitlab-shell/issues/5.json': {
- id: 45,
- iid: 5,
- author_id: 23,
- description: 'Nulla ullam commodi delectus adipisci quis sit.',
- lock_version: null,
- milestone_id: 21,
- position: 0,
- state: 'closed',
- title: 'Vel et nulla voluptatibus corporis dolor iste saepe laborum.',
- updated_by_id: 1,
- created_at: '2017-02-02T21: 49: 49.664Z',
- updated_at: '2017-05-03T22: 26: 03.760Z',
- time_estimate: 0,
- total_time_spent: 0,
- human_time_estimate: null,
- human_total_time_spent: null,
- branch_name: null,
- confidential: false,
- assignees: [
- {
- name: 'User 0',
- username: 'user0',
- id: 22,
- state: 'active',
- avatar_url:
- 'https://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:
- 'https://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:
- 'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
- web_url: 'http: //localhost:3001/michaele.will',
- },
- ],
- due_date: null,
- moved_to_id: null,
- project_id: 4,
- weight: null,
- milestone: {
- id: 21,
- iid: 1,
- project_id: 4,
- title: 'v0.0',
- description: 'Molestiae commodi laboriosam odio sunt eaque reprehenderit.',
- state: 'active',
- created_at: '2017-02-02T21: 49: 30.530Z',
- updated_at: '2017-02-02T21: 49: 30.530Z',
- due_date: null,
- start_date: null,
- },
- labels: [],
- },
- '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras': {
- assignees: [
- {
- name: 'User 0',
- username: 'user0',
- id: 22,
- state: 'active',
- avatar_url:
- 'https://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:
- 'https://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:
- 'https://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:
- 'https://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:
- 'https://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:
- 'https://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,
- name_with_namespace: 'No project',
- },
- {
- id: 20,
- name_with_namespace: '<img src=x onerror=alert(document.domain)> foo / bar',
- },
- ],
- },
- PUT: {
- '/gitlab-org/gitlab-shell/issues/5.json': {
- data: {},
- },
- },
- POST: {
- '/gitlab-org/gitlab-shell/issues/5/move': {
- id: 123,
- iid: 5,
- author_id: 1,
- description: 'some description',
- lock_version: 5,
- milestone_id: null,
- state: 'opened',
- title: 'some title',
- updated_by_id: 1,
- created_at: '2017-06-27T19:54:42.437Z',
- updated_at: '2017-08-18T03:39:49.222Z',
- time_estimate: 0,
- total_time_spent: 0,
- human_time_estimate: null,
- human_total_time_spent: null,
- branch_name: null,
- confidential: false,
- assignees: [],
- due_date: null,
- moved_to_id: null,
- project_id: 7,
- milestone: null,
- labels: [],
- web_url: '/root/some-project/issues/5',
- },
- '/gitlab-org/gitlab-shell/issues/5/toggle_subscription': {},
- },
-};
+// No new code should be added to this file. Instead, modify the
+// file this one re-exports from. For more detail about why, see:
+// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/31349
-const mockData = {
- responseMap: RESPONSE_MAP,
- mediator: {
- endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras',
- toggleSubscriptionEndpoint: '/gitlab-org/gitlab-shell/issues/5/toggle_subscription',
- moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move',
- projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15',
- editable: true,
- currentUser: {
- id: 1,
- name: 'Administrator',
- username: 'root',
- avatar_url:
- 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- },
- rootPath: '/',
- fullPath: '/gitlab-org/gitlab-shell',
- },
- time: {
- time_estimate: 3600,
- total_time_spent: 0,
- human_time_estimate: '1h',
- human_total_time_spent: null,
- },
- user: {
- avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
- id: 1,
- name: 'Administrator',
- username: 'root',
- },
-};
+import mockData from '../../../spec/frontend/sidebar/mock_data';
export default mockData;
diff --git a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
index c7a5ac783b3..caa84faa9c1 100644
--- a/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
+++ b/spec/lib/gitlab/ci/build/prerequisite/kubernetes_namespace_spec.rb
@@ -38,13 +38,29 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
.and_return(double(execute: kubernetes_namespace))
end
- it { is_expected.to be_falsey }
-
- context 'and the service_account_token is blank' do
- let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: nil) }
+ context 'and the knative version role binding is missing' do
+ before do
+ allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
+ .and_return(double(execute: nil))
+ end
it { is_expected.to be_truthy }
end
+
+ context 'and the knative version role binding already exists' do
+ before do
+ allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
+ .and_return(double(execute: true))
+ end
+
+ it { is_expected.to be_falsey }
+
+ context 'and the service_account_token is blank' do
+ let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: nil) }
+
+ it { is_expected.to be_truthy }
+ end
+ end
end
end
@@ -115,6 +131,24 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
subject
end
end
+
+ context 'knative version role binding is missing' do
+ before do
+ allow(Clusters::KubernetesNamespaceFinder).to receive(:new)
+ .and_return(double(execute: kubernetes_namespace))
+ allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
+ .and_return(double(execute: nil))
+ end
+
+ it 'creates the knative version role binding' do
+ expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService)
+ .to receive(:new)
+ .with(cluster: cluster, kubernetes_namespace: kubernetes_namespace)
+ .and_return(service)
+
+ subject
+ end
+ end
end
context 'completion is not required' do
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 6c9467916de..0ab3e513e24 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -17,13 +17,13 @@ describe Gitlab::Git::Commit, :seed_helper do
@committer = {
email: 'mike@smith.com',
name: "Mike Smith",
- time: Time.now
+ time: Time.new(2000, 1, 1, 0, 0, 0, "+08:00")
}
@author = {
email: 'john@smith.com',
name: "John Smith",
- time: Time.now
+ time: Time.new(2000, 1, 1, 0, 0, 0, "-08:00")
}
@parents = [rugged_repo.head.target]
@@ -48,7 +48,7 @@ describe Gitlab::Git::Commit, :seed_helper do
it { expect(@commit.id).to eq(@raw_commit.oid) }
it { expect(@commit.sha).to eq(@raw_commit.oid) }
it { expect(@commit.safe_message).to eq(@raw_commit.message) }
- it { expect(@commit.created_at).to eq(@raw_commit.author[:time]) }
+ it { expect(@commit.created_at).to eq(@raw_commit.committer[:time]) }
it { expect(@commit.date).to eq(@raw_commit.committer[:time]) }
it { expect(@commit.author_email).to eq(@author[:email]) }
it { expect(@commit.author_name).to eq(@author[:name]) }
@@ -79,13 +79,27 @@ describe Gitlab::Git::Commit, :seed_helper do
it { expect(commit.id).to eq(id) }
it { expect(commit.sha).to eq(id) }
it { expect(commit.safe_message).to eq(body) }
- it { expect(commit.created_at).to eq(Time.at(committer.date.seconds)) }
+ it { expect(commit.created_at).to eq(Time.at(committer.date.seconds).utc) }
it { expect(commit.author_email).to eq(author.email) }
it { expect(commit.author_name).to eq(author.name) }
it { expect(commit.committer_name).to eq(committer.name) }
it { expect(commit.committer_email).to eq(committer.email) }
it { expect(commit.parent_ids).to eq(gitaly_commit.parent_ids) }
+ context 'non-UTC dates' do
+ let(:seconds) { Time.now.to_i }
+
+ it 'sets timezones correctly' do
+ gitaly_commit.author.date.seconds = seconds
+ gitaly_commit.author.timezone = '-0800'
+ gitaly_commit.committer.date.seconds = seconds
+ gitaly_commit.committer.timezone = '+0800'
+
+ expect(commit.authored_date).to eq(Time.at(seconds, in: '-08:00'))
+ expect(commit.committed_date).to eq(Time.at(seconds, in: '+08:00'))
+ end
+ end
+
context 'body_size != body.size' do
let(:body) { (+"").force_encoding('ASCII-8BIT') }
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 916f5536ebd..95435c6dabd 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -1197,6 +1197,54 @@ describe Ci::Build do
end
end
+ describe '#expanded_kubernetes_namespace' do
+ let(:build) { create(:ci_build, environment: environment, options: options) }
+
+ subject { build.expanded_kubernetes_namespace }
+
+ context 'environment and namespace are not set' do
+ let(:environment) { nil }
+ let(:options) { nil }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'environment is specified' do
+ let(:environment) { 'production' }
+
+ context 'namespace is not set' do
+ let(:options) { nil }
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'namespace is provided' do
+ let(:options) do
+ {
+ environment: {
+ name: environment,
+ kubernetes: {
+ namespace: namespace
+ }
+ }
+ }
+ end
+
+ context 'with a static value' do
+ let(:namespace) { 'production' }
+
+ it { is_expected.to eq namespace }
+ end
+
+ context 'with a dynamic value' do
+ let(:namespace) { 'deploy-$CI_COMMIT_REF_NAME'}
+
+ it { is_expected.to eq 'deploy-master' }
+ end
+ end
+ end
+ end
+
describe '#starts_environment?' do
subject { build.starts_environment? }
@@ -2987,6 +3035,32 @@ describe Ci::Build do
end
end
+ describe '#deployment_variables' do
+ let(:build) { create(:ci_build, environment: environment) }
+ let(:environment) { 'production' }
+ let(:kubernetes_namespace) { 'namespace' }
+ let(:project_variables) { double }
+
+ subject { build.deployment_variables(environment: environment) }
+
+ before do
+ allow(build).to receive(:expanded_kubernetes_namespace)
+ .and_return(kubernetes_namespace)
+
+ allow(build.project).to receive(:deployment_variables)
+ .with(environment: environment, kubernetes_namespace: kubernetes_namespace)
+ .and_return(project_variables)
+ end
+
+ it { is_expected.to eq(project_variables) }
+
+ context 'environment is nil' do
+ let(:environment) { nil }
+
+ it { is_expected.to be_empty }
+ end
+ end
+
describe '#scoped_variables_hash' do
context 'when overriding CI variables' do
before do
diff --git a/spec/models/clusters/platforms/kubernetes_spec.rb b/spec/models/clusters/platforms/kubernetes_spec.rb
index d53fc32cfef..4271cf9f1b3 100644
--- a/spec/models/clusters/platforms/kubernetes_spec.rb
+++ b/spec/models/clusters/platforms/kubernetes_spec.rb
@@ -290,6 +290,26 @@ describe Clusters::Platforms::Kubernetes do
it { is_expected.to include(key: 'KUBE_TOKEN', value: platform.token, public: false, masked: true) }
it { is_expected.to include(key: 'KUBE_NAMESPACE', value: namespace) }
it { is_expected.to include(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) }
+
+ context 'custom namespace is provided' do
+ let(:custom_namespace) { 'custom-namespace' }
+
+ subject do
+ platform.predefined_variables(
+ project: project,
+ environment_name: environment_name,
+ kubernetes_namespace: custom_namespace
+ )
+ end
+
+ before do
+ allow(platform).to receive(:kubeconfig).with(custom_namespace).and_return(kubeconfig)
+ end
+
+ it { is_expected.to include(key: 'KUBE_TOKEN', value: platform.token, public: false, masked: true) }
+ it { is_expected.to include(key: 'KUBE_NAMESPACE', value: custom_namespace) }
+ it { is_expected.to include(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) }
+ end
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index 839c4cadb5e..37c8484d69b 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -359,7 +359,7 @@ eos
it { expect(data).to be_a(Hash) }
it { expect(data[:message]).to include('adds bar folder and branch-test text file to check Repository merged_to_root_ref method') }
- it { expect(data[:timestamp]).to eq('2016-09-27T14:37:46Z') }
+ it { expect(data[:timestamp]).to eq('2016-09-27T14:37:46+00:00') }
it { expect(data[:added]).to contain_exactly("bar/branch-test.txt") }
it { expect(data[:modified]).to eq([]) }
it { expect(data[:removed]).to eq([]) }
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 45cd2768708..d84a8665dc8 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -106,6 +106,40 @@ describe Milestone do
end
end
+ describe '#merge_requests_enabled?' do
+ context "per project" do
+ it "is true for projects with MRs enabled" do
+ project = create(:project, :merge_requests_enabled)
+ milestone = create(:milestone, project: project)
+
+ expect(milestone.merge_requests_enabled?).to be(true)
+ end
+
+ it "is false for projects with MRs disabled" do
+ project = create(:project, :repository_enabled, :merge_requests_disabled)
+ milestone = create(:milestone, project: project)
+
+ expect(milestone.merge_requests_enabled?).to be(false)
+ end
+
+ it "is false for projects with repository disabled" do
+ project = create(:project, :repository_disabled)
+ milestone = create(:milestone, project: project)
+
+ expect(milestone.merge_requests_enabled?).to be(false)
+ end
+ end
+
+ context "per group" do
+ let(:group) { create(:group) }
+ let(:milestone) { create(:milestone, group: group) }
+
+ it "is always true for groups, for performance reasons" do
+ expect(milestone.merge_requests_enabled?).to be(true)
+ end
+ end
+ end
+
describe "unique milestone title" do
context "per project" do
it "does not accept the same title in a project twice" do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index b1f88c4530e..37604a557ea 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2765,8 +2765,9 @@ describe Project do
describe '#deployment_variables' do
let(:project) { create(:project) }
let(:environment) { 'production' }
+ let(:namespace) { 'namespace' }
- subject { project.deployment_variables(environment: environment) }
+ subject { project.deployment_variables(environment: environment, kubernetes_namespace: namespace) }
before do
expect(project).to receive(:deployment_platform).with(environment: environment)
@@ -2785,7 +2786,7 @@ describe Project do
before do
expect(deployment_platform).to receive(:predefined_variables)
- .with(project: project, environment_name: environment)
+ .with(project: project, environment_name: environment, kubernetes_namespace: namespace)
.and_return(platform_variables)
end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 675b06b057c..eda2f6d854f 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -131,7 +131,7 @@ describe API::Branches do
end
new_branch_name = 'protected-branch'
- CreateBranchService.new(project, current_user).execute(new_branch_name, 'master')
+ ::Branches::CreateService.new(project, current_user).execute(new_branch_name, 'master')
create(:protected_branch, name: new_branch_name, project: project)
expect do
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index ec18156f49f..378441220c7 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -315,11 +315,11 @@ describe API::Files do
expect(range['commit']['message'])
.to eq("Files, encoding and much more\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n")
- expect(range['commit']['authored_date']).to eq('2014-02-27T08:14:56.000Z')
+ expect(range['commit']['authored_date']).to eq('2014-02-27T10:14:56.000+02:00')
expect(range['commit']['author_name']).to eq('Dmitriy Zaporozhets')
expect(range['commit']['author_email']).to eq('dmitriy.zaporozhets@gmail.com')
- expect(range['commit']['committed_date']).to eq('2014-02-27T08:14:56.000Z')
+ expect(range['commit']['committed_date']).to eq('2014-02-27T10:14:56.000+02:00')
expect(range['commit']['committer_name']).to eq('Dmitriy Zaporozhets')
expect(range['commit']['committer_email']).to eq('dmitriy.zaporozhets@gmail.com')
end
diff --git a/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
new file mode 100644
index 00000000000..4d0bb59b030
--- /dev/null
+++ b/spec/requests/api/graphql/mutations/issues/set_confidential_spec.rb
@@ -0,0 +1,51 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Setting an issue as confidential' do
+ include GraphqlHelpers
+
+ let(:current_user) { create(:user) }
+ let(:issue) { create(:issue) }
+ let(:project) { issue.project }
+ let(:input) { { confidential: true } }
+
+ let(:mutation) do
+ variables = {
+ project_path: project.full_path,
+ iid: issue.iid.to_s
+ }
+ graphql_mutation(:issue_set_confidential, variables.merge(input),
+ <<-QL.strip_heredoc
+ clientMutationId
+ errors
+ issue {
+ iid
+ confidential
+ }
+ QL
+ )
+ end
+
+ def mutation_response
+ graphql_mutation_response(:issue_set_confidential)
+ end
+
+ before do
+ project.add_developer(current_user)
+ end
+
+ it 'returns an error if the user is not allowed to update the issue' do
+ error = "The resource that you are attempting to access does not exist or you don't have permission to perform this action"
+ post_graphql_mutation(mutation, current_user: create(:user))
+
+ expect(graphql_errors).to include(a_hash_including('message' => error))
+ end
+
+ it 'updates the issue confidentiality' do
+ post_graphql_mutation(mutation, current_user: current_user)
+
+ expect(response).to have_gitlab_http_status(:success)
+ expect(mutation_response['issue']['confidential']).to be_truthy
+ end
+end
diff --git a/spec/requests/user_avatar_spec.rb b/spec/requests/user_avatar_spec.rb
new file mode 100644
index 00000000000..9451674161c
--- /dev/null
+++ b/spec/requests/user_avatar_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'Loading a user avatar' do
+ let(:user) { create(:user, :with_avatar) }
+
+ context 'when logged in' do
+ # The exact query count will vary depending on the 2FA settings of the
+ # instance, group, and user. Removing those extra 2FA queries in this case
+ # may not be a good idea, so we just set up the ideal case.
+ before do
+ stub_application_setting(require_two_factor_authentication: true)
+
+ login_as(create(:user, :two_factor))
+ end
+
+ # One each for: current user, avatar user, and upload record
+ it 'only performs three SQL queries' do
+ get user.avatar_url # Skip queries on first application load
+
+ expect(response).to have_gitlab_http_status(200)
+ expect { get user.avatar_url }.not_to exceed_query_limit(3)
+ end
+ end
+
+ context 'when logged out' do
+ # One each for avatar user and upload record
+ it 'only performs two SQL queries' do
+ get user.avatar_url # Skip queries on first application load
+
+ expect(response).to have_gitlab_http_status(200)
+ expect { get user.avatar_url }.not_to exceed_query_limit(2)
+ end
+ end
+end
diff --git a/spec/routing/instance_statistics_routing_spec.rb b/spec/routing/instance_statistics_routing_spec.rb
index b94faabfa1d..48a3ac4695c 100644
--- a/spec/routing/instance_statistics_routing_spec.rb
+++ b/spec/routing/instance_statistics_routing_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
describe 'Instance Statistics', 'routing' do
include RSpec::Rails::RequestExampleGroup
- it "routes '/-/instance_statistics' to conversational development index" do
- expect(get('/-/instance_statistics')).to redirect_to('/-/instance_statistics/conversational_development_index')
+ it "routes '/-/instance_statistics' to dev ops score" do
+ expect(get('/-/instance_statistics')).to redirect_to('/-/instance_statistics/dev_ops_score')
end
end
diff --git a/spec/services/create_branch_service_spec.rb b/spec/services/branches/create_service_spec.rb
index 9661173c9e7..444491ed6f3 100644
--- a/spec/services/create_branch_service_spec.rb
+++ b/spec/services/branches/create_service_spec.rb
@@ -2,9 +2,9 @@
require 'spec_helper'
-describe CreateBranchService do
+describe Branches::CreateService do
let(:user) { create(:user) }
- let(:service) { described_class.new(project, user) }
+ subject(:service) { described_class.new(project, user) }
describe '#execute' do
context 'when repository is empty' do
@@ -30,7 +30,7 @@ describe CreateBranchService do
allow(project.repository).to receive(:add_branch).and_return(false)
end
- it 'retruns an error with the branch name' do
+ it 'returns an error with the branch name' do
result = service.execute('my-feature', 'master')
expect(result[:status]).to eq(:error)
diff --git a/spec/services/delete_merged_branches_service_spec.rb b/spec/services/branches/delete_merged_service_spec.rb
index dffc2bd93ee..962af8110f7 100644
--- a/spec/services/delete_merged_branches_service_spec.rb
+++ b/spec/services/branches/delete_merged_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-describe DeleteMergedBranchesService do
+describe Branches::DeleteMergedService do
include ProjectForksHelper
subject(:service) { described_class.new(project, project.owner) }
diff --git a/spec/services/delete_branch_service_spec.rb b/spec/services/branches/delete_service_spec.rb
index b8064c2cbc1..b4848978a6f 100644
--- a/spec/services/delete_branch_service_spec.rb
+++ b/spec/services/branches/delete_service_spec.rb
@@ -2,11 +2,11 @@
require 'spec_helper'
-describe DeleteBranchService do
+describe Branches::DeleteService do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:user) { create(:user) }
- let(:service) { described_class.new(project, user) }
+ subject(:service) { described_class.new(project, user) }
shared_examples 'a deleted branch' do |branch_name|
it 'removes the branch' do
diff --git a/spec/services/branches/validate_new_service_spec.rb b/spec/services/branches/validate_new_service_spec.rb
new file mode 100644
index 00000000000..460f28b5844
--- /dev/null
+++ b/spec/services/branches/validate_new_service_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Branches::ValidateNewService do
+ let(:project) { create(:project, :repository) }
+ subject(:service) { described_class.new(project) }
+
+ describe '#execute' do
+ context 'validation' do
+ it 'returns error with an invalid branch name' do
+ result = service.execute('refs/heads/invalid_branch')
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq('Branch name is invalid')
+ end
+
+ it 'returns success with a valid branch name' do
+ result = service.execute('valid_branch_name')
+
+ expect(result[:status]).to eq(:success)
+ end
+ end
+
+ context 'branch exist' do
+ it 'returns error when branch exists' do
+ result = service.execute('master')
+
+ expect(result[:status]).to eq(:error)
+ expect(result[:message]).to eq('Branch already exists')
+ end
+
+ it 'returns success when branch name is available' do
+ result = service.execute('valid_branch_name')
+
+ expect(result[:status]).to eq(:success)
+ end
+ end
+ end
+end
diff --git a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
index 291e63bbe4a..a9e3e881fd4 100644
--- a/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
+++ b/spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb
@@ -22,7 +22,7 @@ describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do
before do
stub_kubeclient_discover(api_url)
- stub_kubeclient_get_namespace(api_url)
+ stub_kubeclient_get_namespaces(api_url)
stub_kubeclient_get_service_account_error(api_url, 'gitlab')
stub_kubeclient_create_service_account(api_url)
stub_kubeclient_get_secret_error(api_url, 'gitlab-token')
@@ -39,6 +39,8 @@ describe Clusters::Kubernetes::CreateOrUpdateNamespaceService, '#execute' do
stub_kubeclient_put_role_binding(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, namespace: namespace)
stub_kubeclient_put_role(api_url, Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME, namespace: namespace)
stub_kubeclient_put_role_binding(api_url, Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_BINDING_NAME, namespace: namespace)
+ stub_kubeclient_put_cluster_role(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_NAME)
+ stub_kubeclient_put_cluster_role_binding(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_BINDING_NAME)
stub_kubeclient_get_secret(
api_url,
diff --git a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb
index 4df73fcc2ae..b40861e5aaf 100644
--- a/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb
+++ b/spec/services/clusters/kubernetes/create_or_update_service_account_service_spec.rb
@@ -141,12 +141,15 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
before do
cluster.platform_kubernetes.rbac!
+ stub_kubeclient_get_namespaces(api_url)
stub_kubeclient_get_role_binding_error(api_url, role_binding_name, namespace: namespace)
stub_kubeclient_create_role_binding(api_url, namespace: namespace)
stub_kubeclient_put_role(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_NAME, namespace: namespace)
stub_kubeclient_put_role_binding(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_SERVING_ROLE_BINDING_NAME, namespace: namespace)
stub_kubeclient_put_role(api_url, Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_NAME, namespace: namespace)
stub_kubeclient_put_role_binding(api_url, Clusters::Kubernetes::GITLAB_CROSSPLANE_DATABASE_ROLE_BINDING_NAME, namespace: namespace)
+ stub_kubeclient_put_cluster_role(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_NAME)
+ stub_kubeclient_put_cluster_role_binding(api_url, Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_BINDING_NAME)
end
it_behaves_like 'creates service account and token'
@@ -234,6 +237,30 @@ describe Clusters::Kubernetes::CreateOrUpdateServiceAccountService do
)
)
end
+
+ it 'creates a role and role binding granting the ability to get the version of deployments in knative-serving namespace' do
+ subject
+
+ expect(WebMock).to have_requested(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/#{Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_BINDING_NAME}").with(
+ body: hash_including(
+ metadata: {
+ name: Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_BINDING_NAME
+ },
+ roleRef: {
+ apiGroup: "rbac.authorization.k8s.io",
+ kind: "ClusterRole",
+ name: Clusters::Kubernetes::GITLAB_KNATIVE_VERSION_ROLE_NAME
+ },
+ subjects: [
+ {
+ kind: "ServiceAccount",
+ name: service_account_name,
+ namespace: namespace
+ }
+ ]
+ )
+ )
+ end
end
end
end
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index 1bdea973685..61c8103353c 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -211,7 +211,8 @@ describe MergeRequests::MergeService do
end
it 'does not delete the source branch' do
- expect(DeleteBranchService).not_to receive(:new)
+ expect(::Branches::DeleteService).not_to receive(:new)
+
service.execute(merge_request)
end
end
@@ -226,7 +227,7 @@ describe MergeRequests::MergeService do
end
it 'does not delete the source branch' do
- expect(DeleteBranchService).not_to receive(:new)
+ expect(::Branches::DeleteService).not_to receive(:new)
service.execute(merge_request)
end
end
@@ -238,7 +239,7 @@ describe MergeRequests::MergeService do
end
it 'removes the source branch using the author user' do
- expect(DeleteBranchService).to receive(:new)
+ expect(::Branches::DeleteService).to receive(:new)
.with(merge_request.source_project, merge_request.author)
.and_call_original
service.execute(merge_request)
@@ -248,7 +249,7 @@ describe MergeRequests::MergeService do
let(:service) { described_class.new(project, user, merge_params.merge('should_remove_source_branch' => false)) }
it 'does not delete the source branch' do
- expect(DeleteBranchService).not_to receive(:new)
+ expect(::Branches::DeleteService).not_to receive(:new)
service.execute(merge_request)
end
end
@@ -260,7 +261,7 @@ describe MergeRequests::MergeService do
end
it 'removes the source branch using the current user' do
- expect(DeleteBranchService).to receive(:new)
+ expect(::Branches::DeleteService).to receive(:new)
.with(merge_request.source_project, user)
.and_call_original
service.execute(merge_request)
diff --git a/spec/services/merge_requests/merge_to_ref_service_spec.rb b/spec/services/merge_requests/merge_to_ref_service_spec.rb
index cccafddc450..77e38f1eb4c 100644
--- a/spec/services/merge_requests/merge_to_ref_service_spec.rb
+++ b/spec/services/merge_requests/merge_to_ref_service_spec.rb
@@ -61,7 +61,7 @@ describe MergeRequests::MergeToRefService do
end
it 'does not delete the source branch' do
- expect(DeleteBranchService).not_to receive(:new)
+ expect(::Branches::DeleteService).not_to receive(:new)
process_merge_to_ref
end
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 9d0ad60a624..9e69f179da9 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -113,7 +113,7 @@ describe MergeRequests::RefreshService do
context 'when source branch ref does not exists' do
before do
- DeleteBranchService.new(@project, @user).execute(@merge_request.source_branch)
+ ::Branches::DeleteService.new(@project, @user).execute(@merge_request.source_branch)
end
it 'closes MRs without source branch ref' do
diff --git a/spec/services/todo_service_spec.rb b/spec/services/todo_service_spec.rb
index 818794ed956..0d7e17ad52c 100644
--- a/spec/services/todo_service_spec.rb
+++ b/spec/services/todo_service_spec.rb
@@ -1015,6 +1015,30 @@ describe TodoService do
end
end
+ describe '#mark_todo_as_done' do
+ it 'marks a todo done' do
+ todo1 = create(:todo, :pending, user: john_doe)
+
+ described_class.new.mark_todo_as_done(todo1, john_doe)
+
+ expect(todo1.reload.state).to eq('done')
+ end
+
+ context 'when todo is already in state done' do
+ let(:todo1) { create(:todo, :done, user: john_doe) }
+
+ it 'does not update the todo' do
+ expect { described_class.new.mark_todo_as_done(todo1, john_doe) }.not_to change(todo1.reload, :state)
+ end
+
+ it 'does not update cache count' do
+ expect(john_doe).not_to receive(:update_todos_count_cache)
+
+ described_class.new.mark_todo_as_done(todo1, john_doe)
+ end
+ end
+ end
+
describe '#mark_all_todos_as_done_by_user' do
it 'marks all todos done' do
todo1 = create(:todo, user: john_doe, state: :pending)
diff --git a/spec/support/helpers/kubernetes_helpers.rb b/spec/support/helpers/kubernetes_helpers.rb
index 677aef57661..cac43e94a92 100644
--- a/spec/support/helpers/kubernetes_helpers.rb
+++ b/spec/support/helpers/kubernetes_helpers.rb
@@ -194,6 +194,11 @@ module KubernetesHelpers
.to_return(kube_response({}))
end
+ def stub_kubeclient_put_cluster_role_binding(api_url, name)
+ WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings/#{name}")
+ .to_return(kube_response({}))
+ end
+
def stub_kubeclient_get_role_binding(api_url, name, namespace: 'default')
WebMock.stub_request(:get, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/rolebindings/#{name}")
.to_return(kube_response({}))
@@ -219,11 +224,21 @@ module KubernetesHelpers
.to_return(kube_response({}))
end
+ def stub_kubeclient_get_namespaces(api_url)
+ WebMock.stub_request(:get, api_url + '/api/v1/namespaces')
+ .to_return(kube_response(kube_v1_namespace_list_body))
+ end
+
def stub_kubeclient_get_namespace(api_url, namespace: 'default')
WebMock.stub_request(:get, api_url + "/api/v1/namespaces/#{namespace}")
.to_return(kube_response({}))
end
+ def stub_kubeclient_put_cluster_role(api_url, name)
+ WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/clusterroles/#{name}")
+ .to_return(kube_response({}))
+ end
+
def stub_kubeclient_put_role(api_url, name, namespace: 'default')
WebMock.stub_request(:put, api_url + "/apis/rbac.authorization.k8s.io/v1/namespaces/#{namespace}/roles/#{name}")
.to_return(kube_response({}))
@@ -257,6 +272,20 @@ module KubernetesHelpers
}
end
+ def kube_v1_namespace_list_body
+ {
+ "kind" => "NamespaceList",
+ "apiVersion" => "v1",
+ "items" => [
+ {
+ "metadata" => {
+ "name" => "knative-serving"
+ }
+ }
+ ]
+ }
+ end
+
def kube_v1beta1_discovery_body
{
"kind" => "APIResourceList",
diff --git a/spec/support/helpers/position_tracer_helpers.rb b/spec/support/helpers/position_tracer_helpers.rb
index bbf6e06dd40..7516694d4fe 100644
--- a/spec/support/helpers/position_tracer_helpers.rb
+++ b/spec/support/helpers/position_tracer_helpers.rb
@@ -50,7 +50,7 @@ module PositionTracerHelpers
end
def create_branch(new_name, branch_name)
- CreateBranchService.new(project, current_user).execute(new_name, branch_name)
+ ::Branches::CreateService.new(project, current_user).execute(new_name, branch_name)
end
def create_file(branch_name, file_name, content)
diff --git a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
index c24418b2f90..8962d98218a 100644
--- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
+++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb
@@ -74,7 +74,7 @@ shared_examples 'handle uploads' do
end
before do
- expect(FileUploader).to receive(:generate_secret).and_return(secret)
+ allow(FileUploader).to receive(:generate_secret).and_return(secret)
UploadService.new(model, jpg, uploader_class).execute
end
@@ -88,6 +88,18 @@ shared_examples 'handle uploads' do
end
end
+ context 'when the upload does not have a MIME type that Rails knows' do
+ let(:po) { fixture_file_upload('spec/fixtures/missing_metadata.po', 'text/plain') }
+
+ it 'falls back to the null type' do
+ UploadService.new(model, po, uploader_class).execute
+
+ get :show, params: params.merge(secret: secret, filename: 'missing_metadata.po')
+
+ expect(response.headers['Content-Type']).to eq('application/octet-stream')
+ end
+ end
+
context "when the model is public" do
before do
model.update_attribute(:visibility_level, Gitlab::VisibilityLevel::PUBLIC)
diff --git a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
index c0db4cdde72..da966fd2200 100644
--- a/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
+++ b/spec/support/shared_examples/features/creatable_merge_request_shared_examples.rb
@@ -8,11 +8,14 @@ RSpec.shared_examples 'a creatable merge request' do
page.within '.dropdown-menu-user' do
click_link user2.name
end
+
expect(find('input[name="merge_request[assignee_ids][]"]', visible: false).value).to match(user2.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user2.name
end
+
click_link 'Assign to me'
+
expect(find('input[name="merge_request[assignee_ids][]"]', visible: false).value).to match(user.id.to_s)
page.within '.js-assignee-search' do
expect(page).to have_content user.name
@@ -22,6 +25,7 @@ RSpec.shared_examples 'a creatable merge request' do
page.within '.issue-milestone' do
click_link milestone.title
end
+
expect(find('input[name="merge_request[milestone_id]"]', visible: false).value).to match(milestone.id.to_s)
page.within '.js-milestone-select' do
expect(page).to have_content milestone.title
@@ -32,6 +36,7 @@ RSpec.shared_examples 'a creatable merge request' do
click_link label.title
click_link label2.title
end
+
page.within '.js-label-select' do
expect(page).to have_content label.title
end
@@ -58,8 +63,9 @@ RSpec.shared_examples 'a creatable merge request' do
it 'updates the branches when selecting a new target project', :js do
target_project_member = target_project.owner
- CreateBranchService.new(target_project, target_project_member)
- .execute('a-brand-new-branch-to-test', 'master')
+ ::Branches::CreateService.new(target_project, target_project_member)
+ .execute('a-brand-new-branch-to-test', 'master')
+
visit project_new_merge_request_path(source_project)
first('.js-target-project').click
diff --git a/spec/workers/delete_merged_branches_worker_spec.rb b/spec/workers/delete_merged_branches_worker_spec.rb
index a218ca921d9..8c983859e36 100644
--- a/spec/workers/delete_merged_branches_worker_spec.rb
+++ b/spec/workers/delete_merged_branches_worker_spec.rb
@@ -8,8 +8,8 @@ describe DeleteMergedBranchesWorker do
let(:project) { create(:project, :repository) }
describe "#perform" do
- it "calls DeleteMergedBranchesService" do
- expect_any_instance_of(DeleteMergedBranchesService).to receive(:execute).and_return(true)
+ it "delegates to Branches::DeleteMergedService" do
+ expect_any_instance_of(::Branches::DeleteMergedService).to receive(:execute).and_return(true)
worker.perform(project.id, project.owner.id)
end