From 57129140ba1160fd3d61588708d98602c421ee97 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Thu, 26 Apr 2018 01:18:22 +0200 Subject: backport changes from gitlab-org/gitlab-ee!5461 --- .../services/projects/housekeeping_service_spec.rb | 72 ++++++++++++---------- 1 file changed, 41 insertions(+), 31 deletions(-) (limited to 'spec') diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb index b7b5de07380..1cf373d1d72 100644 --- a/spec/services/projects/housekeeping_service_spec.rb +++ b/spec/services/projects/housekeeping_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Projects::HousekeepingService do subject { described_class.new(project) } - let(:project) { create(:project, :repository) } + set(:project) { create(:project, :repository) } before do project.reset_pushes_since_gc @@ -16,12 +16,12 @@ describe Projects::HousekeepingService do it 'enqueues a sidekiq job' do expect(subject).to receive(:try_obtain_lease).and_return(:the_uuid) expect(subject).to receive(:lease_key).and_return(:the_lease_key) - expect(subject).to receive(:task).and_return(:the_task) - expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :the_task, :the_lease_key, :the_uuid) + expect(subject).to receive(:task).and_return(:incremental_repack) + expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :incremental_repack, :the_lease_key, :the_uuid).and_call_original - subject.execute - - expect(project.reload.pushes_since_gc).to eq(0) + Sidekiq::Testing.fake! do + expect { subject.execute }.to change(GitGarbageCollectWorker.jobs, :size).by(1) + end end it 'yields the block if given' do @@ -30,6 +30,16 @@ describe Projects::HousekeepingService do end.to yield_with_no_args end + it 'resets counter after execution' do + expect(subject).to receive(:try_obtain_lease).and_return(:the_uuid) + allow(subject).to receive(:gc_period).and_return(1) + project.increment_pushes_since_gc + + Sidekiq::Testing.inline! do + expect { subject.execute }.to change { project.pushes_since_gc }.to(0) + end + end + context 'when no lease can be obtained' do before do expect(subject).to receive(:try_obtain_lease).and_return(false) @@ -54,6 +64,30 @@ describe Projects::HousekeepingService do end.not_to yield_with_no_args end end + + context 'task type' do + it 'goes through all three housekeeping tasks, executing only the highest task when there is overlap' do + allow(subject).to receive(:try_obtain_lease).and_return(:the_uuid) + allow(subject).to receive(:lease_key).and_return(:the_lease_key) + + # At push 200 + expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :gc, :the_lease_key, :the_uuid) + .exactly(1).times + # At push 50, 100, 150 + expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :full_repack, :the_lease_key, :the_uuid) + .exactly(3).times + # At push 10, 20, ... (except those above) + expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :incremental_repack, :the_lease_key, :the_uuid) + .exactly(16).times + + 201.times do + subject.increment! + subject.execute if subject.needed? + end + + expect(project.pushes_since_gc).to eq(1) + end + end end describe '#needed?' do @@ -69,31 +103,7 @@ describe Projects::HousekeepingService do describe '#increment!' do it 'increments the pushes_since_gc counter' do - expect do - subject.increment! - end.to change { project.pushes_since_gc }.from(0).to(1) + expect { subject.increment! }.to change { project.pushes_since_gc }.by(1) end end - - it 'goes through all three housekeeping tasks, executing only the highest task when there is overlap' do - allow(subject).to receive(:try_obtain_lease).and_return(:the_uuid) - allow(subject).to receive(:lease_key).and_return(:the_lease_key) - - # At push 200 - expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :gc, :the_lease_key, :the_uuid) - .exactly(1).times - # At push 50, 100, 150 - expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :full_repack, :the_lease_key, :the_uuid) - .exactly(3).times - # At push 10, 20, ... (except those above) - expect(GitGarbageCollectWorker).to receive(:perform_async).with(project.id, :incremental_repack, :the_lease_key, :the_uuid) - .exactly(16).times - - 201.times do - subject.increment! - subject.execute if subject.needed? - end - - expect(project.pushes_since_gc).to eq(1) - end end -- cgit v1.2.1 From 631bd9bf082c396059867d512fcfbdc80445c65e Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 21 May 2018 11:39:46 +0200 Subject: Use persisted stages to load pipelines index table --- .../projects/pipelines_controller_spec.rb | 52 +++++++++++++++------- 1 file changed, 37 insertions(+), 15 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 9e7bc20a6d1..d7ff2d6175c 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -19,16 +19,21 @@ describe Projects::PipelinesController do before do %w(pending running created success).each_with_index do |status, index| sha = project.commit("HEAD~#{index}") - create(:ci_empty_pipeline, status: status, project: project, sha: sha) - end - end - subject do - get :index, namespace_id: project.namespace, project_id: project, format: :json + pipeline = create(:ci_empty_pipeline, status: status, + project: project, + sha: sha) + + + create_build(pipeline, 'test', 1, 'unit') + create_build(pipeline, 'test', 1, 'feature') + create_build(pipeline, 'review', 2, 'staging') + create_build(pipeline, 'deploy', 3, 'production') + end end - it 'returns JSON with serialized pipelines' do - subject + it 'returns JSON with serialized pipelines', :request_store do + queries = ActiveRecord::QueryRecorder.new { get_pipelines_index_json } expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('pipeline') @@ -39,22 +44,35 @@ describe Projects::PipelinesController do expect(json_response['count']['running']).to eq '1' expect(json_response['count']['pending']).to eq '1' expect(json_response['count']['finished']).to eq '1' + puts queries.log + expect(queries.count).to be < 25 end it 'does not include coverage data for the pipelines' do - subject + get_pipelines_index_json expect(json_response['pipelines'][0]).not_to include('coverage') end context 'when performing gitaly calls', :request_store do it 'limits the Gitaly requests' do - expect { subject }.to change { Gitlab::GitalyClient.get_request_count }.by(3) + expect { get_pipelines_index_json } + .to change { Gitlab::GitalyClient.get_request_count }.by(2) end end + + def get_pipelines_index_json + get :index, namespace_id: project.namespace, + project_id: project, + format: :json + end + + def create_build(pipeline, stage, stage_idx, name) + create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name) + end end - describe 'GET show JSON' do + describe 'GET show.json' do let(:pipeline) { create(:ci_pipeline_with_one_job, project: project) } it 'returns the pipeline' do @@ -67,6 +85,14 @@ describe Projects::PipelinesController do end context 'when the pipeline has multiple stages and groups', :request_store do + let(:project) { create(:project, :repository) } + + let(:pipeline) do + create(:ci_empty_pipeline, project: project, + user: user, + sha: project.commit.id) + end + before do create_build('build', 0, 'build') create_build('test', 1, 'rspec 0') @@ -74,11 +100,6 @@ describe Projects::PipelinesController do create_build('post deploy', 3, 'pages 0') end - let(:project) { create(:project, :repository) } - let(:pipeline) do - create(:ci_empty_pipeline, project: project, user: user, sha: project.commit.id) - end - it 'does not perform N + 1 queries' do control_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count @@ -90,6 +111,7 @@ describe Projects::PipelinesController do create_build('post deploy', 3, 'pages 2') new_count = ActiveRecord::QueryRecorder.new { get_pipeline_json }.count + expect(new_count).to be_within(12).of(control_count) end end -- cgit v1.2.1 From 6c63f96e0a26fa046fb0cc4664240e37db8b37d8 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 22 May 2018 12:30:45 +0200 Subject: Preload number of warnings in every stage in a pipeline This makes it possible to avoid N+1 queries when loading pipelines table. --- .../projects/pipelines_controller_spec.rb | 45 ++++++++++++---------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index d7ff2d6175c..d5a0d32054b 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -17,35 +17,27 @@ describe Projects::PipelinesController do describe 'GET index.json' do before do - %w(pending running created success).each_with_index do |status, index| - sha = project.commit("HEAD~#{index}") - - pipeline = create(:ci_empty_pipeline, status: status, - project: project, - sha: sha) - - - create_build(pipeline, 'test', 1, 'unit') - create_build(pipeline, 'test', 1, 'feature') - create_build(pipeline, 'review', 2, 'staging') - create_build(pipeline, 'deploy', 3, 'production') - end + %w(pending running running success canceled) + .each_with_index do |status, index| + create_pipeline(status, project.commit("HEAD~#{index}")) + end end it 'returns JSON with serialized pipelines', :request_store do - queries = ActiveRecord::QueryRecorder.new { get_pipelines_index_json } + queries = ActiveRecord::QueryRecorder.new do + get_pipelines_index_json + end expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('pipeline') expect(json_response).to include('pipelines') - expect(json_response['pipelines'].count).to eq 4 - expect(json_response['count']['all']).to eq '4' - expect(json_response['count']['running']).to eq '1' + expect(json_response['pipelines'].count).to eq 5 + expect(json_response['count']['all']).to eq '5' + expect(json_response['count']['running']).to eq '2' expect(json_response['count']['pending']).to eq '1' - expect(json_response['count']['finished']).to eq '1' - puts queries.log - expect(queries.count).to be < 25 + expect(json_response['count']['finished']).to eq '2' + expect(queries.count).to be < 32 end it 'does not include coverage data for the pipelines' do @@ -67,8 +59,19 @@ describe Projects::PipelinesController do format: :json end + def create_pipeline(status, sha) + pipeline = create(:ci_empty_pipeline, status: status, + project: project, + sha: sha) + + create_build(pipeline, 'build', 1, 'build') + create_build(pipeline, 'test', 2, 'test') + create_build(pipeline, 'deploy', 3, 'deploy') + end + def create_build(pipeline, stage, stage_idx, name) - create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name) + status = %w[created running pending success failed canceled].sample + create(:ci_build, pipeline: pipeline, stage: stage, stage_idx: stage_idx, name: name, status: status) end end -- cgit v1.2.1 From 76a7157c76c47fd4f835a27eeeda7b42012936be Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 22 May 2018 13:04:07 +0200 Subject: Abstract persisted/legacy stages in pipeline model --- spec/controllers/projects/pipelines_controller_spec.rb | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index d5a0d32054b..c8080056f69 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -17,8 +17,7 @@ describe Projects::PipelinesController do describe 'GET index.json' do before do - %w(pending running running success canceled) - .each_with_index do |status, index| + %w(pending running success failed).each_with_index do |status, index| create_pipeline(status, project.commit("HEAD~#{index}")) end end @@ -32,11 +31,13 @@ describe Projects::PipelinesController do expect(response).to match_response_schema('pipeline') expect(json_response).to include('pipelines') - expect(json_response['pipelines'].count).to eq 5 - expect(json_response['count']['all']).to eq '5' - expect(json_response['count']['running']).to eq '2' + expect(json_response['pipelines'].count).to eq 4 + expect(json_response['count']['all']).to eq '4' + expect(json_response['count']['running']).to eq '1' expect(json_response['count']['pending']).to eq '1' expect(json_response['count']['finished']).to eq '2' + puts queries.log + puts "Queries count: #{queries.count}" expect(queries.count).to be < 32 end -- cgit v1.2.1 From ea35fd05bb175cf921e94d8b1c5e6bc5f3e217c9 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 22 May 2018 13:55:05 +0200 Subject: Refactor pipeline preloader to split reponsibilities better --- .../projects/pipelines_controller_spec.rb | 2 -- spec/lib/gitlab/ci/pipeline/preloader_spec.rb | 22 ++++++++++++---------- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index c8080056f69..536ef9b2d79 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -36,8 +36,6 @@ describe Projects::PipelinesController do expect(json_response['count']['running']).to eq '1' expect(json_response['count']['pending']).to eq '1' expect(json_response['count']['finished']).to eq '2' - puts queries.log - puts "Queries count: #{queries.count}" expect(queries.count).to be < 32 end diff --git a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb index 477c7477df0..c8cfe2c696d 100644 --- a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb @@ -1,20 +1,22 @@ # frozen_string_literal: true -require 'spec_helper' +require 'fast_spec_helper' describe Gitlab::Ci::Pipeline::Preloader do - describe '.preload' do - it 'preloads the author of every pipeline commit' do - commit = double(:commit) - pipeline = double(:pipeline, commit: commit) + let(:stage) { double(:stage) } + let(:commit) { double(:commit) } - expect(commit) - .to receive(:lazy_author) + let(:pipeline) do + double(:pipeline, commit: commit, stages: [stage]) + end - expect(pipeline) - .to receive(:number_of_warnings) + describe '#preload!' do + it 'preloads commit authors and number of warnings' do + expect(commit).to receive(:lazy_author) + expect(pipeline).to receive(:number_of_warnings) + expect(stage).to receive(:number_of_warnings) - described_class.preload([pipeline]) + described_class.new([pipeline]).preload! end end end -- cgit v1.2.1 From e4eb330af7577940d2440544004d1335fe221839 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 22 May 2018 14:00:42 +0200 Subject: Add pipeline stages factory method import/export support --- spec/lib/gitlab/import_export/all_models.yml | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 8b46b04b8b5..002e5e47208 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -256,6 +256,7 @@ project: - import_data - commit_statuses - pipelines +- stages - builds - runner_projects - runners -- cgit v1.2.1 From 0b3cca568ddaa43b4531392a8ccc391b1688bfdc Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 22 May 2018 14:38:25 +0200 Subject: Fix rubocop offense in pipeline controller specs :cop: --- spec/controllers/projects/pipelines_controller_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 536ef9b2d79..2e0f9b00023 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -18,8 +18,8 @@ describe Projects::PipelinesController do describe 'GET index.json' do before do %w(pending running success failed).each_with_index do |status, index| - create_pipeline(status, project.commit("HEAD~#{index}")) - end + create_pipeline(status, project.commit("HEAD~#{index}")) + end end it 'returns JSON with serialized pipelines', :request_store do -- cgit v1.2.1 From f89f232d19a6c28a3504e964fbfd2b5eb344aa85 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 23 May 2018 10:22:28 +0200 Subject: Simplify pipelines preloader implementation --- spec/lib/gitlab/ci/pipeline/preloader_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb index c8cfe2c696d..16d3631ec7c 100644 --- a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb @@ -10,13 +10,13 @@ describe Gitlab::Ci::Pipeline::Preloader do double(:pipeline, commit: commit, stages: [stage]) end - describe '#preload!' do + describe '.preload!' do it 'preloads commit authors and number of warnings' do expect(commit).to receive(:lazy_author) expect(pipeline).to receive(:number_of_warnings) expect(stage).to receive(:number_of_warnings) - described_class.new([pipeline]).preload! + described_class.preload!([pipeline]) end end end -- cgit v1.2.1 From 8cca6c83a99100fcf3a0a3a56f10eebe3c9b7716 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 23 May 2018 10:37:01 +0200 Subject: DRY creating groups of common builds in a stage --- spec/models/ci/group_spec.rb | 51 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb index 51123e73fe6..9052dd59369 100644 --- a/spec/models/ci/group_spec.rb +++ b/spec/models/ci/group_spec.rb @@ -41,4 +41,55 @@ describe Ci::Group do end end end + + describe '.fabricate' do + let(:pipeline) { create(:ci_empty_pipeline) } + let(:stage) { create(:ci_stage_entity, pipeline: pipeline) } + + before do + create_build(:ci_build, name: 'rspec 0 2') + create_build(:ci_build, name: 'rspec 0 1') + create_build(:ci_build, name: 'spinach 0 1') + create_build(:commit_status, name: 'aaaaa') + end + + it 'returns an array of three groups' do + expect(stage.groups).to be_a Array + expect(stage.groups).to all(be_a Ci::Group) + expect(stage.groups.size).to eq 3 + end + + it 'returns groups with correctly ordered statuses' do + expect(stage.groups.first.jobs.map(&:name)) + .to eq ['aaaaa'] + expect(stage.groups.second.jobs.map(&:name)) + .to eq ['rspec 0 1', 'rspec 0 2'] + expect(stage.groups.third.jobs.map(&:name)) + .to eq ['spinach 0 1'] + end + + it 'returns groups with correct names' do + expect(stage.groups.map(&:name)) + .to eq %w[aaaaa rspec spinach] + end + + context 'when a name is nil on legacy pipelines' do + before do + pipeline.builds.first.update_attribute(:name, nil) + end + + it 'returns an array of three groups' do + expect(stage.groups.map(&:name)) + .to eq ['', 'aaaaa', 'rspec', 'spinach'] + end + end + + def create_build(type, status: 'success', **opts) + create(type, pipeline: pipeline, + stage: stage.name, + status: status, + stage_id: stage.id, + **opts) + end + end end -- cgit v1.2.1 From dab3ae39a2093fa924daf9c1902a2784002cca63 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 23 May 2018 13:29:21 +0200 Subject: Do not paginate pipelines active relation twice --- spec/controllers/projects/pipelines_controller_spec.rb | 2 +- spec/lib/gitlab/ci/pipeline/preloader_spec.rb | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 2e0f9b00023..d7253c90ee5 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -36,7 +36,7 @@ describe Projects::PipelinesController do expect(json_response['count']['running']).to eq '1' expect(json_response['count']['pending']).to eq '1' expect(json_response['count']['finished']).to eq '2' - expect(queries.count).to be < 32 + expect(queries.count).to be_within(2).of(29) end it 'does not include coverage data for the pipelines' do diff --git a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb index 16d3631ec7c..7821d28ab06 100644 --- a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb @@ -18,5 +18,15 @@ describe Gitlab::Ci::Pipeline::Preloader do described_class.preload!([pipeline]) end + + it 'returns original collection' do + allow(commit).to receive(:lazy_author) + allow(pipeline).to receive(:number_of_warnings) + allow(stage).to receive(:number_of_warnings) + + pipelines = [pipeline, pipeline] + + expect(described_class.preload!(pipelines)).to eq pipelines + end end end -- cgit v1.2.1 From 92de5f778faa989fb25f9a5c93c5e23618f2d87b Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 23 May 2018 13:30:34 +0200 Subject: Fix Rubocop offense in grouped statuses class specs --- spec/models/ci/group_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb index 9052dd59369..838fa63cb1f 100644 --- a/spec/models/ci/group_spec.rb +++ b/spec/models/ci/group_spec.rb @@ -55,7 +55,7 @@ describe Ci::Group do it 'returns an array of three groups' do expect(stage.groups).to be_a Array - expect(stage.groups).to all(be_a Ci::Group) + expect(stage.groups).to all(be_a described_class) expect(stage.groups.size).to eq 3 end -- cgit v1.2.1 From bc9a0e10b50430e0b253a15d1628b6776d0bd9fe Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 23 May 2018 14:22:22 +0200 Subject: Reduce amount of expected pipeline serialization queries in specs --- spec/controllers/projects/pipelines_controller_spec.rb | 2 +- spec/serializers/pipeline_serializer_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index d7253c90ee5..62eece8de4a 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -36,7 +36,7 @@ describe Projects::PipelinesController do expect(json_response['count']['running']).to eq '1' expect(json_response['count']['pending']).to eq '1' expect(json_response['count']['finished']).to eq '2' - expect(queries.count).to be_within(2).of(29) + expect(queries.count).to be < 30 end it 'does not include coverage data for the pipelines' do diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index b741308e2c5..5108eb4deec 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -120,7 +120,7 @@ describe PipelineSerializer do it 'verifies number of queries', :request_store do recorded = ActiveRecord::QueryRecorder.new { subject } - expect(recorded.count).to be_within(1).of(44) + expect(recorded.count).to be_within(1).of(38) expect(recorded.cached_count).to eq(0) end end @@ -139,7 +139,7 @@ describe PipelineSerializer do # pipeline. With the same ref this check is cached but if refs are # different then there is an extra query per ref # https://gitlab.com/gitlab-org/gitlab-ce/issues/46368 - expect(recorded.count).to be_within(1).of(51) + expect(recorded.count).to be_within(1).of(45) expect(recorded.cached_count).to eq(0) end end -- cgit v1.2.1 From f0d7445b88f6598db85198296c076bf59508188a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 24 May 2018 16:55:24 +0200 Subject: Reduce pipeline serialization queries when preloaded --- spec/serializers/pipeline_serializer_spec.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 5108eb4deec..9319d29279a 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -99,7 +99,8 @@ describe PipelineSerializer do end end - context 'number of queries' do + describe 'number of queries when preloaded' do + subject { serializer.represent(resource, preload: true) } let(:resource) { Ci::Pipeline.all } before do @@ -120,7 +121,7 @@ describe PipelineSerializer do it 'verifies number of queries', :request_store do recorded = ActiveRecord::QueryRecorder.new { subject } - expect(recorded.count).to be_within(1).of(38) + expect(recorded.count).to be_within(1).of(31) expect(recorded.cached_count).to eq(0) end end @@ -139,7 +140,7 @@ describe PipelineSerializer do # pipeline. With the same ref this check is cached but if refs are # different then there is an extra query per ref # https://gitlab.com/gitlab-org/gitlab-ce/issues/46368 - expect(recorded.count).to be_within(1).of(45) + expect(recorded.count).to be_within(1).of(38) expect(recorded.cached_count).to eq(0) end end -- cgit v1.2.1 From 887818d3cb58406555bc038ed36b75b7a4ce2631 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 25 May 2018 12:43:27 +0200 Subject: Do not update stage status when it is just created --- spec/models/ci/stage_spec.rb | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index a00db1d2bfc..d82bf20b032 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -65,7 +65,31 @@ describe Ci::Stage, :models do end end - context 'when stage is skipped' do + context 'when stage has only created builds' do + let(:stage) { create(:ci_stage_entity, status: :created) } + + before do + create(:ci_build, :created, stage_id: stage.id) + end + + it 'updates status to skipped' do + expect(stage.reload.status).to eq 'created' + end + end + + context 'when stage is skipped because of skipped builds' do + before do + create(:ci_build, :skipped, stage_id: stage.id) + end + + it 'updates status to skipped' do + expect { stage.update_status } + .to change { stage.reload.status } + .to 'skipped' + end + end + + context 'when stage is skipped because is empty' do it 'updates status to skipped' do expect { stage.update_status } .to change { stage.reload.status } -- cgit v1.2.1 From c0827455ab20a156b86a20556c79139e4eb114e5 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 25 May 2018 12:47:56 +0200 Subject: Add specs for stage detailed status and warnings --- spec/models/ci/stage_spec.rb | 104 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index d82bf20b032..b482e7de88b 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -112,7 +112,71 @@ describe Ci::Stage, :models do end end - describe '#index' do + + describe '#detailed_status' do + using RSpec::Parameterized::TableSyntax + + let(:user) { create(:user) } + let(:stage) { create(:ci_stage_entity, status: :created) } + subject { stage.detailed_status(user) } + + where(:statuses, :label) do + %w[created] | :created + %w[success] | :passed + %w[pending] | :pending + %w[skipped] | :skipped + %w[canceled] | :canceled + %w[success failed] | :failed + %w[running pending] | :running + end + + with_them do + before do + statuses.each do |status| + create(:commit_status, project: stage.project, + pipeline: stage.pipeline, + stage_id: stage.id, + status: status) + + stage.update_status + end + end + + it 'has a correct label' do + expect(subject.label).to eq label.to_s + end + end + + context 'when stage has warnings' do + before do + create(:ci_build, project: stage.project, + pipeline: stage.pipeline, + stage_id: stage.id, + status: :failed, + allow_failure: true) + + stage.update_status + end + + it 'is passed with warnings' do + expect(subject.label).to eq 'passed with warnings' + end + end + end + + describe '#groups' do + before do + create(:ci_build, stage_id: stage.id, name: 'rspec 0 1') + create(:ci_build, stage_id: stage.id, name: 'rspec 0 2') + end + + it 'groups stage builds by name' do + expect(stage.groups).to be_one + expect(stage.groups.first.name).to eq 'rspec' + end + end + + describe '#position' do context 'when stage has been imported and does not have position index set' do before do stage.update_column(:position, nil) @@ -143,4 +207,42 @@ describe Ci::Stage, :models do end end end + + context 'when stage has warnings' do + before do + create(:ci_build, :failed, :allowed_to_fail, stage_id: stage.id) + end + + describe '#has_warnings?' do + it 'returns true' do + expect(stage).to have_warnings + end + end + + describe '#number_of_warnings' do + it 'returns a lazy stage warnings counter' do + lazy_queries = ActiveRecord::QueryRecorder.new do + stage.number_of_warnings + end + + synced_queries = ActiveRecord::QueryRecorder.new do + stage.number_of_warnings.to_i + end + + expect(lazy_queries.count).to eq 0 + expect(synced_queries.count).to eq 1 + + expect(stage.number_of_warnings.inspect).to include 'BatchLoader' + expect(stage.number_of_warnings).to eq 1 + end + end + end + + context 'when stage does not have warnings' do + describe '#has_warnings?' do + it 'returns false' do + expect(stage).not_to have_warnings + end + end + end end -- cgit v1.2.1 From c896ae7be889dd3935795b1079ab7a11a12f52e0 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 25 May 2018 12:38:45 +0100 Subject: BE review --- spec/features/projects/labels/update_prioritization_spec.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index ae8b1364ec7..9500e3f3311 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -23,8 +23,10 @@ feature 'Prioritize labels' do expect(page).to have_content('Star labels to start sorting by priority') page.within('.other-labels') do + screenshot_and_open_image all('.js-toggle-priority')[1].click wait_for_requests + screenshot_and_open_image expect(page).not_to have_content('feature') end -- cgit v1.2.1 From 1af2274b4126b3e910604ef321b58d327ea21e63 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 25 May 2018 13:43:11 +0200 Subject: Restore lazy loading of pipeline commits in preloader --- spec/lib/gitlab/ci/pipeline/preloader_spec.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb index 7821d28ab06..40dfd893465 100644 --- a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -require 'fast_spec_helper' +require 'spec_helper' describe Gitlab::Ci::Pipeline::Preloader do let(:stage) { double(:stage) } @@ -11,6 +11,23 @@ describe Gitlab::Ci::Pipeline::Preloader do end describe '.preload!' do + context 'when preloading multiple commits' do + let(:project) { create(:project, :repository) } + + it 'preloads all commits once' do + expect(Commit).to receive(:decorate).once.and_call_original + + pipelines = [build_pipeline(ref: 'HEAD'), + build_pipeline(ref: 'HEAD~1')] + + described_class.preload!(pipelines) + end + + def build_pipeline(ref:) + build_stubbed(:ci_pipeline, project: project, sha: project.commit(ref).id) + end + end + it 'preloads commit authors and number of warnings' do expect(commit).to receive(:lazy_author) expect(pipeline).to receive(:number_of_warnings) -- cgit v1.2.1 From 8a3aa3a6365f511a2620b56946721f1584bade99 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Fri, 25 May 2018 13:47:22 +0200 Subject: Fix Rubocop offenses in pipeline stage specs --- spec/models/ci/stage_spec.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index b482e7de88b..b40496252b4 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -112,7 +112,6 @@ describe Ci::Stage, :models do end end - describe '#detailed_status' do using RSpec::Parameterized::TableSyntax @@ -134,9 +133,9 @@ describe Ci::Stage, :models do before do statuses.each do |status| create(:commit_status, project: stage.project, - pipeline: stage.pipeline, - stage_id: stage.id, - status: status) + pipeline: stage.pipeline, + stage_id: stage.id, + status: status) stage.update_status end @@ -149,13 +148,13 @@ describe Ci::Stage, :models do context 'when stage has warnings' do before do - create(:ci_build, project: stage.project, - pipeline: stage.pipeline, - stage_id: stage.id, - status: :failed, - allow_failure: true) + create(:ci_build, project: stage.project, + pipeline: stage.pipeline, + stage_id: stage.id, + status: :failed, + allow_failure: true) - stage.update_status + stage.update_status end it 'is passed with warnings' do -- cgit v1.2.1 From aac8d1f3363a87f0bcd31009aad41d577f0a3f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Mon, 28 May 2018 21:10:51 +0200 Subject: Add check for nil auto_devops in Projects::UpdateService --- spec/services/projects/update_service_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index 3e6073b9861..1f761bcbbad 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -275,6 +275,10 @@ describe Projects::UpdateService do it { is_expected.to eq(false) } end + context 'when auto devops is nil' do + it { is_expected.to eq(false) } + end + context 'when auto devops is explicitly enabled' do before do project.create_auto_devops!(enabled: true) -- cgit v1.2.1 From fad343ca5b1fcdd4d01e415f31ee4a9fddb4eb99 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 29 May 2018 09:53:33 +0100 Subject: Remove screenshots --- spec/features/projects/labels/update_prioritization_spec.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index 9500e3f3311..ae8b1364ec7 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -23,10 +23,8 @@ feature 'Prioritize labels' do expect(page).to have_content('Star labels to start sorting by priority') page.within('.other-labels') do - screenshot_and_open_image all('.js-toggle-priority')[1].click wait_for_requests - screenshot_and_open_image expect(page).not_to have_content('feature') end -- cgit v1.2.1 From c9e4c1760dae5e1916bb5ad22f260b7fd0b58475 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 29 May 2018 10:25:21 +0100 Subject: Fix project subscription_spec --- spec/features/projects/labels/subscription_spec.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/labels/subscription_spec.rb b/spec/features/projects/labels/subscription_spec.rb index 70e8d436dcb..d5f5036ec72 100644 --- a/spec/features/projects/labels/subscription_spec.rb +++ b/spec/features/projects/labels/subscription_spec.rb @@ -36,7 +36,7 @@ feature 'Labels subscription' do within "#group_label_#{feature.id}" do expect(page).not_to have_button 'Unsubscribe' - click_link_on_dropdown('Group level') + click_link_on_dropdown('Subscribe at group level') expect(page).not_to have_selector('.dropdown-group-label') expect(page).to have_button 'Unsubscribe' @@ -45,7 +45,7 @@ feature 'Labels subscription' do expect(page).to have_selector('.dropdown-group-label') - click_link_on_dropdown('Project level') + click_link_on_dropdown('Subscribe at project level') expect(page).not_to have_selector('.dropdown-group-label') expect(page).to have_button 'Unsubscribe' @@ -67,6 +67,8 @@ feature 'Labels subscription' do def click_link_on_dropdown(text) find('.dropdown-group-label').click + screenshot_and_open_image + page.within('.dropdown-group-label') do find('a.js-subscribe-button', text: text).click end -- cgit v1.2.1 From 35b5c830a783eb36f86d9f5e8f8c08595fd62c54 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 29 May 2018 10:48:26 +0100 Subject: Further fixes for project subscription_spec --- spec/features/projects/labels/subscription_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/labels/subscription_spec.rb b/spec/features/projects/labels/subscription_spec.rb index d5f5036ec72..fafd338e448 100644 --- a/spec/features/projects/labels/subscription_spec.rb +++ b/spec/features/projects/labels/subscription_spec.rb @@ -67,10 +67,8 @@ feature 'Labels subscription' do def click_link_on_dropdown(text) find('.dropdown-group-label').click - screenshot_and_open_image - page.within('.dropdown-group-label') do - find('a.js-subscribe-button', text: text).click + find('.js-subscribe-button', text: text).click end end end -- cgit v1.2.1 From 3b3645136bd524a5e9f79558ab16be976cfe5282 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 29 May 2018 11:07:48 +0100 Subject: Fix update_prioritization_spec --- spec/features/projects/labels/update_prioritization_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/labels/update_prioritization_spec.rb b/spec/features/projects/labels/update_prioritization_spec.rb index ae8b1364ec7..359381c391c 100644 --- a/spec/features/projects/labels/update_prioritization_spec.rb +++ b/spec/features/projects/labels/update_prioritization_spec.rb @@ -102,16 +102,16 @@ feature 'Prioritize labels' do drag_to(selector: '.label-list-item', from_index: 1, to_index: 2) page.within('.prioritized-labels') do - expect(first('li')).to have_content('feature') - expect(page.all('li').last).to have_content('bug') + expect(first('.label-list-item')).to have_content('feature') + expect(page.all('.label-list-item').last).to have_content('bug') end refresh wait_for_requests page.within('.prioritized-labels') do - expect(first('li')).to have_content('feature') - expect(page.all('li').last).to have_content('bug') + expect(first('.label-list-item')).to have_content('feature') + expect(page.all('.label-list-item').last).to have_content('bug') end end -- cgit v1.2.1 From cd0be3ba456f5cf61ed72f1c6b36bef799d7eaaf Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 29 May 2018 12:11:14 +0100 Subject: Fix user_removes_labels_spec --- .../projects/labels/user_removes_labels_spec.rb | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/labels/user_removes_labels_spec.rb b/spec/features/projects/labels/user_removes_labels_spec.rb index f4fda6de465..120c618b530 100644 --- a/spec/features/projects/labels/user_removes_labels_spec.rb +++ b/spec/features/projects/labels/user_removes_labels_spec.rb @@ -17,8 +17,9 @@ describe "User removes labels" do end it "removes label" do - page.within(".labels") do + page.within(".other-labels") do page.first(".label-list-item") do + first('.js-label-options-dropdown').click first(".remove-row").click first(:link, "Delete label").click end @@ -36,17 +37,15 @@ describe "User removes labels" do end it "removes all labels" do - page.within(".labels") do - loop do - li = page.first(".label-list-item") - break unless li - - li.click_link("Delete") - click_link("Delete label") - end - - expect(page).to have_content("Generate a default set of labels").and have_content("New label") + loop do + li = page.first(".label-list-item") + break unless li + li.find('.js-label-options-dropdown').click + li.click_button("Delete") + click_link("Delete label") end + + expect(page).to have_content("Generate a default set of labels").and have_content("New label") end end end -- cgit v1.2.1 From 9b9cdc984cb785ceee4ed1902625c65492640621 Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Tue, 29 May 2018 12:50:29 +0100 Subject: fix lint --- spec/features/projects/labels/user_removes_labels_spec.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/features/projects/labels/user_removes_labels_spec.rb b/spec/features/projects/labels/user_removes_labels_spec.rb index 120c618b530..efa74015c6e 100644 --- a/spec/features/projects/labels/user_removes_labels_spec.rb +++ b/spec/features/projects/labels/user_removes_labels_spec.rb @@ -40,6 +40,7 @@ describe "User removes labels" do loop do li = page.first(".label-list-item") break unless li + li.find('.js-label-options-dropdown').click li.click_button("Delete") click_link("Delete label") -- cgit v1.2.1 From fc3d214130f2038b3c8bdf142506c9116f373244 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 29 May 2018 15:20:10 +0200 Subject: Add a feature flag for switching pipeline stages --- spec/models/ci/pipeline_spec.rb | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index e7845b693a1..f3725e24470 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -500,6 +500,87 @@ describe Ci::Pipeline, :mailer do end end end + + describe '#stages' do + before do + create(:ci_stage_entity, project: project, + pipeline: pipeline, + name: 'build') + end + + it 'returns persisted stages' do + expect(pipeline.stages).not_to be_empty + expect(pipeline.stages).to all(be_persisted) + end + end + + describe '#ordered_stages' do + before do + create(:ci_stage_entity, project: project, + pipeline: pipeline, + position: 4, + name: 'deploy') + + create(:ci_build, project: project, + pipeline: pipeline, + stage: 'test', + stage_idx: 3, + name: 'test') + + create(:ci_build, project: project, + pipeline: pipeline, + stage: 'build', + stage_idx: 2, + name: 'build') + + create(:ci_stage_entity, project: project, + pipeline: pipeline, + position: 1, + name: 'sanity') + + create(:ci_stage_entity, project: project, + pipeline: pipeline, + position: 5, + name: 'cleanup') + end + + subject { pipeline.ordered_stages } + + context 'when using legacy stages' do + before do + stub_feature_flags(ci_pipeline_persisted_stages: false) + end + + it 'returns legacy stages in valid order' do + expect(subject.map(&:name)).to eq %w[build test] + end + end + + context 'when using persisted stages' do + before do + stub_feature_flags(ci_pipeline_persisted_stages: true) + end + + context 'when pipelines is not complete' do + it 'still returns legacy stages' do + expect(subject).to all(be_a Ci::LegacyStage) + expect(subject.map(&:name)).to eq %w[build test] + end + end + + context 'when pipeline is complete' do + before do + pipeline.succeed! + end + + it 'returns stages in valid order' do + expect(subject).to all(be_a Ci::Stage) + expect(subject.map(&:name)) + .to eq %w[sanity build test deploy cleanup] + end + end + end + end end describe 'state machine' do -- cgit v1.2.1 From 3662f147692749b20c5c8ad8ea391fd94e43ed38 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 29 May 2018 17:19:39 +0200 Subject: Improve specs for pipelines controller --- .../projects/pipelines_controller_spec.rb | 67 +++++++++++++++++----- 1 file changed, 53 insertions(+), 14 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 62eece8de4a..92886e93077 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -17,26 +17,65 @@ describe Projects::PipelinesController do describe 'GET index.json' do before do - %w(pending running success failed).each_with_index do |status, index| + %w(pending running success failed canceled).each_with_index do |status, index| create_pipeline(status, project.commit("HEAD~#{index}")) end end - it 'returns JSON with serialized pipelines', :request_store do - queries = ActiveRecord::QueryRecorder.new do - get_pipelines_index_json + context 'when using persisted stages', :request_store do + before do + stub_feature_flags(ci_pipeline_persisted_stages: true) end - expect(response).to have_gitlab_http_status(:ok) - expect(response).to match_response_schema('pipeline') - - expect(json_response).to include('pipelines') - expect(json_response['pipelines'].count).to eq 4 - expect(json_response['count']['all']).to eq '4' - expect(json_response['count']['running']).to eq '1' - expect(json_response['count']['pending']).to eq '1' - expect(json_response['count']['finished']).to eq '2' - expect(queries.count).to be < 30 + it 'returns serialized pipelines', :request_store do + queries = ActiveRecord::QueryRecorder.new do + get_pipelines_index_json + end + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('pipeline') + + expect(json_response).to include('pipelines') + expect(json_response['pipelines'].count).to eq 5 + expect(json_response['count']['all']).to eq '5' + expect(json_response['count']['running']).to eq '1' + expect(json_response['count']['pending']).to eq '1' + expect(json_response['count']['finished']).to eq '3' + + json_response.dig('pipelines', 0, 'details', 'stages').tap do |stages| + expect(stages.count).to eq 3 + end + + expect(queries.count).to be + end + end + + context 'when using legacy stages', :request_store do + before do + stub_feature_flags(ci_pipeline_persisted_stages: false) + end + + it 'returns JSON with serialized pipelines', :request_store do + queries = ActiveRecord::QueryRecorder.new do + get_pipelines_index_json + end + + expect(response).to have_gitlab_http_status(:ok) + expect(response).to match_response_schema('pipeline') + + expect(json_response).to include('pipelines') + expect(json_response['pipelines'].count).to eq 5 + expect(json_response['count']['all']).to eq '5' + expect(json_response['count']['running']).to eq '1' + expect(json_response['count']['pending']).to eq '1' + expect(json_response['count']['finished']).to eq '3' + + json_response.dig('pipelines', 0, 'details', 'stages').tap do |stages| + expect(stages.count).to eq 3 + end + + expect(queries.count).to be_within(3).of(30) + end end it 'does not include coverage data for the pipelines' do -- cgit v1.2.1 From 162cc55e49e155d64ee862dfebefd97cec7d272c Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 29 May 2018 17:23:49 +0200 Subject: Use persisted stage feature to serialize pipelines --- spec/serializers/pipeline_serializer_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 9319d29279a..7c7cdaedf10 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -8,6 +8,10 @@ describe PipelineSerializer do described_class.new(current_user: user) end + before do + stub_feature_flags(ci_pipeline_persisted_stages: true) + end + subject { serializer.represent(resource) } describe '#represent' do -- cgit v1.2.1 From 74caf54704704e30b8ed45e2459828890f416b08 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 30 May 2018 15:49:55 +0200 Subject: Fix pipeline serializer queries count specs --- spec/serializers/pipeline_serializer_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index 7c7cdaedf10..e0e6eecb300 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -112,7 +112,7 @@ describe PipelineSerializer do # gitaly calls in this block # Issue: https://gitlab.com/gitlab-org/gitlab-ce/issues/37772 Gitlab::GitalyClient.allow_n_plus_1_calls do - Ci::Pipeline::AVAILABLE_STATUSES.each do |status| + Ci::Pipeline::COMPLETED_STATUSES.each do |status| create_pipeline(status) end end @@ -125,7 +125,7 @@ describe PipelineSerializer do it 'verifies number of queries', :request_store do recorded = ActiveRecord::QueryRecorder.new { subject } - expect(recorded.count).to be_within(1).of(31) + expect(recorded.count).to be_within(2).of(27) expect(recorded.cached_count).to eq(0) end end @@ -144,7 +144,7 @@ describe PipelineSerializer do # pipeline. With the same ref this check is cached but if refs are # different then there is an extra query per ref # https://gitlab.com/gitlab-org/gitlab-ce/issues/46368 - expect(recorded.count).to be_within(1).of(38) + expect(recorded.count).to be_within(2).of(30) expect(recorded.cached_count).to eq(0) end end -- cgit v1.2.1 From 0d44f4d50ef175997fe1f90de9e622a4f3b867e3 Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Wed, 23 May 2018 09:54:57 +0800 Subject: Rephrase "maintainer" to more precise "members who can merge to the target branch" "Maintainer" will be freed to be used for #42751 --- .../merge_request/maintainer_edits_fork_spec.rb | 2 +- .../user_allows_a_maintainer_to_push_spec.rb | 85 ---------------------- ...ows_commits_from_memebers_who_can_merge_spec.rb | 85 ++++++++++++++++++++++ .../api/schemas/entities/merge_request_basic.json | 1 + .../api/schemas/entities/merge_request_widget.json | 2 +- .../api/schemas/public_api/v4/merge_requests.json | 1 + .../gitlab/import_export/safe_model_attributes.yml | 2 +- spec/lib/gitlab/user_access_spec.rb | 2 +- spec/models/merge_request_spec.rb | 28 +++---- spec/models/project_spec.rb | 22 +++--- spec/policies/ci/build_policy_spec.rb | 2 +- spec/policies/ci/pipeline_policy_spec.rb | 2 +- spec/policies/project_policy_spec.rb | 2 +- spec/requests/api/merge_requests_spec.rb | 12 +-- spec/services/ci/retry_pipeline_service_spec.rb | 4 +- .../services/merge_requests/update_service_spec.rb | 12 +-- 16 files changed, 134 insertions(+), 130 deletions(-) delete mode 100644 spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb create mode 100644 spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb (limited to 'spec') diff --git a/spec/features/merge_request/maintainer_edits_fork_spec.rb b/spec/features/merge_request/maintainer_edits_fork_spec.rb index a3323da1b1f..1808d0c0a0c 100644 --- a/spec/features/merge_request/maintainer_edits_fork_spec.rb +++ b/spec/features/merge_request/maintainer_edits_fork_spec.rb @@ -14,7 +14,7 @@ describe 'a maintainer edits files on a source-branch of an MR from a fork', :js source_branch: 'fix', target_branch: 'master', author: author, - allow_maintainer_to_push: true) + allow_collaboration: true) end before do diff --git a/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb b/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb deleted file mode 100644 index eb41d7de8ed..00000000000 --- a/spec/features/merge_request/user_allows_a_maintainer_to_push_spec.rb +++ /dev/null @@ -1,85 +0,0 @@ -require 'spec_helper' - -describe 'create a merge request that allows maintainers to push', :js do - include ProjectForksHelper - let(:user) { create(:user) } - let(:target_project) { create(:project, :public, :repository) } - let(:source_project) { fork_project(target_project, user, repository: true, namespace: user.namespace) } - - def visit_new_merge_request - visit project_new_merge_request_path( - source_project, - merge_request: { - source_project_id: source_project.id, - target_project_id: target_project.id, - source_branch: 'fix', - target_branch: 'master' - }) - end - - before do - sign_in(user) - end - - it 'allows setting maintainer push possible' do - visit_new_merge_request - - check 'Allow edits from maintainers' - - click_button 'Submit merge request' - - wait_for_requests - - expect(page).to have_content('Allows edits from maintainers') - end - - it 'shows a message when one of the projects is private' do - source_project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) - - visit_new_merge_request - - expect(page).to have_content('Not available for private projects') - end - - it 'shows a message when the source branch is protected' do - create(:protected_branch, project: source_project, name: 'fix') - - visit_new_merge_request - - expect(page).to have_content('Not available for protected branches') - end - - context 'when the merge request is being created within the same project' do - let(:source_project) { target_project } - - it 'hides the checkbox if the merge request is being created within the same project' do - target_project.add_developer(user) - - visit_new_merge_request - - expect(page).not_to have_content('Allows edits from maintainers') - end - end - - context 'when a maintainer tries to edit the option' do - let(:maintainer) { create(:user) } - let(:merge_request) do - create(:merge_request, - source_project: source_project, - target_project: target_project, - source_branch: 'fixes') - end - - before do - target_project.add_master(maintainer) - - sign_in(maintainer) - end - - it 'it hides the option from maintainers' do - visit edit_project_merge_request_path(target_project, merge_request) - - expect(page).not_to have_content('Allows edits from maintainers') - end - end -end diff --git a/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb new file mode 100644 index 00000000000..0af37d76539 --- /dev/null +++ b/spec/features/merge_request/user_allows_commits_from_memebers_who_can_merge_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe 'create a merge request, allowing commits from members who can merge to the target branch', :js do + include ProjectForksHelper + let(:user) { create(:user) } + let(:target_project) { create(:project, :public, :repository) } + let(:source_project) { fork_project(target_project, user, repository: true, namespace: user.namespace) } + + def visit_new_merge_request + visit project_new_merge_request_path( + source_project, + merge_request: { + source_project_id: source_project.id, + target_project_id: target_project.id, + source_branch: 'fix', + target_branch: 'master' + }) + end + + before do + sign_in(user) + end + + it 'allows setting possible' do + visit_new_merge_request + + check 'Allow commits from members who can merge to the target branch' + + click_button 'Submit merge request' + + wait_for_requests + + expect(page).to have_content('Allows commits from members who can merge to the target branch') + end + + it 'shows a message when one of the projects is private' do + source_project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + + visit_new_merge_request + + expect(page).to have_content('Not available for private projects') + end + + it 'shows a message when the source branch is protected' do + create(:protected_branch, project: source_project, name: 'fix') + + visit_new_merge_request + + expect(page).to have_content('Not available for protected branches') + end + + context 'when the merge request is being created within the same project' do + let(:source_project) { target_project } + + it 'hides the checkbox if the merge request is being created within the same project' do + target_project.add_developer(user) + + visit_new_merge_request + + expect(page).not_to have_content('Allows commits from members who can merge to the target branch') + end + end + + context 'when a member who can merge tries to edit the option' do + let(:member) { create(:user) } + let(:merge_request) do + create(:merge_request, + source_project: source_project, + target_project: target_project, + source_branch: 'fixes') + end + + before do + target_project.add_master(member) + + sign_in(member) + end + + it 'it hides the option from members' do + visit edit_project_merge_request_path(target_project, merge_request) + + expect(page).not_to have_content('Allows commits from members who can merge to the target branch') + end + end +end diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json index 46031961cca..f7bc137c90c 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_basic.json +++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json @@ -13,6 +13,7 @@ "assignee_id": { "type": ["integer", "null"] }, "subscribed": { "type": ["boolean", "null"] }, "participants": { "type": "array" }, + "allow_collaboration": { "type": "boolean"}, "allow_maintainer_to_push": { "type": "boolean"} }, "additionalProperties": false diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json index 7be8c9e3e67..ee5588fa6c6 100644 --- a/spec/fixtures/api/schemas/entities/merge_request_widget.json +++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json @@ -31,7 +31,7 @@ "source_project_id": { "type": "integer" }, "target_branch": { "type": "string" }, "target_project_id": { "type": "integer" }, - "allow_maintainer_to_push": { "type": "boolean"}, + "allow_collaboration": { "type": "boolean"}, "metrics": { "oneOf": [ { "type": "null" }, diff --git a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json index f97461ce9cc..f7adc4e0b91 100644 --- a/spec/fixtures/api/schemas/public_api/v4/merge_requests.json +++ b/spec/fixtures/api/schemas/public_api/v4/merge_requests.json @@ -82,6 +82,7 @@ "human_time_estimate": { "type": ["string", "null"] }, "human_total_time_spent": { "type": ["string", "null"] } }, + "allow_collaboration": { "type": ["boolean", "null"] }, "allow_maintainer_to_push": { "type": ["boolean", "null"] } }, "required": [ diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 74e7a45fd6c..d389dcb4e80 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -170,7 +170,7 @@ MergeRequest: - last_edited_by_id - head_pipeline_id - discussion_locked -- allow_maintainer_to_push +- allow_collaboration MergeRequestDiff: - id - state diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb index 97b6069f64d..0469d984a40 100644 --- a/spec/lib/gitlab/user_access_spec.rb +++ b/spec/lib/gitlab/user_access_spec.rb @@ -142,7 +142,7 @@ describe Gitlab::UserAccess do target_project: canonical_project, source_project: project, source_branch: 'awesome-feature', - allow_maintainer_to_push: true + allow_collaboration: true ) end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 9ffa91fc265..8718fe50769 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -2236,25 +2236,25 @@ describe MergeRequest do end end - describe '#allow_maintainer_to_push' do + describe '#allow_collaboration' do let(:merge_request) do - build(:merge_request, source_branch: 'fixes', allow_maintainer_to_push: true) + build(:merge_request, source_branch: 'fixes', allow_collaboration: true) end it 'is false when pushing by a maintainer is not possible' do - expect(merge_request).to receive(:maintainer_push_possible?) { false } + expect(merge_request).to receive(:collaborative_push_possible?) { false } - expect(merge_request.allow_maintainer_to_push).to be_falsy + expect(merge_request.allow_collaboration).to be_falsy end it 'is true when pushing by a maintainer is possible' do - expect(merge_request).to receive(:maintainer_push_possible?) { true } + expect(merge_request).to receive(:collaborative_push_possible?) { true } - expect(merge_request.allow_maintainer_to_push).to be_truthy + expect(merge_request.allow_collaboration).to be_truthy end end - describe '#maintainer_push_possible?' do + describe '#collaborative_push_possible?' do let(:merge_request) do build(:merge_request, source_branch: 'fixes') end @@ -2266,14 +2266,14 @@ describe MergeRequest do it 'does not allow maintainer to push if the source project is the same as the target' do merge_request.target_project = merge_request.source_project = create(:project, :public) - expect(merge_request.maintainer_push_possible?).to be_falsy + expect(merge_request.collaborative_push_possible?).to be_falsy end it 'allows maintainer to push when both source and target are public' do merge_request.target_project = build(:project, :public) merge_request.source_project = build(:project, :public) - expect(merge_request.maintainer_push_possible?).to be_truthy + expect(merge_request.collaborative_push_possible?).to be_truthy end it 'is not available for protected branches' do @@ -2284,11 +2284,11 @@ describe MergeRequest do .with(merge_request.source_project, 'fixes') .and_return(true) - expect(merge_request.maintainer_push_possible?).to be_falsy + expect(merge_request.collaborative_push_possible?).to be_falsy end end - describe '#can_allow_maintainer_to_push?' do + describe '#can_allow_collaboration?' do let(:target_project) { create(:project, :public) } let(:source_project) { fork_project(target_project) } let(:merge_request) do @@ -2300,17 +2300,17 @@ describe MergeRequest do let(:user) { create(:user) } before do - allow(merge_request).to receive(:maintainer_push_possible?) { true } + allow(merge_request).to receive(:collaborative_push_possible?) { true } end it 'is false if the user does not have push access to the source project' do - expect(merge_request.can_allow_maintainer_to_push?(user)).to be_falsy + expect(merge_request.can_allow_collaboration?(user)).to be_falsy end it 'is true when the user has push access to the source project' do source_project.add_developer(user) - expect(merge_request.can_allow_maintainer_to_push?(user)).to be_truthy + expect(merge_request.can_allow_collaboration?(user)).to be_truthy end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index af2240f4f89..b0cbf8796e3 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3583,7 +3583,7 @@ describe Project do target_branch: 'target-branch', source_project: project, source_branch: 'awesome-feature-1', - allow_maintainer_to_push: true + allow_collaboration: true ) end @@ -3620,9 +3620,9 @@ describe Project do end end - describe '#branch_allows_maintainer_push?' do + describe '#branch_allows_collaboration_push?' do it 'allows access if the user can merge the merge request' do - expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1')) + expect(project.branch_allows_collaboration?(user, 'awesome-feature-1')) .to be_truthy end @@ -3630,7 +3630,7 @@ describe Project do guest = create(:user) target_project.add_guest(guest) - expect(project.branch_allows_maintainer_push?(guest, 'awesome-feature-1')) + expect(project.branch_allows_collaboration?(guest, 'awesome-feature-1')) .to be_falsy end @@ -3640,31 +3640,31 @@ describe Project do target_branch: 'target-branch', source_project: project, source_branch: 'rejected-feature-1', - allow_maintainer_to_push: true) + allow_collaboration: true) - expect(project.branch_allows_maintainer_push?(user, 'rejected-feature-1')) + expect(project.branch_allows_collaboration?(user, 'rejected-feature-1')) .to be_falsy end it 'does not allow access if the user cannot merge the merge request' do create(:protected_branch, :masters_can_push, project: target_project, name: 'target-branch') - expect(project.branch_allows_maintainer_push?(user, 'awesome-feature-1')) + expect(project.branch_allows_collaboration?(user, 'awesome-feature-1')) .to be_falsy end it 'caches the result' do - control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') } + control = ActiveRecord::QueryRecorder.new { project.branch_allows_collaboration?(user, 'awesome-feature-1') } - expect { 3.times { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') } } + expect { 3.times { project.branch_allows_collaboration?(user, 'awesome-feature-1') } } .not_to exceed_query_limit(control) end context 'when the requeststore is active', :request_store do it 'only queries per project across instances' do - control = ActiveRecord::QueryRecorder.new { project.branch_allows_maintainer_push?(user, 'awesome-feature-1') } + control = ActiveRecord::QueryRecorder.new { project.branch_allows_collaboration?(user, 'awesome-feature-1') } - expect { 2.times { described_class.find(project.id).branch_allows_maintainer_push?(user, 'awesome-feature-1') } } + expect { 2.times { described_class.find(project.id).branch_allows_collaboration?(user, 'awesome-feature-1') } } .not_to exceed_query_limit(control).with_threshold(2) end end diff --git a/spec/policies/ci/build_policy_spec.rb b/spec/policies/ci/build_policy_spec.rb index 9ca156deaa0..eead55d33ca 100644 --- a/spec/policies/ci/build_policy_spec.rb +++ b/spec/policies/ci/build_policy_spec.rb @@ -101,7 +101,7 @@ describe Ci::BuildPolicy do it 'enables update_build if user is maintainer' do allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false) - allow_any_instance_of(Project).to receive(:branch_allows_maintainer_push?).and_return(true) + allow_any_instance_of(Project).to receive(:branch_allows_collaboration?).and_return(true) expect(policy).to be_allowed :update_build expect(policy).to be_allowed :update_commit_status diff --git a/spec/policies/ci/pipeline_policy_spec.rb b/spec/policies/ci/pipeline_policy_spec.rb index a5e509cfa0f..bd32faf06ef 100644 --- a/spec/policies/ci/pipeline_policy_spec.rb +++ b/spec/policies/ci/pipeline_policy_spec.rb @@ -69,7 +69,7 @@ describe Ci::PipelinePolicy, :models do it 'enables update_pipeline if user is maintainer' do allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false) - allow_any_instance_of(Project).to receive(:branch_allows_maintainer_push?).and_return(true) + allow_any_instance_of(Project).to receive(:branch_allows_collaboration?).and_return(true) expect(policy).to be_allowed :update_pipeline end diff --git a/spec/policies/project_policy_spec.rb b/spec/policies/project_policy_spec.rb index 6609f5f7afd..6ac151f92f3 100644 --- a/spec/policies/project_policy_spec.rb +++ b/spec/policies/project_policy_spec.rb @@ -400,7 +400,7 @@ describe ProjectPolicy do :merge_request, target_project: target_project, source_project: project, - allow_maintainer_to_push: true + allow_collaboration: true ) end let(:maintainer_abilities) do diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index 605761867bf..d4ebfc3f782 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -386,12 +386,13 @@ describe API::MergeRequests do source_project: forked_project, target_project: project, source_branch: 'fixes', - allow_maintainer_to_push: true) + allow_collaboration: true) end - it 'includes the `allow_maintainer_to_push` field' do + it 'includes the `allow_collaboration` field' do get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}", user) + expect(json_response['allow_collaboration']).to be_truthy expect(json_response['allow_maintainer_to_push']).to be_truthy end end @@ -654,11 +655,12 @@ describe API::MergeRequests do expect(response).to have_gitlab_http_status(400) end - it 'allows setting `allow_maintainer_to_push`' do + it 'allows setting `allow_collaboration`' do post api("/projects/#{forked_project.id}/merge_requests", user2), - title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master", - author: user2, target_project_id: project.id, allow_maintainer_to_push: true + title: 'Test merge_request', source_branch: "feature_conflict", target_branch: "master", + author: user2, target_project_id: project.id, allow_collaboration: true expect(response).to have_gitlab_http_status(201) + expect(json_response['allow_collaboration']).to be_truthy expect(json_response['allow_maintainer_to_push']).to be_truthy end diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index a73bd7a0268..688d3b8c038 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -280,12 +280,12 @@ describe Ci::RetryPipelineService, '#execute' do source_project: forked_project, target_project: project, source_branch: 'fixes', - allow_maintainer_to_push: true) + allow_collaboration: true) create_build('rspec 1', :failed, 1) end it 'allows to retry failed pipeline' do - allow_any_instance_of(Project).to receive(:fetch_branch_allows_maintainer_push?).and_return(true) + allow_any_instance_of(Project).to receive(:fetch_branch_allows_collaboration?).and_return(true) allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false) service.execute(pipeline) diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index 5279ea6164e..cc26df725c7 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -541,7 +541,7 @@ describe MergeRequests::UpdateService, :mailer do let(:closed_issuable) { create(:closed_merge_request, source_project: project) } end - context 'setting `allow_maintainer_to_push`' do + context 'setting `allow_collaboration`' do let(:target_project) { create(:project, :public) } let(:source_project) { fork_project(target_project) } let(:user) { create(:user) } @@ -556,23 +556,23 @@ describe MergeRequests::UpdateService, :mailer do allow(ProtectedBranch).to receive(:protected?).with(source_project, 'fixes') { false } end - it 'does not allow a maintainer of the target project to set `allow_maintainer_to_push`' do + it 'does not allow a maintainer of the target project to set `allow_collaboration`' do target_project.add_developer(user) - update_merge_request(allow_maintainer_to_push: true, title: 'Updated title') + update_merge_request(allow_collaboration: true, title: 'Updated title') expect(merge_request.title).to eq('Updated title') - expect(merge_request.allow_maintainer_to_push).to be_falsy + expect(merge_request.allow_collaboration).to be_falsy end it 'is allowed by a user that can push to the source and can update the merge request' do merge_request.update!(assignee: user) source_project.add_developer(user) - update_merge_request(allow_maintainer_to_push: true, title: 'Updated title') + update_merge_request(allow_collaboration: true, title: 'Updated title') expect(merge_request.title).to eq('Updated title') - expect(merge_request.allow_maintainer_to_push).to be_truthy + expect(merge_request.allow_collaboration).to be_truthy end end end -- cgit v1.2.1 From 9b2e19fe37a5d1389e9f83531bb6ba4b06a66de0 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Thu, 24 May 2018 08:55:47 +0200 Subject: Adds variables to POST api/v4/projects/:id/pipeline --- spec/requests/api/pipelines_spec.rb | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 0736329f9fd..f20c2275152 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -294,13 +294,28 @@ describe API::Pipelines do it 'creates and returns a new pipeline' do expect do post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch - end.to change { Ci::Pipeline.count }.by(1) + end.to change { project.pipelines.count }.by(1) expect(response).to have_gitlab_http_status(201) expect(json_response).to be_a Hash expect(json_response['sha']).to eq project.commit.id end + context 'variables given' do + let(:variables_attributes) { [{ 'key' => 'UPLOAD_TO_S3', 'value' => 'true' }] } + + it 'creates and returns a new pipeline using the given variables' do + expect do + post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables_attributes: variables_attributes + end.to change { project.pipelines.count }.by(1) + + expect(response).to have_gitlab_http_status(201) + expect(json_response).to be_a Hash + expect(json_response['sha']).to eq project.commit.id + expect(json_response['variables']).to eq variables_attributes + end + end + it 'fails when using an invalid ref' do post api("/projects/#{project.id}/pipeline", user), ref: 'invalid_ref' -- cgit v1.2.1 From 6ae16b6d4d9fb79b715875073bb78efd3f56929b Mon Sep 17 00:00:00 2001 From: Jacopo Date: Thu, 31 May 2018 09:47:53 +0200 Subject: Rename variables_attributes => variables and adds spec for exclude/only option --- spec/requests/api/pipelines_spec.rb | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index f20c2275152..0c6bb56e11d 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -302,17 +302,32 @@ describe API::Pipelines do end context 'variables given' do - let(:variables_attributes) { [{ 'key' => 'UPLOAD_TO_S3', 'value' => 'true' }] } + let(:variables) { [{ 'key' => 'UPLOAD_TO_S3', 'value' => 'true' }] } it 'creates and returns a new pipeline using the given variables' do expect do - post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables_attributes: variables_attributes + post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables end.to change { project.pipelines.count }.by(1) expect(response).to have_gitlab_http_status(201) expect(json_response).to be_a Hash expect(json_response['sha']).to eq project.commit.id - expect(json_response['variables']).to eq variables_attributes + expect(json_response['variables']).to eq variables + end + end + + context 'when excluding a ref' do + before do + config = YAML.dump(test: { script: 'test', except: [project.default_branch] }) + stub_ci_pipeline_yaml_file(config) + end + + it "doesn't not create a job for the exluded ref" do + expect do + post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch + end.not_to change { project.pipelines.count } + + expect(response).to have_gitlab_http_status(400) end end -- cgit v1.2.1 From 3871ea33ca524ef2d420a4ff311d8535622bd150 Mon Sep 17 00:00:00 2001 From: Jacopo Date: Fri, 1 Jun 2018 15:52:24 +0200 Subject: Review 1 --- spec/requests/api/pipelines_spec.rb | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 0c6bb56e11d..0a64c46bb92 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -316,18 +316,35 @@ describe API::Pipelines do end end - context 'when excluding a ref' do + describe 'using variables conditions' do + let(:variables) { [{ 'key' => 'STAGING', 'value' => 'true' }] } + before do - config = YAML.dump(test: { script: 'test', except: [project.default_branch] }) + config = YAML.dump(test: { script: 'test', only: { variables: ['$STAGING'] } }) stub_ci_pipeline_yaml_file(config) end - it "doesn't not create a job for the exluded ref" do + it 'creates and returns a new pipeline using the given variables' do expect do - post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch - end.not_to change { project.pipelines.count } + post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables + end.to change { project.pipelines.count }.by(1) - expect(response).to have_gitlab_http_status(400) + expect(response).to have_gitlab_http_status(201) + expect(json_response).to be_a Hash + expect(json_response['sha']).to eq project.commit.id + expect(json_response['variables']).to eq variables + end + + context 'condition unmatch' do + let(:variables) { [{ 'key' => 'STAGING', 'value' => 'false' }] } + + it "doesn't create a job" do + expect do + post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch + end.not_to change { project.pipelines.count } + + expect(response).to have_gitlab_http_status(400) + end end end -- cgit v1.2.1 From 5e9687a198f205131d8e65c747f6b4ac2ae092f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 1 Jun 2018 23:39:24 +0200 Subject: Add deploy_strategy to ProjectAutoDevops --- spec/models/project_auto_devops_spec.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'spec') diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 7545c0797e9..1bfc6befb4b 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -5,6 +5,8 @@ describe ProjectAutoDevops do it { is_expected.to belong_to(:project) } + it { is_expected.to define_enum_for(:deploy_strategy) } + it { is_expected.to respond_to(:created_at) } it { is_expected.to respond_to(:updated_at) } -- cgit v1.2.1 From 39412d0a163625bd91632267a1dd36c1ebb23906 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Fri, 1 Jun 2018 23:47:38 +0200 Subject: Add deploy strategy related predefined variables --- spec/factories/project_auto_devops.rb | 1 + spec/models/project_auto_devops_spec.rb | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'spec') diff --git a/spec/factories/project_auto_devops.rb b/spec/factories/project_auto_devops.rb index 5ce1988c76f..a59087cd7eb 100644 --- a/spec/factories/project_auto_devops.rb +++ b/spec/factories/project_auto_devops.rb @@ -3,5 +3,6 @@ FactoryBot.define do project enabled true domain "example.com" + deploy_strategy :continuous end end diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 1bfc6befb4b..37cd1f571e5 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -69,6 +69,19 @@ describe ProjectAutoDevops do end end + context 'when deploy_strategy is continuous' do + let(:domain) { 'example.com' } + + before do + auto_devops.deploy_strategy = 'continuous' + end + + it do + expect(auto_devops.predefined_variables.map { |var| var[:key] }) + .to include("STAGING_ENABLED", "INCREMENTAL_ROLLOUT_ENABLED") + end + end + def domain_variable { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true } end -- cgit v1.2.1 From 5403a4a07ed86770f1ab11108ab5a86fa2b90e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Sat, 2 Jun 2018 11:46:55 +0200 Subject: Add deploy_strategy to safe model attributes --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 74e7a45fd6c..5e6311441f8 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -539,6 +539,7 @@ ProjectAutoDevops: - id - enabled - domain +- deploy_strategy - project_id - created_at - updated_at -- cgit v1.2.1 From caadfcdee31237bbfbcfb304346fc4a5994295dd Mon Sep 17 00:00:00 2001 From: Mario de la Ossa Date: Mon, 21 May 2018 20:24:37 -0600 Subject: Backport changes in app/services/test_hooks/project_service.rb --- spec/services/test_hooks/project_service_spec.rb | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/test_hooks/project_service_spec.rb b/spec/services/test_hooks/project_service_spec.rb index 962b9f40c4f..19e1c5ff3b2 100644 --- a/spec/services/test_hooks/project_service_spec.rb +++ b/spec/services/test_hooks/project_service_spec.rb @@ -6,13 +6,19 @@ describe TestHooks::ProjectService do describe '#execute' do let(:project) { create(:project, :repository) } let(:hook) { create(:project_hook, project: project) } + let(:trigger) { 'not_implemented_events' } let(:service) { described_class.new(hook, current_user, trigger) } let(:sample_data) { { data: 'sample' } } let(:success_result) { { status: :success, http_status: 200, message: 'ok' } } - context 'hook with not implemented test' do - let(:trigger) { 'not_implemented_events' } + it 'allows to set a custom project' do + project = double + service.project = project + + expect(service.project).to eq(project) + end + context 'hook with not implemented test' do it 'returns error message' do expect(hook).not_to receive(:execute) expect(service.execute).to include({ status: :error, message: 'Testing not available for this hook' }) -- cgit v1.2.1 From 3579ed016acbc3a512217d896a112747fcfd33bc Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Sun, 3 Jun 2018 22:17:36 +0900 Subject: Revert "Add a new have_html_escaped_body_text that match an HTML-escaped text" This reverts commit 517598ba10793efa02cb90379f78ab97c9c5b25d. --- spec/mailers/notify_spec.rb | 18 +++++++++--------- spec/support/matchers/email_matchers.rb | 5 ----- 2 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 spec/support/matchers/email_matchers.rb (limited to 'spec') diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 69eafbe4bbe..ecd3d309327 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -660,7 +660,7 @@ describe Notify do is_expected.to have_html_escaped_body_text project.full_name is_expected.to have_body_text project.web_url is_expected.to have_body_text project_member.invite_email - is_expected.to have_html_escaped_body_text invited_user.name + is_expected.to have_body_text invited_user.name end end @@ -932,7 +932,7 @@ describe Notify do end it 'contains the message from the note' do - is_expected.to have_html_escaped_body_text note.note + is_expected.to have_body_text note.note end it 'contains an introduction' do @@ -991,7 +991,7 @@ describe Notify do expect(to_emails).to eq([recipient.notification_email]) is_expected.to have_subject "Request to join the #{group.name} group" - is_expected.to have_html_escaped_body_text group.name + is_expected.to have_body_text group.name is_expected.to have_body_text group_group_members_url(group) is_expected.to have_body_text group_member.human_access end @@ -1010,7 +1010,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject "Access to the #{group.name} group was denied" - is_expected.to have_html_escaped_body_text group.name + is_expected.to have_body_text group.name is_expected.to have_body_text group.web_url end end @@ -1026,7 +1026,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject "Access to the #{group.name} group was granted" - is_expected.to have_html_escaped_body_text group.name + is_expected.to have_body_text group.name is_expected.to have_body_text group.web_url is_expected.to have_body_text group_member.human_access end @@ -1056,7 +1056,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject "Invitation to join the #{group.name} group" - is_expected.to have_html_escaped_body_text group.name + is_expected.to have_body_text group.name is_expected.to have_body_text group.web_url is_expected.to have_body_text group_member.human_access is_expected.to have_body_text group_member.invite_token @@ -1080,10 +1080,10 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject 'Invitation accepted' - is_expected.to have_html_escaped_body_text group.name + is_expected.to have_body_text group.name is_expected.to have_body_text group.web_url is_expected.to have_body_text group_member.invite_email - is_expected.to have_html_escaped_body_text invited_user.name + is_expected.to have_body_text invited_user.name end end @@ -1103,7 +1103,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject 'Invitation declined' - is_expected.to have_html_escaped_body_text group.name + is_expected.to have_body_text group.name is_expected.to have_body_text group.web_url is_expected.to have_body_text group_member.invite_email end diff --git a/spec/support/matchers/email_matchers.rb b/spec/support/matchers/email_matchers.rb deleted file mode 100644 index d9d59ec12ec..00000000000 --- a/spec/support/matchers/email_matchers.rb +++ /dev/null @@ -1,5 +0,0 @@ -RSpec::Matchers.define :have_html_escaped_body_text do |expected| - match do |actual| - expect(actual).to have_body_text(ERB::Util.html_escape(expected)) - end -end -- cgit v1.2.1 From d46c12290d74e9faac888bf5de5cc1d84a00b675 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Sun, 3 Jun 2018 22:22:50 +0900 Subject: Replace have_html_espaced_body_text after 517598ba --- spec/mailers/notify_spec.rb | 38 +++++++++++----------- .../shared_examples/notify_shared_examples.rb | 4 +-- 2 files changed, 21 insertions(+), 21 deletions(-) (limited to 'spec') diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index ecd3d309327..775ca4ba0eb 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -68,7 +68,7 @@ describe Notify do end it 'contains the description' do - is_expected.to have_html_escaped_body_text issue.description + is_expected.to have_body_text issue.description end it 'does not add a reason header' do @@ -89,7 +89,7 @@ describe Notify do end it 'contains a link to note author' do - is_expected.to have_html_escaped_body_text(issue.author_name) + is_expected.to have_body_text(issue.author_name) is_expected.to have_body_text 'created an issue:' end end @@ -115,8 +115,8 @@ describe Notify do it 'has the correct subject and body' do aggregate_failures do is_expected.to have_referable_subject(issue, reply: true) - is_expected.to have_html_escaped_body_text(previous_assignee.name) - is_expected.to have_html_escaped_body_text(assignee.name) + is_expected.to have_body_text(previous_assignee.name) + is_expected.to have_body_text(assignee.name) is_expected.to have_body_text(project_issue_path(project, issue)) end end @@ -190,7 +190,7 @@ describe Notify do aggregate_failures do is_expected.to have_referable_subject(issue, reply: true) is_expected.to have_body_text(status) - is_expected.to have_html_escaped_body_text(current_user.name) + is_expected.to have_body_text(current_user.name) is_expected.to have_body_text(project_issue_path project, issue) end end @@ -243,7 +243,7 @@ describe Notify do end it 'contains the description' do - is_expected.to have_html_escaped_body_text merge_request.description + is_expected.to have_body_text merge_request.description end context 'when sent with a reason' do @@ -260,7 +260,7 @@ describe Notify do end it 'contains a link to note author' do - is_expected.to have_html_escaped_body_text merge_request.author_name + is_expected.to have_body_text merge_request.author_name is_expected.to have_body_text 'created a merge request:' end end @@ -286,9 +286,9 @@ describe Notify do it 'has the correct subject and body' do aggregate_failures do is_expected.to have_referable_subject(merge_request, reply: true) - is_expected.to have_html_escaped_body_text(previous_assignee.name) + is_expected.to have_body_text(previous_assignee.name) is_expected.to have_body_text(project_merge_request_path(project, merge_request)) - is_expected.to have_html_escaped_body_text(assignee.name) + is_expected.to have_body_text(assignee.name) end end @@ -358,7 +358,7 @@ describe Notify do aggregate_failures do is_expected.to have_referable_subject(merge_request, reply: true) is_expected.to have_body_text(status) - is_expected.to have_html_escaped_body_text(current_user.name) + is_expected.to have_body_text(current_user.name) is_expected.to have_body_text(project_merge_request_path(project, merge_request)) end end @@ -526,7 +526,7 @@ describe Notify do it 'has the correct subject and body' do is_expected.to have_referable_subject(project_snippet, reply: true) - is_expected.to have_html_escaped_body_text project_snippet_note.note + is_expected.to have_body_text project_snippet_note.note end end @@ -539,7 +539,7 @@ describe Notify do it 'has the correct subject and body' do is_expected.to have_subject("#{project.name} | Project was moved") - is_expected.to have_html_escaped_body_text project.full_name + is_expected.to have_body_text project.full_name is_expected.to have_body_text(project.ssh_url_to_repo) end end @@ -566,7 +566,7 @@ describe Notify do expect(to_emails).to eq([recipient.notification_email]) is_expected.to have_subject "Request to join the #{project.full_name} project" - is_expected.to have_html_escaped_body_text project.full_name + is_expected.to have_body_text project.full_name is_expected.to have_body_text project_project_members_url(project) is_expected.to have_body_text project_member.human_access end @@ -586,7 +586,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject "Access to the #{project.full_name} project was denied" - is_expected.to have_html_escaped_body_text project.full_name + is_expected.to have_body_text project.full_name is_expected.to have_body_text project.web_url end end @@ -603,7 +603,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject "Access to the #{project.full_name} project was granted" - is_expected.to have_html_escaped_body_text project.full_name + is_expected.to have_body_text project.full_name is_expected.to have_body_text project.web_url is_expected.to have_body_text project_member.human_access end @@ -633,7 +633,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject "Invitation to join the #{project.full_name} project" - is_expected.to have_html_escaped_body_text project.full_name + is_expected.to have_body_text project.full_name is_expected.to have_body_text project.full_name is_expected.to have_body_text project_member.human_access is_expected.to have_body_text project_member.invite_token @@ -657,7 +657,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject 'Invitation accepted' - is_expected.to have_html_escaped_body_text project.full_name + is_expected.to have_body_text project.full_name is_expected.to have_body_text project.web_url is_expected.to have_body_text project_member.invite_email is_expected.to have_body_text invited_user.name @@ -680,7 +680,7 @@ describe Notify do it 'contains all the useful information' do is_expected.to have_subject 'Invitation declined' - is_expected.to have_html_escaped_body_text project.full_name + is_expected.to have_body_text project.full_name is_expected.to have_body_text project.web_url is_expected.to have_body_text project_member.invite_email end @@ -1396,7 +1396,7 @@ describe Notify do it 'has the correct subject and body' do is_expected.to have_referable_subject(personal_snippet, reply: true) - is_expected.to have_html_escaped_body_text personal_snippet_note.note + is_expected.to have_body_text personal_snippet_note.note end end end diff --git a/spec/support/shared_examples/notify_shared_examples.rb b/spec/support/shared_examples/notify_shared_examples.rb index 43fdaddf545..d176d3fa425 100644 --- a/spec/support/shared_examples/notify_shared_examples.rb +++ b/spec/support/shared_examples/notify_shared_examples.rb @@ -212,7 +212,7 @@ shared_examples 'a note email' do end it 'contains the message from the note' do - is_expected.to have_html_escaped_body_text note.note + is_expected.to have_body_text note.note end it 'does not contain note author' do @@ -225,7 +225,7 @@ shared_examples 'a note email' do end it 'contains a link to note author' do - is_expected.to have_html_escaped_body_text note.author_name + is_expected.to have_body_text note.author_name end end end -- cgit v1.2.1 From 3f55e0b29fe39c5fd31c703911c96808bd17335d Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Sun, 3 Jun 2018 23:45:26 +0900 Subject: Use the default strings of timeago.js for timeago --- spec/features/admin/admin_uses_repository_checks_spec.rb | 2 +- spec/features/merge_request/user_posts_notes_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/admin/admin_uses_repository_checks_spec.rb b/spec/features/admin/admin_uses_repository_checks_spec.rb index 90cf5a53787..7371a494d36 100644 --- a/spec/features/admin/admin_uses_repository_checks_spec.rb +++ b/spec/features/admin/admin_uses_repository_checks_spec.rb @@ -28,7 +28,7 @@ feature 'Admin uses repository checks' do visit_admin_project_page(project) page.within('.alert') do - expect(page.text).to match(/Last repository check \(.* ago\) failed/) + expect(page.text).to match(/Last repository check \(just now\) failed/) end end diff --git a/spec/features/merge_request/user_posts_notes_spec.rb b/spec/features/merge_request/user_posts_notes_spec.rb index b54addce993..3bd9f5e2298 100644 --- a/spec/features/merge_request/user_posts_notes_spec.rb +++ b/spec/features/merge_request/user_posts_notes_spec.rb @@ -139,7 +139,7 @@ describe 'Merge request > User posts notes', :js do page.within("#note_#{note.id}") do is_expected.to have_css('.note_edited_ago') expect(find('.note_edited_ago').text) - .to match(/less than a minute ago/) + .to match(/just now/) end end end -- cgit v1.2.1 From 89b4304f12cd37d8715c274cdee080e95f2d3bad Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Tue, 29 May 2018 17:06:14 +0900 Subject: Add background migrations to arhive legacy traces --- .../archive_legacy_traces_spec.rb | 60 ++++++++++++++++++++++ spec/migrations/archive_legacy_traces_spec.rb | 45 ++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb create mode 100644 spec/migrations/archive_legacy_traces_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb new file mode 100644 index 00000000000..ecc6eea9284 --- /dev/null +++ b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, :migration, schema: 20180529152628 do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:builds) { table(:ci_builds) } + let(:job_artifacts) { table(:ci_job_artifacts) } + + before do + namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) + build = builds.create!(id: 1, project_id: 123, status: 'success') + + @legacy_trace_dir = File.join(Settings.gitlab_ci.builds_path, + build.created_at.utc.strftime("%Y_%m"), + build.project_id.to_s) + + FileUtils.mkdir_p(@legacy_trace_dir) + + @legacy_trace_path = File.join(@legacy_trace_dir, "#{build.id}.log") + end + + context 'when trace file exsits at the right place' do + before do + File.open(@legacy_trace_path, 'wb') { |stream| stream.write('aiueo') } + end + + it 'correctly archive legacy traces' do + expect(job_artifacts.count).to eq(0) + expect(File.exist?(@legacy_trace_path)).to be_truthy + + described_class.new.perform(1, 1) + + expect(job_artifacts.count).to eq(1) + expect(File.exist?(@legacy_trace_path)).to be_falsy + expect(File.read(new_trace_path)).to eq('aiueo') + end + end + + context 'when trace file does not exsits at the right place' do + it 'correctly archive legacy traces' do + expect(job_artifacts.count).to eq(0) + expect(File.exist?(@legacy_trace_path)).to be_falsy + + described_class.new.perform(1, 1) + + expect(job_artifacts.count).to eq(0) + end + end + + def new_trace_path + job_artifact = job_artifacts.first + + disk_hash = Digest::SHA2.hexdigest(job_artifact.project_id.to_s) + creation_date = job_artifact.created_at.utc.strftime('%Y_%m_%d') + + File.join(Gitlab.config.artifacts.path, disk_hash[0..1], disk_hash[2..3], disk_hash, + creation_date, job_artifact.job_id.to_s, job_artifact.id.to_s, 'job.log') + end +end diff --git a/spec/migrations/archive_legacy_traces_spec.rb b/spec/migrations/archive_legacy_traces_spec.rb new file mode 100644 index 00000000000..fc61c4bec17 --- /dev/null +++ b/spec/migrations/archive_legacy_traces_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20180529152628_archive_legacy_traces') + +describe ArchiveLegacyTraces, :migration do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:builds) { table(:ci_builds) } + let(:job_artifacts) { table(:ci_job_artifacts) } + + before do + namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) + build = builds.create!(id: 1) + + @legacy_trace_path = File.join( + Settings.gitlab_ci.builds_path, + build.created_at.utc.strftime("%Y_%m"), + build.project_id.to_s, + "#{job.id}.log" + ) + + File.open(@legacy_trace_path, 'wb') { |stream| stream.write('aiueo') } + end + + it 'correctly archive legacy traces' do + expect(job_artifacts.count).to eq(0) + expect(File.exist?(@legacy_trace_path)).to be_truthy + + migrate! + + expect(job_artifacts.count).to eq(1) + expect(File.exist?(@legacy_trace_path)).to be_falsy + expect(File.exist?(new_trace_path)).to be_truthy + end + + def new_trace_path + job_artifact = job_artifacts.first + + disk_hash = Digest::SHA2.hexdigest(job_artifact.project_id.to_s) + creation_date = job_artifact.created_at.utc.strftime('%Y_%m_%d') + + File.join(disk_hash[0..1], disk_hash[2..3], disk_hash, + creation_date, job_artifact.job_id.to_s, job_artifact.id.to_s) + end +end -- cgit v1.2.1 From 0d00d02e842a0c4b22d213e00143a08d97597000 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Sun, 3 Jun 2018 14:21:50 +0900 Subject: Directly refer application code from migration code --- spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb index ecc6eea9284..1a62b30ce81 100644 --- a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb +++ b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb @@ -14,7 +14,7 @@ describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, :migration, schema: 2 @legacy_trace_dir = File.join(Settings.gitlab_ci.builds_path, build.created_at.utc.strftime("%Y_%m"), build.project_id.to_s) - + FileUtils.mkdir_p(@legacy_trace_dir) @legacy_trace_path = File.join(@legacy_trace_dir, "#{build.id}.log") -- cgit v1.2.1 From bcd664f53a4009bc752fbc47e1c4d6f76c0b8cc2 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Sun, 3 Jun 2018 15:04:47 +0900 Subject: Fix specs. Rename migration file name which was conflicted with background migration's. --- .../archive_legacy_traces_spec.rb | 35 ++++------------- spec/migrations/archive_legacy_traces_spec.rb | 45 ---------------------- .../schedule_to_archive_legacy_traces_spec.rb | 45 ++++++++++++++++++++++ spec/support/trace/trace_helpers.rb | 23 +++++++++++ 4 files changed, 76 insertions(+), 72 deletions(-) delete mode 100644 spec/migrations/archive_legacy_traces_spec.rb create mode 100644 spec/migrations/schedule_to_archive_legacy_traces_spec.rb create mode 100644 spec/support/trace/trace_helpers.rb (limited to 'spec') diff --git a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb index 1a62b30ce81..0765f4149f9 100644 --- a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb +++ b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, :migration, schema: 20180529152628 do + include TraceHelpers + let(:namespaces) { table(:namespaces) } let(:projects) { table(:projects) } let(:builds) { table(:ci_builds) } @@ -9,52 +11,31 @@ describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, :migration, schema: 2 before do namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) - build = builds.create!(id: 1, project_id: 123, status: 'success') - - @legacy_trace_dir = File.join(Settings.gitlab_ci.builds_path, - build.created_at.utc.strftime("%Y_%m"), - build.project_id.to_s) - - FileUtils.mkdir_p(@legacy_trace_dir) - - @legacy_trace_path = File.join(@legacy_trace_dir, "#{build.id}.log") + @build = builds.create!(id: 1, project_id: 123, status: 'success', type: 'Ci::Build') end context 'when trace file exsits at the right place' do before do - File.open(@legacy_trace_path, 'wb') { |stream| stream.write('aiueo') } + create_legacy_trace(@build, 'aiueo') end it 'correctly archive legacy traces' do expect(job_artifacts.count).to eq(0) - expect(File.exist?(@legacy_trace_path)).to be_truthy + expect(File.exist?(legacy_trace_path(@build))).to be_truthy described_class.new.perform(1, 1) expect(job_artifacts.count).to eq(1) - expect(File.exist?(@legacy_trace_path)).to be_falsy - expect(File.read(new_trace_path)).to eq('aiueo') + expect(File.exist?(legacy_trace_path(@build))).to be_falsy + expect(File.read(archived_trace_path(job_artifacts.first))).to eq('aiueo') end end context 'when trace file does not exsits at the right place' do - it 'correctly archive legacy traces' do - expect(job_artifacts.count).to eq(0) - expect(File.exist?(@legacy_trace_path)).to be_falsy - + it 'does not raise errors and create job artifact row' do described_class.new.perform(1, 1) expect(job_artifacts.count).to eq(0) end end - - def new_trace_path - job_artifact = job_artifacts.first - - disk_hash = Digest::SHA2.hexdigest(job_artifact.project_id.to_s) - creation_date = job_artifact.created_at.utc.strftime('%Y_%m_%d') - - File.join(Gitlab.config.artifacts.path, disk_hash[0..1], disk_hash[2..3], disk_hash, - creation_date, job_artifact.job_id.to_s, job_artifact.id.to_s, 'job.log') - end end diff --git a/spec/migrations/archive_legacy_traces_spec.rb b/spec/migrations/archive_legacy_traces_spec.rb deleted file mode 100644 index fc61c4bec17..00000000000 --- a/spec/migrations/archive_legacy_traces_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'spec_helper' -require Rails.root.join('db', 'post_migrate', '20180529152628_archive_legacy_traces') - -describe ArchiveLegacyTraces, :migration do - let(:namespaces) { table(:namespaces) } - let(:projects) { table(:projects) } - let(:builds) { table(:ci_builds) } - let(:job_artifacts) { table(:ci_job_artifacts) } - - before do - namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') - projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) - build = builds.create!(id: 1) - - @legacy_trace_path = File.join( - Settings.gitlab_ci.builds_path, - build.created_at.utc.strftime("%Y_%m"), - build.project_id.to_s, - "#{job.id}.log" - ) - - File.open(@legacy_trace_path, 'wb') { |stream| stream.write('aiueo') } - end - - it 'correctly archive legacy traces' do - expect(job_artifacts.count).to eq(0) - expect(File.exist?(@legacy_trace_path)).to be_truthy - - migrate! - - expect(job_artifacts.count).to eq(1) - expect(File.exist?(@legacy_trace_path)).to be_falsy - expect(File.exist?(new_trace_path)).to be_truthy - end - - def new_trace_path - job_artifact = job_artifacts.first - - disk_hash = Digest::SHA2.hexdigest(job_artifact.project_id.to_s) - creation_date = job_artifact.created_at.utc.strftime('%Y_%m_%d') - - File.join(disk_hash[0..1], disk_hash[2..3], disk_hash, - creation_date, job_artifact.job_id.to_s, job_artifact.id.to_s) - end -end diff --git a/spec/migrations/schedule_to_archive_legacy_traces_spec.rb b/spec/migrations/schedule_to_archive_legacy_traces_spec.rb new file mode 100644 index 00000000000..d3eac3c45ea --- /dev/null +++ b/spec/migrations/schedule_to_archive_legacy_traces_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20180529152628_schedule_to_archive_legacy_traces') + +describe ScheduleToArchiveLegacyTraces, :migration do + include TraceHelpers + + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:builds) { table(:ci_builds) } + let(:job_artifacts) { table(:ci_job_artifacts) } + + before do + namespaces.create!(id: 123, name: 'gitlab1', path: 'gitlab1') + projects.create!(id: 123, name: 'gitlab1', path: 'gitlab1', namespace_id: 123) + @build_success = builds.create!(id: 1, project_id: 123, status: 'success', type: 'Ci::Build') + @build_failed = builds.create!(id: 2, project_id: 123, status: 'failed', type: 'Ci::Build') + @builds_canceled = builds.create!(id: 3, project_id: 123, status: 'canceled', type: 'Ci::Build') + @build_running = builds.create!(id: 4, project_id: 123, status: 'running', type: 'Ci::Build') + + create_legacy_trace(@build_success, 'This job is done') + create_legacy_trace(@build_failed, 'This job is done') + create_legacy_trace(@builds_canceled, 'This job is done') + create_legacy_trace(@build_running, 'This job is not done yet') + end + + it 'correctly archive legacy traces' do + expect(job_artifacts.count).to eq(0) + expect(File.exist?(legacy_trace_path(@build_success))).to be_truthy + expect(File.exist?(legacy_trace_path(@build_failed))).to be_truthy + expect(File.exist?(legacy_trace_path(@builds_canceled))).to be_truthy + expect(File.exist?(legacy_trace_path(@build_running))).to be_truthy + + migrate! + + expect(job_artifacts.count).to eq(3) + expect(File.exist?(legacy_trace_path(@build_success))).to be_falsy + expect(File.exist?(legacy_trace_path(@build_failed))).to be_falsy + expect(File.exist?(legacy_trace_path(@builds_canceled))).to be_falsy + expect(File.exist?(legacy_trace_path(@build_running))).to be_truthy + expect(File.exist?(archived_trace_path(job_artifacts.where(job_id: @build_success.id).first))).to be_truthy + expect(File.exist?(archived_trace_path(job_artifacts.where(job_id: @build_failed.id).first))).to be_truthy + expect(File.exist?(archived_trace_path(job_artifacts.where(job_id: @builds_canceled.id).first))).to be_truthy + expect(job_artifacts.where(job_id: @build_running.id)).not_to be_exist + end +end diff --git a/spec/support/trace/trace_helpers.rb b/spec/support/trace/trace_helpers.rb new file mode 100644 index 00000000000..f6d11b61038 --- /dev/null +++ b/spec/support/trace/trace_helpers.rb @@ -0,0 +1,23 @@ +module TraceHelpers + def create_legacy_trace(build, content) + File.open(legacy_trace_path(build), 'wb') { |stream| stream.write(content) } + end + + def legacy_trace_path(build) + legacy_trace_dir = File.join(Settings.gitlab_ci.builds_path, + build.created_at.utc.strftime("%Y_%m"), + build.project_id.to_s) + + FileUtils.mkdir_p(legacy_trace_dir) + + File.join(legacy_trace_dir, "#{build.id}.log") + end + + def archived_trace_path(job_artifact) + disk_hash = Digest::SHA2.hexdigest(job_artifact.project_id.to_s) + creation_date = job_artifact.created_at.utc.strftime('%Y_%m_%d') + + File.join(Gitlab.config.artifacts.path, disk_hash[0..1], disk_hash[2..3], disk_hash, + creation_date, job_artifact.job_id.to_s, job_artifact.id.to_s, 'job.log') + end +end -- cgit v1.2.1 From 8f1f73d4e3ca82e3d449e478606f133d19ead7b1 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Mon, 4 Jun 2018 14:28:21 +0900 Subject: Fix typo in spec. Add a test for the case of when trace is stored in database --- .../archive_legacy_traces_spec.rb | 26 ++++++++++++++++++---- spec/support/trace/trace_helpers.rb | 4 ++++ 2 files changed, 26 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb index 0765f4149f9..877c061d11b 100644 --- a/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb +++ b/spec/lib/gitlab/background_migration/archive_legacy_traces_spec.rb @@ -16,7 +16,7 @@ describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, :migration, schema: 2 context 'when trace file exsits at the right place' do before do - create_legacy_trace(@build, 'aiueo') + create_legacy_trace(@build, 'trace in file') end it 'correctly archive legacy traces' do @@ -27,15 +27,33 @@ describe Gitlab::BackgroundMigration::ArchiveLegacyTraces, :migration, schema: 2 expect(job_artifacts.count).to eq(1) expect(File.exist?(legacy_trace_path(@build))).to be_falsy - expect(File.read(archived_trace_path(job_artifacts.first))).to eq('aiueo') + expect(File.read(archived_trace_path(job_artifacts.first))).to eq('trace in file') end end context 'when trace file does not exsits at the right place' do - it 'does not raise errors and create job artifact row' do - described_class.new.perform(1, 1) + it 'does not raise errors nor create job artifact' do + expect { described_class.new.perform(1, 1) }.not_to raise_error expect(job_artifacts.count).to eq(0) end end + + context 'when trace data exsits in database' do + before do + create_legacy_trace_in_db(@build, 'trace in db') + end + + it 'correctly archive legacy traces' do + expect(job_artifacts.count).to eq(0) + expect(@build.read_attribute(:trace)).not_to be_empty + + described_class.new.perform(1, 1) + + @build.reload + expect(job_artifacts.count).to eq(1) + expect(@build.read_attribute(:trace)).to be_nil + expect(File.read(archived_trace_path(job_artifacts.first))).to eq('trace in db') + end + end end diff --git a/spec/support/trace/trace_helpers.rb b/spec/support/trace/trace_helpers.rb index f6d11b61038..c7802bbcb94 100644 --- a/spec/support/trace/trace_helpers.rb +++ b/spec/support/trace/trace_helpers.rb @@ -3,6 +3,10 @@ module TraceHelpers File.open(legacy_trace_path(build), 'wb') { |stream| stream.write(content) } end + def create_legacy_trace_in_db(build, content) + build.update_column(:trace, content) + end + def legacy_trace_path(build) legacy_trace_dir = File.join(Settings.gitlab_ci.builds_path, build.created_at.utc.strftime("%Y_%m"), -- cgit v1.2.1 From 114c26ccf0f10788271c6108774e72809a7f93e1 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Mon, 4 Jun 2018 11:29:39 +0200 Subject: Raise error if pipeline / stage hits unknown status --- spec/models/ci/pipeline_spec.rb | 37 +++++++++++++++++++++++++++++++++++++ spec/models/ci/stage_spec.rb | 13 +++++++++++++ 2 files changed, 50 insertions(+) (limited to 'spec') diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index a29fa0c4cae..decfef6c8cc 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -1251,6 +1251,43 @@ describe Ci::Pipeline, :mailer do end end + describe '#update_status' do + context 'when pipeline is empty' do + it 'updates does not change pipeline status' do + expect(pipeline.statuses.latest.status).to be_nil + + expect { pipeline.update_status } + .to change { pipeline.reload.status }.to 'skipped' + end + end + + context 'when updating status to pending' do + before do + allow(pipeline) + .to receive_message_chain(:statuses, :latest, :status) + .and_return(:running) + end + + it 'updates pipeline status to running' do + expect { pipeline.update_status } + .to change { pipeline.reload.status }.to 'running' + end + end + + context 'when statuses status was not recognized' do + before do + allow(pipeline) + .to receive(:latest_builds_status) + .and_return(:unknown) + end + + it 'raises an exception' do + expect { pipeline.update_status } + .to raise_error(HasStatus::UnknownStatusError) + end + end + end + describe '#detailed_status' do subject { pipeline.detailed_status(user) } diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index b40496252b4..22a4556c10c 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -110,6 +110,19 @@ describe Ci::Stage, :models do expect(stage.reload).to be_failed end end + + context 'when statuses status was not recognized' do + before do + allow(stage) + .to receive_message_chain(:statuses, :latest, :status) + .and_return(:unknown) + end + + it 'raises an exception' do + expect { stage.update_status } + .to raise_error(HasStatus::UnknownStatusError) + end + end end describe '#detailed_status' do -- cgit v1.2.1 From b8370c9f55843351b49073dafe84a2e9858c8c8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Wed, 9 May 2018 17:27:38 +0200 Subject: Support presigned multipart uploads --- .../artifacts_direct_upload_support_spec.rb | 71 -------- spec/initializers/direct_upload_support_spec.rb | 89 ++++++++++ spec/lib/object_storage/direct_upload_spec.rb | 188 +++++++++++++++++++++ spec/requests/api/runner_spec.rb | 1 + spec/requests/lfs_http_spec.rb | 1 + spec/support/helpers/stub_object_storage.rb | 12 ++ spec/uploaders/object_storage_spec.rb | 134 ++++++++++++--- 7 files changed, 398 insertions(+), 98 deletions(-) delete mode 100644 spec/initializers/artifacts_direct_upload_support_spec.rb create mode 100644 spec/initializers/direct_upload_support_spec.rb create mode 100644 spec/lib/object_storage/direct_upload_spec.rb (limited to 'spec') diff --git a/spec/initializers/artifacts_direct_upload_support_spec.rb b/spec/initializers/artifacts_direct_upload_support_spec.rb deleted file mode 100644 index bfb71da3388..00000000000 --- a/spec/initializers/artifacts_direct_upload_support_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -require 'spec_helper' - -describe 'Artifacts direct upload support' do - subject do - load Rails.root.join('config/initializers/artifacts_direct_upload_support.rb') - end - - let(:connection) do - { provider: provider } - end - - before do - stub_artifacts_setting( - object_store: { - enabled: enabled, - direct_upload: direct_upload, - connection: connection - }) - end - - context 'when object storage is enabled' do - let(:enabled) { true } - - context 'when direct upload is enabled' do - let(:direct_upload) { true } - - context 'when provider is Google' do - let(:provider) { 'Google' } - - it 'succeeds' do - expect { subject }.not_to raise_error - end - end - - context 'when connection is empty' do - let(:connection) { nil } - - it 'raises an error' do - expect { subject }.to raise_error /object storage provider when 'direct_upload' of artifacts is used/ - end - end - - context 'when other provider is used' do - let(:provider) { 'AWS' } - - it 'raises an error' do - expect { subject }.to raise_error /object storage provider when 'direct_upload' of artifacts is used/ - end - end - end - - context 'when direct upload is disabled' do - let(:direct_upload) { false } - let(:provider) { 'AWS' } - - it 'succeeds' do - expect { subject }.not_to raise_error - end - end - end - - context 'when object storage is disabled' do - let(:enabled) { false } - let(:direct_upload) { false } - let(:provider) { 'AWS' } - - it 'succeeds' do - expect { subject }.not_to raise_error - end - end -end diff --git a/spec/initializers/direct_upload_support_spec.rb b/spec/initializers/direct_upload_support_spec.rb new file mode 100644 index 00000000000..f124e726bac --- /dev/null +++ b/spec/initializers/direct_upload_support_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe 'Direct upload support' do + subject do + load Rails.root.join('config/initializers/direct_upload_support.rb') + end + + where(:config_name) do + ['lfs', 'artifacts', 'uploads'] + end + + with_them do + let(:connection) do + { provider: provider } + end + + let(:object_store) do + { + enabled: enabled, + direct_upload: direct_upload, + connection: connection + } + end + + before do + allow(Gitlab.config).to receive_messages(to_settings( + config_name => { object_store: object_store })) + end + + context 'when object storage is enabled' do + let(:enabled) { true } + + context 'when direct upload is enabled' do + let(:direct_upload) { true } + + context 'when provider is AWS' do + let(:provider) { 'AWS' } + + it 'succeeds' do + expect { subject }.not_to raise_error + end + end + + context 'when provider is Google' do + let(:provider) { 'Google' } + + it 'succeeds' do + expect { subject }.not_to raise_error + end + end + + context 'when connection is empty' do + let(:connection) { nil } + + it 'raises an error' do + expect { subject }.to raise_error /are supported as a object storage provider when 'direct_upload' is used/ + end + end + + context 'when other provider is used' do + let(:provider) { 'Rackspace' } + + it 'raises an error' do + expect { subject }.to raise_error /are supported as a object storage provider when 'direct_upload' is used/ + end + end + end + + context 'when direct upload is disabled' do + let(:direct_upload) { false } + let(:provider) { 'AWS' } + + it 'succeeds' do + expect { subject }.not_to raise_error + end + end + end + + context 'when object storage is disabled' do + let(:enabled) { false } + let(:direct_upload) { false } + let(:provider) { 'Rackspace' } + + it 'succeeds' do + expect { subject }.not_to raise_error + end + end + end +end diff --git a/spec/lib/object_storage/direct_upload_spec.rb b/spec/lib/object_storage/direct_upload_spec.rb new file mode 100644 index 00000000000..0f86d10b881 --- /dev/null +++ b/spec/lib/object_storage/direct_upload_spec.rb @@ -0,0 +1,188 @@ +require 'spec_helper' + +describe ObjectStorage::DirectUpload do + let(:credentials) do + { + provider: 'AWS', + aws_access_key_id: 'AWS_ACCESS_KEY_ID', + aws_secret_access_key: 'AWS_SECRET_ACCESS_KEY' + } + end + + let(:storage_url) { 'https://uploads.s3.amazonaws.com/' } + + let(:bucket_name) { 'uploads' } + let(:object_name) { 'tmp/uploads/my-file' } + let(:maximum_size) { 1.gigabyte } + + let(:direct_upload) { described_class.new(credentials, bucket_name, object_name, has_length: has_length, maximum_size: maximum_size) } + + describe '#has_length' do + context 'is known' do + let(:has_length) { true } + let(:maximum_size) { nil } + + it "maximum size is not required" do + expect { direct_upload }.not_to raise_error + end + end + + context 'is unknown' do + let(:has_length) { false } + + context 'and maximum size is specified' do + let(:maximum_size) { 1.gigabyte } + + it "does not raise an error" do + expect { direct_upload }.not_to raise_error + end + end + + context 'and maximum size is not specified' do + let(:maximum_size) { nil } + + it "raises an error" do + expect { direct_upload }.to raise_error /maximum_size has to be specified if length is unknown/ + end + end + end + end + + describe '#to_hash' do + subject { direct_upload.to_hash } + + shared_examples 'a valid upload' do + it "returns valid structure" do + expect(subject).to have_key(:Timeout) + expect(subject[:GetURL]).to start_with(storage_url) + expect(subject[:StoreURL]).to start_with(storage_url) + expect(subject[:DeleteURL]).to start_with(storage_url) + end + end + + shared_examples 'a valid upload with multipart data' do + before do + stub_object_storage_multipart_init(storage_url, "myUpload") + end + + it_behaves_like 'a valid upload' + + it "returns valid structure" do + expect(subject).to have_key(:MultipartUpload) + expect(subject[:MultipartUpload]).to have_key(:PartSize) + expect(subject[:MultipartUpload][:PartURLs]).to all(start_with(storage_url)) + expect(subject[:MultipartUpload][:PartURLs]).to all(include('uploadId=myUpload')) + expect(subject[:MultipartUpload][:CompleteURL]).to start_with(storage_url) + expect(subject[:MultipartUpload][:CompleteURL]).to include('uploadId=myUpload') + expect(subject[:MultipartUpload][:AbortURL]).to start_with(storage_url) + expect(subject[:MultipartUpload][:AbortURL]).to include('uploadId=myUpload') + end + end + + shared_examples 'a valid upload without multipart data' do + it_behaves_like 'a valid upload' + + it "returns valid structure" do + expect(subject).not_to have_key(:MultipartUpload) + end + end + + context 'when AWS is used' do + context 'when length is known' do + let(:has_length) { true } + + it_behaves_like 'a valid upload without multipart data' + end + + context 'when length is unknown' do + let(:has_length) { false } + + it_behaves_like 'a valid upload with multipart data' do + context 'when maximum upload size is 10MB' do + let(:maximum_size) { 10.megabyte } + + it 'returns only 2 parts' do + expect(subject[:MultipartUpload][:PartURLs].length).to eq(2) + end + + it 'part size is mimimum, 5MB' do + expect(subject[:MultipartUpload][:PartSize]).to eq(5.megabyte) + end + end + + context 'when maximum upload size is 12MB' do + let(:maximum_size) { 12.megabyte } + + it 'returns only 3 parts' do + expect(subject[:MultipartUpload][:PartURLs].length).to eq(3) + end + + it 'part size is rounded-up to 5MB' do + expect(subject[:MultipartUpload][:PartSize]).to eq(5.megabyte) + end + end + + context 'when maximum upload size is 49GB' do + let(:maximum_size) { 49.gigabyte } + + it 'returns maximum, 100 parts' do + expect(subject[:MultipartUpload][:PartURLs].length).to eq(100) + end + + it 'part size is rounded-up to 5MB' do + expect(subject[:MultipartUpload][:PartSize]).to eq(505.megabyte) + end + end + end + end + end + + context 'when Google is used' do + let(:credentials) do + { + provider: 'Google', + google_storage_access_key_id: 'GOOGLE_ACCESS_KEY_ID', + google_storage_secret_access_key: 'GOOGLE_SECRET_ACCESS_KEY' + } + end + + let(:storage_url) { 'https://storage.googleapis.com/uploads/' } + + context 'when length is known' do + let(:has_length) { true } + + it_behaves_like 'a valid upload without multipart data' + end + + context 'when length is unknown' do + let(:has_length) { false } + + it_behaves_like 'a valid upload without multipart data' + end + end + end + + describe '#get_url' do + # this method can only be tested with integration tests + end + + describe '#delete_url' do + # this method can only be tested with integration tests + end + + describe '#store_url' do + # this method can only be tested with integration tests + end + + describe '#multipart_part_upload_url' do + # this method can only be tested with integration tests + end + + describe '#multipart_complete_url' do + # this method can only be tested with integration tests + end + + describe '#multipart_abort_url' do + # this method can only be tested with integration tests + end +end diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index 319ac389083..c981a10ac38 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -1101,6 +1101,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do expect(json_response['RemoteObject']).to have_key('GetURL') expect(json_response['RemoteObject']).to have_key('StoreURL') expect(json_response['RemoteObject']).to have_key('DeleteURL') + expect(json_response['RemoteObject']).to have_key('MultipartUpload') end end diff --git a/spec/requests/lfs_http_spec.rb b/spec/requests/lfs_http_spec.rb index 79672fe1cc5..4d30b99262e 100644 --- a/spec/requests/lfs_http_spec.rb +++ b/spec/requests/lfs_http_spec.rb @@ -1021,6 +1021,7 @@ describe 'Git LFS API and storage' do expect(json_response['RemoteObject']).to have_key('GetURL') expect(json_response['RemoteObject']).to have_key('StoreURL') expect(json_response['RemoteObject']).to have_key('DeleteURL') + expect(json_response['RemoteObject']).not_to have_key('MultipartUpload') expect(json_response['LfsOid']).to eq(sample_oid) expect(json_response['LfsSize']).to eq(sample_size) end diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb index 19d744b959a..80204bdab8b 100644 --- a/spec/support/helpers/stub_object_storage.rb +++ b/spec/support/helpers/stub_object_storage.rb @@ -45,4 +45,16 @@ module StubObjectStorage remote_directory: 'uploads', **params) end + + def stub_object_storage_multipart_init(endpoint, upload_id = "upload_id") + stub_request(:post, %r{\A#{endpoint}tmp/uploads/[a-z0-9-]*\?uploads\z}). + to_return status: 200, body: <<-EOS.strip_heredoc + + + example-bucket + example-object + #{upload_id} + + EOS + end end diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index 2dd0925a8e6..01166865e88 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -355,7 +355,10 @@ describe ObjectStorage do end describe '.workhorse_authorize' do - subject { uploader_class.workhorse_authorize } + let(:has_length) { true } + let(:maximum_size) { nil } + + subject { uploader_class.workhorse_authorize(has_length: has_length, maximum_size: maximum_size) } before do # ensure that we use regular Fog libraries @@ -371,10 +374,6 @@ describe ObjectStorage do expect(subject[:TempPath]).to start_with(uploader_class.root) expect(subject[:TempPath]).to include(described_class::TMP_UPLOAD_PATH) end - - it "does not return remote store" do - is_expected.not_to have_key('RemoteObject') - end end shared_examples 'uses remote storage' do @@ -383,7 +382,7 @@ describe ObjectStorage do expect(subject[:RemoteObject]).to have_key(:ID) expect(subject[:RemoteObject]).to include(Timeout: a_kind_of(Integer)) - expect(subject[:RemoteObject][:Timeout]).to be(ObjectStorage::DIRECT_UPLOAD_TIMEOUT) + expect(subject[:RemoteObject][:Timeout]).to be(ObjectStorage::DirectUpload::TIMEOUT) expect(subject[:RemoteObject]).to have_key(:GetURL) expect(subject[:RemoteObject]).to have_key(:DeleteURL) expect(subject[:RemoteObject]).to have_key(:StoreURL) @@ -391,9 +390,31 @@ describe ObjectStorage do expect(subject[:RemoteObject][:DeleteURL]).to include(described_class::TMP_UPLOAD_PATH) expect(subject[:RemoteObject][:StoreURL]).to include(described_class::TMP_UPLOAD_PATH) end + end - it "does not return local store" do - is_expected.not_to have_key('TempPath') + shared_examples 'uses remote storage with multipart uploads' do + it_behaves_like 'uses remote storage' do + it "returns multipart upload" do + is_expected.to have_key(:RemoteObject) + + expect(subject[:RemoteObject]).to have_key(:MultipartUpload) + expect(subject[:RemoteObject][:MultipartUpload]).to have_key(:PartSize) + expect(subject[:RemoteObject][:MultipartUpload]).to have_key(:PartURLs) + expect(subject[:RemoteObject][:MultipartUpload]).to have_key(:CompleteURL) + expect(subject[:RemoteObject][:MultipartUpload]).to have_key(:AbortURL) + expect(subject[:RemoteObject][:MultipartUpload][:PartURLs]).to all(include(described_class::TMP_UPLOAD_PATH)) + expect(subject[:RemoteObject][:MultipartUpload][:CompleteURL]).to include(described_class::TMP_UPLOAD_PATH) + expect(subject[:RemoteObject][:MultipartUpload][:AbortURL]).to include(described_class::TMP_UPLOAD_PATH) + end + end + end + + shared_examples 'uses remote storage without multipart uploads' do + it_behaves_like 'uses remote storage' do + it "does not return multipart upload" do + is_expected.to have_key(:RemoteObject) + expect(subject[:RemoteObject]).not_to have_key(:MultipartUpload) + end end end @@ -416,6 +437,8 @@ describe ObjectStorage do end context 'uses AWS' do + let(:storage_url) { "https://uploads.s3-eu-central-1.amazonaws.com/" } + before do expect(uploader_class).to receive(:object_store_credentials) do { provider: "AWS", @@ -425,18 +448,40 @@ describe ObjectStorage do end end - it_behaves_like 'uses remote storage' do - let(:storage_url) { "https://uploads.s3-eu-central-1.amazonaws.com/" } + context 'for known length' do + it_behaves_like 'uses remote storage without multipart uploads' do + it 'returns links for S3' do + expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + end + end + end + + context 'for unknown length' do + let(:has_length) { false } + let(:maximum_size) { 1.gigabyte } - it 'returns links for S3' do - expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) - expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) - expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + before do + stub_object_storage_multipart_init(storage_url) + end + + it_behaves_like 'uses remote storage with multipart uploads' do + it 'returns links for S3' do + expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:MultipartUpload][:PartURLs]).to all(start_with(storage_url)) + expect(subject[:RemoteObject][:MultipartUpload][:CompleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:MultipartUpload][:AbortURL]).to start_with(storage_url) + end end end end context 'uses Google' do + let(:storage_url) { "https://storage.googleapis.com/uploads/" } + before do expect(uploader_class).to receive(:object_store_credentials) do { provider: "Google", @@ -445,36 +490,71 @@ describe ObjectStorage do end end - it_behaves_like 'uses remote storage' do - let(:storage_url) { "https://storage.googleapis.com/uploads/" } + context 'for known length' do + it_behaves_like 'uses remote storage without multipart uploads' do + it 'returns links for Google Cloud' do + expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + end + end + end + + context 'for unknown length' do + let(:has_length) { false } + let(:maximum_size) { 1.gigabyte } - it 'returns links for Google Cloud' do - expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) - expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) - expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + it_behaves_like 'uses remote storage without multipart uploads' do + it 'returns links for Google Cloud' do + expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + end end end end context 'uses GDK/minio' do + let(:storage_url) { "http://minio:9000/uploads/" } + before do expect(uploader_class).to receive(:object_store_credentials) do { provider: "AWS", aws_access_key_id: "AWS_ACCESS_KEY_ID", aws_secret_access_key: "AWS_SECRET_ACCESS_KEY", - endpoint: 'http://127.0.0.1:9000', + endpoint: 'http://minio:9000', path_style: true, region: "gdk" } end end - it_behaves_like 'uses remote storage' do - let(:storage_url) { "http://127.0.0.1:9000/uploads/" } + context 'for known length' do + it_behaves_like 'uses remote storage without multipart uploads' do + it 'returns links for S3' do + expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + end + end + end + + context 'for unknown length' do + let(:has_length) { false } + let(:maximum_size) { 1.gigabyte } - it 'returns links for S3' do - expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) - expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) - expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + before do + stub_object_storage_multipart_init(storage_url) + end + + it_behaves_like 'uses remote storage with multipart uploads' do + it 'returns links for S3' do + expect(subject[:RemoteObject][:GetURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:DeleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:StoreURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:MultipartUpload][:PartURLs]).to all(start_with(storage_url)) + expect(subject[:RemoteObject][:MultipartUpload][:CompleteURL]).to start_with(storage_url) + expect(subject[:RemoteObject][:MultipartUpload][:AbortURL]).to start_with(storage_url) + end end end end -- cgit v1.2.1 From 2f50b206f2921faf47637af526d810bc10ffb3ef Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 4 Jun 2018 10:41:56 +0200 Subject: Hide archived projects from `shared_projects` Since we don't show the archived projects, we shouldnot load them and pass them to the fronted to be filtered out again. --- spec/controllers/groups/shared_projects_controller_spec.rb | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/groups/shared_projects_controller_spec.rb b/spec/controllers/groups/shared_projects_controller_spec.rb index d8fa41abb18..003c8c262e7 100644 --- a/spec/controllers/groups/shared_projects_controller_spec.rb +++ b/spec/controllers/groups/shared_projects_controller_spec.rb @@ -38,7 +38,7 @@ describe Groups::SharedProjectsController do end it 'allows filtering shared projects' do - project = create(:project, :archived, namespace: user.namespace, name: "Searching for") + project = create(:project, namespace: user.namespace, name: "Searching for") share_project(project) get_shared_projects(filter: 'search') @@ -55,5 +55,14 @@ describe Groups::SharedProjectsController do expect(json_project_ids).to eq([second_project.id, shared_project.id]) end + + it 'does not include archived projects' do + archived_project = create(:project, :archived, namespace: user.namespace) + share_project(archived_project) + + get_shared_projects + + expect(json_project_ids).to contain_exactly(shared_project.id) + end end end -- cgit v1.2.1 From fb71c46805e14419897912f6338f635a21d1d097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarka=20Kadlecov=C3=A1?= Date: Mon, 4 Jun 2018 10:38:18 +0200 Subject: Fix repository_storage spec for Rails5 --- spec/models/application_setting_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 968267a6d24..3e6656e0f12 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -110,10 +110,9 @@ describe ApplicationSetting do # Upgraded databases will have this sort of content context 'repository_storages is a String, not an Array' do before do - setting.__send__(:raw_write_attribute, :repository_storages, 'default') + described_class.where(id: setting.id).update_all(repository_storages: 'default') end - it { expect(setting.repository_storages_before_type_cast).to eq('default') } it { expect(setting.repository_storages).to eq(['default']) } end -- cgit v1.2.1 From 6426b507244b7f1cec4a7308ab29978d20c8ec98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarka=20Kadlecov=C3=A1?= Date: Fri, 1 Jun 2018 09:52:55 +0200 Subject: Include all ancestors milestones in json list & autocomplete --- .../projects/milestones_controller_spec.rb | 35 ++++++++++++++++------ .../services/projects/autocomplete_service_spec.rb | 15 ++++++++++ 2 files changed, 41 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb index 548c5ef36e7..02b30f9bc6d 100644 --- a/spec/controllers/projects/milestones_controller_spec.rb +++ b/spec/controllers/projects/milestones_controller_spec.rb @@ -57,19 +57,36 @@ describe Projects::MilestonesController do context "as json" do let!(:group) { create(:group, :public) } let!(:group_milestone) { create(:milestone, group: group) } - let!(:group_member) { create(:group_member, group: group, user: user) } - before do - project.update(namespace: group) - get :index, namespace_id: project.namespace.id, project_id: project.id, format: :json + context 'with a single group ancestor' do + before do + project.update(namespace: group) + get :index, namespace_id: project.namespace.id, project_id: project.id, format: :json + end + + it "queries projects milestones and groups milestones" do + milestones = assigns(:milestones) + + expect(milestones.count).to eq(2) + expect(milestones).to match_array([milestone, group_milestone]) + end end - it "queries projects milestones and groups milestones" do - milestones = assigns(:milestones) + context 'with nested groups', :nested_groups do + let!(:subgroup) { create(:group, :public, parent: group) } + let!(:subgroup_milestone) { create(:milestone, group: subgroup) } + + before do + project.update(namespace: subgroup) + get :index, namespace_id: project.namespace.id, project_id: project.id, format: :json + end + + it "queries projects milestones and all ancestors milestones" do + milestones = assigns(:milestones) - expect(milestones.count).to eq(2) - expect(milestones.where(project_id: nil).first).to eq(group_milestone) - expect(milestones.where(group_id: nil).first).to eq(milestone) + expect(milestones.count).to eq(3) + expect(milestones).to match_array([milestone, group_milestone, subgroup_milestone]) + end end end end diff --git a/spec/services/projects/autocomplete_service_spec.rb b/spec/services/projects/autocomplete_service_spec.rb index f7ff8b80bd7..6fd73a50511 100644 --- a/spec/services/projects/autocomplete_service_spec.rb +++ b/spec/services/projects/autocomplete_service_spec.rb @@ -115,5 +115,20 @@ describe Projects::AutocompleteService do expect(milestone_titles).to eq([group_milestone2.title, group_milestone1.title]) end + + context 'with nested groups', :nested_groups do + let(:subgroup) { create(:group, :public, parent: group) } + let!(:subgroup_milestone) { create(:milestone, group: subgroup) } + + before do + project.update(namespace: subgroup) + end + + it 'includes project milestones and all acestors milestones' do + expect(milestone_titles).to match_array( + [project_milestone.title, group_milestone2.title, group_milestone1.title, subgroup_milestone.title] + ) + end + end end end -- cgit v1.2.1 From 71ed7987d3a7ab16677cb2b87721f391e8daaf13 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 4 Jun 2018 16:20:01 +0200 Subject: Perform pull request IO work outside a transaction When importing a GitHub pull request we would perform all work in a single database transaction. This is less than ideal, because we perform various slow Git operations when creating a merge request. This in turn can lead to many DB connections being used, while just waiting for an IO operation to complete. To work around this, we now move most of the heavy lifting out of the database transaction. Some extra error handling is added to ensure we can resume importing a partially imported pull request, instead of just throwing an error. This commit also changes the specs for IssueImporter so they don't rely on deprecated RSpec methods. --- .../github_import/importer/issue_importer_spec.rb | 4 +- .../importer/pull_request_importer_spec.rb | 85 ++++++++++++++++++---- 2 files changed, 74 insertions(+), 15 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb index d34ca0b76b8..81fe97c1e49 100644 --- a/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/issue_importer_spec.rb @@ -180,12 +180,12 @@ describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redis_cach allow(importer.user_finder) .to receive(:user_id_for) - .ordered.with(issue.assignees[0]) + .with(issue.assignees[0]) .and_return(4) allow(importer.user_finder) .to receive(:user_id_for) - .ordered.with(issue.assignees[1]) + .with(issue.assignees[1]) .and_return(5) expect(Gitlab::Database) diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb index 35f3fdf8304..6686b7ce0b5 100644 --- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb @@ -40,13 +40,19 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi describe '#execute' do it 'imports the pull request' do + mr = double(:merge_request, id: 10) + expect(importer) .to receive(:create_merge_request) - .and_return(10) + .and_return([mr, false]) + + expect(importer) + .to receive(:insert_git_data) + .with(mr, false) expect_any_instance_of(Gitlab::GithubImport::IssuableFinder) .to receive(:cache_database_id) - .with(10) + .with(mr.id) importer.execute end @@ -99,18 +105,11 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi importer.create_merge_request end - it 'returns the ID of the created merge request' do - id = importer.create_merge_request - - expect(id).to be_a_kind_of(Numeric) - end - - it 'creates the merge request diffs' do - importer.create_merge_request - - mr = project.merge_requests.take + it 'returns the created merge request' do + mr, exists = importer.create_merge_request - expect(mr.merge_request_diffs.exists?).to eq(true) + expect(mr).to be_instance_of(MergeRequest) + expect(exists).to eq(false) end end @@ -217,5 +216,65 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi expect { importer.create_merge_request }.not_to raise_error end end + + context 'when the merge request already exists' do + before do + allow(importer.user_finder) + .to receive(:author_id_for) + .with(pull_request) + .and_return([user.id, true]) + + allow(importer.user_finder) + .to receive(:assignee_id_for) + .with(pull_request) + .and_return(user.id) + end + + it 'returns the existing merge request' do + mr1, exists1 = importer.create_merge_request + mr2, exists2 = importer.create_merge_request + + expect(mr2).to eq(mr1) + expect(exists1).to eq(false) + expect(exists2).to eq(true) + end + end + end + + describe '#insert_git_data' do + before do + allow(importer.milestone_finder) + .to receive(:id_for) + .with(pull_request) + .and_return(milestone.id) + + allow(importer.user_finder) + .to receive(:author_id_for) + .with(pull_request) + .and_return([user.id, true]) + + allow(importer.user_finder) + .to receive(:assignee_id_for) + .with(pull_request) + .and_return(user.id) + end + + it 'creates the merge request diffs' do + mr, exists = importer.create_merge_request + + importer.insert_git_data(mr, exists) + + expect(mr.merge_request_diffs.exists?).to eq(true) + end + + it 'creates the merge request diff commits' do + mr, exists = importer.create_merge_request + + importer.insert_git_data(mr, exists) + + diff = mr.merge_request_diffs.take + + expect(diff.merge_request_diff_commits.exists?).to eq(true) + end end end -- cgit v1.2.1 From f12ee2a2f490e6d126ac6345a5ad7cbf12833791 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 4 Jun 2018 21:34:11 +0200 Subject: Remove unused running_or_pending_build_count --- spec/features/projects/jobs/user_browses_job_spec.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/jobs/user_browses_job_spec.rb b/spec/features/projects/jobs/user_browses_job_spec.rb index bff5bbe99af..ce0b38b7239 100644 --- a/spec/features/projects/jobs/user_browses_job_spec.rb +++ b/spec/features/projects/jobs/user_browses_job_spec.rb @@ -32,8 +32,6 @@ describe 'User browses a job', :js do page.within('.erased') do expect(page).to have_content('Job has been erased') end - - expect(build.project.running_or_pending_build_count).to eq(build.project.builds.running_or_pending.count(:all)) end context 'with a failed job' do -- cgit v1.2.1 From 285ffb223896f2226531be2ba10933414194155c Mon Sep 17 00:00:00 2001 From: tauriedavis Date: Fri, 25 May 2018 16:17:57 -0700 Subject: Messaging on terms page when user already accepted We show a blue flash banner if the user already accepted, and show a button allowing them to continue to the application. --- spec/controllers/users/terms_controller_spec.rb | 22 +++++++++++++-- spec/factories/term_agreements.rb | 8 ++++++ spec/features/users/terms_spec.rb | 16 +++++++++++ spec/models/application_setting/term_spec.rb | 37 +++++++++++++++++++++++++ spec/models/term_agreement_spec.rb | 9 ++++++ 5 files changed, 89 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/controllers/users/terms_controller_spec.rb b/spec/controllers/users/terms_controller_spec.rb index a744463413c..0d77e91a67d 100644 --- a/spec/controllers/users/terms_controller_spec.rb +++ b/spec/controllers/users/terms_controller_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe Users::TermsController do + include TermsHelper let(:user) { create(:user) } let(:term) { create(:term) } @@ -15,10 +16,25 @@ describe Users::TermsController do expect(response).to have_gitlab_http_status(:redirect) end - it 'shows terms when they exist' do - term + context 'when terms exist' do + before do + stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') + term + end + + it 'shows terms when they exist' do + get :index + + expect(response).to have_gitlab_http_status(:success) + end - expect(response).to have_gitlab_http_status(:success) + it 'shows a message when the user already accepted the terms' do + accept_terms(user) + + get :index + + expect(controller).to set_flash.now[:notice].to(/already accepted/) + end end end diff --git a/spec/factories/term_agreements.rb b/spec/factories/term_agreements.rb index 557599e663d..3c4eebd0196 100644 --- a/spec/factories/term_agreements.rb +++ b/spec/factories/term_agreements.rb @@ -3,4 +3,12 @@ FactoryBot.define do term user end + + trait :declined do + accepted false + end + + trait :accepted do + accepted true + end end diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb index 1efa5cd5490..af407c52917 100644 --- a/spec/features/users/terms_spec.rb +++ b/spec/features/users/terms_spec.rb @@ -39,6 +39,22 @@ describe 'Users > Terms' do end end + context 'when the user has already accepted the terms' do + before do + accept_terms(user) + end + + it 'allows the user to continue to the app' do + visit terms_path + + expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}" + + click_link 'Continue' + + expect(current_path).to eq(root_path) + end + end + context 'terms were enforced while session is active', :js do let(:project) { create(:project) } diff --git a/spec/models/application_setting/term_spec.rb b/spec/models/application_setting/term_spec.rb index 1eddf3c56ff..aa49594f4d1 100644 --- a/spec/models/application_setting/term_spec.rb +++ b/spec/models/application_setting/term_spec.rb @@ -12,4 +12,41 @@ describe ApplicationSetting::Term do expect(described_class.latest).to eq(terms) end end + + describe '#accepted_by_user?' do + let(:user) { create(:user) } + let(:term) { create(:term) } + + it 'is true when the user accepted the terms' do + accept_terms(term, user) + + expect(term.accepted_by_user?(user)).to be(true) + end + + it 'is false when the user declined the terms' do + decline_terms(term, user) + + expect(term.accepted_by_user?(user)).to be(false) + end + + it 'does not cause a query when the user accepted the current terms' do + accept_terms(term, user) + + expect { term.accepted_by_user?(user) }.not_to exceed_query_limit(0) + end + + it 'returns false if the currently accepted terms are different' do + accept_terms(create(:term), user) + + expect(term.accepted_by_user?(user)).to be(false) + end + + def accept_terms(term, user) + Users::RespondToTermsService.new(user, term).execute(accepted: true) + end + + def decline_terms(term, user) + Users::RespondToTermsService.new(user, term).execute(accepted: false) + end + end end diff --git a/spec/models/term_agreement_spec.rb b/spec/models/term_agreement_spec.rb index a59bf119692..950dfa09a6a 100644 --- a/spec/models/term_agreement_spec.rb +++ b/spec/models/term_agreement_spec.rb @@ -5,4 +5,13 @@ describe TermAgreement do it { is_expected.to validate_presence_of(:term) } it { is_expected.to validate_presence_of(:user) } end + + describe '.accepted' do + it 'only includes accepted terms' do + accepted = create(:term_agreement, :accepted) + create(:term_agreement, :declined) + + expect(described_class.accepted).to contain_exactly(accepted) + end + end end -- cgit v1.2.1 From eea26a93e7d4ac0c6fefe46592c9baa0d3e6a5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 4 Jun 2018 14:06:07 +0200 Subject: Update validator --- spec/initializers/direct_upload_support_spec.rb | 7 ++++--- spec/lib/object_storage/direct_upload_spec.rb | 24 ------------------------ spec/support/helpers/stub_object_storage.rb | 4 ++-- 3 files changed, 6 insertions(+), 29 deletions(-) (limited to 'spec') diff --git a/spec/initializers/direct_upload_support_spec.rb b/spec/initializers/direct_upload_support_spec.rb index f124e726bac..e51d404e030 100644 --- a/spec/initializers/direct_upload_support_spec.rb +++ b/spec/initializers/direct_upload_support_spec.rb @@ -6,7 +6,7 @@ describe 'Direct upload support' do end where(:config_name) do - ['lfs', 'artifacts', 'uploads'] + %w(lfs artifacts uploads) end with_them do @@ -23,8 +23,9 @@ describe 'Direct upload support' do end before do - allow(Gitlab.config).to receive_messages(to_settings( - config_name => { object_store: object_store })) + allow(Gitlab.config).to receive_messages(to_settings(config_name => { + object_store: object_store + })) end context 'when object storage is enabled' do diff --git a/spec/lib/object_storage/direct_upload_spec.rb b/spec/lib/object_storage/direct_upload_spec.rb index 0f86d10b881..5187821e8f4 100644 --- a/spec/lib/object_storage/direct_upload_spec.rb +++ b/spec/lib/object_storage/direct_upload_spec.rb @@ -161,28 +161,4 @@ describe ObjectStorage::DirectUpload do end end end - - describe '#get_url' do - # this method can only be tested with integration tests - end - - describe '#delete_url' do - # this method can only be tested with integration tests - end - - describe '#store_url' do - # this method can only be tested with integration tests - end - - describe '#multipart_part_upload_url' do - # this method can only be tested with integration tests - end - - describe '#multipart_complete_url' do - # this method can only be tested with integration tests - end - - describe '#multipart_abort_url' do - # this method can only be tested with integration tests - end end diff --git a/spec/support/helpers/stub_object_storage.rb b/spec/support/helpers/stub_object_storage.rb index 80204bdab8b..bceaf8277ee 100644 --- a/spec/support/helpers/stub_object_storage.rb +++ b/spec/support/helpers/stub_object_storage.rb @@ -47,8 +47,8 @@ module StubObjectStorage end def stub_object_storage_multipart_init(endpoint, upload_id = "upload_id") - stub_request(:post, %r{\A#{endpoint}tmp/uploads/[a-z0-9-]*\?uploads\z}). - to_return status: 200, body: <<-EOS.strip_heredoc + stub_request(:post, %r{\A#{endpoint}tmp/uploads/[a-z0-9-]*\?uploads\z}) + .to_return status: 200, body: <<-EOS.strip_heredoc example-bucket -- cgit v1.2.1 From c07ee6415a316a87c7afa71fa881e7cc03b97343 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Mon, 4 Jun 2018 16:14:13 -0500 Subject: Improve modal prop interface --- .../vue_shared/components/gl_modal_spec.js | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/vue_shared/components/gl_modal_spec.js b/spec/javascripts/vue_shared/components/gl_modal_spec.js index 85cb1b90fc6..23be8d93b81 100644 --- a/spec/javascripts/vue_shared/components/gl_modal_spec.js +++ b/spec/javascripts/vue_shared/components/gl_modal_spec.js @@ -190,4 +190,37 @@ describe('GlModal', () => { }); }); }); + + describe('handling sizes', () => { + it('should render modal-sm', () => { + vm = mountComponent(modalComponent, { + modalSize: 'sm', + }); + + expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-sm')).toEqual(true); + }); + + it('should render modal-lg', () => { + vm = mountComponent(modalComponent, { + modalSize: 'lg', + }); + + expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-lg')).toEqual(true); + }); + + it('should not add modal size classes when md size is passed', () => { + vm = mountComponent(modalComponent, { + modalSize: 'md', + }); + + expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-md')).toEqual(false); + }); + + it('should not add modal size classes by default', () => { + vm = mountComponent(modalComponent, {}); + + expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-sm')).toEqual(false); + expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-lg')).toEqual(false); + }); + }); }); -- cgit v1.2.1 From 11a9389c4f6c72509c0c4aa3be6227a972adab78 Mon Sep 17 00:00:00 2001 From: Jose Date: Mon, 4 Jun 2018 16:39:44 -0500 Subject: fix labels showing up with no title --- spec/javascripts/labels_select_spec.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/labels_select_spec.js b/spec/javascripts/labels_select_spec.js index a2b89c0aef5..386e00bfd0c 100644 --- a/spec/javascripts/labels_select_spec.js +++ b/spec/javascripts/labels_select_spec.js @@ -40,5 +40,9 @@ describe('LabelsSelect', () => { it('generated label item template has correct label styles', () => { expect($labelEl.find('span.label').attr('style')).toBe(`background-color: ${label.color}; color: ${label.text_color};`); }); + + it('generated label item has a badge class', () => { + expect($labelEl.find('span').hasClass('badge')).toEqual(true); + }); }); }); -- cgit v1.2.1 From cbc20d2b7f8c73e2892c0c458619df2a9fe0c9ab Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 3 Jun 2018 03:31:41 -0700 Subject: Remove N+1 query for author in issues API This was being masked by the statement cache because only one author was used per issue in the test.. Also adds support for an Rspec matcher `exceed_all_query_limit`. --- spec/requests/api/issues_spec.rb | 8 ++-- spec/support/helpers/query_recorder.rb | 7 ++-- spec/support/matchers/exceed_query_limit.rb | 65 ++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 21 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 4181f4ebbbe..a15d60aafe0 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -630,15 +630,17 @@ describe API::Issues do end it 'avoids N+1 queries' do - control_count = ActiveRecord::QueryRecorder.new do + get api("/projects/#{project.id}/issues", user) + + control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do get api("/projects/#{project.id}/issues", user) end.count - create(:issue, author: user, project: project) + create_list(:issue, 3, project: project) expect do get api("/projects/#{project.id}/issues", user) - end.not_to exceed_query_limit(control_count) + end.not_to exceed_all_query_limit(control_count) end it 'returns 404 when project does not exist' do diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb index 28536bbef5e..7ce63375d34 100644 --- a/spec/support/helpers/query_recorder.rb +++ b/spec/support/helpers/query_recorder.rb @@ -1,10 +1,11 @@ module ActiveRecord class QueryRecorder - attr_reader :log, :cached + attr_reader :log, :skip_cached, :cached - def initialize(&block) + def initialize(skip_cached: true, &block) @log = [] @cached = [] + @skip_cached = skip_cached ActiveSupport::Notifications.subscribed(method(:callback), 'sql.active_record', &block) end @@ -16,7 +17,7 @@ module ActiveRecord def callback(name, start, finish, message_id, values) show_backtrace(values) if ENV['QUERY_RECORDER_DEBUG'] - if values[:name]&.include?("CACHE") + if values[:name]&.include?("CACHE") && skip_cached @cached << values[:sql] elsif !values[:name]&.include?("SCHEMA") @log << values[:sql] diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb index 88d22a3ddd9..cd042401f3a 100644 --- a/spec/support/matchers/exceed_query_limit.rb +++ b/spec/support/matchers/exceed_query_limit.rb @@ -1,17 +1,4 @@ -RSpec::Matchers.define :exceed_query_limit do |expected| - supports_block_expectations - - match do |block| - @subject_block = block - actual_count > expected_count + threshold - end - - failure_message_when_negated do |actual| - threshold_message = threshold > 0 ? " (+#{@threshold})" : '' - counts = "#{expected_count}#{threshold_message}" - "Expected a maximum of #{counts} queries, got #{actual_count}:\n\n#{log_message}" - end - +module ExceedQueryLimitHelpers def with_threshold(threshold) @threshold = threshold self @@ -43,7 +30,7 @@ RSpec::Matchers.define :exceed_query_limit do |expected| end def recorder - @recorder ||= ActiveRecord::QueryRecorder.new(&@subject_block) + @recorder ||= ActiveRecord::QueryRecorder.new(skip_cached: skip_cached, &@subject_block) end def count_queries(queries) @@ -61,4 +48,52 @@ RSpec::Matchers.define :exceed_query_limit do |expected| @recorder.log_message end end + + def skip_cached + true + end + + def verify_count(&block) + @subject_block = block + actual_count > expected_count + threshold + end + + def failure_message + threshold_message = threshold > 0 ? " (+#{@threshold})" : '' + counts = "#{expected_count}#{threshold_message}" + "Expected a maximum of #{counts} queries, got #{actual_count}:\n\n#{log_message}" + end +end + +RSpec::Matchers.define :exceed_all_query_limit do |expected| + supports_block_expectations + + include ExceedQueryLimitHelpers + + match do |block| + verify_count(&block) + end + + failure_message_when_negated do |actual| + failure_message + end + + def skip_cached + false + end +end + +# Excludes cached methods from the query count +RSpec::Matchers.define :exceed_query_limit do |expected| + supports_block_expectations + + include ExceedQueryLimitHelpers + + match do |block| + verify_count(&block) + end + + failure_message_when_negated do |actual| + failure_message + end end -- cgit v1.2.1 From c26cbfcdfb6a0c83253f42be016692abc3548e8c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 3 Jun 2018 03:31:41 -0700 Subject: Remove N+1 query for author in issues API This was being masked by the statement cache because only one author was used per issue in the test.. Also adds support for an Rspec matcher `exceed_all_query_limit`. --- spec/requests/api/issues_spec.rb | 8 ++-- spec/support/helpers/query_recorder.rb | 7 ++-- spec/support/matchers/exceed_query_limit.rb | 65 ++++++++++++++++++++++------- 3 files changed, 59 insertions(+), 21 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 4181f4ebbbe..a15d60aafe0 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -630,15 +630,17 @@ describe API::Issues do end it 'avoids N+1 queries' do - control_count = ActiveRecord::QueryRecorder.new do + get api("/projects/#{project.id}/issues", user) + + control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do get api("/projects/#{project.id}/issues", user) end.count - create(:issue, author: user, project: project) + create_list(:issue, 3, project: project) expect do get api("/projects/#{project.id}/issues", user) - end.not_to exceed_query_limit(control_count) + end.not_to exceed_all_query_limit(control_count) end it 'returns 404 when project does not exist' do diff --git a/spec/support/helpers/query_recorder.rb b/spec/support/helpers/query_recorder.rb index 28536bbef5e..7ce63375d34 100644 --- a/spec/support/helpers/query_recorder.rb +++ b/spec/support/helpers/query_recorder.rb @@ -1,10 +1,11 @@ module ActiveRecord class QueryRecorder - attr_reader :log, :cached + attr_reader :log, :skip_cached, :cached - def initialize(&block) + def initialize(skip_cached: true, &block) @log = [] @cached = [] + @skip_cached = skip_cached ActiveSupport::Notifications.subscribed(method(:callback), 'sql.active_record', &block) end @@ -16,7 +17,7 @@ module ActiveRecord def callback(name, start, finish, message_id, values) show_backtrace(values) if ENV['QUERY_RECORDER_DEBUG'] - if values[:name]&.include?("CACHE") + if values[:name]&.include?("CACHE") && skip_cached @cached << values[:sql] elsif !values[:name]&.include?("SCHEMA") @log << values[:sql] diff --git a/spec/support/matchers/exceed_query_limit.rb b/spec/support/matchers/exceed_query_limit.rb index 88d22a3ddd9..cd042401f3a 100644 --- a/spec/support/matchers/exceed_query_limit.rb +++ b/spec/support/matchers/exceed_query_limit.rb @@ -1,17 +1,4 @@ -RSpec::Matchers.define :exceed_query_limit do |expected| - supports_block_expectations - - match do |block| - @subject_block = block - actual_count > expected_count + threshold - end - - failure_message_when_negated do |actual| - threshold_message = threshold > 0 ? " (+#{@threshold})" : '' - counts = "#{expected_count}#{threshold_message}" - "Expected a maximum of #{counts} queries, got #{actual_count}:\n\n#{log_message}" - end - +module ExceedQueryLimitHelpers def with_threshold(threshold) @threshold = threshold self @@ -43,7 +30,7 @@ RSpec::Matchers.define :exceed_query_limit do |expected| end def recorder - @recorder ||= ActiveRecord::QueryRecorder.new(&@subject_block) + @recorder ||= ActiveRecord::QueryRecorder.new(skip_cached: skip_cached, &@subject_block) end def count_queries(queries) @@ -61,4 +48,52 @@ RSpec::Matchers.define :exceed_query_limit do |expected| @recorder.log_message end end + + def skip_cached + true + end + + def verify_count(&block) + @subject_block = block + actual_count > expected_count + threshold + end + + def failure_message + threshold_message = threshold > 0 ? " (+#{@threshold})" : '' + counts = "#{expected_count}#{threshold_message}" + "Expected a maximum of #{counts} queries, got #{actual_count}:\n\n#{log_message}" + end +end + +RSpec::Matchers.define :exceed_all_query_limit do |expected| + supports_block_expectations + + include ExceedQueryLimitHelpers + + match do |block| + verify_count(&block) + end + + failure_message_when_negated do |actual| + failure_message + end + + def skip_cached + false + end +end + +# Excludes cached methods from the query count +RSpec::Matchers.define :exceed_query_limit do |expected| + supports_block_expectations + + include ExceedQueryLimitHelpers + + match do |block| + verify_count(&block) + end + + failure_message_when_negated do |actual| + failure_message + end end -- cgit v1.2.1 From 2bb94ff7f915bdc09275085a075e202f92241811 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 3 Jun 2018 04:36:22 -0700 Subject: Eliminate N+1 queries for CI job artifacts in /api/projects/:id/pipelines/:pipeline_id/jobs --- spec/requests/api/jobs_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/jobs_spec.rb b/spec/requests/api/jobs_spec.rb index 45082e644ca..50d6f4b4d99 100644 --- a/spec/requests/api/jobs_spec.rb +++ b/spec/requests/api/jobs_spec.rb @@ -177,6 +177,18 @@ describe API::Jobs do json_response.each { |job| expect(job['pipeline']['id']).to eq(pipeline.id) } end end + + it 'avoids N+1 queries' do + control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do + get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query + end.count + + 3.times { create(:ci_build, :artifacts, pipeline: pipeline) } + + expect do + get api("/projects/#{project.id}/pipelines/#{pipeline.id}/jobs", api_user), query + end.not_to exceed_all_query_limit(control_count) + end end context 'unauthorized user' do -- cgit v1.2.1 From bc7dbfdc5d88a2e78239bdf481b7b52e03e890b6 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Mon, 4 Jun 2018 20:23:40 -0500 Subject: Backport of Resolve "Epics Page Styling is broken" --- .../vue_shared/components/sidebar/labels_select/dropdown_value_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js index 4397b00acfa..370a296bd8f 100644 --- a/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js +++ b/spec/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_spec.js @@ -82,7 +82,7 @@ describe('DropdownValueComponent', () => { }); it('renders label element with tooltip and styles based on label details', () => { - const labelEl = vm.$el.querySelector('a span.label.color-label'); + const labelEl = vm.$el.querySelector('a span.badge.color-label'); expect(labelEl).not.toBeNull(); expect(labelEl.dataset.placement).toBe('bottom'); expect(labelEl.dataset.container).toBe('body'); -- cgit v1.2.1 From c503429e5e8538649bec02d74963ec0eb8f0cb98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Mon, 4 Jun 2018 23:00:25 -0500 Subject: Add migration to disable the usage of DSA keys Additionally the current application setting is also updated to disable the usage of DSA keys. --- ...e_default_value_for_dsa_key_restriction_spec.rb | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 spec/migrations/change_default_value_for_dsa_key_restriction_spec.rb (limited to 'spec') diff --git a/spec/migrations/change_default_value_for_dsa_key_restriction_spec.rb b/spec/migrations/change_default_value_for_dsa_key_restriction_spec.rb new file mode 100644 index 00000000000..7e61ab9b52e --- /dev/null +++ b/spec/migrations/change_default_value_for_dsa_key_restriction_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require Rails.root.join('db', 'migrate', '20180531220618_change_default_value_for_dsa_key_restriction.rb') + +describe ChangeDefaultValueForDsaKeyRestriction, :migration do + let(:application_settings) { table(:application_settings) } + + before do + application_settings.create! + end + + it 'changes the default value for dsa_key_restriction' do + expect(application_settings.first.dsa_key_restriction).to eq(0) + + migrate! + + application_settings.reset_column_information + new_setting = application_settings.create! + + expect(application_settings.count).to eq(2) + expect(new_setting.dsa_key_restriction).to eq(-1) + end + + it 'changes the existing setting' do + setting = application_settings.last + + expect(setting.dsa_key_restriction).to eq(0) + + migrate! + + expect(application_settings.count).to eq(1) + expect(setting.reload.dsa_key_restriction).to eq(-1) + end +end -- cgit v1.2.1 From f46739191a71d881501bb3fc4740b953824a9fb3 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Mon, 4 Jun 2018 19:20:58 -0300 Subject: Adjust insufficient diff hunks being persisted on NoteDiffFile This currently causes 500's errors when loading the MR page (Discussion) in a few scenarios. We were not considering detailed diff headers such as "--- a/doc/update/mysql_to_postgresql.md\n+++ b/doc/update/mysql_to_postgresql.md" to crop the diff. In order to address it, we're now using Gitlab::Diff::Parser, clean the diffs and builds Gitlab::Diff::Line objects we can iterate and filter on. --- spec/lib/gitlab/diff/file_spec.rb | 113 +++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 50 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index 0588fe935c3..f0e83ccfc7a 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -470,56 +470,69 @@ describe Gitlab::Diff::File do end describe '#diff_hunk' do - let(:raw_diff) do - < path } -- options = { chdir: path } -+ -+ vars = { -+ "PWD" => path -+ } -+ -+ options = { -+ chdir: path -+ } - - unless File.directory?(path) - FileUtils.mkdir_p(path) -@@ -19,6 +25,7 @@ module Popen - - @cmd_output = "" - @cmd_status = 0 -+ - Open3.popen3(vars, *cmd, options) do |stdin, stdout, stderr, wait_thr| - @cmd_output << stdout.read - @cmd_output << stderr.read -EOS - end - - it 'returns raw diff up to given line index' do - allow(diff_file).to receive(:raw_diff) { raw_diff } - diff_line = instance_double(Gitlab::Diff::Line, index: 5) - - diff_hunk = < Date: Mon, 4 Jun 2018 22:54:50 +0800 Subject: Also verify if extending would override a class method Since extending a class means including on the singleton class of the class, this should now complain this: ``` ruby module M extend Gitlab::Utils::Override override :f def f super.succ end end class C extend M def self.f 0 end end ``` It should complain because `C.f` wasn't calling `M#f`. This should pass verification: ``` ruby module M extend Gitlab::Utils::Override override :f def f super.succ end end class B def self.f 0 end end class C < B extend M end ``` Because `C.f` would now call `M#f`, and `M#f` does override something. --- spec/lib/gitlab/utils/override_spec.rb | 170 +++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 62 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/utils/override_spec.rb b/spec/lib/gitlab/utils/override_spec.rb index 7c97cee982a..fc08ebcfc6d 100644 --- a/spec/lib/gitlab/utils/override_spec.rb +++ b/spec/lib/gitlab/utils/override_spec.rb @@ -1,7 +1,13 @@ -require 'spec_helper' +require 'fast_spec_helper' describe Gitlab::Utils::Override do - let(:base) { Struct.new(:good) } + let(:base) do + Struct.new(:good) do + def self.good + 0 + end + end + end let(:derived) { Class.new(base).tap { |m| m.extend described_class } } let(:extension) { Module.new.tap { |m| m.extend described_class } } @@ -9,6 +15,14 @@ describe Gitlab::Utils::Override do let(:prepending_class) { base.tap { |m| m.prepend extension } } let(:including_class) { base.tap { |m| m.include extension } } + let(:prepending_class_methods) do + base.tap { |m| m.singleton_class.prepend extension } + end + + let(:extending_class_methods) do + base.tap { |m| m.extend extension } + end + let(:klass) { subject } def good(mod) @@ -36,7 +50,7 @@ describe Gitlab::Utils::Override do shared_examples 'checking as intended' do it 'checks ok for overriding method' do good(subject) - result = klass.new(0).good + result = instance.good expect(result).to eq(1) described_class.verify! @@ -45,7 +59,25 @@ describe Gitlab::Utils::Override do it 'raises NotImplementedError when it is not overriding anything' do expect do bad(subject) - klass.new(0).bad + instance.bad + described_class.verify! + end.to raise_error(NotImplementedError) + end + end + + shared_examples 'checking as intended, nothing was overridden' do + it 'raises NotImplementedError because it is not overriding it' do + expect do + good(subject) + instance.good + described_class.verify! + end.to raise_error(NotImplementedError) + end + + it 'raises NotImplementedError when it is not overriding anything' do + expect do + bad(subject) + instance.bad described_class.verify! end.to raise_error(NotImplementedError) end @@ -54,7 +86,7 @@ describe Gitlab::Utils::Override do shared_examples 'nothing happened' do it 'does not complain when it is overriding something' do good(subject) - result = klass.new(0).good + result = instance.good expect(result).to eq(1) described_class.verify! @@ -62,7 +94,7 @@ describe Gitlab::Utils::Override do it 'does not complain when it is not overriding anything' do bad(subject) - result = klass.new(0).bad + result = instance.bad expect(result).to eq(true) described_class.verify! @@ -75,83 +107,97 @@ describe Gitlab::Utils::Override do end describe '#override' do - context 'when STATIC_VERIFICATION is set' do - before do - stub_env('STATIC_VERIFICATION', 'true') - end + context 'when instance is klass.new(0)' do + let(:instance) { klass.new(0) } - context 'when subject is a class' do - subject { derived } + context 'when STATIC_VERIFICATION is set' do + before do + stub_env('STATIC_VERIFICATION', 'true') + end - it_behaves_like 'checking as intended' - end + context 'when subject is a class' do + subject { derived } + + it_behaves_like 'checking as intended' + end + + context 'when subject is a module, and class is prepending it' do + subject { extension } + let(:klass) { prepending_class } + + it_behaves_like 'checking as intended' + end - context 'when subject is a module, and class is prepending it' do - subject { extension } - let(:klass) { prepending_class } + context 'when subject is a module, and class is including it' do + subject { extension } + let(:klass) { including_class } - it_behaves_like 'checking as intended' + it_behaves_like 'checking as intended, nothing was overridden' + end end - context 'when subject is a module, and class is including it' do - subject { extension } - let(:klass) { including_class } + context 'when STATIC_VERIFICATION is not set' do + before do + stub_env('STATIC_VERIFICATION', nil) + end - it 'raises NotImplementedError because it is not overriding it' do - expect do - good(subject) - klass.new(0).good - described_class.verify! - end.to raise_error(NotImplementedError) + context 'when subject is a class' do + subject { derived } + + it_behaves_like 'nothing happened' end - it 'raises NotImplementedError when it is not overriding anything' do - expect do - bad(subject) - klass.new(0).bad - described_class.verify! - end.to raise_error(NotImplementedError) + context 'when subject is a module, and class is prepending it' do + subject { extension } + let(:klass) { prepending_class } + + it_behaves_like 'nothing happened' end - end - end - end - context 'when STATIC_VERIFICATION is not set' do - before do - stub_env('STATIC_VERIFICATION', nil) - end + context 'when subject is a module, and class is including it' do + subject { extension } + let(:klass) { including_class } - context 'when subject is a class' do - subject { derived } + it 'does not complain when it is overriding something' do + good(subject) + result = instance.good - it_behaves_like 'nothing happened' - end + expect(result).to eq(0) + described_class.verify! + end - context 'when subject is a module, and class is prepending it' do - subject { extension } - let(:klass) { prepending_class } + it 'does not complain when it is not overriding anything' do + bad(subject) + result = instance.bad - it_behaves_like 'nothing happened' + expect(result).to eq(true) + described_class.verify! + end + end + end end - context 'when subject is a module, and class is including it' do - subject { extension } - let(:klass) { including_class } + context 'when instance is klass' do + let(:instance) { klass } - it 'does not complain when it is overriding something' do - good(subject) - result = klass.new(0).good + context 'when STATIC_VERIFICATION is set' do + before do + stub_env('STATIC_VERIFICATION', 'true') + end - expect(result).to eq(0) - described_class.verify! - end + context 'when subject is a module, and class is prepending it' do + subject { extension } + let(:klass) { prepending_class_methods } - it 'does not complain when it is not overriding anything' do - bad(subject) - result = klass.new(0).bad + it_behaves_like 'checking as intended' + end - expect(result).to eq(true) - described_class.verify! + context 'when subject is a module, and class is extending it' do + subject { extension } + let(:klass) { extending_class_methods } + + it_behaves_like 'checking as intended, nothing was overridden' + end end end end -- cgit v1.2.1 From 993438ada993880c166c376eba4ae6ab02e3064b Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 5 Jun 2018 08:11:13 +0000 Subject: Support smarter system notes --- spec/javascripts/notes/mock_data.js | 578 +++++++++++++++++++++ .../notes/stores/collapse_utils_spec.js | 46 ++ spec/javascripts/notes/stores/getters_spec.js | 19 +- 3 files changed, 642 insertions(+), 1 deletion(-) create mode 100644 spec/javascripts/notes/stores/collapse_utils_spec.js (limited to 'spec') diff --git a/spec/javascripts/notes/mock_data.js b/spec/javascripts/notes/mock_data.js index bfe3a65feee..fa7adc32193 100644 --- a/spec/javascripts/notes/mock_data.js +++ b/spec/javascripts/notes/mock_data.js @@ -340,6 +340,79 @@ export const loggedOutnoteableData = { '/gitlab-org/gitlab-ce/preview_markdown?quick_actions_target_id=98&quick_actions_target_type=Issue', }; +export const collapseNotesMock = [ + { + expanded: true, + id: '0fb4e0e3f9276e55ff32eb4195add694aece4edd', + individual_note: true, + notes: [ + { + id: 1390, + attachment: null, + author: { + id: 1, + name: 'Root', + username: 'root', + state: 'active', + avatar_url: 'test', + path: '/root', + }, + created_at: '2018-02-26T18:07:41.071Z', + updated_at: '2018-02-26T18:07:41.071Z', + system: true, + system_note_icon_name: 'pencil', + noteable_id: 98, + noteable_type: 'Issue', + type: null, + human_access: 'Owner', + note: 'changed the description', + note_html: '

changed the description

', + current_user: { can_edit: false }, + discussion_id: 'b97fb7bda470a65b3e009377a9032edec0a4dd05', + emoji_awardable: false, + path: '/h5bp/html5-boilerplate/notes/1057', + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fh5bp%2Fhtml5-boilerplate%2Fissues%2F10%23note_1057&user_id=1', + }, + ], + }, + { + expanded: true, + id: 'ffde43f25984ad7f2b4275135e0e2846875336c0', + individual_note: true, + notes: [ + { + id: 1391, + attachment: null, + author: { + id: 1, + name: 'Root', + username: 'root', + state: 'active', + avatar_url: 'test', + path: '/root', + }, + created_at: '2018-02-26T18:13:24.071Z', + updated_at: '2018-02-26T18:13:24.071Z', + system: true, + system_note_icon_name: 'pencil', + noteable_id: 99, + noteable_type: 'Issue', + type: null, + human_access: 'Owner', + note: 'changed the description', + note_html: '

changed the description

', + current_user: { can_edit: false }, + discussion_id: '3eb958b4d81dec207ec3537a2f3bd8b9f271bb34', + emoji_awardable: false, + path: '/h5bp/html5-boilerplate/notes/1057', + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fh5bp%2Fhtml5-boilerplate%2Fissues%2F10%23note_1057&user_id=1', + }, + ], + }, +]; + export const INDIVIDUAL_NOTE_RESPONSE_MAP = { GET: { '/gitlab-org/gitlab-ce/issues/26/discussions.json': [ @@ -575,3 +648,508 @@ export function discussionNoteInterceptor(request, next) { }), ); } + +export const notesWithDescriptionChanges = [ + { + id: '39b271c2033e9ed43d8edb393702f65f7a830459', + reply_id: '39b271c2033e9ed43d8edb393702f65f7a830459', + expanded: true, + notes: [ + { + id: 901, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:05:36.117Z', + updated_at: '2018-05-29T12:05:36.117Z', + system: false, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + note_html: + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

', + current_user: { can_edit: true, can_award_emoji: true }, + resolved: false, + resolved_by: null, + discussion_id: '39b271c2033e9ed43d8edb393702f65f7a830459', + emoji_awardable: true, + award_emoji: [], + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_901&user_id=1', + human_access: 'Owner', + toggle_award_path: '/gitlab-org/gitlab-shell/notes/901/toggle_award_emoji', + path: '/gitlab-org/gitlab-shell/notes/901', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: '4852335d7dc40b9ceb8fde1a2bb9c1b67e4c7795', + reply_id: '4852335d7dc40b9ceb8fde1a2bb9c1b67e4c7795', + expanded: true, + notes: [ + { + id: 902, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:05:58.694Z', + updated_at: '2018-05-29T12:05:58.694Z', + system: false, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: + 'Varius vel pharetra vel turpis nunc eget lorem. Ipsum dolor sit amet consectetur adipiscing.', + note_html: + '

Varius vel pharetra vel turpis nunc eget lorem. Ipsum dolor sit amet consectetur adipiscing.

', + current_user: { can_edit: true, can_award_emoji: true }, + resolved: false, + resolved_by: null, + discussion_id: '4852335d7dc40b9ceb8fde1a2bb9c1b67e4c7795', + emoji_awardable: true, + award_emoji: [], + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_902&user_id=1', + human_access: 'Owner', + toggle_award_path: '/gitlab-org/gitlab-shell/notes/902/toggle_award_emoji', + path: '/gitlab-org/gitlab-shell/notes/902', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: '7f1feda384083eb31763366e6392399fde6f3f31', + reply_id: '7f1feda384083eb31763366e6392399fde6f3f31', + expanded: true, + notes: [ + { + id: 903, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:06:05.772Z', + updated_at: '2018-05-29T12:06:05.772Z', + system: true, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: 'changed the description', + note_html: '

changed the description

', + current_user: { can_edit: false, can_award_emoji: true }, + resolved: false, + resolved_by: null, + system_note_icon_name: 'pencil-square', + discussion_id: '7f1feda384083eb31763366e6392399fde6f3f31', + emoji_awardable: false, + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_903&user_id=1', + human_access: 'Owner', + path: '/gitlab-org/gitlab-shell/notes/903', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: '091865fe3ae20f0045234a3d103e3b15e73405b5', + reply_id: '091865fe3ae20f0045234a3d103e3b15e73405b5', + expanded: true, + notes: [ + { + id: 904, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:06:16.112Z', + updated_at: '2018-05-29T12:06:16.112Z', + system: false, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: 'Ullamcorper eget nulla facilisi etiam', + note_html: '

Ullamcorper eget nulla facilisi etiam

', + current_user: { can_edit: true, can_award_emoji: true }, + resolved: false, + resolved_by: null, + discussion_id: '091865fe3ae20f0045234a3d103e3b15e73405b5', + emoji_awardable: true, + award_emoji: [], + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_904&user_id=1', + human_access: 'Owner', + toggle_award_path: '/gitlab-org/gitlab-shell/notes/904/toggle_award_emoji', + path: '/gitlab-org/gitlab-shell/notes/904', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: 'a21cf2e804acc3c60d07e37d75e395f5a9a4d044', + reply_id: 'a21cf2e804acc3c60d07e37d75e395f5a9a4d044', + expanded: true, + notes: [ + { + id: 905, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:06:28.851Z', + updated_at: '2018-05-29T12:06:28.851Z', + system: true, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: 'changed the description', + note_html: '

changed the description

', + current_user: { can_edit: false, can_award_emoji: true }, + resolved: false, + resolved_by: null, + system_note_icon_name: 'pencil-square', + discussion_id: 'a21cf2e804acc3c60d07e37d75e395f5a9a4d044', + emoji_awardable: false, + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_905&user_id=1', + human_access: 'Owner', + path: '/gitlab-org/gitlab-shell/notes/905', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: '70411b08cdfc01f24187a06d77daa33464cb2620', + reply_id: '70411b08cdfc01f24187a06d77daa33464cb2620', + expanded: true, + notes: [ + { + id: 906, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:20:02.925Z', + updated_at: '2018-05-29T12:20:02.925Z', + system: true, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: 'changed the description', + note_html: '

changed the description

', + current_user: { can_edit: false, can_award_emoji: true }, + resolved: false, + resolved_by: null, + system_note_icon_name: 'pencil-square', + discussion_id: '70411b08cdfc01f24187a06d77daa33464cb2620', + emoji_awardable: false, + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_906&user_id=1', + human_access: 'Owner', + path: '/gitlab-org/gitlab-shell/notes/906', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, +]; + +export const collapsedSystemNotes = [ + { + id: '39b271c2033e9ed43d8edb393702f65f7a830459', + reply_id: '39b271c2033e9ed43d8edb393702f65f7a830459', + expanded: true, + notes: [ + { + id: 901, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:05:36.117Z', + updated_at: '2018-05-29T12:05:36.117Z', + system: false, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + note_html: + '

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

', + current_user: { can_edit: true, can_award_emoji: true }, + resolved: false, + resolved_by: null, + discussion_id: '39b271c2033e9ed43d8edb393702f65f7a830459', + emoji_awardable: true, + award_emoji: [], + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_901&user_id=1', + human_access: 'Owner', + toggle_award_path: '/gitlab-org/gitlab-shell/notes/901/toggle_award_emoji', + path: '/gitlab-org/gitlab-shell/notes/901', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: '4852335d7dc40b9ceb8fde1a2bb9c1b67e4c7795', + reply_id: '4852335d7dc40b9ceb8fde1a2bb9c1b67e4c7795', + expanded: true, + notes: [ + { + id: 902, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:05:58.694Z', + updated_at: '2018-05-29T12:05:58.694Z', + system: false, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: + 'Varius vel pharetra vel turpis nunc eget lorem. Ipsum dolor sit amet consectetur adipiscing.', + note_html: + '

Varius vel pharetra vel turpis nunc eget lorem. Ipsum dolor sit amet consectetur adipiscing.

', + current_user: { can_edit: true, can_award_emoji: true }, + resolved: false, + resolved_by: null, + discussion_id: '4852335d7dc40b9ceb8fde1a2bb9c1b67e4c7795', + emoji_awardable: true, + award_emoji: [], + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_902&user_id=1', + human_access: 'Owner', + toggle_award_path: '/gitlab-org/gitlab-shell/notes/902/toggle_award_emoji', + path: '/gitlab-org/gitlab-shell/notes/902', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: '091865fe3ae20f0045234a3d103e3b15e73405b5', + reply_id: '091865fe3ae20f0045234a3d103e3b15e73405b5', + expanded: true, + notes: [ + { + id: 904, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:06:16.112Z', + updated_at: '2018-05-29T12:06:16.112Z', + system: false, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: 'Ullamcorper eget nulla facilisi etiam', + note_html: '

Ullamcorper eget nulla facilisi etiam

', + current_user: { can_edit: true, can_award_emoji: true }, + resolved: false, + resolved_by: null, + discussion_id: '091865fe3ae20f0045234a3d103e3b15e73405b5', + emoji_awardable: true, + award_emoji: [], + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_904&user_id=1', + human_access: 'Owner', + toggle_award_path: '/gitlab-org/gitlab-shell/notes/904/toggle_award_emoji', + path: '/gitlab-org/gitlab-shell/notes/904', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: 'a21cf2e804acc3c60d07e37d75e395f5a9a4d044', + reply_id: 'a21cf2e804acc3c60d07e37d75e395f5a9a4d044', + expanded: true, + notes: [ + { + id: 905, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:06:28.851Z', + updated_at: '2018-05-29T12:06:28.851Z', + system: true, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: 'changed the description', + note_html: '\n

changed the description 2 times within 1 minute

', + current_user: { can_edit: false, can_award_emoji: true }, + resolved: false, + resolved_by: null, + system_note_icon_name: 'pencil-square', + discussion_id: 'a21cf2e804acc3c60d07e37d75e395f5a9a4d044', + emoji_awardable: false, + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_905&user_id=1', + human_access: 'Owner', + path: '/gitlab-org/gitlab-shell/notes/905', + times_updated: 2, + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, + { + id: '70411b08cdfc01f24187a06d77daa33464cb2620', + reply_id: '70411b08cdfc01f24187a06d77daa33464cb2620', + expanded: true, + notes: [ + { + id: 906, + type: null, + attachment: null, + author: { + id: 1, + name: 'Administrator', + username: 'root', + state: 'active', + avatar_url: + 'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon', + path: '/root', + }, + created_at: '2018-05-29T12:20:02.925Z', + updated_at: '2018-05-29T12:20:02.925Z', + system: true, + noteable_id: 182, + noteable_type: 'Issue', + resolvable: false, + noteable_iid: 12, + note: 'changed the description', + note_html: '

changed the description

', + current_user: { can_edit: false, can_award_emoji: true }, + resolved: false, + resolved_by: null, + system_note_icon_name: 'pencil-square', + discussion_id: '70411b08cdfc01f24187a06d77daa33464cb2620', + emoji_awardable: false, + report_abuse_path: + '/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_906&user_id=1', + human_access: 'Owner', + path: '/gitlab-org/gitlab-shell/notes/906', + }, + ], + individual_note: true, + resolvable: false, + resolved: false, + diff_discussion: false, + }, +]; diff --git a/spec/javascripts/notes/stores/collapse_utils_spec.js b/spec/javascripts/notes/stores/collapse_utils_spec.js new file mode 100644 index 00000000000..06a6aab932a --- /dev/null +++ b/spec/javascripts/notes/stores/collapse_utils_spec.js @@ -0,0 +1,46 @@ +import { + isDescriptionSystemNote, + changeDescriptionNote, + getTimeDifferenceMinutes, + collapseSystemNotes, +} from '~/notes/stores/collapse_utils'; +import { + notesWithDescriptionChanges, + collapsedSystemNotes, +} from '../mock_data'; + +describe('Collapse utils', () => { + const mockSystemNote = { + note: 'changed the description', + note_html: '

changed the description

', + system: true, + created_at: '2018-05-14T21:28:00.000Z', + }; + + it('checks if a system note is of a description type', () => { + expect(isDescriptionSystemNote(mockSystemNote)).toEqual(true); + }); + + it('returns false when a system note is not a description type', () => { + expect(isDescriptionSystemNote(Object.assign({}, mockSystemNote, { note: 'foo' }))).toEqual(false); + }); + + it('changes the description to contain the number of changed times', () => { + const changedNote = changeDescriptionNote(mockSystemNote, 3, 5); + + expect(changedNote.times_updated).toEqual(3); + expect(changedNote.note_html.trim()).toContain('

changed the description 3 times within 5 minutes

'); + }); + + it('gets the time difference between two notes', () => { + const anotherSystemNote = { + created_at: '2018-05-14T21:33:00.000Z', + }; + + expect(getTimeDifferenceMinutes(mockSystemNote, anotherSystemNote)).toEqual(5); + }); + + it('collapses all description system notes made within 10 minutes or less from each other', () => { + expect(collapseSystemNotes(notesWithDescriptionChanges)).toEqual(collapsedSystemNotes); + }); +}); diff --git a/spec/javascripts/notes/stores/getters_spec.js b/spec/javascripts/notes/stores/getters_spec.js index 8b2a8d2cd7a..e5550580bf8 100644 --- a/spec/javascripts/notes/stores/getters_spec.js +++ b/spec/javascripts/notes/stores/getters_spec.js @@ -1,8 +1,9 @@ import * as getters from '~/notes/stores/getters'; -import { notesDataMock, userDataMock, noteableDataMock, individualNote } from '../mock_data'; +import { notesDataMock, userDataMock, noteableDataMock, individualNote, collapseNotesMock } from '../mock_data'; describe('Getters Notes Store', () => { let state; + beforeEach(() => { state = { notes: [individualNote], @@ -20,6 +21,22 @@ describe('Getters Notes Store', () => { }); }); + describe('Collapsed notes', () => { + const stateCollapsedNotes = { + notes: collapseNotesMock, + targetNoteHash: 'hash', + lastFetchedAt: 'timestamp', + + notesData: notesDataMock, + userData: userDataMock, + noteableData: noteableDataMock, + }; + + it('should return a single system note when a description was updated multiple times', () => { + expect(getters.notes(stateCollapsedNotes).length).toEqual(1); + }); + }); + describe('targetNoteHash', () => { it('should return `targetNoteHash`', () => { expect(getters.targetNoteHash(state)).toEqual('hash'); -- cgit v1.2.1 From 36fbe1422666cb5553ccde9e534bb2a504f0f2c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 28 May 2018 18:17:18 +0200 Subject: Do not validate cached data --- spec/models/ci/runner_spec.rb | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index 0f072aa1719..f6433234573 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -549,7 +549,7 @@ describe Ci::Runner do end describe '#update_cached_info' do - let(:runner) { create(:ci_runner) } + let(:runner) { create(:ci_runner, :project) } subject { runner.update_cached_info(architecture: '18-bit') } @@ -570,17 +570,22 @@ describe Ci::Runner do runner.contacted_at = 2.hours.ago end - it 'updates database' do - expect_redis_update + context 'with invalid runner' do + before do + runner.projects = [] + end + + it 'still updates redis cache and database' do + expect(runner).to be_invalid - expect { subject }.to change { runner.reload.read_attribute(:contacted_at) } - .and change { runner.reload.read_attribute(:architecture) } + expect_redis_update + does_db_update + end end - it 'updates cache' do + it 'updates redis cache and database' do expect_redis_update - - subject + does_db_update end end @@ -590,6 +595,11 @@ describe Ci::Runner do expect(redis).to receive(:set).with(redis_key, anything, any_args) end end + + def does_db_update + expect { subject }.to change { runner.reload.read_attribute(:contacted_at) } + .and change { runner.reload.read_attribute(:architecture) } + end end describe '#destroy' do -- cgit v1.2.1 From 491e1fc905ef52dcc2e7df7deabd3c1f6e42aa52 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 4 Jun 2018 17:04:04 +0200 Subject: Render a 403 when showing an access denied message When we want to show an access denied message to a user, we don't have to hide the resource's existence. So in that case we render a 403, this 403 is not handled by nginx on omnibus installs, making sure the message is visible to the user. --- spec/controllers/application_controller_spec.rb | 24 ++++++++++++++++++++++ ...troller_with_cross_project_access_check_spec.rb | 12 +++++------ spec/controllers/search_controller_spec.rb | 2 +- 3 files changed, 31 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index b048da1991c..683c57c96f8 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -477,4 +477,28 @@ describe ApplicationController do end end end + + describe '#access_denied' do + controller(described_class) do + def index + access_denied!(params[:message]) + end + end + + before do + sign_in user + end + + it 'renders a 404 without a message' do + get :index + + expect(response).to have_gitlab_http_status(404) + end + + it 'renders a 403 when a message is passed to access denied' do + get :index, message: 'None shall pass' + + expect(response).to have_gitlab_http_status(403) + end + end end diff --git a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb index 27f558e1b5d..d20471ef603 100644 --- a/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb +++ b/spec/controllers/concerns/controller_with_cross_project_access_check_spec.rb @@ -43,13 +43,13 @@ describe ControllerWithCrossProjectAccessCheck do end end - it 'renders a 404 with trying to access a cross project page' do + it 'renders a 403 with trying to access a cross project page' do message = "This page is unavailable because you are not allowed to read "\ "information across multiple projects." get :index - expect(response).to have_gitlab_http_status(404) + expect(response).to have_gitlab_http_status(403) expect(response.body).to match(/#{message}/) end @@ -119,7 +119,7 @@ describe ControllerWithCrossProjectAccessCheck do get :index - expect(response).to have_gitlab_http_status(404) + expect(response).to have_gitlab_http_status(403) end it 'is executed when the `unless` condition returns true' do @@ -127,19 +127,19 @@ describe ControllerWithCrossProjectAccessCheck do get :index - expect(response).to have_gitlab_http_status(404) + expect(response).to have_gitlab_http_status(403) end it 'does not skip the check on an action that is not skipped' do get :show, id: 'hello' - expect(response).to have_gitlab_http_status(404) + expect(response).to have_gitlab_http_status(403) end it 'does not skip the check on an action that was not defined to skip' do get :edit, id: 'hello' - expect(response).to have_gitlab_http_status(404) + expect(response).to have_gitlab_http_status(403) end end end diff --git a/spec/controllers/search_controller_spec.rb b/spec/controllers/search_controller_spec.rb index 30c06ddf744..416a09e1684 100644 --- a/spec/controllers/search_controller_spec.rb +++ b/spec/controllers/search_controller_spec.rb @@ -32,7 +32,7 @@ describe SearchController do it 'still blocks searches without a project_id' do get :show, search: 'hello' - expect(response).to have_gitlab_http_status(404) + expect(response).to have_gitlab_http_status(403) end it 'allows searches with a project_id' do -- cgit v1.2.1 From b009a0084c67877ba6a808c4c8a81c568598d624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Mon, 4 Jun 2018 21:49:39 +0200 Subject: Remove PagesService and instead make it explicit that we call PagesWorker --- spec/models/ci/build_spec.rb | 72 +++++++++++++++++++++++++++++++++++++ spec/services/pages_service_spec.rb | 53 --------------------------- 2 files changed, 72 insertions(+), 53 deletions(-) delete mode 100644 spec/services/pages_service_spec.rb (limited to 'spec') diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 66c9708b4cf..e5982a44e89 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -2506,4 +2506,76 @@ describe Ci::Build do end end end + + describe 'pages deployments' do + set(:build) { create(:ci_build, project: project, user: user) } + + context 'when job is "pages"' do + before do + build.name = 'pages' + end + + context 'when pages are enabled' do + before do + allow(Gitlab.config.pages).to receive_messages(enabled: true) + end + + it 'is marked as pages generator' do + expect(build).to be_pages_generator + end + + context 'job succeeds' do + it "calls pages worker" do + expect(PagesWorker).to receive(:perform_async).with(:deploy, build.id) + + build.success! + end + end + + context 'job fails' do + it "does not call pages worker" do + expect(PagesWorker).not_to receive(:perform_async) + + build.drop! + end + end + end + + context 'when pages are disabled' do + before do + allow(Gitlab.config.pages).to receive_messages(enabled: false) + end + + it 'is not marked as pages generator' do + expect(build).not_to be_pages_generator + end + + context 'job succeeds' do + it "does not call pages worker" do + expect(PagesWorker).not_to receive(:perform_async) + + build.success! + end + end + end + end + + context 'when job is not "pages"' do + before do + build.name = 'other-job' + end + + it 'is not marked as pages generator' do + expect(build).not_to be_pages_generator + end + + context 'job succeeds' do + it "does not call pages worker" do + expect(PagesWorker).not_to receive(:perform_async) + + build.success + end + end + end + end end diff --git a/spec/services/pages_service_spec.rb b/spec/services/pages_service_spec.rb deleted file mode 100644 index f8db6900a0a..00000000000 --- a/spec/services/pages_service_spec.rb +++ /dev/null @@ -1,53 +0,0 @@ -require 'spec_helper' - -describe PagesService do - let(:build) { create(:ci_build) } - let(:data) { Gitlab::DataBuilder::Build.build(build) } - let(:service) { described_class.new(data) } - - before do - allow(Gitlab.config.pages).to receive(:enabled).and_return(true) - end - - context 'execute asynchronously for pages job' do - before do - build.name = 'pages' - end - - context 'on success' do - before do - build.success - end - - it 'executes worker' do - expect(PagesWorker).to receive(:perform_async) - service.execute - end - end - - %w(pending running failed canceled).each do |status| - context "on #{status}" do - before do - build.status = status - end - - it 'does not execute worker' do - expect(PagesWorker).not_to receive(:perform_async) - service.execute - end - end - end - end - - context 'for other jobs' do - before do - build.name = 'other job' - build.success - end - - it 'does not execute worker' do - expect(PagesWorker).not_to receive(:perform_async) - service.execute - end - end -end -- cgit v1.2.1 From bc59fc3719869e60ee4ff00c7da766ea01293239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lu=C3=ADs?= Date: Tue, 5 Jun 2018 10:10:34 +0000 Subject: Resolve "Add Xcode Button in UI" --- spec/helpers/projects_helper_spec.rb | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'spec') diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index f8877b6d1aa..4e5391295b6 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -435,4 +435,46 @@ describe ProjectsHelper do expect(helper.send(:git_user_name)).to eq('John \"A\" Doe53') end end + + describe 'show_xcode_link' do + let!(:project) { create(:project) } + let(:mac_ua) { 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36' } + let(:ios_ua) { 'Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3' } + + context 'when the repository is xcode compatible' do + before do + allow(project.repository).to receive(:xcode_project?).and_return(true) + end + + it 'returns false if the visitor is not using macos' do + allow(helper).to receive(:browser).and_return(Browser.new(ios_ua)) + + expect(helper.show_xcode_link?(project)).to eq(false) + end + + it 'returns true if the visitor is using macos' do + allow(helper).to receive(:browser).and_return(Browser.new(mac_ua)) + + expect(helper.show_xcode_link?(project)).to eq(true) + end + end + + context 'when the repository is not xcode compatible' do + before do + allow(project.repository).to receive(:xcode_project?).and_return(false) + end + + it 'returns false if the visitor is not using macos' do + allow(helper).to receive(:browser).and_return(Browser.new(ios_ua)) + + expect(helper.show_xcode_link?(project)).to eq(false) + end + + it 'returns false if the visitor is using macos' do + allow(helper).to receive(:browser).and_return(Browser.new(mac_ua)) + + expect(helper.show_xcode_link?(project)).to eq(false) + end + end + end end -- cgit v1.2.1 From 463d77a59e7d3c5f0089d932692aeddaff96c4c0 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 5 Jun 2018 12:51:38 +0200 Subject: Fix Rubocop offense in build specs --- spec/models/ci/build_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index e5982a44e89..5e27cca6771 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -2545,7 +2545,7 @@ describe Ci::Build do before do allow(Gitlab.config.pages).to receive_messages(enabled: false) end - + it 'is not marked as pages generator' do expect(build).not_to be_pages_generator end -- cgit v1.2.1 From 3a4ecfd0c9a58bcac565426df552cec0cfe77017 Mon Sep 17 00:00:00 2001 From: "Jacob Vosmaer (GitLab)" Date: Tue, 5 Jun 2018 12:55:41 +0000 Subject: Prevent Gitaly WriteConfig log noise --- spec/lib/gitlab/git/repository_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 7a9621d9c78..20b0b2c53a0 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -2002,6 +2002,18 @@ describe Gitlab::Git::Repository, seed_helper: true do expect(config).to include("fullpath = #{repository_path}") end end + + context 'repository does not exist' do + it 'raises NoRepository and does not call Gitaly WriteConfig' do + repository = Gitlab::Git::Repository.new('default', 'does/not/exist.git', '') + + expect(repository.gitaly_repository_client).not_to receive(:write_config) + + expect do + repository.write_config(full_path: 'foo/bar.git') + end.to raise_error(Gitlab::Git::Repository::NoRepository) + end + end end context "when gitaly_write_config is enabled" do -- cgit v1.2.1 From 6ecf819f73ae28547e1b816780de0d85c3a653cf Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 19 Apr 2018 17:22:23 +0100 Subject: Fix an N+1 in avatar URLs This is tricky: the query was being run in `ObjectStorage::Extension::RecordsUploads#retrieve_from_store!`, but we can't just add batch loading there, because the `#upload=` method there would use the result immediately, making the batch only have one item. Instead, we can pre-emptively add an item to the batch whenever an avatarable object is initialized, and then reuse that batch item in `#retrieve_from_store!`. However, this also has problems: 1. There is a lot of logic in `Avatarable#retrieve_upload_from_batch`. 2. Some of that logic constructs a 'fake' model for the batch key. This should be fine, because of ActiveRecord's override of `#==`, but it relies on that staying the same. --- spec/uploaders/object_storage_spec.rb | 22 ++++++++++++++++++++++ .../object_storage/background_move_worker_spec.rb | 6 ++++-- 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index 01166865e88..cda911032b2 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -739,4 +739,26 @@ describe ObjectStorage do end end end + + describe '#retrieve_from_store!' do + [:group, :project, :user].each do |model| + context "for #{model}s" do + let(:models) { create_list(model, 3, :with_avatar).map(&:reload) } + let(:avatars) { models.map(&:avatar) } + + it 'batches fetching uploads from the database' do + # Ensure that these are all created and fully loaded before we start + # running queries for avatars + models + + expect { avatars }.not_to exceed_query_limit(1) + end + + it 'fetches a unique upload for each model' do + expect(avatars.map(&:url).uniq).to eq(avatars.map(&:url)) + expect(avatars.map(&:upload).uniq).to eq(avatars.map(&:upload)) + end + end + end + end end diff --git a/spec/uploaders/workers/object_storage/background_move_worker_spec.rb b/spec/uploaders/workers/object_storage/background_move_worker_spec.rb index b34f427fd8a..95813d15e52 100644 --- a/spec/uploaders/workers/object_storage/background_move_worker_spec.rb +++ b/spec/uploaders/workers/object_storage/background_move_worker_spec.rb @@ -125,8 +125,10 @@ describe ObjectStorage::BackgroundMoveWorker do it "migrates file to remote storage" do perform + project.reload + BatchLoader::Executor.clear_current - expect(project.reload.avatar.file_storage?).to be_falsey + expect(project.avatar).not_to be_file_storage end end @@ -137,7 +139,7 @@ describe ObjectStorage::BackgroundMoveWorker do it "migrates file to remote storage" do perform - expect(project.reload.avatar.file_storage?).to be_falsey + expect(project.reload.avatar).not_to be_file_storage end end end -- cgit v1.2.1 From c8a4d202c99c772822a2b9b09fa6da2c90b2ae81 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 26 Sep 2017 09:51:24 +0200 Subject: favicon uploader generating ci status favicons --- spec/uploaders/favicon_uploader_spec.rb | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 spec/uploaders/favicon_uploader_spec.rb (limited to 'spec') diff --git a/spec/uploaders/favicon_uploader_spec.rb b/spec/uploaders/favicon_uploader_spec.rb new file mode 100644 index 00000000000..5989d294112 --- /dev/null +++ b/spec/uploaders/favicon_uploader_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +RSpec.describe FaviconUploader do + include CarrierWave::Test::Matchers + + let(:uploader) { described_class.new(build_stubbed(:user)) } + + after do + uploader.remove! + end + + def upload_fixture(filename) + fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) + end + + context 'versions' do + before do + uploader.store!(upload_fixture('dk.png')) + end + + it 'has the correct format' do + expect(uploader.default).to be_format('ico') + end + + it 'has the correct dimensions' do + expect(uploader.default).to have_dimensions(32, 32) + end + + it 'generates all the status icons' do + # make sure that the following each statement actually loops + expect(FaviconUploader::STATUS_ICON_NAMES.count).to eq 10 + + FaviconUploader::STATUS_ICON_NAMES.each do |status_name| + expect(File.exist?(uploader.status_not_found.file.file)).to be true + end + end + end +end -- cgit v1.2.1 From 40d8d7df4bd437efc81f0bdff5f93b4b65844cb5 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 26 Sep 2017 16:07:53 +0200 Subject: feature spec for managing appearance > favicon --- spec/features/admin/admin_appearance_spec.rb | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'spec') diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index d91dcf76191..556aa10d226 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -76,6 +76,40 @@ feature 'Admin Appearance' do expect(page).not_to have_css(header_logo_selector) end + scenario 'Favicon' do + sign_in(create(:admin)) + visit admin_appearances_path + + attach_file(:appearance_favicon, logo_fixture) + click_button 'Save' + + expect(page).to have_css('//img[data-src$="/default_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_canceled_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_created_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_failed_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_manual_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_not_found_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_pending_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_running_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_skipped_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_success_dk.ico"]') + expect(page).to have_css('//img[data-src$="/status_warning_dk.ico"]') + + click_link 'Remove favicon' + + expect(page).not_to have_css('//img[data-src$="/default_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_canceled_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_created_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_failed_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_manual_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_not_found_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_pending_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_running_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_skipped_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_success_dk.ico"]') + expect(page).not_to have_css('//img[data-src$="/status_warning_dk.ico"]') + end + def expect_custom_sign_in_appearance(appearance) expect(page).to have_content appearance.title expect(page).to have_content appearance.description -- cgit v1.2.1 From 8967fc0477d176cb5b93ad3a9f2cf19eaca14876 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 26 Sep 2017 16:22:04 +0200 Subject: use custom main favicon --- spec/helpers/page_layout_helper_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'spec') diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index b77114a8152..53ecf25612f 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -55,6 +55,11 @@ describe PageLayoutHelper do stub_env('CANARY', 'true') expect(helper.favicon).to eq 'favicon-yellow.ico' end + + it 'uses the custom favicon if an favicon appearance is present' do + create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) + expect(helper.favicon).to match %r{/uploads/-/system/appearance/favicon/\d+/default_dk.ico} + end end describe 'page_image' do -- cgit v1.2.1 From a6f3f6b8cd2e79acbc824c401435284635071e1a Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 26 Sep 2017 17:04:37 +0200 Subject: extract favicon logic to lib class --- spec/helpers/page_layout_helper_spec.rb | 22 ---------------------- spec/lib/gitlab/favicon_spec.rb | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 22 deletions(-) create mode 100644 spec/lib/gitlab/favicon_spec.rb (limited to 'spec') diff --git a/spec/helpers/page_layout_helper_spec.rb b/spec/helpers/page_layout_helper_spec.rb index 53ecf25612f..cf98eed27f1 100644 --- a/spec/helpers/page_layout_helper_spec.rb +++ b/spec/helpers/page_layout_helper_spec.rb @@ -40,28 +40,6 @@ describe PageLayoutHelper do end end - describe 'favicon' do - it 'defaults to favicon.ico' do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) - expect(helper.favicon).to eq 'favicon.ico' - end - - it 'has blue favicon for development' do - allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) - expect(helper.favicon).to eq 'favicon-blue.ico' - end - - it 'has yellow favicon for canary' do - stub_env('CANARY', 'true') - expect(helper.favicon).to eq 'favicon-yellow.ico' - end - - it 'uses the custom favicon if an favicon appearance is present' do - create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) - expect(helper.favicon).to match %r{/uploads/-/system/appearance/favicon/\d+/default_dk.ico} - end - end - describe 'page_image' do it 'defaults to the GitLab logo' do expect(helper.page_image).to match_asset_path 'assets/gitlab_logo.png' diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb new file mode 100644 index 00000000000..51a8ed47abf --- /dev/null +++ b/spec/lib/gitlab/favicon_spec.rb @@ -0,0 +1,25 @@ +require 'rails_helper' + +RSpec.describe Gitlab::Favicon do + describe '.default' do + it 'defaults to favicon.ico' do + allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) + expect(described_class.default).to eq 'favicon.ico' + end + + it 'has blue favicon for development' do + allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) + expect(described_class.default).to eq 'favicon-blue.ico' + end + + it 'has yellow favicon for canary' do + stub_env('CANARY', 'true') + expect(described_class.favicon).to eq 'favicon-yellow.ico' + end + + it 'uses the custom favicon if a favicon appearance is present' do + create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) + expect(described_class.default).to match %r{/uploads/-/system/appearance/favicon/\d+/default_dk.ico} + end + end +end -- cgit v1.2.1 From 44d7b1583348513f8faa680a864efdbb39be70ab Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 27 Sep 2017 13:18:49 +0200 Subject: use custom favicon for ci build status favicons --- spec/lib/gitlab/favicon_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index 51a8ed47abf..d74dabf1458 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -22,4 +22,17 @@ RSpec.describe Gitlab::Favicon do expect(described_class.default).to match %r{/uploads/-/system/appearance/favicon/\d+/default_dk.ico} end end + + describe '.status' do + subject { described_class.status('created') } + + it 'defaults to the stock icon' do + expect(subject).to eq 'ci_favicons/favicon_status_created.ico' + end + + it 'uses the custom favicon if a favicon appearance is present' do + create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) + expect(subject).to match(%r{/uploads/-/system/appearance/favicon/\d+/status_created_dk.ico}) + end + end end -- cgit v1.2.1 From bf27c6841c1cb6b68f67d33d6eb2de63ad8b390f Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 27 Sep 2017 13:21:58 +0200 Subject: send ico files with inline disposition --- spec/models/group_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/models/user_spec.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index f83b52e8975..8f1f4938065 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -240,7 +240,7 @@ describe Group do it "is false if avatar is html page" do group.update_attribute(:avatar, 'uploads/avatar.html') - expect(group.avatar_type).to eq(["file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff"]) + expect(group.avatar_type).to eq(["file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico"]) end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9a76452a808..ed1253c6d97 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -960,7 +960,7 @@ describe Project do it 'is false if avatar is html page' do project.update_attribute(:avatar, 'uploads/avatar.html') - expect(project.avatar_type).to eq(['file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff']) + expect(project.avatar_type).to eq(['file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico']) end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 09dfeae6377..097144d04ce 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1260,7 +1260,7 @@ describe User do it 'is false if avatar is html page' do user.update_attribute(:avatar, 'uploads/avatar.html') - expect(user.avatar_type).to eq(['file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff']) + expect(user.avatar_type).to eq(['file format is not supported. Please try one of the following supported formats: png, jpg, jpeg, gif, bmp, tiff, ico']) end end -- cgit v1.2.1 From 822023c64ccab23cfdacb42e191dcec4f812adfd Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 27 Sep 2017 13:23:05 +0200 Subject: Add a '?' to the custom favicon's urls Without the '?' at the end of the favicon url the custom favicon (i.e. the favicons that are served through `UploadController`) are not shown in the browser. It may have something to do with how `#send_file` / `#send_data` set http headers. When serving the same icon file from the public directory everything is fine. --- spec/lib/gitlab/favicon_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index d74dabf1458..fe0bff51308 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -19,7 +19,7 @@ RSpec.describe Gitlab::Favicon do it 'uses the custom favicon if a favicon appearance is present' do create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) - expect(described_class.default).to match %r{/uploads/-/system/appearance/favicon/\d+/default_dk.ico} + expect(described_class.default).to match %r{/uploads/-/system/appearance/favicon/\d+/default_dk.ico\?} end end @@ -32,7 +32,7 @@ RSpec.describe Gitlab::Favicon do it 'uses the custom favicon if a favicon appearance is present' do create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) - expect(subject).to match(%r{/uploads/-/system/appearance/favicon/\d+/status_created_dk.ico}) + expect(subject).to match(%r{/uploads/-/system/appearance/favicon/\d+/status_created_dk.ico\?}) end end end -- cgit v1.2.1 From 85a8e6f26a8fa0ea9f430f0094fb14706bfd2991 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 27 Sep 2017 15:03:49 +0200 Subject: whitelist allowed file types for custom favicons --- spec/features/admin/admin_appearance_spec.rb | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'spec') diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 556aa10d226..ffffd14752e 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -108,6 +108,12 @@ feature 'Admin Appearance' do expect(page).not_to have_css('//img[data-src$="/status_skipped_dk.ico"]') expect(page).not_to have_css('//img[data-src$="/status_success_dk.ico"]') expect(page).not_to have_css('//img[data-src$="/status_warning_dk.ico"]') + + # allowed file types + attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg')) + click_button 'Save' + + expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, jpg, jpeg, gif, bmp, tiff, ico' end def expect_custom_sign_in_appearance(appearance) -- cgit v1.2.1 From 40ffa8401b96dda5f67ea699dbcca0ff64263810 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 28 Sep 2017 10:45:50 +0200 Subject: add request store caching to favicon --- spec/lib/gitlab/favicon_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index fe0bff51308..ddfa81c0b5d 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe Gitlab::Favicon do +RSpec.describe Gitlab::Favicon, :request_store do describe '.default' do it 'defaults to favicon.ico' do allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) -- cgit v1.2.1 From 67fe0a17d87a7a5380b41e04ef23212d5da637ba Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 28 Sep 2017 13:57:08 +0200 Subject: call Gitlab::Favicon.status in serializer this ways we can keep the `lib/gitlab/ci/status/*` classes to return the bare favicon name as it was before. also the favicon uploader versions are now have the same names as the stock favicons (+ `favicon_` prefix), which makes working with the status names easier. --- spec/lib/gitlab/favicon_spec.rb | 16 ++++++++-------- spec/uploaders/favicon_uploader_spec.rb | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index ddfa81c0b5d..51b8fda81d1 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -1,38 +1,38 @@ require 'rails_helper' RSpec.describe Gitlab::Favicon, :request_store do - describe '.default' do + describe '.main' do it 'defaults to favicon.ico' do allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) - expect(described_class.default).to eq 'favicon.ico' + expect(described_class.main).to eq 'favicon.ico' end it 'has blue favicon for development' do allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) - expect(described_class.default).to eq 'favicon-blue.ico' + expect(described_class.main).to eq 'favicon-blue.ico' end it 'has yellow favicon for canary' do stub_env('CANARY', 'true') - expect(described_class.favicon).to eq 'favicon-yellow.ico' + expect(described_class.main).to eq 'favicon-yellow.ico' end it 'uses the custom favicon if a favicon appearance is present' do create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) - expect(described_class.default).to match %r{/uploads/-/system/appearance/favicon/\d+/default_dk.ico\?} + expect(described_class.main).to match %r{/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.ico} end end describe '.status' do - subject { described_class.status('created') } + subject { described_class.status('favicon_status_created') } it 'defaults to the stock icon' do - expect(subject).to eq 'ci_favicons/favicon_status_created.ico' + expect(subject).to eq '/assets/ci_favicons/favicon_status_created.ico' end it 'uses the custom favicon if a favicon appearance is present' do create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) - expect(subject).to match(%r{/uploads/-/system/appearance/favicon/\d+/status_created_dk.ico\?}) + expect(subject).to match(%r{/uploads/-/system/appearance/favicon/\d+/favicon_status_created_dk.ico}) end end end diff --git a/spec/uploaders/favicon_uploader_spec.rb b/spec/uploaders/favicon_uploader_spec.rb index 5989d294112..b521670addb 100644 --- a/spec/uploaders/favicon_uploader_spec.rb +++ b/spec/uploaders/favicon_uploader_spec.rb @@ -19,11 +19,11 @@ RSpec.describe FaviconUploader do end it 'has the correct format' do - expect(uploader.default).to be_format('ico') + expect(uploader.favicon_main).to be_format('ico') end it 'has the correct dimensions' do - expect(uploader.default).to have_dimensions(32, 32) + expect(uploader.favicon_main).to have_dimensions(32, 32) end it 'generates all the status icons' do @@ -31,7 +31,7 @@ RSpec.describe FaviconUploader do expect(FaviconUploader::STATUS_ICON_NAMES.count).to eq 10 FaviconUploader::STATUS_ICON_NAMES.each do |status_name| - expect(File.exist?(uploader.status_not_found.file.file)).to be true + expect(File.exist?(uploader.favicon_status_not_found.file.file)).to be true end end end -- cgit v1.2.1 From 5202c3f0c8da618e2d3821917f6f5d48ae8ae3c2 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 5 Dec 2017 18:47:31 +0100 Subject: fix resetFavicon so that it actually resets --- spec/javascripts/lib/utils/common_utils_spec.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 27f06573432..64d13275a59 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -395,6 +395,7 @@ describe('common_utils', () => { const favicon = document.createElement('link'); favicon.setAttribute('id', 'favicon'); favicon.setAttribute('href', 'default/favicon'); + favicon.setAttribute('data-default-href', 'default/favicon'); document.body.appendChild(favicon); }); @@ -413,7 +414,7 @@ describe('common_utils', () => { beforeEach(() => { const favicon = document.createElement('link'); favicon.setAttribute('id', 'favicon'); - favicon.setAttribute('href', 'default/favicon'); + favicon.setAttribute('data-original-href', 'default/favicon'); document.body.appendChild(favicon); }); @@ -421,7 +422,9 @@ describe('common_utils', () => { document.body.removeChild(document.getElementById('favicon')); }); - it('should reset page favicon to tanuki', () => { + it('should reset page favicon to the default icon', () => { + const favicon = document.getElementById('favicon'); + favicon.setAttribute('href', 'new/favicon'); commonUtils.resetFavicon(); expect(document.getElementById('favicon').getAttribute('href')).toEqual('default/favicon'); }); @@ -434,6 +437,8 @@ describe('common_utils', () => { beforeEach(() => { const favicon = document.createElement('link'); favicon.setAttribute('id', 'favicon'); + favicon.setAttribute('href', 'null'); + favicon.setAttribute('data-original-href', faviconDataUrl); document.body.appendChild(favicon); mock = new MockAdapter(axios); }); @@ -449,7 +454,7 @@ describe('common_utils', () => { commonUtils.setCiStatusFavicon(BUILD_URL) .then(() => { const favicon = document.getElementById('favicon'); - expect(favicon.getAttribute('href')).toEqual('null'); + expect(favicon.getAttribute('href')).toEqual(faviconDataUrl); done(); }) // Error is already caught in catch() block of setCiStatusFavicon, -- cgit v1.2.1 From 9e14f437b6ed205744d916f5566ee2c11e52b734 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Wed, 6 Dec 2017 21:04:53 +0100 Subject: create favicon overlay on the client the initial reason for this change was that graphicsmagick does not support writing to ico files. this fact lead to a chain of changes: 1. use png instead of ico (browser support is good enough) 2. render the overlays on the client using the canvas API. this way we only need to store the original favion and generate the overlay versions dynamically. this change also enables (next step) to simplify the handling of the stock favicons as well, as we don't need to generate all the versions upfront. --- spec/features/admin/admin_appearance_spec.rb | 27 +++------------- spec/javascripts/lib/utils/common_utils_spec.js | 36 +++++++++++++++++++--- spec/javascripts/lib/utils/mock_data.js | 5 +++ .../vue_mr_widget/mr_widget_options_spec.js | 13 +++++--- spec/lib/gitlab/favicon_spec.rb | 30 +++++++++++++----- spec/uploaders/favicon_uploader_spec.rb | 11 +------ 6 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 spec/javascripts/lib/utils/mock_data.js (limited to 'spec') diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index ffffd14752e..0ac4f111c52 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -76,38 +76,19 @@ feature 'Admin Appearance' do expect(page).not_to have_css(header_logo_selector) end - scenario 'Favicon' do + scenario 'Favicon', :js do sign_in(create(:admin)) visit admin_appearances_path attach_file(:appearance_favicon, logo_fixture) click_button 'Save' - expect(page).to have_css('//img[data-src$="/default_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_canceled_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_created_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_failed_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_manual_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_not_found_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_pending_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_running_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_skipped_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_success_dk.ico"]') - expect(page).to have_css('//img[data-src$="/status_warning_dk.ico"]') + # 11 = 1 original + 10 overlay variations + expect(page).to have_css('.appearance-light-logo-preview', count: 11) click_link 'Remove favicon' - expect(page).not_to have_css('//img[data-src$="/default_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_canceled_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_created_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_failed_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_manual_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_not_found_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_pending_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_running_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_skipped_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_success_dk.ico"]') - expect(page).not_to have_css('//img[data-src$="/status_warning_dk.ico"]') + expect(page).not_to have_css('.appearance-light-logo-preview') # allowed file types attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg')) diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 64d13275a59..2d7cc3443cf 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -2,6 +2,7 @@ import axios from '~/lib/utils/axios_utils'; import * as commonUtils from '~/lib/utils/common_utils'; import MockAdapter from 'axios-mock-adapter'; +import { faviconDataUrl, overlayDataUrl, faviconWithOverlayDataUrl } from './mock_data'; describe('common_utils', () => { describe('parseUrl', () => { @@ -430,6 +431,35 @@ describe('common_utils', () => { }); }); + describe('createOverlayIcon', () => { + it('should return the favicon with the overlay', (done) => { + commonUtils.createOverlayIcon(faviconDataUrl, overlayDataUrl).then((url) => { + expect(url).toEqual(faviconWithOverlayDataUrl); + done(); + }); + }); + }); + + describe('setFaviconOverlay', () => { + beforeEach(() => { + const favicon = document.createElement('link'); + favicon.setAttribute('id', 'favicon'); + favicon.setAttribute('data-original-href', faviconDataUrl); + document.body.appendChild(favicon); + }); + + afterEach(() => { + document.body.removeChild(document.getElementById('favicon')); + }); + + it('should set page favicon to provided favicon overlay', (done) => { + commonUtils.setFaviconOverlay(overlayDataUrl).then(() => { + expect(document.getElementById('favicon').getAttribute('href')).toEqual(faviconWithOverlayDataUrl); + done(); + }); + }); + }); + describe('setCiStatusFavicon', () => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1/status.json`; let mock; @@ -463,16 +493,14 @@ describe('common_utils', () => { }); it('should set page favicon to CI status favicon based on provided status', (done) => { - const FAVICON_PATH = '//icon_status_success'; - mock.onGet(BUILD_URL).reply(200, { - favicon: FAVICON_PATH, + favicon: overlayDataUrl, }); commonUtils.setCiStatusFavicon(BUILD_URL) .then(() => { const favicon = document.getElementById('favicon'); - expect(favicon.getAttribute('href')).toEqual(FAVICON_PATH); + expect(favicon.getAttribute('href')).toEqual(faviconWithOverlayDataUrl); done(); }) .catch(done.fail); diff --git a/spec/javascripts/lib/utils/mock_data.js b/spec/javascripts/lib/utils/mock_data.js new file mode 100644 index 00000000000..fd0d62b751f --- /dev/null +++ b/spec/javascripts/lib/utils/mock_data.js @@ -0,0 +1,5 @@ +export const faviconDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACcFBMVEX////iQyniQyniQyniQyniQyniQyniQyniQynhRiriQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniRCniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQyniQynhQiniQiniQiniQinhQinpUSjqUSjqTyjqTyjqTyjlSCniRCniQynjRCjqTyjsZSjrWyj8oib9kSb8pyb9pib8oyb8fyb3ZSb4Zib8fCb8oyb8oyb8oyb8pCb8cSbiQyn7bCb8cib8oyb8oSb8bSbtVSjpTij8nyb8oyb8oyb8lCb2Yyf3ZCf8mCb8oyb8oyb8oyb8iib8bSbiRCn8gyb8oyb8eCbpTinrUSj8oyb8oyb8oyb8pSb8bib4Zif0YCf8byb8oyb8oyb8oyb7oib8oyb8nCbjRSn9bib8ayb8nib8oyb8oyb8oyb8kSbpTyjpTyj8jib8oyb8oyb8oyb8fib0Xyf2ZSb8gCb8oyb6pSb8oyb8dib+cCbgQCnjRSn8cCb8oib8oyb8oyb8oybqUCjnSyn8bCb8oyb8oyb8oyb8myb2YyfyXyf8oyb8oyb8hibhQSn+bib8iSb8oyb8qCb+fSbmSSnqTyj8oib9pCb1YifxXyf7pSb8oCb8pCb+mCb0fCf8pSb7hSXvcSjiQyniQinqTyj9kCb9bib9byb+cCbqUSjiRCnsVCj+cSb8pib8bCb8bSbgQCn7bCb8bibjRSn8oyb8ayb8oib8aib8pCbjRCn8pybhQinhQSn8pSb7ayb7aSb6aib8eib///8IbM+7AAAAr3RSTlMBA3NtX2vT698HGQcRLwWLiXnv++3V+eEd/R8HE2V/Y5HjyefdFw99YWfJ+/3nwQP78/HvX1VTQ/kdA2HzbQXj9fX79/3DGf379/33T/v99/f7ba33+/f1+9/18/v59V339flzF/H9+fX3/fMhBwOh9/v5/fmvBV/z+fP3Awnp9/f38+UFgff7+/37+4c77/f7/flFz/f59dFr7/v98Wnr+/f3I5/197EDBU1ZAwUD8/kLUwAAAAFiS0dEAIgFHUgAAAAHdElNRQfhBQoLHiBV6/1lAAACHUlEQVQ4y41TZXsTQRCe4FAIUigN7m7FXY+iLRQKBG2x4g7BjhZ3Le7uMoEkFJprwyQk0CC/iZnNhUZaHt4vt6/szO7cHcD/wFKjZrJWq3YMq1M3eVc9rFzXR2yQkuA3RGxkjZLGiEk9miA2tURJs1RsnhhokYYtzaU13WZDbBVnW1sjo43J2vI6tZ0lLtFeAh1M0lECneI7dGYtrUtk3RUVIKaEJR25qw27yT0s3W0qEHuPlB4RradivXo7GX36xnbo51SQ+fWHARmCgYMGDxkaxbD3SssYPmIkwKgPLrfA87EETTg/fVaSa/SYsQDjSsd7DcGEsr+BieVKmaRNBsjUtClTfUI900y/5Mt05c8oJQKYSURZ2UqYFa0w283M588JEM2BuRwI5EqT8nmmXzZf4l8XsGNfCIv4QcHFklhiBpaqAsuC4tghj+ySyOdjeJYrP7RCCuR/E5tWAqxaLcmCNSyujdxjHZdbn8UHoA0bN/GoNm8hjQJb/ZzYpo6w3TB27JRduxxqrA7YzbWCezixN8RD2Oc2/Ptlfx7o5uT1A4XMiwzj4HfEikNe7+Ew0ZGjeuW70eEYaeHjxomTiKd++E4XnKGz8d+HDufOB3Ky3RcwdNF1qZiKLyf/B44r2tWf15wV143cwI2qfi8dbtKtX6Hbd+6G74EDqkTm/QcPH/0ufFyNLXjy9NnzF9Xb8BJevYY38C+8fZcg/AF3QTYemVkCwwAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxNy0wNS0xMFQxMTozMDozMiswMjowMMzup8UAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTctMDUtMTBUMTE6MzA6MzIrMDI6MDC9sx95AAAAAElFTkSuQmCC'; + +export const overlayDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAA85JREFUWAntVllIVGEUPv/9b46O41KplYN7PeRkti8TjQlhCUGh3MmeQugpIsGKAi2soIcIooiohxYKK2daqDAlIpIiWwxtQaJcaHE0d5tMrbn37z9XRqfR0TvVW56Hudf//uec72zfEWBCJjIwkYGJDPzvGSD/KgExN3Oi2Q+2DJgSDYQEMwItVGH1iZGmJw/Si1y+/PwVAMYYib22MYc/8hVQFgKDEfYoId0KYzagAQebsos/ewMZoeB9wdffcTYpQSaCTWHKoqSQaDk7zkIt0+aCUR8BelEHrf3dUNv9AcqbnsHtT5UKB/hTASh0SLYjnjb/CIDRJi0XiFAaJOpCD8zLpdb4NB66b1OfelthX815dtdRRfiti2aAXLvVLiMQ6olGyztGDkSo4JGGXk8/QFdGpYzpHG2GBQTDhtgVhPEaVbbVpvI6GJz22rv4TcAfrYI1x7Rj5MWWAppomKFVVb2302SFzUkZHAbkG+0b1+Gh77yNYjrmqnWTrLBLRxdvBWv8qlFujH/kYjJYyvLkj71t78zAUvzMAMnHhpN4zf9UREJhd8omyssxu1IgazQDwDnHUcNuH6vhPIE1fmuBzHt74Hn7W89jWGtcAjoaIDOFrdcMYJBkgOCoaRF0Lj0oglddDbCj6tRvKjphEpgjkzEQs2YAKsNxMzjn3nKurhzK+Ly7xe28ua8TwgMMcHJZnvvT0BPtEEKM4tDJ+C8GvIIk4ylINIXVZ0EUKJxYuh3mhCeokbudl6TtVc88dfBdLwbyaWB6zQCYQJpBYSrDGQxBQ/ZWRM2B+VNmQnVnHWx7elyNuL2/R336co7KyJR8CL9oLgEuFlREevWUkEl6uGwpVEG4FBm0OEf9N10NMgPlvWYAuNVwsWDKvcUNYsHUWTCZ13ysyFEXe6TO6aC8CUr9IiK+A05TQrc8yjwmxARHeeMAPlfQJw+AQRwu0YhL/GDXi9NwufG+S8dYkuYMqIb4SsWthotlNMOUCOM6r+G9cqXxPmd1dqrBav/o1zJy2l5/NUjJA/VORwYuFnOUaTQcPs9wMqwV++Xv8oADxKAcZ8nLPr8AoGW+xR6HSqYk3GodAz2QNj0V+Gr26dT9ASNH5239Pf0gktVNWZca8ZvfAFBprWS6hSu1pqt++Y0PD+WIwDAhIWQGtzvSHDbcodfFUFB9hg1Gjs5LXqIdFL+acFBl+FddqYwdxsWC3I70OvgfUaA65zhq2O2c8VxYcyIGFTVlXegYtvCXANCQZJMobjVcLMjtSK/IcEgyOOe8Ve5w7ryKDefp2P3+C/5ohv8HZmVLAAAAAElFTkSuQmCC'; + +export const faviconWithOverlayDataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAGt0lEQVRYR8WWf3DT5R3H35/vN0lDiCztSuiPAEnTFhSOUamIzFGokwMH55g0E845yjbP6+4qIoiHY6JjnHLeRI6h9jgQpQcD3ImH2u00eHBwjGthKLI1TSm26S8oKYVS0vT7/X52z7ckTUhqC/yx55/kks/zeb+ez6/nIWYm/B8XJQB4SGq6lL+CJA47vvRtvWs2D0nNl/Kf0qBZxx6u23arv0QAAIHivK8BynB4ffa7BgDQXJx/ngGnw+uThgTwP5ZnMocoJAxVxZDVZ+0L5n5WF75TkMafjLdJxpSg2E+gqW1X7zk3rbpaifhLiEBgTv4mEFbpBoTyu01DoDj/dQAv9rvjtdnp/k3Yx9rgAMV5QYCsAAwAgg6vL/1OTy/2BYrzzwLIBWACuNHhrXPG+otGoKaw0JA58kqGJtOFfgPS8yWT4sz88nzj7UIIfz+wd0mRdEZPLMnp2V/8R0+JrhLbBYFHJvwWzBUxYgqYNzhG+zfEhm24MIE5ectBtP0W+y0Or29FcoDifHFSRxwAcMrh9c0YrmisXaA4r0V0U8xvopgDDq9PpCQ+Ag0/zbEbNUNbMiG9fTwkDTsKHpJa2t1Zmiw1AqLg+tMZ+R6WVVtnZ2qP6Ib+FIjh05G3lsDrB4xjUIbRDeM+WZLJYZ4B1rKMzKPm/fdyzs9qg6WT225IMnPcuYjxbPZhn57qaA00zc4/QYT7b1b/wAZmDYSLjsN1WcmiM+6jXz7JTCs1aNPASBjrtrCGOXVBLK9ph72772bc0REZcsQlkEVoOxblhaFBH0Bxi6GBWFNC8gpV0XqYSe/hI85R9o1zxr/QaZbdbmuW9oRzljRrzBRkW9JhMaTgYugKzl35DlXNJ/Fp43FImoZnz7T0ln7bLihM0g85N627vkWPgLrbvYyCvAP1+rRIWETA5QsyQlcJYOCbMRasWpALtljwSsFyeJxFYsoNWqdN1y/ildM78Y/WGjxx8TL+ol3oluy8VupKe7cfoNLdCJkdqEUPOmBJ5ksJoae91mBps5lQ6pkIm20MPiz6A3KsmcNukDe/3Ye3zh3A77Q2XqcGjslLz88i/nB8pkpSoL8nAFSTBpUN4qSxS5KB5jOGUOniCebmzFQcevSN2xKP+Fp7ajt21f8TOxU/5i45JZFS6XwcTB9HxZgUnGTRNgk31x5jet+aGU7jWw+UweOcPeyTxxoqrGL25+UwdjehSvnmOVIqcz4C8y8GAABcQwjnYI5NheikhQWT+EZmDh2ev/l7cz4U2cGmYyg78TYqVH87Kbtd1wFY4hsVQAt14zu2RiDaTUZMf/BHWD35STx37wDv94k1dLeh7MRmvDZ1GR5Inxg17dX6MPnjZfh5X6tGSqXrV2B8ACIx98UNGOlV4CxCuA6zqIeq9FQ8c68bhx7ZiIK06CQdVF+Il3y1Hq03gnDfk4Uj8zbH2T51dCPOtlW39Q+iPTl2VSMfwKPiKw8aTuhgpl1Zdqxzj8PphRWwm21xZjv9VcgYkYb52dP132PFbSYr/la0DpNtrrg9a2oqsKfB2zlwG+4nSe1z7QDjaQBi2Eh6J4QRwimYt43LwOsuB2oX7YLVMCLqTAya3xx/EwZJxtYHy3WhyMkHExebXz3zAbbXfdo7AFBRaMAz1Ypa6XoaoPejKRGteZm6D3SlWVdOcOHo/Lfj2u9aXw+WHNmA00G/DiFEO0Jd+meyk0fIf/+vLfik6Xhj4qN0v7i5HCY1bBQPk+ij9GSzNbzYNdH03kMrscARfzvHQgiBocSFTVHVCrW+u+WrpK9iCIgS1rRK93oG/1GkRJVIup8KMNs1Sw/1rUtALD36ZzRca8XeJDmPtRc18vDn5SCJViYHENY3IZTK3JkE7RAYtpdkp3bAaJeOzN+CsSMTX+wqa7ih9sbVSLI2WV3znihAJYXZPThA7M6KQoM2MniyhUxTioxTpKLMadjx8Jqh5k3S//8d9GOh92XWmP/aXLKvfHgA0ZTklL0jj9m6UR6L5+9bjFWTPLcFIWbCY1+8pHb0drWybJ4aWLQrODyAWJndzoyylNyGg0hL+bV7Ll4rKIWB5CFBxMlLj21SL4W6QjDQjwOL9n4tNt0+AADPfo+UqgXPHJLSJrkso7F6ylLMy56OFMmYACIKblvtQext8Iqp0swyLYiI3zEAbs6Ml3cXv/p3Y+ryq5KcnSKb1Jmj75P7X0Rm/UV0tvO86r/WIhORwszvkmHEehH2WMo7ikDUQUWhoaIG+NNc96Os8eMEmklE2Qy2ANTO0OrA+CwFOFBfsq8pWZ7+B25aDBxvPp+QAAAAAElFTkSuQmCC'; diff --git a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js index 30918428da2..6342ea00436 100644 --- a/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js +++ b/spec/javascripts/vue_mr_widget/mr_widget_options_spec.js @@ -5,6 +5,7 @@ import notify from '~/lib/utils/notify'; import { stateKey } from '~/vue_merge_request_widget/stores/state_maps'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; import mockData from './mock_data'; +import { faviconDataUrl, overlayDataUrl, faviconWithOverlayDataUrl } from '../lib/utils/mock_data'; const returnPromise = data => new Promise((resolve) => { resolve({ @@ -273,6 +274,7 @@ describe('mrWidgetOptions', () => { beforeEach(() => { const favicon = document.createElement('link'); favicon.setAttribute('id', 'favicon'); + favicon.setAttribute('data-original-href', faviconDataUrl); document.body.appendChild(favicon); faviconElement = document.getElementById('favicon'); @@ -282,10 +284,13 @@ describe('mrWidgetOptions', () => { document.body.removeChild(document.getElementById('favicon')); }); - it('should call setFavicon method', () => { - vm.setFaviconHelper(); - - expect(faviconElement.getAttribute('href')).toEqual(vm.mr.ciStatusFaviconPath); + it('should call setFavicon method', (done) => { + vm.mr.ciStatusFaviconPath = overlayDataUrl; + vm.setFaviconHelper().then(() => { + expect(faviconElement.getAttribute('href')).toEqual(faviconWithOverlayDataUrl); + done(); + }) + .catch(done.fail); }); it('should not call setFavicon when there is no ciStatusFaviconPath', () => { diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index 51b8fda81d1..22b9c631ed8 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -19,20 +19,34 @@ RSpec.describe Gitlab::Favicon, :request_store do it 'uses the custom favicon if a favicon appearance is present' do create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) - expect(described_class.main).to match %r{/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.ico} + expect(described_class.main).to match %r{/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.png} end end - describe '.status' do - subject { described_class.status('favicon_status_created') } + describe '.status_overlay' do + subject { described_class.status_overlay('favicon_status_created') } - it 'defaults to the stock icon' do - expect(subject).to eq '/assets/ci_favicons/favicon_status_created.ico' + it 'returns the overlay for the status' do + expect(subject).to eq '/assets/ci_favicons/overlays/favicon_status_created.png' end + end - it 'uses the custom favicon if a favicon appearance is present' do - create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) - expect(subject).to match(%r{/uploads/-/system/appearance/favicon/\d+/favicon_status_created_dk.ico}) + describe '.available_status_names' do + subject { described_class.available_status_names } + + it 'returns the available status names' do + expect(subject).to eq %w( + favicon_status_canceled + favicon_status_created + favicon_status_failed + favicon_status_manual + favicon_status_not_found + favicon_status_pending + favicon_status_running + favicon_status_skipped + favicon_status_success + favicon_status_warning + ) end end end diff --git a/spec/uploaders/favicon_uploader_spec.rb b/spec/uploaders/favicon_uploader_spec.rb index b521670addb..db8a3207f4d 100644 --- a/spec/uploaders/favicon_uploader_spec.rb +++ b/spec/uploaders/favicon_uploader_spec.rb @@ -19,20 +19,11 @@ RSpec.describe FaviconUploader do end it 'has the correct format' do - expect(uploader.favicon_main).to be_format('ico') + expect(uploader.favicon_main).to be_format('png') end it 'has the correct dimensions' do expect(uploader.favicon_main).to have_dimensions(32, 32) end - - it 'generates all the status icons' do - # make sure that the following each statement actually loops - expect(FaviconUploader::STATUS_ICON_NAMES.count).to eq 10 - - FaviconUploader::STATUS_ICON_NAMES.each do |status_name| - expect(File.exist?(uploader.favicon_status_not_found.file.file)).to be true - end - end end end -- cgit v1.2.1 From 949c30d42b91a0dd3959a3ca303b8f76158a2556 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 7 Dec 2017 13:15:49 +0100 Subject: remove all .ico favicon variations, use png always the ci status icons are generated client side, wo we don't need the static files anymore. --- spec/controllers/projects/jobs_controller_spec.rb | 2 +- .../projects/merge_requests_controller_spec.rb | 2 +- spec/controllers/projects/pipelines_controller_spec.rb | 2 +- .../user_creates_image_diff_notes_spec.rb | 2 +- spec/javascripts/jobs/mock_data.js | 4 ++-- spec/javascripts/pipelines/graph/mock_data.js | 18 +++++++++--------- spec/lib/gitlab/favicon_spec.rb | 10 +++++----- spec/models/project_services/jira_service_spec.rb | 2 +- spec/serializers/build_serializer_spec.rb | 4 ++-- spec/serializers/pipeline_serializer_spec.rb | 2 +- spec/serializers/status_entity_spec.rb | 6 +++--- spec/services/system_note_service_spec.rb | 6 +++--- 12 files changed, 30 insertions(+), 30 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index a08fcea27a5..06c8a432561 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -265,7 +265,7 @@ describe Projects::JobsController, :clean_gitlab_redis_shared_state do expect(json_response['text']).to eq status.text expect(json_response['label']).to eq status.label expect(json_response['icon']).to eq status.icon - expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.ico" + expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.png" end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 6e8de6db9c3..eb83884d54e 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -681,7 +681,7 @@ describe Projects::MergeRequestsController do expect(json_response['text']).to eq status.text expect(json_response['label']).to eq status.label expect(json_response['icon']).to eq status.icon - expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.ico" + expect(json_response['favicon']).to match_asset_path "/assets/ci_favicons/#{status.favicon}.png" end end diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 9e7bc20a6d1..c524f5d7f8a 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -190,7 +190,7 @@ describe Projects::PipelinesController do expect(json_response['text']).to eq status.text expect(json_response['label']).to eq status.label expect(json_response['icon']).to eq status.icon - expect(json_response['favicon']).to match_asset_path("/assets/ci_favicons/#{status.favicon}.ico") + expect(json_response['favicon']).to match_asset_path("/assets/ci_favicons/#{status.favicon}.png") end end diff --git a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb index 7c4fd25bb39..25c408516d1 100644 --- a/spec/features/merge_request/user_creates_image_diff_notes_spec.rb +++ b/spec/features/merge_request/user_creates_image_diff_notes_spec.rb @@ -12,7 +12,7 @@ feature 'Merge request > User creates image diff notes', :js do # Stub helper to return any blob file as image from public app folder. # This is necessary to run this specs since we don't display repo images in capybara. allow_any_instance_of(DiffHelper).to receive(:diff_file_blob_raw_url).and_return('/apple-touch-icon.png') - allow_any_instance_of(DiffHelper).to receive(:diff_file_old_blob_raw_url).and_return('/favicon.ico') + allow_any_instance_of(DiffHelper).to receive(:diff_file_old_blob_raw_url).and_return('/favicon.png') end context 'create commit diff notes' do diff --git a/spec/javascripts/jobs/mock_data.js b/spec/javascripts/jobs/mock_data.js index 25ca8eb6c0b..dd025255bd1 100644 --- a/spec/javascripts/jobs/mock_data.js +++ b/spec/javascripts/jobs/mock_data.js @@ -20,7 +20,7 @@ export default { group: 'success', has_details: true, details_path: '/root/ci-mock/-/jobs/4757', - favicon: '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + favicon: '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', action: { icon: 'retry', title: 'Retry', @@ -78,7 +78,7 @@ export default { group: 'success', has_details: true, details_path: '/root/ci-mock/pipelines/140', - favicon: '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + favicon: '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', }, duration: 6, finished_at: '2017-06-01T17:32:00.042Z', diff --git a/spec/javascripts/pipelines/graph/mock_data.js b/spec/javascripts/pipelines/graph/mock_data.js index 70eba98e939..9e25a4b3fed 100644 --- a/spec/javascripts/pipelines/graph/mock_data.js +++ b/spec/javascripts/pipelines/graph/mock_data.js @@ -20,7 +20,7 @@ export default { has_details: true, details_path: '/root/ci-mock/pipelines/123', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', }, duration: 9, finished_at: '2017-04-19T14:30:27.542Z', @@ -40,7 +40,7 @@ export default { has_details: true, details_path: '/root/ci-mock/builds/4153', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', action: { icon: 'retry', title: 'Retry', @@ -65,7 +65,7 @@ export default { has_details: true, details_path: '/root/ci-mock/builds/4153', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', action: { icon: 'retry', title: 'Retry', @@ -85,7 +85,7 @@ export default { has_details: true, details_path: '/root/ci-mock/pipelines/123#test', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', }, path: '/root/ci-mock/pipelines/123#test', dropdown_path: '/root/ci-mock/pipelines/123/stage.json?stage=test', @@ -105,7 +105,7 @@ export default { has_details: true, details_path: '/root/ci-mock/builds/4166', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', action: { icon: 'retry', title: 'Retry', @@ -130,7 +130,7 @@ export default { has_details: true, details_path: '/root/ci-mock/builds/4166', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', action: { icon: 'retry', title: 'Retry', @@ -152,7 +152,7 @@ export default { has_details: true, details_path: '/root/ci-mock/builds/4159', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', action: { icon: 'retry', title: 'Retry', @@ -177,7 +177,7 @@ export default { has_details: true, details_path: '/root/ci-mock/builds/4159', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', action: { icon: 'retry', title: 'Retry', @@ -197,7 +197,7 @@ export default { has_details: true, details_path: '/root/ci-mock/pipelines/123#deploy', favicon: - '/assets/ci_favicons/dev/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.ico', + '/assets/ci_favicons/favicon_status_success-308b4fc054cdd1b68d0865e6cfb7b02e92e3472f201507418f8eddb74ac11a59.png', }, path: '/root/ci-mock/pipelines/123#deploy', dropdown_path: '/root/ci-mock/pipelines/123/stage.json?stage=deploy', diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index 22b9c631ed8..fdc5c0180e4 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -2,19 +2,19 @@ require 'rails_helper' RSpec.describe Gitlab::Favicon, :request_store do describe '.main' do - it 'defaults to favicon.ico' do + it 'defaults to favicon.png' do allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('production')) - expect(described_class.main).to eq 'favicon.ico' + expect(described_class.main).to match_asset_path '/assets/favicon.png' end it 'has blue favicon for development' do allow(Rails).to receive(:env).and_return(ActiveSupport::StringInquirer.new('development')) - expect(described_class.main).to eq 'favicon-blue.ico' + expect(described_class.main).to match_asset_path '/assets/favicon-blue.png' end it 'has yellow favicon for canary' do stub_env('CANARY', 'true') - expect(described_class.main).to eq 'favicon-yellow.ico' + expect(described_class.main).to match_asset_path 'favicon-yellow.png' end it 'uses the custom favicon if a favicon appearance is present' do @@ -27,7 +27,7 @@ RSpec.describe Gitlab::Favicon, :request_store do subject { described_class.status_overlay('favicon_status_created') } it 'returns the overlay for the status' do - expect(subject).to eq '/assets/ci_favicons/overlays/favicon_status_created.png' + expect(subject).to match_asset_path '/assets/ci_favicons/favicon_status_created.png' end end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 54ef0be67ff..3a6a6c116c2 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -173,7 +173,7 @@ describe JiraService do object: { url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/#{merge_request.diff_head_sha}", title: "GitLab: Solved by commit #{merge_request.diff_head_sha}.", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" }, + icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, status: { resolved: true } } ) diff --git a/spec/serializers/build_serializer_spec.rb b/spec/serializers/build_serializer_spec.rb index 98cd15e248b..52459cd369d 100644 --- a/spec/serializers/build_serializer_spec.rb +++ b/spec/serializers/build_serializer_spec.rb @@ -39,7 +39,7 @@ describe BuildSerializer do expect(subject[:label]).to eq('failed') expect(subject[:tooltip]).to eq('failed
(unknown failure)') expect(subject[:icon]).to eq(status.icon) - expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.ico") + expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.png") end end @@ -54,7 +54,7 @@ describe BuildSerializer do expect(subject[:label]).to eq('passed') expect(subject[:tooltip]).to eq('passed') expect(subject[:icon]).to eq(status.icon) - expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.ico") + expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.png") end end end diff --git a/spec/serializers/pipeline_serializer_spec.rb b/spec/serializers/pipeline_serializer_spec.rb index b741308e2c5..33c8213f9a7 100644 --- a/spec/serializers/pipeline_serializer_spec.rb +++ b/spec/serializers/pipeline_serializer_spec.rb @@ -174,7 +174,7 @@ describe PipelineSerializer do expect(subject[:text]).to eq(status.text) expect(subject[:label]).to eq(status.label) expect(subject[:icon]).to eq(status.icon) - expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.ico") + expect(subject[:favicon]).to match_asset_path("/assets/ci_favicons/#{status.favicon}.png") end end end diff --git a/spec/serializers/status_entity_spec.rb b/spec/serializers/status_entity_spec.rb index 559475e571c..73f81405d54 100644 --- a/spec/serializers/status_entity_spec.rb +++ b/spec/serializers/status_entity_spec.rb @@ -18,17 +18,17 @@ describe StatusEntity do it 'contains status details' do expect(subject).to include :text, :icon, :favicon, :label, :group, :tooltip expect(subject).to include :has_details, :details_path - expect(subject[:favicon]).to match_asset_path('/assets/ci_favicons/favicon_status_success.ico') + expect(subject[:favicon]).to match_asset_path('/assets/ci_favicons/favicon_status_success.png') end it 'contains a dev namespaced favicon if dev env' do allow(Rails.env).to receive(:development?) { true } - expect(entity.as_json[:favicon]).to match_asset_path('/assets/ci_favicons/dev/favicon_status_success.ico') + expect(entity.as_json[:favicon]).to match_asset_path('/assets/ci_favicons/favicon_status_success.png') end it 'contains a canary namespaced favicon if canary env' do stub_env('CANARY', 'true') - expect(entity.as_json[:favicon]).to match_asset_path('/assets/ci_favicons/canary/favicon_status_success.ico') + expect(entity.as_json[:favicon]).to match_asset_path('/assets/ci_favicons/canary/favicon_status_success.png') end end end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index e28b0ea5cf2..b7f38874c26 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -789,7 +789,7 @@ describe SystemNoteService do object: { url: project_commit_url(project, commit), title: "GitLab: Mentioned on commit - #{commit.title}", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" }, + icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, status: { resolved: false } } ) @@ -815,7 +815,7 @@ describe SystemNoteService do object: { url: project_issue_url(project, issue), title: "GitLab: Mentioned on issue - #{issue.title}", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" }, + icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, status: { resolved: false } } ) @@ -841,7 +841,7 @@ describe SystemNoteService do object: { url: project_snippet_url(project, snippet), title: "GitLab: Mentioned on snippet - #{snippet.title}", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.ico" }, + icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, status: { resolved: false } } ) -- cgit v1.2.1 From b4d84c07bcf143aeab7abccb8d0cdb849f605af5 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 5 Feb 2018 15:41:37 +0100 Subject: remove favicon preview on appearance page --- spec/features/admin/admin_appearance_spec.rb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index 0ac4f111c52..bd879635d2f 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -76,15 +76,14 @@ feature 'Admin Appearance' do expect(page).not_to have_css(header_logo_selector) end - scenario 'Favicon', :js do + scenario 'Favicon' do sign_in(create(:admin)) visit admin_appearances_path attach_file(:appearance_favicon, logo_fixture) click_button 'Save' - # 11 = 1 original + 10 overlay variations - expect(page).to have_css('.appearance-light-logo-preview', count: 11) + expect(page).to have_css('.appearance-light-logo-preview') click_link 'Remove favicon' -- cgit v1.2.1 From 256d959729f14094a490c102508e2878c1dd87fc Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 12 Apr 2018 14:11:21 +0200 Subject: ability to get an image's alternative version --- spec/controllers/uploads_controller_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'spec') diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 376b229ffc9..ae62039fb32 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -560,5 +560,27 @@ describe UploadsController do end end end + + context 'the version filename must match' do + let!(:appearance) { create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } + + context 'has a valid filename on the version file' do + it 'successfully returns the file' do + get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'favicon_main_dk.png' + + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Disposition']).to eq 'inline; filename="favicon_main_dk.png"' + end + end + + context 'has an invalid filename on the version file' do + it 'returns the original file' do + get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'favicon_bogusversion_dk.png' + + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Disposition']).to eq 'inline; filename="dk.png"' + end + end + end end end -- cgit v1.2.1 From 96d0b1c67bc1f2a2881298ff898954ba00cd563f Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Thu, 12 Apr 2018 14:13:06 +0200 Subject: require uploaded file's name to match in any case --- spec/controllers/uploads_controller_spec.rb | 92 +++++++++++++++++------------ 1 file changed, 54 insertions(+), 38 deletions(-) (limited to 'spec') diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index ae62039fb32..912aa82526a 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -136,7 +136,7 @@ describe UploadsController do context 'for PNG files' do it 'returns Content-Disposition: inline' do note = create(:note, :with_attachment, project: project) - get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'image.png' + get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png' expect(response['Content-Disposition']).to start_with('inline;') end @@ -145,7 +145,7 @@ describe UploadsController do context 'for SVG files' do it 'returns Content-Disposition: attachment' do note = create(:note, :with_svg_attachment, project: project) - get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'image.svg' + get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'unsanitized.svg' expect(response['Content-Disposition']).to start_with('attachment;') end @@ -164,7 +164,7 @@ describe UploadsController do end it "redirects to the sign in page" do - get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png" + get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" expect(response).to redirect_to(new_user_session_path) end @@ -172,14 +172,14 @@ describe UploadsController do context "when the user isn't blocked" do it "responds with status 200" do - get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png" + get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'user', mounted_as: 'avatar', id: user.id, filename: 'image.png' + get :show, model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png' response end @@ -189,14 +189,14 @@ describe UploadsController do context "when not signed in" do it "responds with status 200" do - get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "image.png" + get :show, model: "user", mounted_as: "avatar", id: user.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'user', mounted_as: 'avatar', id: user.id, filename: 'image.png' + get :show, model: 'user', mounted_as: 'avatar', id: user.id, filename: 'dk.png' response end @@ -214,14 +214,14 @@ describe UploadsController do context "when not signed in" do it "responds with status 200" do - get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'image.png' + get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png' response end @@ -234,14 +234,14 @@ describe UploadsController do end it "responds with status 200" do - get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'image.png' + get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png' response end @@ -256,7 +256,7 @@ describe UploadsController do context "when not signed in" do it "redirects to the sign in page" do - get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" expect(response).to redirect_to(new_user_session_path) end @@ -279,7 +279,7 @@ describe UploadsController do end it "redirects to the sign in page" do - get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" expect(response).to redirect_to(new_user_session_path) end @@ -287,14 +287,14 @@ describe UploadsController do context "when the user isn't blocked" do it "responds with status 200" do - get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'image.png' + get :show, model: 'project', mounted_as: 'avatar', id: project.id, filename: 'dk.png' response end @@ -304,7 +304,7 @@ describe UploadsController do context "when the user doesn't have access to the project" do it "responds with status 404" do - get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "image.png" + get :show, model: "project", mounted_as: "avatar", id: project.id, filename: "dk.png" expect(response).to have_gitlab_http_status(404) end @@ -319,14 +319,14 @@ describe UploadsController do context "when the group is public" do context "when not signed in" do it "responds with status 200" do - get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'image.png' + get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png' response end @@ -339,14 +339,14 @@ describe UploadsController do end it "responds with status 200" do - get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'image.png' + get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png' response end @@ -375,7 +375,7 @@ describe UploadsController do end it "redirects to the sign in page" do - get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" expect(response).to redirect_to(new_user_session_path) end @@ -383,14 +383,14 @@ describe UploadsController do context "when the user isn't blocked" do it "responds with status 200" do - get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'image.png' + get :show, model: 'group', mounted_as: 'avatar', id: group.id, filename: 'dk.png' response end @@ -400,7 +400,7 @@ describe UploadsController do context "when the user doesn't have access to the project" do it "responds with status 404" do - get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "image.png" + get :show, model: "group", mounted_as: "avatar", id: group.id, filename: "dk.png" expect(response).to have_gitlab_http_status(404) end @@ -420,14 +420,14 @@ describe UploadsController do context "when not signed in" do it "responds with status 200" do - get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'image.png' + get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png' response end @@ -440,14 +440,14 @@ describe UploadsController do end it "responds with status 200" do - get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'image.png' + get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png' response end @@ -462,7 +462,7 @@ describe UploadsController do context "when not signed in" do it "redirects to the sign in page" do - get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" expect(response).to redirect_to(new_user_session_path) end @@ -485,7 +485,7 @@ describe UploadsController do end it "redirects to the sign in page" do - get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" expect(response).to redirect_to(new_user_session_path) end @@ -493,14 +493,14 @@ describe UploadsController do context "when the user isn't blocked" do it "responds with status 200" do - get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" expect(response).to have_gitlab_http_status(200) end it_behaves_like 'content not cached without revalidation' do subject do - get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'image.png' + get :show, model: 'note', mounted_as: 'attachment', id: note.id, filename: 'dk.png' response end @@ -510,7 +510,7 @@ describe UploadsController do context "when the user doesn't have access to the project" do it "responds with status 404" do - get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "image.png" + get :show, model: "note", mounted_as: "attachment", id: note.id, filename: "dk.png" expect(response).to have_gitlab_http_status(404) end @@ -561,24 +561,40 @@ describe UploadsController do end end - context 'the version filename must match' do + context 'original filename or a version filename must match' do let!(:appearance) { create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } + context 'has a valid filename on the original file' do + it 'successfully returns the file' do + get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'dk.png' + + expect(response).to have_gitlab_http_status(200) + expect(response.header['Content-Disposition']).to end_with 'filename="dk.png"' + end + end + + context 'has an invalid filename on the original file' do + it 'returns a 404' do + get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'bogus.png' + + expect(response).to have_gitlab_http_status(404) + end + end + context 'has a valid filename on the version file' do it 'successfully returns the file' do get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'favicon_main_dk.png' expect(response).to have_gitlab_http_status(200) - expect(response.header['Content-Disposition']).to eq 'inline; filename="favicon_main_dk.png"' + expect(response.header['Content-Disposition']).to end_with 'filename="favicon_main_dk.png"' end end context 'has an invalid filename on the version file' do - it 'returns the original file' do + it 'returns a 404' do get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'favicon_bogusversion_dk.png' - expect(response).to have_gitlab_http_status(200) - expect(response.header['Content-Disposition']).to eq 'inline; filename="dk.png"' + expect(response).to have_gitlab_http_status(404) end end end -- cgit v1.2.1 From 7706b3a471de37240c0da6fcc14c7d38c6d62eb9 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 13 Apr 2018 22:30:08 +0200 Subject: use Gitlab::Favicon for jira service --- spec/models/project_services/jira_service_spec.rb | 18 +++++++++++++++++- spec/services/system_note_service_spec.rb | 8 +++++--- 2 files changed, 22 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 3a6a6c116c2..50bdb80ff92 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -164,6 +164,8 @@ describe JiraService do it "creates Remote Link reference in JIRA for comment" do @jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project)) + favicon_path = "http://localhost/assets/#{Rails.application.assets.find_asset('favicon.png').digest_path}" + # Creates comment expect(WebMock).to have_requested(:post, @comment_url) # Creates Remote Link in JIRA issue fields @@ -173,7 +175,7 @@ describe JiraService do object: { url: "#{Gitlab.config.gitlab.url}/#{project.full_path}/commit/#{merge_request.diff_head_sha}", title: "GitLab: Solved by commit #{merge_request.diff_head_sha}.", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, + icon: { title: "GitLab", url16x16: favicon_path }, status: { resolved: true } } ) @@ -464,4 +466,18 @@ describe JiraService do end end end + + describe 'favicon urls', :request_store do + it 'includes the standard favicon' do + props = described_class.new.send(:build_remote_link_props, url: 'http://example.com', title: 'title') + expect(props[:object][:icon][:url16x16]).to match %r{^http://localhost/assets/favicon(?:-\h+).png$} + end + + it 'includes returns the custom favicon' do + create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) + + props = described_class.new.send(:build_remote_link_props, url: 'http://example.com', title: 'title') + expect(props[:object][:icon][:url16x16]).to match %r{^http://localhost/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.png$} + end + end end diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index b7f38874c26..e2ee421921c 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -769,6 +769,8 @@ describe SystemNoteService do end describe "new reference" do + let(:favicon_path) { "http://localhost/assets/#{Rails.application.assets.find_asset('favicon.png').digest_path}" } + before do allow(JIRA::Resource::Remotelink).to receive(:all).and_return([]) end @@ -789,7 +791,7 @@ describe SystemNoteService do object: { url: project_commit_url(project, commit), title: "GitLab: Mentioned on commit - #{commit.title}", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, + icon: { title: "GitLab", url16x16: favicon_path }, status: { resolved: false } } ) @@ -815,7 +817,7 @@ describe SystemNoteService do object: { url: project_issue_url(project, issue), title: "GitLab: Mentioned on issue - #{issue.title}", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, + icon: { title: "GitLab", url16x16: favicon_path }, status: { resolved: false } } ) @@ -841,7 +843,7 @@ describe SystemNoteService do object: { url: project_snippet_url(project, snippet), title: "GitLab: Mentioned on snippet - #{snippet.title}", - icon: { title: "GitLab", url16x16: "http://localhost/favicon.png" }, + icon: { title: "GitLab", url16x16: favicon_path }, status: { resolved: false } } ) -- cgit v1.2.1 From 1e9c33acd1129557124e330df2f178fb097d67e5 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Sat, 14 Apr 2018 15:37:32 +0200 Subject: remove obsolete favicon related spec the favicon variations don't need to be tested on the entity anymore, as they are A) tested in the dedicated `Gitlab::Favicon` and B) they are created on the client (i.e. the overlays are always the same for all base favicon variants). --- spec/serializers/status_entity_spec.rb | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'spec') diff --git a/spec/serializers/status_entity_spec.rb b/spec/serializers/status_entity_spec.rb index 73f81405d54..0b010ebd507 100644 --- a/spec/serializers/status_entity_spec.rb +++ b/spec/serializers/status_entity_spec.rb @@ -20,15 +20,5 @@ describe StatusEntity do expect(subject).to include :has_details, :details_path expect(subject[:favicon]).to match_asset_path('/assets/ci_favicons/favicon_status_success.png') end - - it 'contains a dev namespaced favicon if dev env' do - allow(Rails.env).to receive(:development?) { true } - expect(entity.as_json[:favicon]).to match_asset_path('/assets/ci_favicons/favicon_status_success.png') - end - - it 'contains a canary namespaced favicon if canary env' do - stub_env('CANARY', 'true') - expect(entity.as_json[:favicon]).to match_asset_path('/assets/ci_favicons/canary/favicon_status_success.png') - end end end -- cgit v1.2.1 From 197932a2225904898778e7edadc0e447b91cc2ef Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 30 Apr 2018 12:45:07 +0200 Subject: allow only png, ico for favicon uploads the related omnibus graphicsmagick package only supports those formats. see https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests/1975 --- spec/features/admin/admin_appearance_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/admin/admin_appearance_spec.rb b/spec/features/admin/admin_appearance_spec.rb index bd879635d2f..a5e0ac592b9 100644 --- a/spec/features/admin/admin_appearance_spec.rb +++ b/spec/features/admin/admin_appearance_spec.rb @@ -93,7 +93,7 @@ feature 'Admin Appearance' do attach_file(:appearance_favicon, Rails.root.join('spec', 'fixtures', 'sanitized.svg')) click_button 'Save' - expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, jpg, jpeg, gif, bmp, tiff, ico' + expect(page).to have_content 'Favicon You are not allowed to upload "svg" files, allowed types: png, ico' end def expect_custom_sign_in_appearance(appearance) -- cgit v1.2.1 From 6f4a0a92e6331b7033a8165c5b5e9cc7b0f880c2 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sun, 3 Jun 2018 04:36:22 -0700 Subject: Eliminate N+1 queries with authors and push_data_payload in Events API --- spec/requests/api/events_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/events_spec.rb b/spec/requests/api/events_spec.rb index 962c845f36d..e6a61fdcf39 100644 --- a/spec/requests/api/events_spec.rb +++ b/spec/requests/api/events_spec.rb @@ -176,7 +176,7 @@ describe API::Events do end it 'avoids N+1 queries' do - control_count = ActiveRecord::QueryRecorder.new do + control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do get api("/projects/#{private_project.id}/events", user), target_type: :merge_request end.count @@ -184,7 +184,7 @@ describe API::Events do expect do get api("/projects/#{private_project.id}/events", user), target_type: :merge_request - end.not_to exceed_query_limit(control_count) + end.not_to exceed_all_query_limit(control_count) expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers -- cgit v1.2.1 From 53d1c87c8673fa6c9d83519490698b37d67572df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Tue, 5 Jun 2018 16:17:04 +0200 Subject: Fix Fog mocking --- spec/initializers/fog_google_https_private_urls_spec.rb | 12 ++++++------ spec/lib/backup/manager_spec.rb | 7 ++----- spec/lib/object_storage/direct_upload_spec.rb | 4 ++++ spec/spec_helper.rb | 4 ++++ spec/uploaders/object_storage_spec.rb | 7 ------- 5 files changed, 16 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/initializers/fog_google_https_private_urls_spec.rb b/spec/initializers/fog_google_https_private_urls_spec.rb index de3c157ab7b..08346b71fee 100644 --- a/spec/initializers/fog_google_https_private_urls_spec.rb +++ b/spec/initializers/fog_google_https_private_urls_spec.rb @@ -1,13 +1,13 @@ require 'spec_helper' -describe 'Fog::Storage::GoogleXML::File' do +describe 'Fog::Storage::GoogleXML::File', :fog_requests do let(:storage) do Fog.mock! - Fog::Storage.new({ - google_storage_access_key_id: "asdf", - google_storage_secret_access_key: "asdf", - provider: "Google" - }) + Fog::Storage.new( + google_storage_access_key_id: "asdf", + google_storage_secret_access_key: "asdf", + provider: "Google" + ) end let(:file) do diff --git a/spec/lib/backup/manager_spec.rb b/spec/lib/backup/manager_spec.rb index 23c04a1a101..ca319679e80 100644 --- a/spec/lib/backup/manager_spec.rb +++ b/spec/lib/backup/manager_spec.rb @@ -274,16 +274,13 @@ describe Backup::Manager do } ) - # the Fog mock only knows about directories we create explicitly Fog.mock! + + # the Fog mock only knows about directories we create explicitly connection = ::Fog::Storage.new(Gitlab.config.backup.upload.connection.symbolize_keys) connection.directories.create(key: Gitlab.config.backup.upload.remote_directory) end - after do - Fog.unmock! - end - context 'target path' do it 'uses the tar filename by default' do expect_any_instance_of(Fog::Collection).to receive(:create) diff --git a/spec/lib/object_storage/direct_upload_spec.rb b/spec/lib/object_storage/direct_upload_spec.rb index 5187821e8f4..e0569218d78 100644 --- a/spec/lib/object_storage/direct_upload_spec.rb +++ b/spec/lib/object_storage/direct_upload_spec.rb @@ -17,6 +17,10 @@ describe ObjectStorage::DirectUpload do let(:direct_upload) { described_class.new(credentials, bucket_name, object_name, has_length: has_length, maximum_size: maximum_size) } + before do + Fog.unmock! + end + describe '#has_length' do context 'is known' do let(:has_length) { true } diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index d3de2331244..e093444121a 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -133,6 +133,10 @@ RSpec.configure do |config| RequestStore.clear! end + config.after(:example) do + Fog.unmock! if Fog.mock? + end + config.before(:example, :mailer) do reset_delivered_emails! end diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index 01166865e88..fb51ae4c02c 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -360,13 +360,6 @@ describe ObjectStorage do subject { uploader_class.workhorse_authorize(has_length: has_length, maximum_size: maximum_size) } - before do - # ensure that we use regular Fog libraries - # other tests might call `Fog.mock!` and - # it will make tests to fail - Fog.unmock! - end - shared_examples 'uses local storage' do it "returns temporary path" do is_expected.to have_key(:TempPath) -- cgit v1.2.1 From a0808df0b627180d7773d5d13a0f64d6e7c45f5d Mon Sep 17 00:00:00 2001 From: "Jacob Vosmaer (GitLab)" Date: Tue, 5 Jun 2018 15:51:14 +0000 Subject: Find and mark more Git disk access locations --- .../projects/import_export/import_file_spec.rb | 6 ++- spec/lib/backup/files_spec.rb | 4 +- spec/lib/backup/repository_spec.rb | 4 +- .../gitlab/bare_repository_import/importer_spec.rb | 7 ++++ .../bare_repository_import/repository_spec.rb | 6 ++- spec/lib/gitlab/git/repository_spec.rb | 4 ++ spec/lib/gitlab/git/rev_list_spec.rb | 4 +- spec/lib/gitlab/git_access_spec.rb | 32 ++++++++-------- spec/lib/gitlab/import_export/fork_spec.rb | 6 ++- .../lib/gitlab/import_export/repo_restorer_spec.rb | 10 +++-- spec/lib/gitlab/shell_spec.rb | 6 ++- spec/models/merge_request_spec.rb | 12 +++++- spec/models/namespace_spec.rb | 10 ++++- spec/models/repository_spec.rb | 43 +++++++++++++++++++--- spec/requests/api/tags_spec.rb | 5 ++- spec/services/projects/transfer_service_spec.rb | 14 +++++-- spec/services/projects/update_service_spec.rb | 4 +- spec/support/helpers/cycle_analytics_helpers.rb | 6 ++- spec/tasks/gitlab/backup_rake_spec.rb | 19 +++++++--- .../single_repository_worker_spec.rb | 8 +++- 20 files changed, 158 insertions(+), 52 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index 60fe30bd898..d0912e645bc 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -87,11 +87,13 @@ feature 'Import/Export - project import integration test', :js do def wiki_exists?(project) wiki = ProjectWiki.new(project) - File.exist?(wiki.repository.path_to_repo) && !wiki.repository.empty? + wiki.repository.exists? && !wiki.repository.empty? end def project_hook_exists?(project) - Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository).exists? + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository).exists? + end end def click_import_project_tab diff --git a/spec/lib/backup/files_spec.rb b/spec/lib/backup/files_spec.rb index 99872211a4e..63f2298357f 100644 --- a/spec/lib/backup/files_spec.rb +++ b/spec/lib/backup/files_spec.rb @@ -46,7 +46,9 @@ describe Backup::Files do end it 'calls tar command with unlink' do - expect(subject).to receive(:run_pipeline!).with([%w(gzip -cd), %w(tar --unlink-first --recursive-unlink -C /var/gitlab-registry -xf -)], any_args) + expect(subject).to receive(:tar).and_return('blabla-tar') + + expect(subject).to receive(:run_pipeline!).with([%w(gzip -cd), %w(blabla-tar --unlink-first --recursive-unlink -C /var/gitlab-registry -xf -)], any_args) subject.restore end end diff --git a/spec/lib/backup/repository_spec.rb b/spec/lib/backup/repository_spec.rb index f583b2021a2..92a27e308d2 100644 --- a/spec/lib/backup/repository_spec.rb +++ b/spec/lib/backup/repository_spec.rb @@ -34,7 +34,9 @@ describe Backup::Repository do let(:timestamp) { Time.utc(2017, 3, 22) } let(:temp_dirs) do Gitlab.config.repositories.storages.map do |name, storage| - File.join(storage.legacy_disk_path, '..', 'repositories.old.' + timestamp.to_i.to_s) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + File.join(storage.legacy_disk_path, '..', 'repositories.old.' + timestamp.to_i.to_s) + end end end diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb index 5c8a19a53bc..468f6ff6d24 100644 --- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb @@ -20,6 +20,13 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do Rainbow.enabled = @rainbow end + around do |example| + # TODO migrate BareRepositoryImport https://gitlab.com/gitlab-org/gitaly/issues/953 + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + shared_examples 'importing a repository' do describe '.execute' do it 'creates a project for a repository in storage' do diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb index 1504826c7a5..afd8f5da39f 100644 --- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb +++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb @@ -62,8 +62,10 @@ describe ::Gitlab::BareRepositoryImport::Repository do before do gitlab_shell.create_repository(repository_storage, hashed_path) - repository = Rugged::Repository.new(repo_path) - repository.config['gitlab.fullpath'] = 'to/repo' + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository = Rugged::Repository.new(repo_path) + repository.config['gitlab.fullpath'] = 'to/repo' + end end after do diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 20b0b2c53a0..8dd7911f49c 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -159,6 +159,7 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:feature2) { 'feature2' } around do |example| + # discover_default_branch will be moved to gitaly-ruby Gitlab::GitalyClient::StorageSettings.allow_disk_access do example.run end @@ -373,6 +374,7 @@ describe Gitlab::Git::Repository, seed_helper: true do context '#submodules' do around do |example| + # TODO #submodules will be removed, has been migrated to gitaly Gitlab::GitalyClient::StorageSettings.allow_disk_access do example.run end @@ -1055,6 +1057,7 @@ describe Gitlab::Git::Repository, seed_helper: true do describe "#rugged_commits_between" do around do |example| + # TODO #rugged_commits_between will be removed, has been migrated to gitaly Gitlab::GitalyClient::StorageSettings.allow_disk_access do example.run end @@ -1703,6 +1706,7 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:refs) { ['deadbeef', SeedRepo::RubyBlob::ID, '909e6157199'] } around do |example| + # TODO #batch_existence isn't used anywhere, can we remove it? Gitlab::GitalyClient::StorageSettings.allow_disk_access do example.run end diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index 32ec1e029c8..95dc47e2a00 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -9,9 +9,11 @@ describe Gitlab::Git::RevList do end def stub_popen_rev_list(*additional_args, with_lazy_block: true, output:) + repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.path } + params = [ args_for_popen(additional_args), - repository.path, + repo_path, {}, hash_including(lazy_block: with_lazy_block ? anything : nil) ] diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index dfffea7797f..0d5f6a0b576 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -552,7 +552,7 @@ describe Gitlab::GitAccess do it 'returns not found' do project.add_guest(user) repo = project.repository - FileUtils.rm_rf(repo.path) + Gitlab::GitalyClient::StorageSettings.allow_disk_access { FileUtils.rm_rf(repo.path) } # Sanity check for rm_rf expect(repo.exists?).to eq(false) @@ -750,20 +750,22 @@ describe Gitlab::GitAccess do def merge_into_protected_branch @protected_branch_merge_commit ||= begin - stub_git_hooks - project.repository.add_branch(user, unprotected_branch, 'feature') - target_branch = project.repository.lookup('feature') - source_branch = project.repository.create_file( - user, - 'filename', - 'This is the file content', - message: 'This is a good commit message', - branch_name: unprotected_branch) - rugged = project.repository.rugged - author = { email: "email@example.com", time: Time.now, name: "Example Git User" } - - merge_index = rugged.merge_commits(target_branch, source_branch) - Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged)) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + stub_git_hooks + project.repository.add_branch(user, unprotected_branch, 'feature') + target_branch = project.repository.lookup('feature') + source_branch = project.repository.create_file( + user, + 'filename', + 'This is the file content', + message: 'This is a good commit message', + branch_name: unprotected_branch) + rugged = project.repository.rugged + author = { email: "email@example.com", time: Time.now, name: "Example Git User" } + + merge_index = rugged.merge_commits(target_branch, source_branch) + Rugged::Commit.create(rugged, author: author, committer: author, message: "commit message", parents: [target_branch, source_branch], tree: merge_index.write_tree(rugged)) + end end end diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb index 17e06a6a83f..71fd5a51c3b 100644 --- a/spec/lib/gitlab/import_export/fork_spec.rb +++ b/spec/lib/gitlab/import_export/fork_spec.rb @@ -41,8 +41,10 @@ describe 'forked project import' do after do FileUtils.rm_rf(export_path) - FileUtils.rm_rf(project_with_repo.repository.path_to_repo) - FileUtils.rm_rf(project.repository.path_to_repo) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + FileUtils.rm_rf(project_with_repo.repository.path_to_repo) + FileUtils.rm_rf(project.repository.path_to_repo) + end end it 'can access the MR' do diff --git a/spec/lib/gitlab/import_export/repo_restorer_spec.rb b/spec/lib/gitlab/import_export/repo_restorer_spec.rb index dc806d036ff..013b8895f67 100644 --- a/spec/lib/gitlab/import_export/repo_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/repo_restorer_spec.rb @@ -23,8 +23,10 @@ describe Gitlab::ImportExport::RepoRestorer do after do FileUtils.rm_rf(export_path) - FileUtils.rm_rf(project_with_repo.repository.path_to_repo) - FileUtils.rm_rf(project.repository.path_to_repo) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + FileUtils.rm_rf(project_with_repo.repository.path_to_repo) + FileUtils.rm_rf(project.repository.path_to_repo) + end end it 'restores the repo successfully' do @@ -34,7 +36,9 @@ describe Gitlab::ImportExport::RepoRestorer do it 'has the webhooks' do restorer.restore - expect(Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository)).to exist + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + expect(Gitlab::Git::Hook.new('post-receive', project.repository.raw_repository)).to exist + end end end end diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index bf6ee4b0b59..14eae22a2ec 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -405,7 +405,11 @@ describe Gitlab::Shell do describe '#create_repository' do shared_examples '#create_repository' do let(:repository_storage) { 'default' } - let(:repository_storage_path) { Gitlab.config.repositories.storages[repository_storage].legacy_disk_path } + let(:repository_storage_path) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab.config.repositories.storages[repository_storage].legacy_disk_path + end + end let(:repo_name) { 'project/path' } let(:created_path) { File.join(repository_storage_path, repo_name + '.git') } diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 7e85a99494a..3f028b3bd5c 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -16,7 +16,11 @@ describe MergeRequest do describe '#squash_in_progress?' do shared_examples 'checking whether a squash is in progress' do - let(:repo_path) { subject.source_project.repository.path } + let(:repo_path) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + subject.source_project.repository.path + end + end let(:squash_path) { File.join(repo_path, "gitlab-worktree", "squash-#{subject.id}") } before do @@ -2197,7 +2201,11 @@ describe MergeRequest do describe '#rebase_in_progress?' do shared_examples 'checking whether a rebase is in progress' do - let(:repo_path) { subject.source_project.repository.path } + let(:repo_path) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + subject.source_project.repository.path + end + end let(:rebase_path) { File.join(repo_path, "gitlab-worktree", "rebase-#{subject.id}") } before do diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 6f702d8d95e..18b01c3e6b7 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -301,12 +301,18 @@ describe Namespace do end def project_rugged(project) - project.repository.rugged + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.rugged + end end end describe '#rm_dir', 'callback' do - let(:repository_storage_path) { Gitlab.config.repositories.storages.default.legacy_disk_path } + let(:repository_storage_path) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab.config.repositories.storages.default.legacy_disk_path + end + end let(:path_in_dir) { File.join(repository_storage_path, namespace.full_path) } let(:deleted_path) { namespace.full_path.gsub(namespace.path, "#{namespace.full_path}+#{namespace.id}+deleted") } let(:deleted_path_in_dir) { File.join(repository_storage_path, deleted_path) } diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 0ccf55bd895..c1aa7d80c94 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -136,7 +136,10 @@ describe Repository do before do options = { message: 'test tag message\n', tagger: { name: 'John Smith', email: 'john@gmail.com' } } - repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options) + + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged.tags.create(annotated_tag_name, 'a48e4fc218069f68ef2e769dd8dfea3991362175', options) + end double_first = double(committed_date: Time.now - 1.second) double_last = double(committed_date: Time.now) @@ -1048,6 +1051,13 @@ describe Repository do let(:target_project) { project } let(:target_repository) { target_project.repository } + around do |example| + # TODO Gitlab::Git::OperationService will be moved to gitaly-ruby and disappear from this repo + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + context 'when pre hooks were successful' do before do service = Gitlab::Git::HooksService.new @@ -1309,6 +1319,13 @@ describe Repository do end describe '#update_autocrlf_option' do + around do |example| + # TODO Gitlab::Git::OperationService will be moved to gitaly-ruby and disappear from this repo + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + describe 'when autocrlf is not already set to :input' do before do repository.raw_repository.autocrlf = true @@ -1802,7 +1819,9 @@ describe Repository do expect(repository.branch_count).to be_an(Integer) # NOTE: Until rugged goes away, make sure rugged and gitaly are in sync - rugged_count = repository.raw_repository.rugged.branches.count + rugged_count = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.raw_repository.rugged.branches.count + end expect(repository.branch_count).to eq(rugged_count) end @@ -1813,7 +1832,9 @@ describe Repository do expect(repository.tag_count).to be_an(Integer) # NOTE: Until rugged goes away, make sure rugged and gitaly are in sync - rugged_count = repository.raw_repository.rugged.tags.count + rugged_count = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.raw_repository.rugged.tags.count + end expect(repository.tag_count).to eq(rugged_count) end @@ -2073,7 +2094,10 @@ describe Repository do it "attempting to call keep_around on truncated ref does not fail" do repository.keep_around(sample_commit.id) ref = repository.send(:keep_around_ref_name, sample_commit.id) - path = File.join(repository.path, ref) + + path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + File.join(repository.path, ref) + end # Corrupt the reference File.truncate(path, 0) @@ -2088,6 +2112,13 @@ describe Repository do end describe '#update_ref' do + around do |example| + # TODO Gitlab::Git::OperationService will be moved to gitaly-ruby and disappear from this repo + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + it 'can create a ref' do Gitlab::Git::OperationService.new(nil, repository.raw_repository).send(:update_ref, 'refs/heads/foobar', 'refs/heads/master', Gitlab::Git::BLANK_SHA) @@ -2372,7 +2403,9 @@ describe Repository do end def create_remote_branch(remote_name, branch_name, target) - rugged = repository.rugged + rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged + end rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", target.id) end diff --git a/spec/requests/api/tags_spec.rb b/spec/requests/api/tags_spec.rb index e2b19ad59f9..969710d6613 100644 --- a/spec/requests/api/tags_spec.rb +++ b/spec/requests/api/tags_spec.rb @@ -287,7 +287,10 @@ describe API::Tags do context 'annotated tag' do it 'creates a new annotated tag' do # Identity must be set in .gitconfig to create annotated tag. - repo_path = project.repository.path_to_repo + repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.path_to_repo + end + system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.name #{user.name})) system(*%W(#{Gitlab.config.git.bin_path} --git-dir=#{repo_path} config user.email #{user.email})) diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 3e6483d7e28..5100987c2fe 100644 --- a/spec/services/projects/transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb @@ -64,7 +64,7 @@ describe Projects::TransferService do it 'updates project full path in .git/config' do transfer_project(project, user, group) - expect(project.repository.rugged.config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" + expect(rugged_config['gitlab.fullpath']).to eq "#{group.full_path}/#{project.path}" end end @@ -84,7 +84,9 @@ describe Projects::TransferService do end def project_path(project) - project.repository.path_to_repo + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.path_to_repo + end end def current_path @@ -101,7 +103,7 @@ describe Projects::TransferService do it 'rolls back project full path in .git/config' do attempt_project_transfer - expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path + expect(rugged_config['gitlab.fullpath']).to eq project.full_path end it "doesn't send move notifications" do @@ -264,4 +266,10 @@ describe Projects::TransferService do transfer_project(project, owner, group) end end + + def rugged_config + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.rugged.config + end + end end diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb index 1f761bcbbad..ecf1ba05618 100644 --- a/spec/services/projects/update_service_spec.rb +++ b/spec/services/projects/update_service_spec.rb @@ -125,7 +125,7 @@ describe Projects::UpdateService do context 'when we update project but not enabling a wiki' do it 'does not try to create an empty wiki' do - FileUtils.rm_rf(project.wiki.repository.path) + Gitlab::Shell.new.rm_directory(project.repository_storage, project.wiki.path) result = update_project(project, user, { name: 'test1' }) @@ -146,7 +146,7 @@ describe Projects::UpdateService do context 'when enabling a wiki' do it 'creates a wiki' do project.project_feature.update(wiki_access_level: ProjectFeature::DISABLED) - FileUtils.rm_rf(project.wiki.repository.path) + Gitlab::Shell.new.rm_directory(project.repository_storage, project.wiki.path) result = update_project(project, user, project_feature_attributes: { wiki_access_level: ProjectFeature::ENABLED }) diff --git a/spec/support/helpers/cycle_analytics_helpers.rb b/spec/support/helpers/cycle_analytics_helpers.rb index 06a76d53354..32d9807f06a 100644 --- a/spec/support/helpers/cycle_analytics_helpers.rb +++ b/spec/support/helpers/cycle_analytics_helpers.rb @@ -123,7 +123,11 @@ module CycleAnalyticsHelpers if branch_update.newrev _, opts = args - commit = raw_repository.commit(branch_update.newrev).rugged_commit + + commit = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + raw_repository.commit(branch_update.newrev).rugged_commit + end + branch_update.newrev = commit.amend( update_ref: "#{Gitlab::Git::BRANCH_REF_PREFIX}#{opts[:branch_name]}", author: commit.author.merge(time: new_date), diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index c9252bebb2e..93a436cb2b5 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -101,7 +101,9 @@ describe 'gitlab:app namespace rake task' do before do stub_env('SKIP', 'db') - path = File.join(project.repository.path_to_repo, 'custom_hooks') + path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + File.join(project.repository.path_to_repo, 'custom_hooks') + end FileUtils.mkdir_p(path) FileUtils.touch(File.join(path, "dummy.txt")) end @@ -122,7 +124,10 @@ describe 'gitlab:app namespace rake task' do expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout expect { run_rake_task('gitlab:backup:restore') }.to output.to_stdout - expect(Dir.entries(File.join(project.repository.path, 'custom_hooks'))).to include("dummy.txt") + repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.path + end + expect(Dir.entries(File.join(repo_path, 'custom_hooks'))).to include("dummy.txt") end end @@ -243,10 +248,12 @@ describe 'gitlab:app namespace rake task' do FileUtils.mkdir_p(b_storage_dir) # Even when overriding the storage, we have to move it there, so it exists - FileUtils.mv( - File.join(Settings.absolute(storages['default'].legacy_disk_path), project_b.repository.disk_path + '.git'), - Rails.root.join(storages['test_second_storage'].legacy_disk_path, project_b.repository.disk_path + '.git') - ) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + FileUtils.mv( + File.join(Settings.absolute(storages['default'].legacy_disk_path), project_b.repository.disk_path + '.git'), + Rails.root.join(storages['test_second_storage'].legacy_disk_path, project_b.repository.disk_path + '.git') + ) + end expect { run_rake_task('gitlab:backup:create') }.to output.to_stdout diff --git a/spec/workers/repository_check/single_repository_worker_spec.rb b/spec/workers/repository_check/single_repository_worker_spec.rb index a021235aed6..22fc64c1536 100644 --- a/spec/workers/repository_check/single_repository_worker_spec.rb +++ b/spec/workers/repository_check/single_repository_worker_spec.rb @@ -88,7 +88,9 @@ describe RepositoryCheck::SingleRepositoryWorker do end def break_wiki(project) - break_repo(wiki_path(project)) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + break_repo(wiki_path(project)) + end end def wiki_path(project) @@ -96,7 +98,9 @@ describe RepositoryCheck::SingleRepositoryWorker do end def break_project(project) - break_repo(project.repository.path_to_repo) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + break_repo(project.repository.path_to_repo) + end end def break_repo(repo) -- cgit v1.2.1 From 7519a25a6161b2ca540ca9fc4e42e4b03aed4eeb Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 5 Jun 2018 17:21:33 +0100 Subject: Use `started` key to show the triggered date --- spec/javascripts/jobs/header_spec.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/jobs/header_spec.js b/spec/javascripts/jobs/header_spec.js index 4f861c39d3f..cef30a007db 100644 --- a/spec/javascripts/jobs/header_spec.js +++ b/spec/javascripts/jobs/header_spec.js @@ -13,6 +13,9 @@ describe('Job details header', () => { const threeWeeksAgo = new Date(); threeWeeksAgo.setDate(threeWeeksAgo.getDate() - 21); + const twoDaysAgo = new Date(); + twoDaysAgo.setDate(twoDaysAgo.getDate() - 2); + props = { job: { status: { @@ -31,7 +34,7 @@ describe('Job details header', () => { email: 'foo@bar.com', avatar_url: 'link', }, - started: '2018-01-08T09:48:27.319Z', + started: twoDaysAgo.toISOString(), new_issue_path: 'path', }, isLoading: false, @@ -69,7 +72,7 @@ describe('Job details header', () => { .querySelector('.header-main-content') .textContent.replace(/\s+/g, ' ') .trim(), - ).toEqual('failed Job #123 triggered 3 weeks ago by Foo'); + ).toEqual('failed Job #123 triggered 2 days ago by Foo'); }); it('should render new issue link', () => { -- cgit v1.2.1 From df5b4c0038c31385c3e4452115becd9f8fc335e4 Mon Sep 17 00:00:00 2001 From: Sam Beckham Date: Tue, 5 Jun 2018 16:38:22 +0000 Subject: Resolve "BS4: Pagination is pipeline's page has no styling" --- spec/javascripts/vue_shared/components/table_pagination_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/vue_shared/components/table_pagination_spec.js b/spec/javascripts/vue_shared/components/table_pagination_spec.js index c63f15e5880..c36b607a34e 100644 --- a/spec/javascripts/vue_shared/components/table_pagination_spec.js +++ b/spec/javascripts/vue_shared/components/table_pagination_spec.js @@ -51,7 +51,7 @@ describe('Pagination component', () => { expect( component.$el.querySelector('.js-previous-button').classList.contains('disabled'), - ).toEqual(true); + ).toEqual(true); component.$el.querySelector('.js-previous-button a').click(); -- cgit v1.2.1 From fc916b068199f2624c5b9cfeb0389760448910ff Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Sun, 27 May 2018 22:02:47 +0200 Subject: Migrate jobs in object_storage_upload queue --- ...ate_object_storage_upload_sidekiq_queue_spec.rb | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb (limited to 'spec') diff --git a/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb b/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb new file mode 100644 index 00000000000..1ee6c440cf4 --- /dev/null +++ b/spec/migrations/migrate_object_storage_upload_sidekiq_queue_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +require Rails.root.join('db', 'post_migrate', '20180603190921_migrate_object_storage_upload_sidekiq_queue.rb') + +describe MigrateObjectStorageUploadSidekiqQueue, :sidekiq, :redis do + include Gitlab::Database::MigrationHelpers + + context 'when there are jobs in the queue' do + it 'correctly migrates queue when migrating up' do + Sidekiq::Testing.disable! do + stubbed_worker(queue: 'object_storage_upload').perform_async('Something', [1]) + stubbed_worker(queue: 'object_storage:object_storage_background_move').perform_async('Something', [1]) + + described_class.new.up + + expect(sidekiq_queue_length('object_storage_upload')).to eq 0 + expect(sidekiq_queue_length('object_storage:object_storage_background_move')).to eq 2 + end + end + end + + context 'when there are no jobs in the queues' do + it 'does not raise error when migrating up' do + expect { described_class.new.up }.not_to raise_error + end + end + + def stubbed_worker(queue:) + Class.new do + include Sidekiq::Worker + sidekiq_options queue: queue + end + end +end -- cgit v1.2.1 From 9c6c17cbcdb8bf8185fc1b873dcfd08f723e4df5 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 16 Aug 2017 14:04:41 +0100 Subject: Add a minimal GraphQL API --- spec/controllers/graphql_controller_spec.rb | 58 ++++++++++++++++++++++++ spec/graphql/gitlab_schema_spec.rb | 27 +++++++++++ spec/graphql/loaders/full_path_loader_spec.rb | 38 ++++++++++++++++ spec/graphql/loaders/iid_loader_spec.rb | 64 +++++++++++++++++++++++++++ spec/graphql/types/query_type_spec.rb | 37 ++++++++++++++++ spec/graphql/types/time_type_spec.rb | 16 +++++++ spec/lib/gitlab/path_regex_spec.rb | 12 ++--- spec/support/helpers/graphql_helpers.rb | 29 ++++++++++++ spec/support/matchers/graphql_matchers.rb | 31 +++++++++++++ 9 files changed, 307 insertions(+), 5 deletions(-) create mode 100644 spec/controllers/graphql_controller_spec.rb create mode 100644 spec/graphql/gitlab_schema_spec.rb create mode 100644 spec/graphql/loaders/full_path_loader_spec.rb create mode 100644 spec/graphql/loaders/iid_loader_spec.rb create mode 100644 spec/graphql/types/query_type_spec.rb create mode 100644 spec/graphql/types/time_type_spec.rb create mode 100644 spec/support/helpers/graphql_helpers.rb create mode 100644 spec/support/matchers/graphql_matchers.rb (limited to 'spec') diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb new file mode 100644 index 00000000000..d6689dbc3c6 --- /dev/null +++ b/spec/controllers/graphql_controller_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe GraphqlController do + describe 'execute' do + before do + sign_in(user) if user + + run_test_query! + end + + subject { query_response } + + context 'graphql is disabled by feature flag' do + let(:user) { nil } + + before do + stub_feature_flags(graphql: false) + end + + it 'returns 404' do + run_test_query! + + expect(response).to have_gitlab_http_status(404) + end + end + + context 'signed out' do + let(:user) { nil } + + it 'runs the query with current_user: nil' do + is_expected.to eq('echo' => 'nil says: test success') + end + end + + context 'signed in' do + let(:user) { create(:user, username: 'Simon') } + + it 'runs the query with current_user set' do + is_expected.to eq('echo' => '"Simon" says: test success') + end + end + end + + # Chosen to exercise all the moving parts in GraphqlController#execute + def run_test_query! + query = <<~QUERY + query Echo($text: String) { + echo(text: $text) + } + QUERY + + post :execute, query: query, operationName: 'Echo', variables: { 'text' => 'test success' } + end + + def query_response + json_response['data'] + end +end diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb new file mode 100644 index 00000000000..3582f297866 --- /dev/null +++ b/spec/graphql/gitlab_schema_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe GitlabSchema do + it 'uses batch loading' do + expect(described_class.instrumenters[:multiplex]).to include(GraphQL::Batch::SetupMultiplex) + end + + it 'enables the preload instrumenter' do + expect(field_instrumenters).to include(instance_of(::GraphQL::Preload::Instrument)) + end + + it 'enables the authorization instrumenter' do + expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Authorize)) + end + + it 'has the base mutation' do + expect(described_class.mutation).to eq(::Types::MutationType) + end + + it 'has the base query' do + expect(described_class.query).to eq(::Types::QueryType) + end + + def field_instrumenters + described_class.instrumenters[:field] + end +end diff --git a/spec/graphql/loaders/full_path_loader_spec.rb b/spec/graphql/loaders/full_path_loader_spec.rb new file mode 100644 index 00000000000..2a473239550 --- /dev/null +++ b/spec/graphql/loaders/full_path_loader_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper' + +describe Loaders::FullPathLoader do + include GraphqlHelpers + + set(:project1) { create(:project) } + set(:project2) { create(:project) } + + set(:other_project) { create(:project) } + + describe '.project' do + it 'batch-resolves projects by full path' do + paths = [project1.full_path, project2.full_path] + + result = batch(max_queries: 1) do + paths.map { |path| resolve_project(path) } + end + + expect(result).to contain_exactly(project1, project2) + end + + it 'resolves an unknown full_path to nil' do + result = batch { resolve_project('unknown/project') } + + expect(result).to be_nil + end + + it 'returns a promise' do + batch do + expect(resolve_project(project1.full_path)).to be_a(Promise) + end + end + end + + def resolve_project(full_path) + resolve(described_class, :project, args: { full_path: full_path }) + end +end diff --git a/spec/graphql/loaders/iid_loader_spec.rb b/spec/graphql/loaders/iid_loader_spec.rb new file mode 100644 index 00000000000..8a0c1f0791a --- /dev/null +++ b/spec/graphql/loaders/iid_loader_spec.rb @@ -0,0 +1,64 @@ +require 'spec_helper' + +describe Loaders::IidLoader do + include GraphqlHelpers + + set(:project) { create(:project, :repository) } + set(:merge_request_1) { create(:merge_request, :simple, source_project: project, target_project: project) } + set(:merge_request_2) { create(:merge_request, :rebased, source_project: project, target_project: project) } + + set(:other_project) { create(:project, :repository) } + set(:other_merge_request) { create(:merge_request, source_project: other_project, target_project: other_project) } + + let(:full_path) { project.full_path } + let(:iid_1) { merge_request_1.iid } + let(:iid_2) { merge_request_2.iid } + + let(:other_full_path) { other_project.full_path } + let(:other_iid) { other_merge_request.iid } + + describe '.merge_request' do + it 'batch-resolves merge requests by target project full path and IID' do + path = full_path # avoid database query + + result = batch(max_queries: 2) do + [resolve_mr(path, iid_1), resolve_mr(path, iid_2)] + end + + expect(result).to contain_exactly(merge_request_1, merge_request_2) + end + + it 'can batch-resolve merge requests from different projects' do + path = project.full_path # avoid database queries + other_path = other_full_path + + result = batch(max_queries: 3) do + [resolve_mr(path, iid_1), resolve_mr(path, iid_2), resolve_mr(other_path, other_iid)] + end + + expect(result).to contain_exactly(merge_request_1, merge_request_2, other_merge_request) + end + + it 'resolves an unknown iid to nil' do + result = batch { resolve_mr(full_path, -1) } + + expect(result).to be_nil + end + + it 'resolves a known iid for an unknown full_path to nil' do + result = batch { resolve_mr('unknown/project', iid_1) } + + expect(result).to be_nil + end + + it 'returns a promise' do + batch do + expect(resolve_mr(full_path, iid_1)).to be_a(Promise) + end + end + end + + def resolve_mr(full_path, iid) + resolve(described_class, :merge_request, args: { project: full_path, iid: iid }) + end +end diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb new file mode 100644 index 00000000000..17d9395504c --- /dev/null +++ b/spec/graphql/types/query_type_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe GitlabSchema.types['Query'] do + it 'is called Query' do + expect(described_class.name).to eq('Query') + end + + it { is_expected.to have_graphql_fields(:project, :merge_request, :echo) } + + describe 'project field' do + subject { described_class.fields['project'] } + + it 'finds projects by full path' do + is_expected.to have_graphql_arguments(:full_path) + is_expected.to have_graphql_type(Types::ProjectType) + is_expected.to have_graphql_resolver(Loaders::FullPathLoader[:project]) + end + + it 'authorizes with read_project' do + is_expected.to require_graphql_authorizations(:read_project) + end + end + + describe 'merge_request field' do + subject { described_class.fields['merge_request'] } + + it 'finds MRs by project and IID' do + is_expected.to have_graphql_arguments(:project, :iid) + is_expected.to have_graphql_type(Types::MergeRequestType) + is_expected.to have_graphql_resolver(Loaders::IidLoader[:merge_request]) + end + + it 'authorizes with read_merge_request' do + is_expected.to require_graphql_authorizations(:read_merge_request) + end + end +end diff --git a/spec/graphql/types/time_type_spec.rb b/spec/graphql/types/time_type_spec.rb new file mode 100644 index 00000000000..087655cc67d --- /dev/null +++ b/spec/graphql/types/time_type_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe GitlabSchema.types['Time'] do + let(:float) { 1504630455.96215 } + let(:time) { Time.at(float) } + + it { expect(described_class.name).to eq('Time') } + + it 'coerces Time into fractional seconds since epoch' do + expect(described_class.coerce_isolated_result(time)).to eq(float) + end + + it 'coerces fractional seconds since epoch into Time' do + expect(described_class.coerce_isolated_input(float)).to eq(time) + end +end diff --git a/spec/lib/gitlab/path_regex_spec.rb b/spec/lib/gitlab/path_regex_spec.rb index a40330d853f..e90e0aba0a4 100644 --- a/spec/lib/gitlab/path_regex_spec.rb +++ b/spec/lib/gitlab/path_regex_spec.rb @@ -90,11 +90,13 @@ describe Gitlab::PathRegex do let(:routes_not_starting_in_wildcard) { routes_without_format.select { |p| p !~ %r{^/[:*]} } } let(:top_level_words) do - words = routes_not_starting_in_wildcard.map do |route| - route.split('/')[1] - end.compact - - (words + ee_top_level_words + files_in_public + Array(API::API.prefix.to_s)).uniq + routes_not_starting_in_wildcard + .map { |route| route.split('/')[1] } + .concat(ee_top_level_words) + .concat(files_in_public) + .concat(Array(API::API.prefix.to_s)) + .compact + .uniq end let(:ee_top_level_words) do diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb new file mode 100644 index 00000000000..5bb2cf9dd9e --- /dev/null +++ b/spec/support/helpers/graphql_helpers.rb @@ -0,0 +1,29 @@ +module GraphqlHelpers + # Run a loader's named resolver + def resolve(kls, name, obj: nil, args: {}, ctx: {}) + kls[name].call(obj, args, ctx) + end + + # Runs a block inside a GraphQL::Batch wrapper + def batch(max_queries: nil, &blk) + wrapper = proc do + GraphQL::Batch.batch do + result = yield + + if result.is_a?(Array) + Promise.all(result) + else + result + end + end + end + + if max_queries + result = nil + expect { result = wrapper.call }.not_to exceed_query_limit(max_queries) + result + else + wrapper.call + end + end +end diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb new file mode 100644 index 00000000000..c0ed16ecaba --- /dev/null +++ b/spec/support/matchers/graphql_matchers.rb @@ -0,0 +1,31 @@ +RSpec::Matchers.define :require_graphql_authorizations do |*expected| + match do |field| + authorizations = field.metadata[:authorize] + + expect(authorizations).to contain_exactly(*expected) + end +end + +RSpec::Matchers.define :have_graphql_fields do |*expected| + match do |kls| + expect(kls.fields.keys).to contain_exactly(*expected.map(&:to_s)) + end +end + +RSpec::Matchers.define :have_graphql_arguments do |*expected| + match do |field| + expect(field.arguments.keys).to contain_exactly(*expected.map(&:to_s)) + end +end + +RSpec::Matchers.define :have_graphql_type do |expected| + match do |field| + expect(field.type).to eq(expected) + end +end + +RSpec::Matchers.define :have_graphql_resolver do |expected| + match do |field| + expect(field.resolve_proc).to eq(expected) + end +end -- cgit v1.2.1 From 287c34ca1f9af4e395493c99623af8437f82d919 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Fri, 23 Feb 2018 15:36:40 +0000 Subject: Convert from GraphQL::Batch to BatchLoader --- spec/graphql/gitlab_schema_spec.rb | 2 +- spec/graphql/loaders/full_path_loader_spec.rb | 6 ------ spec/graphql/loaders/iid_loader_spec.rb | 6 ------ spec/support/helpers/graphql_helpers.rb | 17 +++++++---------- 4 files changed, 8 insertions(+), 23 deletions(-) (limited to 'spec') diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb index 3582f297866..070b851b109 100644 --- a/spec/graphql/gitlab_schema_spec.rb +++ b/spec/graphql/gitlab_schema_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GitlabSchema do it 'uses batch loading' do - expect(described_class.instrumenters[:multiplex]).to include(GraphQL::Batch::SetupMultiplex) + expect(field_instrumenters).to include(BatchLoader::GraphQL) end it 'enables the preload instrumenter' do diff --git a/spec/graphql/loaders/full_path_loader_spec.rb b/spec/graphql/loaders/full_path_loader_spec.rb index 2a473239550..2732dd8c9da 100644 --- a/spec/graphql/loaders/full_path_loader_spec.rb +++ b/spec/graphql/loaders/full_path_loader_spec.rb @@ -24,12 +24,6 @@ describe Loaders::FullPathLoader do expect(result).to be_nil end - - it 'returns a promise' do - batch do - expect(resolve_project(project1.full_path)).to be_a(Promise) - end - end end def resolve_project(full_path) diff --git a/spec/graphql/loaders/iid_loader_spec.rb b/spec/graphql/loaders/iid_loader_spec.rb index 8a0c1f0791a..0a57d7c4ed4 100644 --- a/spec/graphql/loaders/iid_loader_spec.rb +++ b/spec/graphql/loaders/iid_loader_spec.rb @@ -50,12 +50,6 @@ describe Loaders::IidLoader do expect(result).to be_nil end - - it 'returns a promise' do - batch do - expect(resolve_mr(full_path, iid_1)).to be_a(Promise) - end - end end def resolve_mr(full_path, iid) diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index 5bb2cf9dd9e..1eaa7603af0 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -4,20 +4,17 @@ module GraphqlHelpers kls[name].call(obj, args, ctx) end - # Runs a block inside a GraphQL::Batch wrapper + # Runs a block inside a BatchLoader::Executor wrapper def batch(max_queries: nil, &blk) wrapper = proc do - GraphQL::Batch.batch do - result = yield - - if result.is_a?(Array) - Promise.all(result) - else - result - end + begin + BatchLoader::Executor.ensure_current + blk.call + ensure + BatchLoader::Executor.clear_current end end - + if max_queries result = nil expect { result = wrapper.call }.not_to exceed_query_limit(max_queries) -- cgit v1.2.1 From aa4b1ae71260720b47695b8a256134f20280f61a Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 21 May 2018 09:52:24 +0200 Subject: Add `present_using` to types By specifying a presenter for the object type, we can keep the logic out of `GitlabSchema`. The presenter gets initialized using the object being presented, and the context (including the `current_user`). --- spec/graphql/gitlab_schema_spec.rb | 7 +++++ spec/requests/graphql/merge_request_query_spec.rb | 24 ++++++++++++++++ spec/requests/graphql/project_query_spec.rb | 23 +++++++++++++++ spec/support/helpers/graphql_helpers.rb | 33 ++++++++++++++++++++-- .../requests/graphql_shared_examples.rb | 18 ++++++++++++ 5 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 spec/requests/graphql/merge_request_query_spec.rb create mode 100644 spec/requests/graphql/project_query_spec.rb create mode 100644 spec/support/shared_examples/requests/graphql_shared_examples.rb (limited to 'spec') diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb index 070b851b109..f25cc2fd6c9 100644 --- a/spec/graphql/gitlab_schema_spec.rb +++ b/spec/graphql/gitlab_schema_spec.rb @@ -13,7 +13,14 @@ describe GitlabSchema do expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Authorize)) end + it 'enables using presenters' do + expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Present)) + end + it 'has the base mutation' do + pending <<~REASON + Having empty mutations breaks the automatic documentation in Graphiql, so removed for now." + REASON expect(described_class.mutation).to eq(::Types::MutationType) end diff --git a/spec/requests/graphql/merge_request_query_spec.rb b/spec/requests/graphql/merge_request_query_spec.rb new file mode 100644 index 00000000000..cbc19782e2f --- /dev/null +++ b/spec/requests/graphql/merge_request_query_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe 'getting merge request information' do + include GraphqlHelpers + + let(:project) { create(:project, :repository, :public) } + let(:merge_request) { create(:merge_request, source_project: project) } + + let(:query) do + <<~QUERY + { + merge_request(project: "#{merge_request.project.full_path}", iid: "#{merge_request.iid}") { + #{all_graphql_fields_for(MergeRequest)} + } + } + QUERY + end + + it_behaves_like 'a working graphql query' do + it 'renders a merge request with all fields' do + expect(response_data['merge_request']).not_to be_nil + end + end +end diff --git a/spec/requests/graphql/project_query_spec.rb b/spec/requests/graphql/project_query_spec.rb new file mode 100644 index 00000000000..110ed433e03 --- /dev/null +++ b/spec/requests/graphql/project_query_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe 'getting project information' do + include GraphqlHelpers + + let(:project) { create(:project, :repository, :public) } + + let(:query) do + <<~QUERY + { + project(full_path: "#{project.full_path}") { + #{all_graphql_fields_for(Project)} + } + } + QUERY + end + + it_behaves_like 'a working graphql query' do + it 'renders a project with all fields' do + expect(response_data['project']).not_to be_nil + end + end +end diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index 1eaa7603af0..ae29b16e32c 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -9,12 +9,12 @@ module GraphqlHelpers wrapper = proc do begin BatchLoader::Executor.ensure_current - blk.call + yield ensure BatchLoader::Executor.clear_current end end - + if max_queries result = nil expect { result = wrapper.call }.not_to exceed_query_limit(max_queries) @@ -23,4 +23,33 @@ module GraphqlHelpers wrapper.call end end + + def all_graphql_fields_for(klass) + type = GitlabSchema.types[klass.name] + return "" unless type + + type.fields.map do |name, field| + if scalar?(field) + name + else + "#{name} { #{all_graphql_fields_for(field_type(field))} }" + end + end.join("\n") + end + + def post_graphql(query) + post '/api/graphql', query: query + end + + def scalar?(field) + field_type(field).kind.scalar? + end + + def field_type(field) + if field.type.respond_to?(:of_type) + field.type.of_type + else + field.type + end + end end diff --git a/spec/support/shared_examples/requests/graphql_shared_examples.rb b/spec/support/shared_examples/requests/graphql_shared_examples.rb new file mode 100644 index 00000000000..c143b83696e --- /dev/null +++ b/spec/support/shared_examples/requests/graphql_shared_examples.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +shared_examples 'a working graphql query' do + include GraphqlHelpers + + let(:parsed_response) { JSON.parse(response.body) } + let(:response_data) { parsed_response['data'] } + + before do + post_graphql(query) + end + + it 'is returns a successfull response', :aggregate_failures do + expect(response).to be_success + expect(parsed_response['errors']).to be_nil + expect(response_data).not_to be_empty + end +end -- cgit v1.2.1 From c443133e779c4c508b9c6429dd4ba623d64f03f1 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Mon, 21 May 2018 13:42:07 +0200 Subject: Handle exceptions outside the GraphQL schema This allows us to report JSON parse exceptions to clients and ignore them in sentry. --- spec/controllers/graphql_controller_spec.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/controllers/graphql_controller_spec.rb b/spec/controllers/graphql_controller_spec.rb index d6689dbc3c6..1449036e148 100644 --- a/spec/controllers/graphql_controller_spec.rb +++ b/spec/controllers/graphql_controller_spec.rb @@ -2,6 +2,8 @@ require 'spec_helper' describe GraphqlController do describe 'execute' do + let(:user) { nil } + before do sign_in(user) if user @@ -39,17 +41,26 @@ describe GraphqlController do is_expected.to eq('echo' => '"Simon" says: test success') end end + + context 'invalid variables' do + it 'returns an error' do + run_test_query!(variables: "This is not JSON") + + expect(response).to have_gitlab_http_status(422) + expect(json_response['errors'].first['message']).not_to be_nil + end + end end # Chosen to exercise all the moving parts in GraphqlController#execute - def run_test_query! + def run_test_query!(variables: { 'text' => 'test success' }) query = <<~QUERY query Echo($text: String) { echo(text: $text) } QUERY - post :execute, query: query, operationName: 'Echo', variables: { 'text' => 'test success' } + post :execute, query: query, operationName: 'Echo', variables: variables end def query_response -- cgit v1.2.1 From 65dbead7967937eb87ffdc987c319d7006662889 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 5 Jun 2018 19:22:55 +0100 Subject: Fix repository archive generation when hashed storage is enabled --- spec/lib/gitlab/git/repository_spec.rb | 2 +- spec/models/repository_spec.rb | 26 ++++++++++++++++++++++++++ spec/requests/api/repositories_spec.rb | 9 +++------ 3 files changed, 30 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 8dd7911f49c..1744db1b17e 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -256,7 +256,7 @@ describe Gitlab::Git::Repository, seed_helper: true do let(:expected_path) { File.join(storage_path, cache_key, expected_filename) } let(:expected_prefix) { "gitlab-git-test-#{ref}-#{SeedRepo::LastCommit::ID}" } - subject(:metadata) { repository.archive_metadata(ref, storage_path, format, append_sha: append_sha) } + subject(:metadata) { repository.archive_metadata(ref, storage_path, 'gitlab-git-test', format, append_sha: append_sha) } it 'sets CommitId to the commit SHA' do expect(metadata['CommitId']).to eq(SeedRepo::LastCommit::ID) diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index c1aa7d80c94..7c0a1cd967c 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -2443,6 +2443,32 @@ describe Repository do end end + describe '#archive_metadata' do + let(:ref) { 'master' } + let(:storage_path) { '/tmp' } + + let(:prefix) { [project.path, ref].join('-') } + let(:filename) { prefix + '.tar.gz' } + + subject(:result) { repository.archive_metadata(ref, storage_path, append_sha: false) } + + context 'with hashed storage disabled' do + let(:project) { create(:project, :repository, :legacy_storage) } + + it 'uses the project path to generate the filename' do + expect(result['ArchivePrefix']).to eq(prefix) + expect(File.basename(result['ArchivePath'])).to eq(filename) + end + end + + context 'with hashed storage enabled' do + it 'uses the project path to generate the filename' do + expect(result['ArchivePrefix']).to eq(prefix) + expect(File.basename(result['ArchivePath'])).to eq(filename) + end + end + end + describe 'commit cache' do set(:project) { create(:project, :repository) } diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 9e6d69e3874..cd135dfc32a 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -220,11 +220,10 @@ describe API::Repositories do expect(response).to have_gitlab_http_status(200) - repo_name = project.repository.name.gsub("\.git", "") type, params = workhorse_send_data expect(type).to eq('git-archive') - expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/) + expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\.tar.gz/) end it 'returns the repository archive archive.zip' do @@ -232,11 +231,10 @@ describe API::Repositories do expect(response).to have_gitlab_http_status(200) - repo_name = project.repository.name.gsub("\.git", "") type, params = workhorse_send_data expect(type).to eq('git-archive') - expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/) + expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\.zip/) end it 'returns the repository archive archive.tar.bz2' do @@ -244,11 +242,10 @@ describe API::Repositories do expect(response).to have_gitlab_http_status(200) - repo_name = project.repository.name.gsub("\.git", "") type, params = workhorse_send_data expect(type).to eq('git-archive') - expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/) + expect(params['ArchivePath']).to match(/#{project.path}\-[^\.]+\.tar.bz2/) end context 'when sha does not exist' do -- cgit v1.2.1 From 46317b7dabd585bed42cf9c0008a7c69c080d33f Mon Sep 17 00:00:00 2001 From: Jacopo Date: Tue, 5 Jun 2018 21:57:29 +0200 Subject: Removes variables from pipelines api --- spec/requests/api/pipelines_spec.rb | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/pipelines_spec.rb b/spec/requests/api/pipelines_spec.rb index 0a64c46bb92..78ea77cb3bb 100644 --- a/spec/requests/api/pipelines_spec.rb +++ b/spec/requests/api/pipelines_spec.rb @@ -285,6 +285,15 @@ describe API::Pipelines do end describe 'POST /projects/:id/pipeline ' do + def expect_variables(variables, expected_variables) + variables.each_with_index do |variable, index| + expected_variable = expected_variables[index] + + expect(variable.key).to eq(expected_variable['key']) + expect(variable.value).to eq(expected_variable['value']) + end + end + context 'authorized user' do context 'with gitlab-ci.yml' do before do @@ -308,11 +317,12 @@ describe API::Pipelines do expect do post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables end.to change { project.pipelines.count }.by(1) + expect_variables(project.pipelines.last.variables, variables) expect(response).to have_gitlab_http_status(201) expect(json_response).to be_a Hash expect(json_response['sha']).to eq project.commit.id - expect(json_response['variables']).to eq variables + expect(json_response).not_to have_key('variables') end end @@ -328,11 +338,12 @@ describe API::Pipelines do expect do post api("/projects/#{project.id}/pipeline", user), ref: project.default_branch, variables: variables end.to change { project.pipelines.count }.by(1) + expect_variables(project.pipelines.last.variables, variables) expect(response).to have_gitlab_http_status(201) expect(json_response).to be_a Hash expect(json_response['sha']).to eq project.commit.id - expect(json_response['variables']).to eq variables + expect(json_response).not_to have_key('variables') end context 'condition unmatch' do -- cgit v1.2.1 From 9c3c198daf30981d7512f0dfbb58b4f1b7df4416 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 5 Jun 2018 15:00:55 -0500 Subject: Combine multiple `it` blocks to improve Markdown feature spec times The setup of each spec is too expensive to perform as many times as we were doing it. Reduced duration from 255 seconds to 43. --- spec/features/markdown/markdown_spec.rb | 204 +++++++++++++++----------------- 1 file changed, 97 insertions(+), 107 deletions(-) (limited to 'spec') diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb index f13d78d24e3..c86ba8c50a5 100644 --- a/spec/features/markdown/markdown_spec.rb +++ b/spec/features/markdown/markdown_spec.rb @@ -24,7 +24,7 @@ require 'erb' # # See the MarkdownFeature class for setup details. -describe 'GitLab Markdown' do +describe 'GitLab Markdown', :aggregate_failures do include Capybara::Node::Matchers include MarkupHelper include MarkdownMatchers @@ -44,112 +44,102 @@ describe 'GitLab Markdown' do # Shared behavior that all pipelines should exhibit shared_examples 'all pipelines' do - describe 'Redcarpet extensions' do - it 'does not parse emphasis inside of words' do + it 'includes Redcarpet extensions' do + aggregate_failures 'does not parse emphasis inside of words' do expect(doc.to_html).not_to match('foobarbaz') end - it 'parses table Markdown' do - aggregate_failures do - expect(doc).to have_selector('th:contains("Header")') - expect(doc).to have_selector('th:contains("Row")') - expect(doc).to have_selector('th:contains("Example")') - end + aggregate_failures 'parses table Markdown' do + expect(doc).to have_selector('th:contains("Header")') + expect(doc).to have_selector('th:contains("Row")') + expect(doc).to have_selector('th:contains("Example")') end - it 'allows Markdown in tables' do + aggregate_failures 'allows Markdown in tables' do expect(doc.at_css('td:contains("Baz")').children.to_html) .to eq 'Baz' end - it 'parses fenced code blocks' do - aggregate_failures do - expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.c') - expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.python') - end + aggregate_failures 'parses fenced code blocks' do + expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.c') + expect(doc).to have_selector('pre.code.highlight.js-syntax-highlight.python') end - it 'parses mermaid code block' do - aggregate_failures do - expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid') - end + aggregate_failures 'parses mermaid code block' do + expect(doc).to have_selector('pre[lang=mermaid] > code.js-render-mermaid') end - it 'parses strikethroughs' do + aggregate_failures 'parses strikethroughs' do expect(doc).to have_selector(%{del:contains("and this text doesn't")}) end - it 'parses superscript' do + aggregate_failures 'parses superscript' do expect(doc).to have_selector('sup', count: 2) end end - describe 'SanitizationFilter' do - it 'permits b elements' do + it 'includes SanitizationFilter' do + aggregate_failures 'permits b elements' do expect(doc).to have_selector('b:contains("b tag")') end - it 'permits em elements' do + aggregate_failures 'permits em elements' do expect(doc).to have_selector('em:contains("em tag")') end - it 'permits code elements' do + aggregate_failures 'permits code elements' do expect(doc).to have_selector('code:contains("code tag")') end - it 'permits kbd elements' do + aggregate_failures 'permits kbd elements' do expect(doc).to have_selector('kbd:contains("s")') end - it 'permits strike elements' do + aggregate_failures 'permits strike elements' do expect(doc).to have_selector('strike:contains(Emoji)') end - it 'permits img elements' do + aggregate_failures 'permits img elements' do expect(doc).to have_selector('img[data-src*="smile.png"]') end - it 'permits br elements' do + aggregate_failures 'permits br elements' do expect(doc).to have_selector('br') end - it 'permits hr elements' do + aggregate_failures 'permits hr elements' do expect(doc).to have_selector('hr') end - it 'permits span elements' do + aggregate_failures 'permits span elements' do expect(doc).to have_selector('span:contains("span tag")') end - it 'permits details elements' do + aggregate_failures 'permits details elements' do expect(doc).to have_selector('details:contains("Hiding the details")') end - it 'permits summary elements' do + aggregate_failures 'permits summary elements' do expect(doc).to have_selector('details summary:contains("collapsible")') end - it 'permits style attribute in th elements' do - aggregate_failures do - expect(doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center' - expect(doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right' - expect(doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left' - end + aggregate_failures 'permits style attribute in th elements' do + expect(doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center' + expect(doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right' + expect(doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left' end - it 'permits style attribute in td elements' do - aggregate_failures do - expect(doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center' - expect(doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right' - expect(doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left' - end + aggregate_failures 'permits style attribute in td elements' do + expect(doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center' + expect(doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right' + expect(doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left' end - it 'removes `rel` attribute from links' do + aggregate_failures 'removes `rel` attribute from links' do expect(doc).not_to have_selector('a[rel="bookmark"]') end - it "removes `href` from `a` elements if it's fishy" do + aggregate_failures "removes `href` from `a` elements if it's fishy" do expect(doc).not_to have_selector('a[href*="javascript"]') end end @@ -176,26 +166,26 @@ describe 'GitLab Markdown' do end end - describe 'ExternalLinkFilter' do - it 'adds nofollow to external link' do + it 'includes ExternalLinkFilter' do + aggregate_failures 'adds nofollow to external link' do link = doc.at_css('a:contains("Google")') expect(link.attr('rel')).to include('nofollow') end - it 'adds noreferrer to external link' do + aggregate_failures 'adds noreferrer to external link' do link = doc.at_css('a:contains("Google")') expect(link.attr('rel')).to include('noreferrer') end - it 'adds _blank to target attribute for external links' do + aggregate_failures 'adds _blank to target attribute for external links' do link = doc.at_css('a:contains("Google")') expect(link.attr('target')).to match('_blank') end - it 'ignores internal link' do + aggregate_failures 'ignores internal link' do link = doc.at_css('a:contains("GitLab Root")') expect(link.attr('rel')).not_to match 'nofollow' @@ -219,24 +209,24 @@ describe 'GitLab Markdown' do it_behaves_like 'all pipelines' - it 'includes RelativeLinkFilter' do - expect(doc).to parse_relative_links - end + it 'includes custom filters' do + aggregate_failures 'RelativeLinkFilter' do + expect(doc).to parse_relative_links + end - it 'includes EmojiFilter' do - expect(doc).to parse_emoji - end + aggregate_failures 'EmojiFilter' do + expect(doc).to parse_emoji + end - it 'includes TableOfContentsFilter' do - expect(doc).to create_header_links - end + aggregate_failures 'TableOfContentsFilter' do + expect(doc).to create_header_links + end - it 'includes AutolinkFilter' do - expect(doc).to create_autolinks - end + aggregate_failures 'AutolinkFilter' do + expect(doc).to create_autolinks + end - it 'includes all reference filters' do - aggregate_failures do + aggregate_failures 'all reference filters' do expect(doc).to reference_users expect(doc).to reference_issues expect(doc).to reference_merge_requests @@ -246,22 +236,22 @@ describe 'GitLab Markdown' do expect(doc).to reference_labels expect(doc).to reference_milestones end - end - it 'includes TaskListFilter' do - expect(doc).to parse_task_lists - end + aggregate_failures 'TaskListFilter' do + expect(doc).to parse_task_lists + end - it 'includes InlineDiffFilter' do - expect(doc).to parse_inline_diffs - end + aggregate_failures 'InlineDiffFilter' do + expect(doc).to parse_inline_diffs + end - it 'includes VideoLinkFilter' do - expect(doc).to parse_video_links - end + aggregate_failures 'VideoLinkFilter' do + expect(doc).to parse_video_links + end - it 'includes ColorFilter' do - expect(doc).to parse_colors + aggregate_failures 'ColorFilter' do + expect(doc).to parse_colors + end end end @@ -280,24 +270,24 @@ describe 'GitLab Markdown' do it_behaves_like 'all pipelines' - it 'includes RelativeLinkFilter' do - expect(doc).not_to parse_relative_links - end + it 'includes custom filters' do + aggregate_failures 'RelativeLinkFilter' do + expect(doc).not_to parse_relative_links + end - it 'includes EmojiFilter' do - expect(doc).to parse_emoji - end + aggregate_failures 'EmojiFilter' do + expect(doc).to parse_emoji + end - it 'includes TableOfContentsFilter' do - expect(doc).to create_header_links - end + aggregate_failures 'TableOfContentsFilter' do + expect(doc).to create_header_links + end - it 'includes AutolinkFilter' do - expect(doc).to create_autolinks - end + aggregate_failures 'AutolinkFilter' do + expect(doc).to create_autolinks + end - it 'includes all reference filters' do - aggregate_failures do + aggregate_failures 'all reference filters' do expect(doc).to reference_users expect(doc).to reference_issues expect(doc).to reference_merge_requests @@ -307,26 +297,26 @@ describe 'GitLab Markdown' do expect(doc).to reference_labels expect(doc).to reference_milestones end - end - it 'includes TaskListFilter' do - expect(doc).to parse_task_lists - end + aggregate_failures 'TaskListFilter' do + expect(doc).to parse_task_lists + end - it 'includes GollumTagsFilter' do - expect(doc).to parse_gollum_tags - end + aggregate_failures 'GollumTagsFilter' do + expect(doc).to parse_gollum_tags + end - it 'includes InlineDiffFilter' do - expect(doc).to parse_inline_diffs - end + aggregate_failures 'InlineDiffFilter' do + expect(doc).to parse_inline_diffs + end - it 'includes VideoLinkFilter' do - expect(doc).to parse_video_links - end + aggregate_failures 'VideoLinkFilter' do + expect(doc).to parse_video_links + end - it 'includes ColorFilter' do - expect(doc).to parse_colors + aggregate_failures 'ColorFilter' do + expect(doc).to parse_colors + end end end -- cgit v1.2.1 From 36a8f1a677df85d61c4948e9f28293a1c75096a9 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 5 Jun 2018 14:39:44 -0700 Subject: Reject GPG keys that have e-mail or names with non-valid UTF-8 encodings These were causing 500 Errors when accessing GPG keys for some users. Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/47280 --- spec/lib/gitlab/gpg_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/gpg_spec.rb b/spec/lib/gitlab/gpg_spec.rb index ab9a166db00..47f37cae98f 100644 --- a/spec/lib/gitlab/gpg_spec.rb +++ b/spec/lib/gitlab/gpg_spec.rb @@ -74,6 +74,19 @@ describe Gitlab::Gpg do email: 'nannie.bernhard@example.com' }]) end + + it 'rejects non UTF-8 names and addresses' do + public_key = double(:key) + fingerprints = double(:fingerprints) + email = "\xEEch@test.com".force_encoding('ASCII-8BIT') + uid = double(:uid, name: 'Test User', email: email) + raw_key = double(:raw_key, uids: [uid]) + allow(Gitlab::Gpg::CurrentKeyChain).to receive(:fingerprints_from_key).with(public_key).and_return(fingerprints) + allow(GPGME::Key).to receive(:find).with(:public, anything).and_return([raw_key]) + + user_infos = described_class.user_infos_from_key(public_key) + expect(user_infos).to eq([]) + end end describe '.current_home_dir' do -- cgit v1.2.1 From bbafb85395cf2786f21a5a92745b9b3a181a4ce8 Mon Sep 17 00:00:00 2001 From: Ash McKenzie Date: Tue, 5 Jun 2018 21:42:18 +1000 Subject: Add missing tests around rendering invalid merge requests (HTML+JSON) --- .../projects/merge_requests_controller_spec.rb | 20 ++++++++++++++++++++ spec/factories/merge_requests.rb | 6 ++++++ 2 files changed, 26 insertions(+) (limited to 'spec') diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 6e8de6db9c3..6e710c9b20b 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -80,6 +80,16 @@ describe Projects::MergeRequestsController do )) end end + + context "that is invalid" do + let(:merge_request) { create(:invalid_merge_request, target_project: project, source_project: project) } + + it "renders merge request page" do + go(format: :html) + + expect(response).to be_success + end + end end describe 'as json' do @@ -106,6 +116,16 @@ describe Projects::MergeRequestsController do expect(response).to match_response_schema('entities/merge_request_widget') end end + + context "that is invalid" do + let(:merge_request) { create(:invalid_merge_request, target_project: project, source_project: project) } + + it "renders merge request page" do + go(format: :json) + + expect(response).to be_success + end + end end describe "as diff" do diff --git a/spec/factories/merge_requests.rb b/spec/factories/merge_requests.rb index fab0ec22450..3441ce1b8cb 100644 --- a/spec/factories/merge_requests.rb +++ b/spec/factories/merge_requests.rb @@ -54,6 +54,11 @@ FactoryBot.define do state :opened end + trait :invalid do + source_branch "feature_one" + target_branch "feature_two" + end + trait :locked do state :locked end @@ -98,6 +103,7 @@ FactoryBot.define do factory :merged_merge_request, traits: [:merged] factory :closed_merge_request, traits: [:closed] factory :reopened_merge_request, traits: [:opened] + factory :invalid_merge_request, traits: [:invalid] factory :merge_request_with_diffs, traits: [:with_diffs] factory :merge_request_with_diff_notes do after(:create) do |mr| -- cgit v1.2.1 From b61e1e7a5cd496a9b2de3d6a6192b3aed2d6acdd Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 6 Jun 2018 01:09:58 +0000 Subject: Fix invisible rows on importer status --- spec/helpers/projects_helper_spec.rb | 6 +++--- spec/javascripts/importer_status_spec.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 4e5391295b6..d372e58f63d 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -5,9 +5,9 @@ describe ProjectsHelper do describe "#project_status_css_class" do it "returns appropriate class" do - expect(project_status_css_class("started")).to eq("active") - expect(project_status_css_class("failed")).to eq("danger") - expect(project_status_css_class("finished")).to eq("success") + expect(project_status_css_class("started")).to eq("table-active") + expect(project_status_css_class("failed")).to eq("table-danger") + expect(project_status_css_class("finished")).to eq("table-success") end end diff --git a/spec/javascripts/importer_status_spec.js b/spec/javascripts/importer_status_spec.js index 0575d02886d..87b46ccf7c3 100644 --- a/spec/javascripts/importer_status_spec.js +++ b/spec/javascripts/importer_status_spec.js @@ -45,7 +45,7 @@ describe('Importer Status', () => { currentTarget: document.querySelector('.js-add-to-import'), }) .then(() => { - expect(document.querySelector('tr').classList.contains('active')).toEqual(true); + expect(document.querySelector('tr').classList.contains('table-active')).toEqual(true); done(); }) .catch(done.fail); -- cgit v1.2.1 From 078a5dcd1b285fdb1f2ec029054da389b9e1203f Mon Sep 17 00:00:00 2001 From: Jasper Maes Date: Wed, 6 Jun 2018 07:22:54 +0200 Subject: Rails 5 fix unknown keywords: changes, key_id, project, gl_repository, action, secret_token, protocol --- spec/requests/api/internal_spec.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index 5dc3ddd4b36..bc32372d3a9 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -835,8 +835,7 @@ describe API::Internal do end def push(key, project, protocol = 'ssh', env: nil) - post( - api("/internal/allowed"), + params = { changes: 'd14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/master', key_id: key.id, project: project.full_path, @@ -845,7 +844,19 @@ describe API::Internal do secret_token: secret_token, protocol: protocol, env: env - ) + } + + if Gitlab.rails5? + post( + api("/internal/allowed"), + params: params + ) + else + post( + api("/internal/allowed"), + params + ) + end end def archive(key, project) -- cgit v1.2.1 From 2d1faddbcb3b814a381f91cf48cc597d47b29ee0 Mon Sep 17 00:00:00 2001 From: Jasper Maes Date: Wed, 6 Jun 2018 08:46:42 +0200 Subject: Rails 5 fix glob spec --- spec/lib/gitlab/sql/glob_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/sql/glob_spec.rb b/spec/lib/gitlab/sql/glob_spec.rb index f0bb4294d62..1cf8935bfe3 100644 --- a/spec/lib/gitlab/sql/glob_spec.rb +++ b/spec/lib/gitlab/sql/glob_spec.rb @@ -35,8 +35,9 @@ describe Gitlab::SQL::Glob do value = query("SELECT #{quote(string)} LIKE #{pattern}") .rows.flatten.first + check = Gitlab.rails5? ? true : 't' case value - when 't', 1 + when check, 1 true else false -- cgit v1.2.1 From 2d6022e0865642deb10d458d58d6b0b8c072e98e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 1 Jun 2018 14:44:22 +0100 Subject: store specs --- spec/javascripts/ide/mock_data.js | 4 + .../ide/stores/modules/pipelines/actions_spec.js | 135 +++++++++++++++++++++ .../ide/stores/modules/pipelines/mutations_spec.js | 49 ++++++++ 3 files changed, 188 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/ide/mock_data.js b/spec/javascripts/ide/mock_data.js index dcf857f7e04..dd87a43f370 100644 --- a/spec/javascripts/ide/mock_data.js +++ b/spec/javascripts/ide/mock_data.js @@ -75,6 +75,7 @@ export const jobs = [ }, stage: 'test', duration: 1, + started: new Date(), }, { id: 2, @@ -86,6 +87,7 @@ export const jobs = [ }, stage: 'test', duration: 1, + started: new Date(), }, { id: 3, @@ -97,6 +99,7 @@ export const jobs = [ }, stage: 'test', duration: 1, + started: new Date(), }, { id: 4, @@ -108,6 +111,7 @@ export const jobs = [ }, stage: 'build', duration: 1, + started: new Date(), }, ]; diff --git a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js index f26eaf9c81f..f2f8e780cd1 100644 --- a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js @@ -13,9 +13,15 @@ import actions, { receiveJobsSuccess, fetchJobs, toggleStageCollapsed, + setDetailJob, + requestJobTrace, + receiveJobTraceError, + receiveJobTraceSuccess, + fetchJobTrace, } from '~/ide/stores/modules/pipelines/actions'; import state from '~/ide/stores/modules/pipelines/state'; import * as types from '~/ide/stores/modules/pipelines/mutation_types'; +import { rightSidebarViews } from '~/ide/constants'; import testAction from '../../../../helpers/vuex_action_helper'; import { pipelines, jobs } from '../../../mock_data'; @@ -281,4 +287,133 @@ describe('IDE pipelines actions', () => { ); }); }); + + describe('setDetailJob', () => { + it('commits job', done => { + testAction( + setDetailJob, + 'job', + mockedState, + [{ type: types.SET_DETAIL_JOB, payload: 'job' }], + [{ type: 'setRightPane' }], + done, + ); + }); + + it('dispatches setRightPane as pipeline when job is null', done => { + testAction( + setDetailJob, + null, + mockedState, + [{ type: types.SET_DETAIL_JOB }], + [{ type: 'setRightPane', payload: rightSidebarViews.pipelines }], + done, + ); + }); + + it('dispatches setRightPane as job', done => { + testAction( + setDetailJob, + 'job', + mockedState, + [{ type: types.SET_DETAIL_JOB }], + [{ type: 'setRightPane', payload: rightSidebarViews.jobsDetail }], + done, + ); + }); + }); + + describe('requestJobTrace', () => { + it('commits request', done => { + testAction(requestJobTrace, null, mockedState, [{ type: types.REQUEST_JOB_TRACE }], [], done); + }); + }); + + describe('receiveJobTraceError', () => { + it('commits error', done => { + testAction( + receiveJobTraceError, + null, + mockedState, + [{ type: types.RECEIVE_JOB_TRACE_ERROR }], + [], + done, + ); + }); + + it('creates flash message', () => { + const flashSpy = spyOnDependency(actions, 'flash'); + + receiveJobTraceError({ commit() {} }); + + expect(flashSpy).toHaveBeenCalled(); + }); + }); + + describe('receiveJobTraceSuccess', () => { + it('commits data', done => { + testAction( + receiveJobTraceSuccess, + 'data', + mockedState, + [{ type: types.RECEIVE_JOB_TRACE_SUCCESS, payload: 'data' }], + [], + done, + ); + }); + }); + + describe('fetchJobTrace', () => { + beforeEach(() => { + mockedState.detailJob = { + path: `${gl.TEST_HOST}/project/builds`, + }; + }); + + describe('success', () => { + beforeEach(() => { + spyOn(axios, 'get').and.callThrough(); + mock.onGet(`${gl.TEST_HOST}/project/builds/trace`).replyOnce(200, { html: 'html' }); + }); + + it('dispatches request', done => { + testAction( + fetchJobTrace, + null, + mockedState, + [], + [ + { type: 'requestJobTrace' }, + { type: 'receiveJobTraceSuccess', payload: { html: 'html' } }, + ], + done, + ); + }); + + it('sends get request to correct URL', () => { + fetchJobTrace({ state: mockedState, dispatch() {} }); + + expect(axios.get).toHaveBeenCalledWith(`${gl.TEST_HOST}/project/builds/trace`, { + params: { format: 'json' }, + }); + }); + }); + + describe('error', () => { + beforeEach(() => { + mock.onGet(`${gl.TEST_HOST}/project/builds/trace`).replyOnce(500); + }); + + it('dispatches error', done => { + testAction( + fetchJobTrace, + null, + mockedState, + [], + [{ type: 'requestJobTrace' }, { type: 'receiveJobTraceError' }], + done, + ); + }); + }); + }); }); diff --git a/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js b/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js index 6285c01d483..eb7346bd5fc 100644 --- a/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js +++ b/spec/javascripts/ide/stores/modules/pipelines/mutations_spec.js @@ -147,6 +147,10 @@ describe('IDE pipelines mutations', () => { name: job.name, status: job.status, path: job.build_path, + rawPath: `${job.build_path}/raw`, + started: job.started, + isLoading: false, + output: '', })), ); }); @@ -171,4 +175,49 @@ describe('IDE pipelines mutations', () => { expect(mockedState.stages[0].isCollapsed).toBe(false); }); }); + + describe(types.SET_DETAIL_JOB, () => { + it('sets detail job', () => { + mutations[types.SET_DETAIL_JOB](mockedState, jobs[0]); + + expect(mockedState.detailJob).toEqual(jobs[0]); + }); + }); + + describe(types.REQUEST_JOB_TRACE, () => { + beforeEach(() => { + mockedState.detailJob = { ...jobs[0] }; + }); + + it('sets loading on detail job', () => { + mutations[types.REQUEST_JOB_TRACE](mockedState); + + expect(mockedState.detailJob.isLoading).toBe(true); + }); + }); + + describe(types.RECEIVE_JOB_TRACE_ERROR, () => { + beforeEach(() => { + mockedState.detailJob = { ...jobs[0], isLoading: true }; + }); + + it('sets loading to false on detail job', () => { + mutations[types.RECEIVE_JOB_TRACE_ERROR](mockedState); + + expect(mockedState.detailJob.isLoading).toBe(false); + }); + }); + + describe(types.RECEIVE_JOB_TRACE_SUCCESS, () => { + beforeEach(() => { + mockedState.detailJob = { ...jobs[0], isLoading: true }; + }); + + it('sets output on detail job', () => { + mutations[types.RECEIVE_JOB_TRACE_SUCCESS](mockedState, { html: 'html' }); + + expect(mockedState.detailJob.output).toBe('html'); + expect(mockedState.detailJob.isLoading).toBe(false); + }); + }); }); -- cgit v1.2.1 From f73b2c8e5ee0e02407b6674b9b0021ce4843349b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Sat, 2 Jun 2018 14:45:58 +0100 Subject: component specs --- .../ide/components/jobs/detail/description_spec.js | 28 ++++ .../components/jobs/detail/scroll_button_spec.js | 59 +++++++ .../javascripts/ide/components/jobs/detail_spec.js | 170 +++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 spec/javascripts/ide/components/jobs/detail/description_spec.js create mode 100644 spec/javascripts/ide/components/jobs/detail/scroll_button_spec.js create mode 100644 spec/javascripts/ide/components/jobs/detail_spec.js (limited to 'spec') diff --git a/spec/javascripts/ide/components/jobs/detail/description_spec.js b/spec/javascripts/ide/components/jobs/detail/description_spec.js new file mode 100644 index 00000000000..9b715a41499 --- /dev/null +++ b/spec/javascripts/ide/components/jobs/detail/description_spec.js @@ -0,0 +1,28 @@ +import Vue from 'vue'; +import Description from '~/ide/components/jobs/detail/description.vue'; +import mountComponent from '../../../../helpers/vue_mount_component_helper'; +import { jobs } from '../../../mock_data'; + +describe('IDE job description', () => { + const Component = Vue.extend(Description); + let vm; + + beforeEach(() => { + vm = mountComponent(Component, { + job: jobs[0], + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders job details', () => { + expect(vm.$el.textContent).toContain('#1'); + expect(vm.$el.textContent).toContain('test'); + }); + + it('renders CI icon', () => { + expect(vm.$el.querySelector('.ci-status-icon .ic-status_passed_borderless')).not.toBe(null); + }); +}); diff --git a/spec/javascripts/ide/components/jobs/detail/scroll_button_spec.js b/spec/javascripts/ide/components/jobs/detail/scroll_button_spec.js new file mode 100644 index 00000000000..fff382a107f --- /dev/null +++ b/spec/javascripts/ide/components/jobs/detail/scroll_button_spec.js @@ -0,0 +1,59 @@ +import Vue from 'vue'; +import ScrollButton from '~/ide/components/jobs/detail/scroll_button.vue'; +import mountComponent from '../../../../helpers/vue_mount_component_helper'; + +describe('IDE job log scroll button', () => { + const Component = Vue.extend(ScrollButton); + let vm; + + beforeEach(() => { + vm = mountComponent(Component, { + direction: 'up', + disabled: false, + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + describe('iconName', () => { + ['up', 'down'].forEach(direction => { + it(`returns icon name for ${direction}`, () => { + vm.direction = direction; + + expect(vm.iconName).toBe(`scroll_${direction}`); + }); + }); + }); + + describe('tooltipTitle', () => { + it('returns title for up', () => { + expect(vm.tooltipTitle).toBe('Scroll to top'); + }); + + it('returns title for down', () => { + vm.direction = 'down'; + + expect(vm.tooltipTitle).toBe('Scroll to bottom'); + }); + }); + + it('emits click event on click', () => { + spyOn(vm, '$emit'); + + vm.$el.querySelector('.btn-scroll').click(); + + expect(vm.$emit).toHaveBeenCalledWith('click'); + }); + + it('disables button when disabled is true', done => { + vm.disabled = true; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.btn-scroll').hasAttribute('disabled')).toBe(true); + + done(); + }); + }); +}); diff --git a/spec/javascripts/ide/components/jobs/detail_spec.js b/spec/javascripts/ide/components/jobs/detail_spec.js new file mode 100644 index 00000000000..00a2dc6c74c --- /dev/null +++ b/spec/javascripts/ide/components/jobs/detail_spec.js @@ -0,0 +1,170 @@ +import Vue from 'vue'; +import JobDetail from '~/ide/components/jobs/detail.vue'; +import { createStore } from '~/ide/stores'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { jobs } from '../../mock_data'; + +describe('IDE jobs detail view', () => { + const Component = Vue.extend(JobDetail); + let vm; + + beforeEach(() => { + const store = createStore(); + + store.state.pipelines.detailJob = { + ...jobs[0], + isLoading: true, + output: 'testing', + rawPath: `${gl.TEST_HOST}/raw`, + }; + + vm = createComponentWithStore(Component, store); + + spyOn(vm, 'fetchJobTrace').and.returnValue(Promise.resolve()); + + vm = vm.$mount(); + + spyOn(vm.$refs.buildTrace, 'scrollTo'); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('calls fetchJobTrace on mount', () => { + expect(vm.fetchJobTrace).toHaveBeenCalled(); + }); + + it('scrolls to bottom on mount', done => { + setTimeout(() => { + expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalled(); + + done(); + }); + }); + + it('renders job output', () => { + expect(vm.$el.querySelector('.bash').textContent).toContain('testing'); + }); + + it('renders loading icon', () => { + expect(vm.$el.querySelector('.build-loader-animation')).not.toBe(null); + expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe(''); + }); + + it('hide loading icon when isLoading is false', done => { + vm.$store.state.pipelines.detailJob.isLoading = false; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe('none'); + + done(); + }); + }); + + it('resets detailJob when clicking header button', () => { + spyOn(vm, 'setDetailJob'); + + vm.$el.querySelector('.btn').click(); + + expect(vm.setDetailJob).toHaveBeenCalledWith(null); + }); + + it('renders raw path link', () => { + expect(vm.$el.querySelector('.controllers-buttons').getAttribute('href')).toBe( + `${gl.TEST_HOST}/raw`, + ); + }); + + describe('scroll buttons', () => { + it('triggers scrollDown when clicking down button', done => { + spyOn(vm, 'scrollDown'); + + vm.$el.querySelectorAll('.btn-scroll')[1].click(); + + vm.$nextTick(() => { + expect(vm.scrollDown).toHaveBeenCalled(); + + done(); + }); + }); + + it('triggers scrollUp when clicking up button', done => { + spyOn(vm, 'scrollUp'); + + vm.scrollPos = 1; + + vm + .$nextTick() + .then(() => vm.$el.querySelector('.btn-scroll').click()) + .then(() => vm.$nextTick()) + .then(() => { + expect(vm.scrollUp).toHaveBeenCalled(); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('scrollDown', () => { + it('scrolls build trace to bottom', () => { + spyOnProperty(vm.$refs.buildTrace, 'scrollHeight').and.returnValue(1000); + + vm.scrollDown(); + + expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalledWith(0, 1000); + }); + }); + + describe('scrollUp', () => { + it('scrolls build trace to top', () => { + vm.scrollUp(); + + expect(vm.$refs.buildTrace.scrollTo).toHaveBeenCalledWith(0, 0); + }); + }); + + describe('scrollBuildLog', () => { + beforeEach(() => { + spyOnProperty(vm.$refs.buildTrace, 'offsetHeight').and.returnValue(100); + spyOnProperty(vm.$refs.buildTrace, 'scrollHeight').and.returnValue(200); + }); + + it('sets scrollPos to bottom when at the bottom', done => { + spyOnProperty(vm.$refs.buildTrace, 'scrollTop').and.returnValue(100); + + vm.scrollBuildLog(); + + setTimeout(() => { + expect(vm.scrollPos).toBe(1); + + done(); + }); + }); + + it('sets scrollPos to top when at the top', done => { + spyOnProperty(vm.$refs.buildTrace, 'scrollTop').and.returnValue(0); + vm.scrollPos = 1; + + vm.scrollBuildLog(); + + setTimeout(() => { + expect(vm.scrollPos).toBe(0); + + done(); + }); + }); + + it('resets scrollPos when not at top or bottom', done => { + spyOnProperty(vm.$refs.buildTrace, 'scrollTop').and.returnValue(10); + + vm.scrollBuildLog(); + + setTimeout(() => { + expect(vm.scrollPos).toBe(''); + + done(); + }); + }); + }); +}); -- cgit v1.2.1 From ec37b1b20c09d3a5b5a0e2cd0b03311ec95d7c68 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 6 Jun 2018 08:43:15 +0100 Subject: added empty state --- spec/javascripts/ide/components/jobs/detail_spec.js | 10 ++++++++++ spec/javascripts/ide/components/jobs/item_spec.js | 10 ++++++++++ 2 files changed, 20 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/ide/components/jobs/detail_spec.js b/spec/javascripts/ide/components/jobs/detail_spec.js index 00a2dc6c74c..641ba06f653 100644 --- a/spec/javascripts/ide/components/jobs/detail_spec.js +++ b/spec/javascripts/ide/components/jobs/detail_spec.js @@ -47,6 +47,16 @@ describe('IDE jobs detail view', () => { expect(vm.$el.querySelector('.bash').textContent).toContain('testing'); }); + it('renders empty message output', done => { + vm.$store.state.pipelines.detailJob.output = ''; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.bash').textContent).toContain('No messages were logged'); + + done(); + }); + }); + it('renders loading icon', () => { expect(vm.$el.querySelector('.build-loader-animation')).not.toBe(null); expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe(''); diff --git a/spec/javascripts/ide/components/jobs/item_spec.js b/spec/javascripts/ide/components/jobs/item_spec.js index 7c1dd4e475c..79e07f00e7b 100644 --- a/spec/javascripts/ide/components/jobs/item_spec.js +++ b/spec/javascripts/ide/components/jobs/item_spec.js @@ -26,4 +26,14 @@ describe('IDE jobs item', () => { it('renders CI icon', () => { expect(vm.$el.querySelector('.ic-status_passed_borderless')).not.toBe(null); }); + + it('does not render view logs button if not started', done => { + vm.job.started = false; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.btn')).toBe(null); + + done(); + }); + }); }); -- cgit v1.2.1 From c8f0e4b5da0c9d578035e74b524f5adcb80efcf6 Mon Sep 17 00:00:00 2001 From: Imre Date: Fri, 18 May 2018 10:49:02 +0200 Subject: Add Avatar API --- spec/requests/api/avatar_spec.rb | 106 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 spec/requests/api/avatar_spec.rb (limited to 'spec') diff --git a/spec/requests/api/avatar_spec.rb b/spec/requests/api/avatar_spec.rb new file mode 100644 index 00000000000..26e0435a6d5 --- /dev/null +++ b/spec/requests/api/avatar_spec.rb @@ -0,0 +1,106 @@ +require 'spec_helper' + +describe API::Avatar do + let(:gravatar_service) { double('GravatarService') } + + describe 'GET /avatar' do + context 'avatar uploaded to GitLab' do + context 'user with matching public email address' do + let(:user) { create(:user, :with_avatar, email: 'public@example.com', public_email: 'public@example.com') } + + before do + user + end + + it 'returns the avatar url' do + get api('/avatar'), { email: 'public@example.com' } + + expect(response.status).to eq 200 + expect(json_response['avatar_url']).to eql("#{::Settings.gitlab.base_url}#{user.avatar.local_url}") + end + end + + context 'no user with matching public email address' do + before do + expect(GravatarService).to receive(:new).and_return(gravatar_service) + expect(gravatar_service).to( + receive(:execute) + .with('private@example.com', nil, 2, { username: nil }) + .and_return('https://gravatar')) + end + + it 'returns the avatar url from Gravatar' do + get api('/avatar'), { email: 'private@example.com' } + + expect(response.status).to eq 200 + expect(json_response['avatar_url']).to eq('https://gravatar') + end + end + end + + context 'avatar uploaded to Gravatar' do + context 'user with matching public email address' do + let(:user) { create(:user, email: 'public@example.com', public_email: 'public@example.com') } + + before do + user + + expect(GravatarService).to receive(:new).and_return(gravatar_service) + expect(gravatar_service).to( + receive(:execute) + .with('public@example.com', nil, 2, { username: user.username }) + .and_return('https://gravatar')) + end + + it 'returns the avatar url from Gravatar' do + get api('/avatar'), { email: 'public@example.com' } + + expect(response.status).to eq 200 + expect(json_response['avatar_url']).to eq('https://gravatar') + end + end + + context 'no user with matching public email address' do + before do + expect(GravatarService).to receive(:new).and_return(gravatar_service) + expect(gravatar_service).to( + receive(:execute) + .with('private@example.com', nil, 2, { username: nil }) + .and_return('https://gravatar')) + end + + it 'returns the avatar url from Gravatar' do + get api('/avatar'), { email: 'private@example.com' } + + expect(response.status).to eq 200 + expect(json_response['avatar_url']).to eq('https://gravatar') + end + end + + context 'public visibility level restricted' do + let(:user) { create(:user, :with_avatar, email: 'public@example.com', public_email: 'public@example.com') } + + before do + user + + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + context 'when authenticated' do + it 'returns the avatar url' do + get api('/avatar', user), { email: 'public@example.com' } + + expect(response.status).to eq 200 + expect(json_response['avatar_url']).to eql("#{::Settings.gitlab.base_url}#{user.avatar.local_url}") + end + end + + context 'when unauthenticated' do + it_behaves_like '403 response' do + let(:request) { get api('/avatar'), { email: 'public@example.com' } } + end + end + end + end + end +end -- cgit v1.2.1 From 3ed66d4abde28c9f586342fe8e6481360825b823 Mon Sep 17 00:00:00 2001 From: Tiago Botelho Date: Tue, 5 Jun 2018 19:12:26 +0100 Subject: Adds #human_import_status_name to make it comply with ProjectImportState#human_status_name --- spec/models/project_spec.rb | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'spec') diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 9a76452a808..59d1671b036 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1693,6 +1693,31 @@ describe Project do end end + describe '#human_import_status_name' do + context 'when import_state exists' do + it 'returns the humanized status name' do + project = create(:project) + create(:import_state, :started, project: project) + + expect(project.human_import_status_name).to eq("started") + end + end + + context 'when import_state was not created yet' do + let(:project) { create(:project, :import_started) } + + it 'ensures import_state is created and returns humanized status name' do + expect do + project.human_import_status_name + end.to change { ProjectImportState.count }.from(0).to(1) + end + + it 'returns humanized status name' do + expect(project.human_import_status_name).to eq("started") + end + end + end + describe 'Project import job' do let(:project) { create(:project, import_url: generate(:url)) } -- cgit v1.2.1 From 3a722ff53fe86ce6194f81ade810196f4f8e870c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Tue, 5 Jun 2018 22:34:06 -0700 Subject: Show a more helpful error for import status Importing a project from GitHub for a project namespace that already exists would show an unhelpful error, "An error occurred while importing project." We now add the base message from Projects::CreateService when this fails. Closes #47365 --- spec/javascripts/importer_status_spec.js | 18 ++++++++++++++++ .../githubish_import_controller_shared_examples.rb | 24 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/importer_status_spec.js b/spec/javascripts/importer_status_spec.js index 87b46ccf7c3..63cdb3d5114 100644 --- a/spec/javascripts/importer_status_spec.js +++ b/spec/javascripts/importer_status_spec.js @@ -50,6 +50,24 @@ describe('Importer Status', () => { }) .catch(done.fail); }); + + it('shows error message after failed POST request', (done) => { + appendSetFixtures('
'); + + mock.onPost(importUrl).reply(422, { + errors: 'You forgot your lunch', + }); + + instance.addToImport({ + currentTarget: document.querySelector('.js-add-to-import'), + }) + .then(() => { + const flashMessage = document.querySelector('.flash-text'); + expect(flashMessage.textContent.trim()).toEqual('An error occurred while importing project: You forgot your lunch'); + done(); + }) + .catch(done.fail); + }); }); describe('autoUpdate', () => { diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb index 368439aa5b0..1a53c5fa487 100644 --- a/spec/support/controllers/githubish_import_controller_shared_examples.rb +++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb @@ -118,14 +118,34 @@ shared_examples 'a GitHub-ish import controller: POST create' do expect(response).to have_gitlab_http_status(200) end - it 'returns 422 response when the project could not be imported' do + it 'returns 422 response with the base error when the project could not be imported' do + project = build(:project) + error_message = 'This is an error' + project.errors.add(:base, error_message) + + allow(Gitlab::LegacyGithubImport::ProjectCreator) + .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider) + .and_return(double(execute: project)) + + post :create, format: :json + + expect(response).to have_gitlab_http_status(422) + expect(json_response['errors']).to eq(error_message) + end + + it 'returns 422 response with a combined error when the project could not be imported' do + project = build(:project) + project.errors.add(:name, 'is invalid') + project.errors.add(:path, 'is old') + allow(Gitlab::LegacyGithubImport::ProjectCreator) .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider) - .and_return(double(execute: build(:project))) + .and_return(double(execute: project)) post :create, format: :json expect(response).to have_gitlab_http_status(422) + expect(json_response['errors']).to eq('Name is invalid, Path is old') end context "when the repository owner is the provider user" do -- cgit v1.2.1 From 4b458ca79ad516cbc556ad9cd7e384c10bce037f Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 23 May 2018 15:51:50 +0900 Subject: Add tests --- .../workers/rescue_stale_live_trace_worker_spec.rb | 71 ++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 spec/workers/rescue_stale_live_trace_worker_spec.rb (limited to 'spec') diff --git a/spec/workers/rescue_stale_live_trace_worker_spec.rb b/spec/workers/rescue_stale_live_trace_worker_spec.rb new file mode 100644 index 00000000000..f2b6361c54b --- /dev/null +++ b/spec/workers/rescue_stale_live_trace_worker_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe RescueStaleLiveTraceWorker do + subject { described_class.new.perform } + + before do + stub_feature_flags(ci_enable_live_trace: true) + end + + shared_examples_for 'schedules to archive traces' do + it do + expect(ArchiveTraceWorker).to receive(:bulk_perform_async).with([[build.id]]) + + subject + end + end + + shared_examples_for 'does not schedule to archive traces' do + it do + expect(ArchiveTraceWorker).not_to receive(:bulk_perform_async) + + subject + end + end + + context 'when a job was succeeded 2 hours ago' do + let!(:build) { create(:ci_build, :success, :trace_live) } + + before do + build.update(finished_at: 2.hours.ago) + end + + it_behaves_like 'schedules to archive traces' + end + + context 'when a job was failed 2 hours ago' do + let!(:build) { create(:ci_build, :failed, :trace_live) } + + before do + build.update(finished_at: 2.hours.ago) + end + + it_behaves_like 'schedules to archive traces' + end + + context 'when a job was cancelled 2 hours ago' do + let!(:build) { create(:ci_build, :canceled, :trace_live) } + + before do + build.update(finished_at: 2.hours.ago) + end + + it_behaves_like 'schedules to archive traces' + end + + context 'when a job has been finished 10 minutes ago' do + let!(:build) { create(:ci_build, :success, :trace_live) } + + before do + build.update(finished_at: 10.minutes.ago) + end + + it_behaves_like 'does not schedule to archive traces' + end + + context 'when a job is running' do + let!(:build) { create(:ci_build, :running, :trace_live) } + + it_behaves_like 'does not schedule to archive traces' + end +end -- cgit v1.2.1 From fb1e35e556f50636645d48c739dad37a4c7f722c Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Thu, 31 May 2018 16:29:17 +0900 Subject: Fix spec fiel location --- .../ci/rescue_stale_live_trace_worker_spec.rb | 71 ++++++++++++++++++++++ .../workers/rescue_stale_live_trace_worker_spec.rb | 71 ---------------------- 2 files changed, 71 insertions(+), 71 deletions(-) create mode 100644 spec/workers/ci/rescue_stale_live_trace_worker_spec.rb delete mode 100644 spec/workers/rescue_stale_live_trace_worker_spec.rb (limited to 'spec') diff --git a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb new file mode 100644 index 00000000000..87796fd66db --- /dev/null +++ b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe Ci::RescueStaleLiveTraceWorker do + subject { described_class.new.perform } + + before do + stub_feature_flags(ci_enable_live_trace: true) + end + + shared_examples_for 'schedules to archive traces' do + it do + expect(ArchiveTraceWorker).to receive(:bulk_perform_async).with([[build.id]]) + + subject + end + end + + shared_examples_for 'does not schedule to archive traces' do + it do + expect(ArchiveTraceWorker).not_to receive(:bulk_perform_async) + + subject + end + end + + context 'when a job was succeeded 2 hours ago' do + let!(:build) { create(:ci_build, :success, :trace_live) } + + before do + build.update(finished_at: 2.hours.ago) + end + + it_behaves_like 'schedules to archive traces' + end + + context 'when a job was failed 2 hours ago' do + let!(:build) { create(:ci_build, :failed, :trace_live) } + + before do + build.update(finished_at: 2.hours.ago) + end + + it_behaves_like 'schedules to archive traces' + end + + context 'when a job was cancelled 2 hours ago' do + let!(:build) { create(:ci_build, :canceled, :trace_live) } + + before do + build.update(finished_at: 2.hours.ago) + end + + it_behaves_like 'schedules to archive traces' + end + + context 'when a job has been finished 10 minutes ago' do + let!(:build) { create(:ci_build, :success, :trace_live) } + + before do + build.update(finished_at: 10.minutes.ago) + end + + it_behaves_like 'does not schedule to archive traces' + end + + context 'when a job is running' do + let!(:build) { create(:ci_build, :running, :trace_live) } + + it_behaves_like 'does not schedule to archive traces' + end +end diff --git a/spec/workers/rescue_stale_live_trace_worker_spec.rb b/spec/workers/rescue_stale_live_trace_worker_spec.rb deleted file mode 100644 index f2b6361c54b..00000000000 --- a/spec/workers/rescue_stale_live_trace_worker_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -require 'spec_helper' - -describe RescueStaleLiveTraceWorker do - subject { described_class.new.perform } - - before do - stub_feature_flags(ci_enable_live_trace: true) - end - - shared_examples_for 'schedules to archive traces' do - it do - expect(ArchiveTraceWorker).to receive(:bulk_perform_async).with([[build.id]]) - - subject - end - end - - shared_examples_for 'does not schedule to archive traces' do - it do - expect(ArchiveTraceWorker).not_to receive(:bulk_perform_async) - - subject - end - end - - context 'when a job was succeeded 2 hours ago' do - let!(:build) { create(:ci_build, :success, :trace_live) } - - before do - build.update(finished_at: 2.hours.ago) - end - - it_behaves_like 'schedules to archive traces' - end - - context 'when a job was failed 2 hours ago' do - let!(:build) { create(:ci_build, :failed, :trace_live) } - - before do - build.update(finished_at: 2.hours.ago) - end - - it_behaves_like 'schedules to archive traces' - end - - context 'when a job was cancelled 2 hours ago' do - let!(:build) { create(:ci_build, :canceled, :trace_live) } - - before do - build.update(finished_at: 2.hours.ago) - end - - it_behaves_like 'schedules to archive traces' - end - - context 'when a job has been finished 10 minutes ago' do - let!(:build) { create(:ci_build, :success, :trace_live) } - - before do - build.update(finished_at: 10.minutes.ago) - end - - it_behaves_like 'does not schedule to archive traces' - end - - context 'when a job is running' do - let!(:build) { create(:ci_build, :running, :trace_live) } - - it_behaves_like 'does not schedule to archive traces' - end -end -- cgit v1.2.1 From 32f825c648cb5fc829cd32b3392530613c62e983 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 1 Jun 2018 14:22:31 +0900 Subject: Add tests for each new code --- spec/lib/gitlab/ci/trace_spec.rb | 2 +- spec/models/ci/build_trace_chunk_spec.rb | 40 ++++++++++++++++++++++ .../shared_examples/ci_trace_shared_examples.rb | 25 ++++++++++++++ .../ci/rescue_stale_live_trace_worker_spec.rb | 34 ++++++++++++------ 4 files changed, 89 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb index e9d755c2021..d6510649dba 100644 --- a/spec/lib/gitlab/ci/trace_spec.rb +++ b/spec/lib/gitlab/ci/trace_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Gitlab::Ci::Trace, :clean_gitlab_redis_cache do +describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state do let(:build) { create(:ci_build) } let(:trace) { described_class.new(build) } diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb index cbcf1e55979..246152d1c8f 100644 --- a/spec/models/ci/build_trace_chunk_spec.rb +++ b/spec/models/ci/build_trace_chunk_spec.rb @@ -35,6 +35,46 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do end end + describe '.find_stale_in_batches' do + subject { described_class.find_stale_in_batches } + + context 'when build status is finished' do + context 'when build finished 2 days ago' do + context 'when build has an archived trace' do + let!(:build) { create(:ci_build, :success, :trace_artifact, finished_at: 2.days.ago) } + + it 'does not yield build id' do + expect { |b| described_class.find_stale_in_batches(&b) }.not_to yield_control + end + end + + context 'when build has a live trace' do + let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } + + it 'yields build id' do + expect { |b| described_class.find_stale_in_batches(&b) }.to yield_with_args([build.id]) + end + end + end + + context 'when build finished 10 minutes ago' do + let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 10.minutes.ago) } + + it 'does not yield build id' do + expect { |b| described_class.find_stale_in_batches(&b) }.not_to yield_control + end + end + end + + context 'when build status is running' do + let!(:build) { create(:ci_build, :running, :trace_live) } + + it 'does not yield build id' do + expect { |b| described_class.find_stale_in_batches(&b) }.not_to yield_control + end + end + end + describe '#data' do subject { build_trace_chunk.data } diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb index 21c6f3c829f..a3a0b2d0eb5 100644 --- a/spec/support/shared_examples/ci_trace_shared_examples.rb +++ b/spec/support/shared_examples/ci_trace_shared_examples.rb @@ -227,6 +227,31 @@ shared_examples_for 'common trace features' do end end end + + describe '#archive!' do + subject { trace.archive! } + + context 'when build status is success' do + let!(:build) { create(:ci_build, :success, :trace_live) } + + it 'archives a trace' do + subject + + expect(build.job_artifacts_trace).to be_exist + end + + context 'when anothe process had already been archiving', :clean_gitlab_redis_shared_state do + before do + Gitlab::ExclusiveLease.new("trace:archive:#{trace.job.id}", timeout: 1.hour).try_obtain + end + + it 'prevents multiple archiving' do + build.reload + expect(build.job_artifacts_trace).to be_nil + end + end + end + end end shared_examples_for 'trace with disabled live trace feature' do diff --git a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb index 87796fd66db..43a6362a131 100644 --- a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb +++ b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb @@ -7,19 +7,20 @@ describe Ci::RescueStaleLiveTraceWorker do stub_feature_flags(ci_enable_live_trace: true) end - shared_examples_for 'schedules to archive traces' do + shared_examples_for 'archives trace' do it do - expect(ArchiveTraceWorker).to receive(:bulk_perform_async).with([[build.id]]) - subject + + expect(build.job_artifacts_trace).to be_exist end end - shared_examples_for 'does not schedule to archive traces' do + shared_examples_for 'does not archive trace' do it do - expect(ArchiveTraceWorker).not_to receive(:bulk_perform_async) - subject + + build.reload + expect(build.job_artifacts_trace).to be_nil end end @@ -30,7 +31,18 @@ describe Ci::RescueStaleLiveTraceWorker do build.update(finished_at: 2.hours.ago) end - it_behaves_like 'schedules to archive traces' + it_behaves_like 'archives trace' + + context 'when build has both archived trace and live trace' do + let!(:build2) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } + + it 'archives only available targets' do + subject + + build.reload + expect(build.job_artifacts_trace).to be_exist + end + end end context 'when a job was failed 2 hours ago' do @@ -40,7 +52,7 @@ describe Ci::RescueStaleLiveTraceWorker do build.update(finished_at: 2.hours.ago) end - it_behaves_like 'schedules to archive traces' + it_behaves_like 'archives trace' end context 'when a job was cancelled 2 hours ago' do @@ -50,7 +62,7 @@ describe Ci::RescueStaleLiveTraceWorker do build.update(finished_at: 2.hours.ago) end - it_behaves_like 'schedules to archive traces' + it_behaves_like 'archives trace' end context 'when a job has been finished 10 minutes ago' do @@ -60,12 +72,12 @@ describe Ci::RescueStaleLiveTraceWorker do build.update(finished_at: 10.minutes.ago) end - it_behaves_like 'does not schedule to archive traces' + it_behaves_like 'does not archive trace' end context 'when a job is running' do let!(:build) { create(:ci_build, :running, :trace_live) } - it_behaves_like 'does not schedule to archive traces' + it_behaves_like 'does not archive trace' end end -- cgit v1.2.1 From 2522691eda46ef3ed572b747074e9b3b2e776198 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 1 Jun 2018 16:15:41 +0900 Subject: Fix ambiguous stuck ci job worker's spec. Rename lease key of archive --- spec/workers/ci/rescue_stale_live_trace_worker_spec.rb | 2 +- spec/workers/stuck_ci_jobs_worker_spec.rb | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb index 43a6362a131..1a694290562 100644 --- a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb +++ b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb @@ -35,7 +35,7 @@ describe Ci::RescueStaleLiveTraceWorker do context 'when build has both archived trace and live trace' do let!(:build2) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } - + it 'archives only available targets' do subject diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb index bdc64c6785b..c3294fce5ea 100644 --- a/spec/workers/stuck_ci_jobs_worker_spec.rb +++ b/spec/workers/stuck_ci_jobs_worker_spec.rb @@ -132,8 +132,10 @@ describe StuckCiJobsWorker do end it 'cancels exclusive lease after worker perform' do - expect(Gitlab::ExclusiveLease).to receive(:cancel).with(described_class::EXCLUSIVE_LEASE_KEY, exclusive_lease_uuid) worker.perform + + expect(Gitlab::ExclusiveLease.new(described_class::EXCLUSIVE_LEASE_KEY, timeout: 1.hour).exists?) + .to be_falsy end end end -- cgit v1.2.1 From 4064481501a24d31872914c845f5d8c2cfc08040 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 1 Jun 2018 16:25:17 +0900 Subject: Rename find_stale_in_batches to find_builds_from_stale_live_trace. Fix comments --- spec/models/ci/build_trace_chunk_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb index 246152d1c8f..5d524d7cf49 100644 --- a/spec/models/ci/build_trace_chunk_spec.rb +++ b/spec/models/ci/build_trace_chunk_spec.rb @@ -35,8 +35,8 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do end end - describe '.find_stale_in_batches' do - subject { described_class.find_stale_in_batches } + describe '.find_builds_from_stale_live_trace' do + subject { described_class.find_builds_from_stale_live_trace } context 'when build status is finished' do context 'when build finished 2 days ago' do @@ -44,7 +44,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :success, :trace_artifact, finished_at: 2.days.ago) } it 'does not yield build id' do - expect { |b| described_class.find_stale_in_batches(&b) }.not_to yield_control + expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.not_to yield_control end end @@ -52,7 +52,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } it 'yields build id' do - expect { |b| described_class.find_stale_in_batches(&b) }.to yield_with_args([build.id]) + expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.to yield_with_args([build.id]) end end end @@ -61,7 +61,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 10.minutes.ago) } it 'does not yield build id' do - expect { |b| described_class.find_stale_in_batches(&b) }.not_to yield_control + expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.not_to yield_control end end end @@ -70,7 +70,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :running, :trace_live) } it 'does not yield build id' do - expect { |b| described_class.find_stale_in_batches(&b) }.not_to yield_control + expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.not_to yield_control end end end -- cgit v1.2.1 From 2084e7ab9aad92d4a8196af01b9b8e02ffacb0a4 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Fri, 1 Jun 2018 17:09:46 +0900 Subject: Move find_builds_from_stale_live_traces method to Ci::Build --- spec/models/ci/build_trace_chunk_spec.rb | 12 ++++++------ spec/workers/ci/rescue_stale_live_trace_worker_spec.rb | 17 +++++++++-------- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb index 5d524d7cf49..2dd8e935d62 100644 --- a/spec/models/ci/build_trace_chunk_spec.rb +++ b/spec/models/ci/build_trace_chunk_spec.rb @@ -35,8 +35,8 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do end end - describe '.find_builds_from_stale_live_trace' do - subject { described_class.find_builds_from_stale_live_trace } + describe '.find_builds_from_stale_live_traces' do + subject { described_class.find_builds_from_stale_live_traces } context 'when build status is finished' do context 'when build finished 2 days ago' do @@ -44,7 +44,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :success, :trace_artifact, finished_at: 2.days.ago) } it 'does not yield build id' do - expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.not_to yield_control + expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.not_to yield_control end end @@ -52,7 +52,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } it 'yields build id' do - expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.to yield_with_args([build.id]) + expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.to yield_with_args([build.id]) end end end @@ -61,7 +61,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 10.minutes.ago) } it 'does not yield build id' do - expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.not_to yield_control + expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.not_to yield_control end end end @@ -70,7 +70,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do let!(:build) { create(:ci_build, :running, :trace_live) } it 'does not yield build id' do - expect { |b| described_class.find_builds_from_stale_live_trace(&b) }.not_to yield_control + expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.not_to yield_control end end end diff --git a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb index 1a694290562..6eee08fdbb5 100644 --- a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb +++ b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb @@ -11,6 +11,7 @@ describe Ci::RescueStaleLiveTraceWorker do it do subject + build.reload expect(build.job_artifacts_trace).to be_exist end end @@ -33,16 +34,16 @@ describe Ci::RescueStaleLiveTraceWorker do it_behaves_like 'archives trace' - context 'when build has both archived trace and live trace' do - let!(:build2) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } + # context 'when build has both archived trace and live trace' do + # let!(:build2) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } - it 'archives only available targets' do - subject + # it 'archives only available targets' do + # subject - build.reload - expect(build.job_artifacts_trace).to be_exist - end - end + # build.reload + # expect(build.job_artifacts_trace).to be_exist + # end + # end end context 'when a job was failed 2 hours ago' do -- cgit v1.2.1 From 5a1ee0c391a06a323d960eab6ffb33dfcf2edca7 Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Sat, 2 Jun 2018 13:08:34 +0900 Subject: Fix the query to select stale live traces --- spec/models/ci/build_spec.rb | 20 +++++++++ spec/models/ci/build_trace_chunk_spec.rb | 40 ------------------ .../ci/rescue_stale_live_trace_worker_spec.rb | 47 +++++----------------- spec/workers/stuck_ci_jobs_worker_spec.rb | 4 +- 4 files changed, 33 insertions(+), 78 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 5e27cca6771..1b26c8d3b49 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -116,6 +116,26 @@ describe Ci::Build do end end + describe '.with_live_trace' do + subject { described_class.with_live_trace } + + context 'when build has live trace' do + let!(:build) { create(:ci_build, :success, :trace_live) } + + it 'selects the build' do + is_expected.to eq([build]) + end + end + + context 'when build does not have live trace' do + let!(:build) { create(:ci_build, :success, :trace_artifact) } + + it 'selects the build' do + is_expected.to be_empty + end + end + end + describe '#actionize' do context 'when build is a created' do before do diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb index 2dd8e935d62..cbcf1e55979 100644 --- a/spec/models/ci/build_trace_chunk_spec.rb +++ b/spec/models/ci/build_trace_chunk_spec.rb @@ -35,46 +35,6 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do end end - describe '.find_builds_from_stale_live_traces' do - subject { described_class.find_builds_from_stale_live_traces } - - context 'when build status is finished' do - context 'when build finished 2 days ago' do - context 'when build has an archived trace' do - let!(:build) { create(:ci_build, :success, :trace_artifact, finished_at: 2.days.ago) } - - it 'does not yield build id' do - expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.not_to yield_control - end - end - - context 'when build has a live trace' do - let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } - - it 'yields build id' do - expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.to yield_with_args([build.id]) - end - end - end - - context 'when build finished 10 minutes ago' do - let!(:build) { create(:ci_build, :success, :trace_live, finished_at: 10.minutes.ago) } - - it 'does not yield build id' do - expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.not_to yield_control - end - end - end - - context 'when build status is running' do - let!(:build) { create(:ci_build, :running, :trace_live) } - - it 'does not yield build id' do - expect { |b| described_class.find_builds_from_stale_live_traces(&b) }.not_to yield_control - end - end - end - describe '#data' do subject { build_trace_chunk.data } diff --git a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb index 6eee08fdbb5..0e3fbe2d3a9 100644 --- a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb +++ b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb @@ -25,57 +25,32 @@ describe Ci::RescueStaleLiveTraceWorker do end end - context 'when a job was succeeded 2 hours ago' do + context 'when a job was succeeded' do let!(:build) { create(:ci_build, :success, :trace_live) } - before do - build.update(finished_at: 2.hours.ago) - end - it_behaves_like 'archives trace' - # context 'when build has both archived trace and live trace' do - # let!(:build2) { create(:ci_build, :success, :trace_live, finished_at: 2.days.ago) } + context 'when archive raised an exception' do + let!(:build) { create(:ci_build, :success, :trace_artifact, :trace_live) } + let!(:build2) { create(:ci_build, :success, :trace_live) } - # it 'archives only available targets' do - # subject - - # build.reload - # expect(build.job_artifacts_trace).to be_exist - # end - # end - end + it 'archives valid targets' do + expect(Rails.logger).to receive(:error).with("Failed to archive stale live trace. id: #{build.id} message: Already archived") - context 'when a job was failed 2 hours ago' do - let!(:build) { create(:ci_build, :failed, :trace_live) } + subject - before do - build.update(finished_at: 2.hours.ago) + build2.reload + expect(build2.job_artifacts_trace).to be_exist + end end - - it_behaves_like 'archives trace' end - context 'when a job was cancelled 2 hours ago' do + context 'when a job was cancelled' do let!(:build) { create(:ci_build, :canceled, :trace_live) } - before do - build.update(finished_at: 2.hours.ago) - end - it_behaves_like 'archives trace' end - context 'when a job has been finished 10 minutes ago' do - let!(:build) { create(:ci_build, :success, :trace_live) } - - before do - build.update(finished_at: 10.minutes.ago) - end - - it_behaves_like 'does not archive trace' - end - context 'when a job is running' do let!(:build) { create(:ci_build, :running, :trace_live) } diff --git a/spec/workers/stuck_ci_jobs_worker_spec.rb b/spec/workers/stuck_ci_jobs_worker_spec.rb index c3294fce5ea..2605c14334f 100644 --- a/spec/workers/stuck_ci_jobs_worker_spec.rb +++ b/spec/workers/stuck_ci_jobs_worker_spec.rb @@ -134,8 +134,8 @@ describe StuckCiJobsWorker do it 'cancels exclusive lease after worker perform' do worker.perform - expect(Gitlab::ExclusiveLease.new(described_class::EXCLUSIVE_LEASE_KEY, timeout: 1.hour).exists?) - .to be_falsy + expect(Gitlab::ExclusiveLease.new(described_class::EXCLUSIVE_LEASE_KEY, timeout: 1.hour)) + .not_to be_exists end end end -- cgit v1.2.1 From f9b821f08dfc8feee2ed8a06c8f21c85c3c9d2ec Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Sat, 2 Jun 2018 14:09:24 +0900 Subject: Fix specs for exclusive lease --- .../shared_examples/ci_trace_shared_examples.rb | 29 ++++++++++++++-------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb index a3a0b2d0eb5..59efce1b5f0 100644 --- a/spec/support/shared_examples/ci_trace_shared_examples.rb +++ b/spec/support/shared_examples/ci_trace_shared_examples.rb @@ -234,20 +234,29 @@ shared_examples_for 'common trace features' do context 'when build status is success' do let!(:build) { create(:ci_build, :success, :trace_live) } - it 'archives a trace' do - subject - - expect(build.job_artifacts_trace).to be_exist + it 'does not have an archived trace yet' do + expect(build.job_artifacts_trace).to be_nil end - context 'when anothe process had already been archiving', :clean_gitlab_redis_shared_state do - before do - Gitlab::ExclusiveLease.new("trace:archive:#{trace.job.id}", timeout: 1.hour).try_obtain - end + context 'when archives' do + it 'has an archived trace' do + subject - it 'prevents multiple archiving' do build.reload - expect(build.job_artifacts_trace).to be_nil + expect(build.job_artifacts_trace).to be_exist + end + + context 'when anothe process had already been archiving', :clean_gitlab_redis_shared_state do + before do + Gitlab::ExclusiveLease.new("trace:archive:#{trace.job.id}", timeout: 1.hour).try_obtain + end + + it 'prevents to archive concurently' do + subject + + build.reload + expect(build.job_artifacts_trace).to be_nil + end end end end -- cgit v1.2.1 From cae17352761d9c34de444cb95e77d8fa1a8bd56a Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Mon, 4 Jun 2018 14:12:45 +0900 Subject: Fix typos and add a small spec --- spec/models/ci/build_spec.rb | 2 +- spec/support/shared_examples/ci_trace_shared_examples.rb | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 1b26c8d3b49..0a0d7d3fea9 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -130,7 +130,7 @@ describe Ci::Build do context 'when build does not have live trace' do let!(:build) { create(:ci_build, :success, :trace_artifact) } - it 'selects the build' do + it 'does not select the build' do is_expected.to be_empty end end diff --git a/spec/support/shared_examples/ci_trace_shared_examples.rb b/spec/support/shared_examples/ci_trace_shared_examples.rb index 59efce1b5f0..6dbe0f6f980 100644 --- a/spec/support/shared_examples/ci_trace_shared_examples.rb +++ b/spec/support/shared_examples/ci_trace_shared_examples.rb @@ -246,12 +246,14 @@ shared_examples_for 'common trace features' do expect(build.job_artifacts_trace).to be_exist end - context 'when anothe process had already been archiving', :clean_gitlab_redis_shared_state do + context 'when another process has already been archiving', :clean_gitlab_redis_shared_state do before do Gitlab::ExclusiveLease.new("trace:archive:#{trace.job.id}", timeout: 1.hour).try_obtain end - it 'prevents to archive concurently' do + it 'blocks concurrent archiving' do + expect(Rails.logger).to receive(:error).with('Cannot obtain an exclusive lease. There must be another instance already in execution.') + subject build.reload -- cgit v1.2.1 From 9b65d4bb417fb4939289eab94487c894f0a62db6 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 23 May 2018 09:55:14 +0200 Subject: Initial setup GraphQL using graphql-ruby 1.8 - All definitions have been replaced by classes: http://graphql-ruby.org/schema/class_based_api.html - Authorization & Presentation have been refactored to work in the class based system - Loaders have been replaced by resolvers - Times are now coersed as ISO 8601 --- spec/graphql/gitlab_schema_spec.rb | 15 +++--- spec/graphql/loaders/full_path_loader_spec.rb | 32 ------------ spec/graphql/loaders/iid_loader_spec.rb | 58 ---------------------- .../resolvers/merge_request_resolver_spec.rb | 58 ++++++++++++++++++++++ spec/graphql/resolvers/project_resolver_spec.rb | 32 ++++++++++++ spec/graphql/types/project_type_spec.rb | 5 ++ spec/graphql/types/query_type_spec.rb | 10 ++-- spec/graphql/types/time_type_spec.rb | 14 +++--- .../api/graphql/merge_request_query_spec.rb | 49 ++++++++++++++++++ spec/requests/api/graphql/project_query_spec.rb | 39 +++++++++++++++ spec/requests/graphql/merge_request_query_spec.rb | 24 --------- spec/requests/graphql/project_query_spec.rb | 23 --------- spec/routing/api_routing_spec.rb | 31 ++++++++++++ spec/support/helpers/graphql_helpers.rb | 47 +++++++++++++++--- spec/support/matchers/graphql_matchers.rb | 23 ++++++--- .../requests/graphql_shared_examples.rb | 11 +--- 16 files changed, 292 insertions(+), 179 deletions(-) delete mode 100644 spec/graphql/loaders/full_path_loader_spec.rb delete mode 100644 spec/graphql/loaders/iid_loader_spec.rb create mode 100644 spec/graphql/resolvers/merge_request_resolver_spec.rb create mode 100644 spec/graphql/resolvers/project_resolver_spec.rb create mode 100644 spec/graphql/types/project_type_spec.rb create mode 100644 spec/requests/api/graphql/merge_request_query_spec.rb create mode 100644 spec/requests/api/graphql/project_query_spec.rb delete mode 100644 spec/requests/graphql/merge_request_query_spec.rb delete mode 100644 spec/requests/graphql/project_query_spec.rb create mode 100644 spec/routing/api_routing_spec.rb (limited to 'spec') diff --git a/spec/graphql/gitlab_schema_spec.rb b/spec/graphql/gitlab_schema_spec.rb index f25cc2fd6c9..b892f6b44ed 100644 --- a/spec/graphql/gitlab_schema_spec.rb +++ b/spec/graphql/gitlab_schema_spec.rb @@ -6,26 +6,25 @@ describe GitlabSchema do end it 'enables the preload instrumenter' do - expect(field_instrumenters).to include(instance_of(::GraphQL::Preload::Instrument)) + expect(field_instrumenters).to include(BatchLoader::GraphQL) end it 'enables the authorization instrumenter' do - expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Authorize)) + expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Authorize::Instrumentation)) end it 'enables using presenters' do - expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Present)) + expect(field_instrumenters).to include(instance_of(::Gitlab::Graphql::Present::Instrumentation)) end it 'has the base mutation' do - pending <<~REASON - Having empty mutations breaks the automatic documentation in Graphiql, so removed for now." - REASON - expect(described_class.mutation).to eq(::Types::MutationType) + pending('Adding an empty mutation breaks the documentation explorer') + + expect(described_class.mutation).to eq(::Types::MutationType.to_graphql) end it 'has the base query' do - expect(described_class.query).to eq(::Types::QueryType) + expect(described_class.query).to eq(::Types::QueryType.to_graphql) end def field_instrumenters diff --git a/spec/graphql/loaders/full_path_loader_spec.rb b/spec/graphql/loaders/full_path_loader_spec.rb deleted file mode 100644 index 2732dd8c9da..00000000000 --- a/spec/graphql/loaders/full_path_loader_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require 'spec_helper' - -describe Loaders::FullPathLoader do - include GraphqlHelpers - - set(:project1) { create(:project) } - set(:project2) { create(:project) } - - set(:other_project) { create(:project) } - - describe '.project' do - it 'batch-resolves projects by full path' do - paths = [project1.full_path, project2.full_path] - - result = batch(max_queries: 1) do - paths.map { |path| resolve_project(path) } - end - - expect(result).to contain_exactly(project1, project2) - end - - it 'resolves an unknown full_path to nil' do - result = batch { resolve_project('unknown/project') } - - expect(result).to be_nil - end - end - - def resolve_project(full_path) - resolve(described_class, :project, args: { full_path: full_path }) - end -end diff --git a/spec/graphql/loaders/iid_loader_spec.rb b/spec/graphql/loaders/iid_loader_spec.rb deleted file mode 100644 index 0a57d7c4ed4..00000000000 --- a/spec/graphql/loaders/iid_loader_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -require 'spec_helper' - -describe Loaders::IidLoader do - include GraphqlHelpers - - set(:project) { create(:project, :repository) } - set(:merge_request_1) { create(:merge_request, :simple, source_project: project, target_project: project) } - set(:merge_request_2) { create(:merge_request, :rebased, source_project: project, target_project: project) } - - set(:other_project) { create(:project, :repository) } - set(:other_merge_request) { create(:merge_request, source_project: other_project, target_project: other_project) } - - let(:full_path) { project.full_path } - let(:iid_1) { merge_request_1.iid } - let(:iid_2) { merge_request_2.iid } - - let(:other_full_path) { other_project.full_path } - let(:other_iid) { other_merge_request.iid } - - describe '.merge_request' do - it 'batch-resolves merge requests by target project full path and IID' do - path = full_path # avoid database query - - result = batch(max_queries: 2) do - [resolve_mr(path, iid_1), resolve_mr(path, iid_2)] - end - - expect(result).to contain_exactly(merge_request_1, merge_request_2) - end - - it 'can batch-resolve merge requests from different projects' do - path = project.full_path # avoid database queries - other_path = other_full_path - - result = batch(max_queries: 3) do - [resolve_mr(path, iid_1), resolve_mr(path, iid_2), resolve_mr(other_path, other_iid)] - end - - expect(result).to contain_exactly(merge_request_1, merge_request_2, other_merge_request) - end - - it 'resolves an unknown iid to nil' do - result = batch { resolve_mr(full_path, -1) } - - expect(result).to be_nil - end - - it 'resolves a known iid for an unknown full_path to nil' do - result = batch { resolve_mr('unknown/project', iid_1) } - - expect(result).to be_nil - end - end - - def resolve_mr(full_path, iid) - resolve(described_class, :merge_request, args: { project: full_path, iid: iid }) - end -end diff --git a/spec/graphql/resolvers/merge_request_resolver_spec.rb b/spec/graphql/resolvers/merge_request_resolver_spec.rb new file mode 100644 index 00000000000..af015533209 --- /dev/null +++ b/spec/graphql/resolvers/merge_request_resolver_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe Resolvers::MergeRequestResolver do + include GraphqlHelpers + + set(:project) { create(:project, :repository) } + set(:merge_request_1) { create(:merge_request, :simple, source_project: project, target_project: project) } + set(:merge_request_2) { create(:merge_request, :rebased, source_project: project, target_project: project) } + + set(:other_project) { create(:project, :repository) } + set(:other_merge_request) { create(:merge_request, source_project: other_project, target_project: other_project) } + + let(:full_path) { project.full_path } + let(:iid_1) { merge_request_1.iid } + let(:iid_2) { merge_request_2.iid } + + let(:other_full_path) { other_project.full_path } + let(:other_iid) { other_merge_request.iid } + + describe '#resolve' do + it 'batch-resolves merge requests by target project full path and IID' do + path = full_path # avoid database query + + result = batch(max_queries: 2) do + [resolve_mr(path, iid_1), resolve_mr(path, iid_2)] + end + + expect(result).to contain_exactly(merge_request_1, merge_request_2) + end + + it 'can batch-resolve merge requests from different projects' do + path = project.full_path # avoid database queries + other_path = other_full_path + + result = batch(max_queries: 3) do + [resolve_mr(path, iid_1), resolve_mr(path, iid_2), resolve_mr(other_path, other_iid)] + end + + expect(result).to contain_exactly(merge_request_1, merge_request_2, other_merge_request) + end + + it 'resolves an unknown iid to nil' do + result = batch { resolve_mr(full_path, -1) } + + expect(result).to be_nil + end + + it 'resolves a known iid for an unknown full_path to nil' do + result = batch { resolve_mr('unknown/project', iid_1) } + + expect(result).to be_nil + end + end + + def resolve_mr(full_path, iid) + resolve(described_class, args: { full_path: full_path, iid: iid }) + end +end diff --git a/spec/graphql/resolvers/project_resolver_spec.rb b/spec/graphql/resolvers/project_resolver_spec.rb new file mode 100644 index 00000000000..d4990c6492c --- /dev/null +++ b/spec/graphql/resolvers/project_resolver_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe Resolvers::ProjectResolver do + include GraphqlHelpers + + set(:project1) { create(:project) } + set(:project2) { create(:project) } + + set(:other_project) { create(:project) } + + describe '#resolve' do + it 'batch-resolves projects by full path' do + paths = [project1.full_path, project2.full_path] + + result = batch(max_queries: 1) do + paths.map { |path| resolve_project(path) } + end + + expect(result).to contain_exactly(project1, project2) + end + + it 'resolves an unknown full_path to nil' do + result = batch { resolve_project('unknown/project') } + + expect(result).to be_nil + end + end + + def resolve_project(full_path) + resolve(described_class, args: { full_path: full_path }) + end +end diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb new file mode 100644 index 00000000000..e0f89105b86 --- /dev/null +++ b/spec/graphql/types/project_type_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe GitlabSchema.types['Project'] do + it { expect(described_class.graphql_name).to eq('Project') } +end diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb index 17d9395504c..8488252fd59 100644 --- a/spec/graphql/types/query_type_spec.rb +++ b/spec/graphql/types/query_type_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GitlabSchema.types['Query'] do it 'is called Query' do - expect(described_class.name).to eq('Query') + expect(described_class.graphql_name).to eq('Query') end it { is_expected.to have_graphql_fields(:project, :merge_request, :echo) } @@ -13,7 +13,7 @@ describe GitlabSchema.types['Query'] do it 'finds projects by full path' do is_expected.to have_graphql_arguments(:full_path) is_expected.to have_graphql_type(Types::ProjectType) - is_expected.to have_graphql_resolver(Loaders::FullPathLoader[:project]) + is_expected.to have_graphql_resolver(Resolvers::ProjectResolver) end it 'authorizes with read_project' do @@ -22,12 +22,12 @@ describe GitlabSchema.types['Query'] do end describe 'merge_request field' do - subject { described_class.fields['merge_request'] } + subject { described_class.fields['mergeRequest'] } it 'finds MRs by project and IID' do - is_expected.to have_graphql_arguments(:project, :iid) + is_expected.to have_graphql_arguments(:full_path, :iid) is_expected.to have_graphql_type(Types::MergeRequestType) - is_expected.to have_graphql_resolver(Loaders::IidLoader[:merge_request]) + is_expected.to have_graphql_resolver(Resolvers::MergeRequestResolver) end it 'authorizes with read_merge_request' do diff --git a/spec/graphql/types/time_type_spec.rb b/spec/graphql/types/time_type_spec.rb index 087655cc67d..4196d9d27d4 100644 --- a/spec/graphql/types/time_type_spec.rb +++ b/spec/graphql/types/time_type_spec.rb @@ -1,16 +1,16 @@ require 'spec_helper' describe GitlabSchema.types['Time'] do - let(:float) { 1504630455.96215 } - let(:time) { Time.at(float) } + let(:iso) { "2018-06-04T15:23:50+02:00" } + let(:time) { Time.parse(iso) } - it { expect(described_class.name).to eq('Time') } + it { expect(described_class.graphql_name).to eq('Time') } - it 'coerces Time into fractional seconds since epoch' do - expect(described_class.coerce_isolated_result(time)).to eq(float) + it 'coerces Time object into ISO 8601' do + expect(described_class.coerce_isolated_result(time)).to eq(iso) end - it 'coerces fractional seconds since epoch into Time' do - expect(described_class.coerce_isolated_input(float)).to eq(time) + it 'coerces an ISO-time into Time object' do + expect(described_class.coerce_isolated_input(iso)).to eq(time) end end diff --git a/spec/requests/api/graphql/merge_request_query_spec.rb b/spec/requests/api/graphql/merge_request_query_spec.rb new file mode 100644 index 00000000000..12b1d5d18a2 --- /dev/null +++ b/spec/requests/api/graphql/merge_request_query_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe 'getting merge request information' do + include GraphqlHelpers + + let(:project) { create(:project, :repository) } + let(:merge_request) { create(:merge_request, source_project: project) } + let(:current_user) { create(:user) } + + let(:query) do + attributes = { + 'fullPath' => merge_request.project.full_path, + 'iid' => merge_request.iid + } + graphql_query_for('mergeRequest', attributes) + end + + context 'when the user has access to the merge request' do + before do + project.add_developer(current_user) + post_graphql(query, current_user: current_user) + end + + it 'returns the merge request' do + expect(graphql_data['mergeRequest']).not_to be_nil + end + + # This is a field coming from the `MergeRequestPresenter` + it 'includes a web_url' do + expect(graphql_data['mergeRequest']['webUrl']).to be_present + end + + it_behaves_like 'a working graphql query' + end + + context 'when the user does not have access to the merge request' do + before do + post_graphql(query, current_user: current_user) + end + + it 'returns an empty field' do + post_graphql(query, current_user: current_user) + + expect(graphql_data['mergeRequest']).to be_nil + end + + it_behaves_like 'a working graphql query' + end +end diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb new file mode 100644 index 00000000000..8196bcfa87c --- /dev/null +++ b/spec/requests/api/graphql/project_query_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe 'getting project information' do + include GraphqlHelpers + + let(:project) { create(:project, :repository) } + let(:current_user) { create(:user) } + + let(:query) do + graphql_query_for('project', 'fullPath' => project.full_path) + end + + context 'when the user has access to the project' do + before do + project.add_developer(current_user) + post_graphql(query, current_user: current_user) + end + + it 'includes the project' do + expect(graphql_data['project']).not_to be_nil + end + + it_behaves_like 'a working graphql query' + end + + context 'when the user does not have access to the project' do + before do + post_graphql(query, current_user: current_user) + end + + it 'returns an empty field' do + post_graphql(query, current_user: current_user) + + expect(graphql_data['project']).to be_nil + end + + it_behaves_like 'a working graphql query' + end +end diff --git a/spec/requests/graphql/merge_request_query_spec.rb b/spec/requests/graphql/merge_request_query_spec.rb deleted file mode 100644 index cbc19782e2f..00000000000 --- a/spec/requests/graphql/merge_request_query_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require 'spec_helper' - -describe 'getting merge request information' do - include GraphqlHelpers - - let(:project) { create(:project, :repository, :public) } - let(:merge_request) { create(:merge_request, source_project: project) } - - let(:query) do - <<~QUERY - { - merge_request(project: "#{merge_request.project.full_path}", iid: "#{merge_request.iid}") { - #{all_graphql_fields_for(MergeRequest)} - } - } - QUERY - end - - it_behaves_like 'a working graphql query' do - it 'renders a merge request with all fields' do - expect(response_data['merge_request']).not_to be_nil - end - end -end diff --git a/spec/requests/graphql/project_query_spec.rb b/spec/requests/graphql/project_query_spec.rb deleted file mode 100644 index 110ed433e03..00000000000 --- a/spec/requests/graphql/project_query_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -require 'spec_helper' - -describe 'getting project information' do - include GraphqlHelpers - - let(:project) { create(:project, :repository, :public) } - - let(:query) do - <<~QUERY - { - project(full_path: "#{project.full_path}") { - #{all_graphql_fields_for(Project)} - } - } - QUERY - end - - it_behaves_like 'a working graphql query' do - it 'renders a project with all fields' do - expect(response_data['project']).not_to be_nil - end - end -end diff --git a/spec/routing/api_routing_spec.rb b/spec/routing/api_routing_spec.rb new file mode 100644 index 00000000000..5fde4bd885b --- /dev/null +++ b/spec/routing/api_routing_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe 'api', 'routing' do + context 'when graphql is disabled' do + before do + stub_feature_flags(graphql: false) + end + + it 'does not route to the GraphqlController' do + expect(get('/api/graphql')).not_to route_to('graphql#execute') + end + + it 'does not expose graphiql' do + expect(get('/-/graphql-explorer')).not_to route_to('graphiql/rails/editors#show') + end + end + + context 'when graphql is disabled' do + before do + stub_feature_flags(graphql: true) + end + + it 'routes to the GraphqlController' do + expect(get('/api/graphql')).not_to route_to('graphql#execute') + end + + it 'exposes graphiql' do + expect(get('/-/graphql-explorer')).not_to route_to('graphiql/rails/editors#show') + end + end +end diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb index ae29b16e32c..30ff9a1196a 100644 --- a/spec/support/helpers/graphql_helpers.rb +++ b/spec/support/helpers/graphql_helpers.rb @@ -1,7 +1,16 @@ module GraphqlHelpers + # makes an underscored string look like a fieldname + # "merge_request" => "mergeRequest" + def self.fieldnamerize(underscored_field_name) + graphql_field_name = underscored_field_name.to_s.camelize + graphql_field_name[0] = graphql_field_name[0].downcase + + graphql_field_name + end + # Run a loader's named resolver - def resolve(kls, name, obj: nil, args: {}, ctx: {}) - kls[name].call(obj, args, ctx) + def resolve(resolver_class, obj: nil, args: {}, ctx: {}) + resolver_class.new(object: obj, context: ctx).resolve(args) end # Runs a block inside a BatchLoader::Executor wrapper @@ -24,8 +33,20 @@ module GraphqlHelpers end end - def all_graphql_fields_for(klass) - type = GitlabSchema.types[klass.name] + def graphql_query_for(name, attributes = {}, fields = nil) + fields ||= all_graphql_fields_for(name.classify) + attributes = attributes_to_graphql(attributes) + <<~QUERY + { + #{name}(#{attributes}) { + #{fields} + } + } + QUERY + end + + def all_graphql_fields_for(class_name) + type = GitlabSchema.types[class_name.to_s] return "" unless type type.fields.map do |name, field| @@ -37,8 +58,22 @@ module GraphqlHelpers end.join("\n") end - def post_graphql(query) - post '/api/graphql', query: query + def attributes_to_graphql(attributes) + attributes.map do |name, value| + "#{GraphqlHelpers.fieldnamerize(name.to_s)}: \"#{value}\"" + end.join(", ") + end + + def post_graphql(query, current_user: nil) + post api('/', current_user, version: 'graphql'), query: query + end + + def graphql_data + json_response['data'] + end + + def graphql_errors + json_response['data'] end def scalar?(field) diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb index c0ed16ecaba..ba7a1c8cde0 100644 --- a/spec/support/matchers/graphql_matchers.rb +++ b/spec/support/matchers/graphql_matchers.rb @@ -1,31 +1,40 @@ RSpec::Matchers.define :require_graphql_authorizations do |*expected| match do |field| - authorizations = field.metadata[:authorize] - - expect(authorizations).to contain_exactly(*expected) + field_definition = field.metadata[:type_class] + expect(field_definition).to respond_to(:required_permissions) + expect(field_definition.required_permissions).to contain_exactly(*expected) end end RSpec::Matchers.define :have_graphql_fields do |*expected| match do |kls| - expect(kls.fields.keys).to contain_exactly(*expected.map(&:to_s)) + field_names = expected.map { |name| GraphqlHelpers.fieldnamerize(name) } + expect(kls.fields.keys).to contain_exactly(*field_names) end end RSpec::Matchers.define :have_graphql_arguments do |*expected| + include GraphqlHelpers + match do |field| - expect(field.arguments.keys).to contain_exactly(*expected.map(&:to_s)) + argument_names = expected.map { |name| GraphqlHelpers.fieldnamerize(name) } + expect(field.arguments.keys).to contain_exactly(*argument_names) end end RSpec::Matchers.define :have_graphql_type do |expected| match do |field| - expect(field.type).to eq(expected) + expect(field.type).to eq(expected.to_graphql) end end RSpec::Matchers.define :have_graphql_resolver do |expected| match do |field| - expect(field.resolve_proc).to eq(expected) + case expected + when Method + expect(field.metadata[:type_class].resolve_proc).to eq(expected) + else + expect(field.metadata[:type_class].resolver).to eq(expected) + end end end diff --git a/spec/support/shared_examples/requests/graphql_shared_examples.rb b/spec/support/shared_examples/requests/graphql_shared_examples.rb index c143b83696e..9b2b74593a5 100644 --- a/spec/support/shared_examples/requests/graphql_shared_examples.rb +++ b/spec/support/shared_examples/requests/graphql_shared_examples.rb @@ -3,16 +3,9 @@ require 'spec_helper' shared_examples 'a working graphql query' do include GraphqlHelpers - let(:parsed_response) { JSON.parse(response.body) } - let(:response_data) { parsed_response['data'] } - - before do - post_graphql(query) - end - it 'is returns a successfull response', :aggregate_failures do expect(response).to be_success - expect(parsed_response['errors']).to be_nil - expect(response_data).not_to be_empty + expect(graphql_errors['errors']).to be_nil + expect(json_response.keys).to include('data') end end -- cgit v1.2.1 From 332275b766283ff65d0637ada3e4080c3cd4f038 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 6 Jun 2018 01:56:50 -0700 Subject: Simplify error message handling in Projects::CreateService There's no need to add a redundant message to the errors if the model is invalid. This cleans up the message as well for the importer. --- .../githubish_import_controller_shared_examples.rb | 15 --------------- 1 file changed, 15 deletions(-) (limited to 'spec') diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb index 1a53c5fa487..1c1b68c12a2 100644 --- a/spec/support/controllers/githubish_import_controller_shared_examples.rb +++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb @@ -119,21 +119,6 @@ shared_examples 'a GitHub-ish import controller: POST create' do end it 'returns 422 response with the base error when the project could not be imported' do - project = build(:project) - error_message = 'This is an error' - project.errors.add(:base, error_message) - - allow(Gitlab::LegacyGithubImport::ProjectCreator) - .to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider) - .and_return(double(execute: project)) - - post :create, format: :json - - expect(response).to have_gitlab_http_status(422) - expect(json_response['errors']).to eq(error_message) - end - - it 'returns 422 response with a combined error when the project could not be imported' do project = build(:project) project.errors.add(:name, 'is invalid') project.errors.add(:path, 'is old') -- cgit v1.2.1 From 29598f6e6d8ebbe9c1b64018fcb925655ccceb67 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 22 May 2018 18:37:35 +0200 Subject: find assets in test for CI and local test Due to the change in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14583/diffs we can't use the same method to access assets in a CI and the local test environment anymore. --- spec/models/project_services/jira_service_spec.rb | 3 ++- spec/services/system_note_service_spec.rb | 3 ++- spec/support/helpers/assets_helpers.rb | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 spec/support/helpers/assets_helpers.rb (limited to 'spec') diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 50bdb80ff92..c3b4eb17a5c 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -2,6 +2,7 @@ require 'spec_helper' describe JiraService do include Gitlab::Routing + include AssetsHelpers describe '#options' do let(:service) do @@ -164,7 +165,7 @@ describe JiraService do it "creates Remote Link reference in JIRA for comment" do @jira_service.close_issue(merge_request, ExternalIssue.new("JIRA-123", project)) - favicon_path = "http://localhost/assets/#{Rails.application.assets.find_asset('favicon.png').digest_path}" + favicon_path = "http://localhost/assets/#{find_asset('favicon.png').digest_path}" # Creates comment expect(WebMock).to have_requested(:post, @comment_url) diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb index e2ee421921c..57d081cffb3 100644 --- a/spec/services/system_note_service_spec.rb +++ b/spec/services/system_note_service_spec.rb @@ -3,6 +3,7 @@ require 'spec_helper' describe SystemNoteService do include Gitlab::Routing include RepoHelpers + include AssetsHelpers set(:group) { create(:group) } set(:project) { create(:project, :repository, group: group) } @@ -769,7 +770,7 @@ describe SystemNoteService do end describe "new reference" do - let(:favicon_path) { "http://localhost/assets/#{Rails.application.assets.find_asset('favicon.png').digest_path}" } + let(:favicon_path) { "http://localhost/assets/#{find_asset('favicon.png').digest_path}" } before do allow(JIRA::Resource::Remotelink).to receive(:all).and_return([]) diff --git a/spec/support/helpers/assets_helpers.rb b/spec/support/helpers/assets_helpers.rb new file mode 100644 index 00000000000..09bbf451671 --- /dev/null +++ b/spec/support/helpers/assets_helpers.rb @@ -0,0 +1,15 @@ +module AssetsHelpers + # In a CI environment the assets are not compiled, as there is a CI job + # `compile-assets` that compiles them in the prepare stage for all following + # specs. + # Locally the assets are precompiled dynamically. + # + # Sprockets doesn't provide one method to access an asset for both cases. + def find_asset(asset_name) + if ENV['CI'] + Sprockets::Railtie.build_environment(Rails.application, true)[asset_name] + else + Rails.application.assets.find_asset(asset_name) + end + end +end -- cgit v1.2.1 From c5e44dc5d1a98a92362b93c30342ebf1f972061c Mon Sep 17 00:00:00 2001 From: Imre Farkas Date: Tue, 5 Jun 2018 22:20:37 +0200 Subject: Use Github repo visibility during import while respecting restricted visibility levels --- .../legacy_github_import/project_creator_spec.rb | 40 ++++++++++++++++++---- 1 file changed, 34 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb b/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb index eb1b13704ea..972b17d5b12 100644 --- a/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb +++ b/spec/lib/gitlab/legacy_github_import/project_creator_spec.rb @@ -44,16 +44,44 @@ describe Gitlab::LegacyGithubImport::ProjectCreator do end context 'when GitHub project is public' do - before do - allow_any_instance_of(ApplicationSetting).to receive(:default_project_visibility).and_return(Gitlab::VisibilityLevel::INTERNAL) - end - - it 'sets project visibility to the default project visibility' do + it 'sets project visibility to public' do repo.private = false project = service.execute - expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC) + end + end + + context 'when visibility level is restricted' do + context 'when GitHub project is private' do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PRIVATE]) + allow_any_instance_of(ApplicationSetting).to receive(:default_project_visibility).and_return(Gitlab::VisibilityLevel::INTERNAL) + end + + it 'sets project visibility to the default project visibility' do + repo.private = true + + project = service.execute + + expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + end + end + + context 'when GitHub project is public' do + before do + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + allow_any_instance_of(ApplicationSetting).to receive(:default_project_visibility).and_return(Gitlab::VisibilityLevel::INTERNAL) + end + + it 'sets project visibility to the default project visibility' do + repo.private = false + + project = service.execute + + expect(project.visibility_level).to eq(Gitlab::VisibilityLevel::INTERNAL) + end end end -- cgit v1.2.1 From f8d8b63f32176975c802313d966fb81c2bb2122a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 5 Jun 2018 08:57:13 +0100 Subject: fixed karma --- .../stores/modules/merge_requests/actions_spec.js | 84 +++++++++++++++++----- 1 file changed, 66 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js index b571cfb963a..d178a44b76a 100644 --- a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js @@ -8,7 +8,9 @@ import actions, { receiveMergeRequestsSuccess, fetchMergeRequests, resetMergeRequests, + openMergeRequest, } from '~/ide/stores/modules/merge_requests/actions'; +import router from '~/ide/ide_router'; import { mergeRequests } from '../../../mock_data'; import testAction from '../../../../helpers/vuex_action_helper'; @@ -29,9 +31,9 @@ describe('IDE merge requests actions', () => { it('should should commit request', done => { testAction( requestMergeRequests, - null, + 'created', mockedState, - [{ type: types.REQUEST_MERGE_REQUESTS }], + [{ type: types.REQUEST_MERGE_REQUESTS, payload: 'created' }], [], done, ); @@ -48,16 +50,16 @@ describe('IDE merge requests actions', () => { it('should should commit error', done => { testAction( receiveMergeRequestsError, - null, + 'created', mockedState, - [{ type: types.RECEIVE_MERGE_REQUESTS_ERROR }], + [{ type: types.RECEIVE_MERGE_REQUESTS_ERROR, payload: 'created' }], [], done, ); }); it('creates flash message', () => { - receiveMergeRequestsError({ commit() {} }); + receiveMergeRequestsError({ commit() {} }, 'created'); expect(flashSpy).toHaveBeenCalled(); }); @@ -67,9 +69,14 @@ describe('IDE merge requests actions', () => { it('should commit received data', done => { testAction( receiveMergeRequestsSuccess, - 'data', + { type: 'created', data: 'data' }, mockedState, - [{ type: types.RECEIVE_MERGE_REQUESTS_SUCCESS, payload: 'data' }], + [ + { + type: types.RECEIVE_MERGE_REQUESTS_SUCCESS, + payload: { type: 'created', data: 'data' }, + }, + ], [], done, ); @@ -86,14 +93,14 @@ describe('IDE merge requests actions', () => { mock.onGet(/\/api\/v4\/merge_requests(.*)$/).replyOnce(200, mergeRequests); }); - it('calls API with params from state', () => { + it('calls API with params', () => { const apiSpy = spyOn(axios, 'get').and.callThrough(); - fetchMergeRequests({ dispatch() {}, state: mockedState }); + fetchMergeRequests({ dispatch() {}, state: mockedState }, { type: 'created' }); expect(apiSpy).toHaveBeenCalledWith(jasmine.anything(), { params: { - scope: 'assigned-to-me', + scope: 'created-by-me', state: 'opened', search: '', }, @@ -103,11 +110,14 @@ describe('IDE merge requests actions', () => { it('calls API with search', () => { const apiSpy = spyOn(axios, 'get').and.callThrough(); - fetchMergeRequests({ dispatch() {}, state: mockedState }, 'testing search'); + fetchMergeRequests( + { dispatch() {}, state: mockedState }, + { type: 'created', search: 'testing search' }, + ); expect(apiSpy).toHaveBeenCalledWith(jasmine.anything(), { params: { - scope: 'assigned-to-me', + scope: 'created-by-me', state: 'opened', search: 'testing search', }, @@ -117,7 +127,7 @@ describe('IDE merge requests actions', () => { it('dispatches request', done => { testAction( fetchMergeRequests, - null, + { type: 'created' }, mockedState, [], [ @@ -132,13 +142,16 @@ describe('IDE merge requests actions', () => { it('dispatches success with received data', done => { testAction( fetchMergeRequests, - null, + { type: 'created' }, mockedState, [], [ { type: 'requestMergeRequests' }, { type: 'resetMergeRequests' }, - { type: 'receiveMergeRequestsSuccess', payload: mergeRequests }, + { + type: 'receiveMergeRequestsSuccess', + payload: { type: 'created', data: mergeRequests }, + }, ], done, ); @@ -153,7 +166,7 @@ describe('IDE merge requests actions', () => { it('dispatches error', done => { testAction( fetchMergeRequests, - null, + { type: 'created' }, mockedState, [], [ @@ -171,12 +184,47 @@ describe('IDE merge requests actions', () => { it('commits reset', done => { testAction( resetMergeRequests, - null, + 'created', mockedState, - [{ type: types.RESET_MERGE_REQUESTS }], + [{ type: types.RESET_MERGE_REQUESTS, payload: 'created' }], [], done, ); }); }); + + describe('openMergeRequest', () => { + beforeEach(() => { + spyOn(router, 'push'); + }); + + it('commits reset mutations and actions', done => { + testAction( + openMergeRequest, + { projectPath: 'gitlab-org/gitlab-ce', id: '1' }, + mockedState, + [ + { type: 'CLEAR_PROJECTS' }, + { type: 'SET_CURRENT_MERGE_REQUEST', payload: '1' }, + { type: 'RESET_OPEN_FILES' }, + ], + [ + { type: 'pipelines/stopPipelinePolling' }, + { type: 'pipelines/clearEtagPoll' }, + { type: 'pipelines/resetLatestPipeline' }, + { type: 'setCurrentBranchId', payload: '' }, + ], + done, + ); + }); + + it('pushes new route', () => { + openMergeRequest( + { commit() {}, dispatch() {} }, + { projectPath: 'gitlab-org/gitlab-ce', id: '1' }, + ); + + expect(router.push).toHaveBeenCalledWith('/project/gitlab-org/gitlab-ce/merge_requests/1'); + }); + }); }); -- cgit v1.2.1 From 95b3ff056fb9edabef6c512c5de353c5c4a8bcb3 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 5 Jun 2018 09:50:48 +0100 Subject: fixed mutations spec --- .../stores/modules/merge_requests/mutations_spec.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js index 664d3914564..ea03131d90d 100644 --- a/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js +++ b/spec/javascripts/ide/stores/modules/merge_requests/mutations_spec.js @@ -12,26 +12,29 @@ describe('IDE merge requests mutations', () => { describe(types.REQUEST_MERGE_REQUESTS, () => { it('sets loading to true', () => { - mutations[types.REQUEST_MERGE_REQUESTS](mockedState); + mutations[types.REQUEST_MERGE_REQUESTS](mockedState, 'created'); - expect(mockedState.isLoading).toBe(true); + expect(mockedState.created.isLoading).toBe(true); }); }); describe(types.RECEIVE_MERGE_REQUESTS_ERROR, () => { it('sets loading to false', () => { - mutations[types.RECEIVE_MERGE_REQUESTS_ERROR](mockedState); + mutations[types.RECEIVE_MERGE_REQUESTS_ERROR](mockedState, 'created'); - expect(mockedState.isLoading).toBe(false); + expect(mockedState.created.isLoading).toBe(false); }); }); describe(types.RECEIVE_MERGE_REQUESTS_SUCCESS, () => { it('sets merge requests', () => { gon.gitlab_url = gl.TEST_HOST; - mutations[types.RECEIVE_MERGE_REQUESTS_SUCCESS](mockedState, mergeRequests); + mutations[types.RECEIVE_MERGE_REQUESTS_SUCCESS](mockedState, { + type: 'created', + data: mergeRequests, + }); - expect(mockedState.mergeRequests).toEqual([ + expect(mockedState.created.mergeRequests).toEqual([ { id: 1, iid: 1, @@ -47,9 +50,9 @@ describe('IDE merge requests mutations', () => { it('clears merge request array', () => { mockedState.mergeRequests = ['test']; - mutations[types.RESET_MERGE_REQUESTS](mockedState); + mutations[types.RESET_MERGE_REQUESTS](mockedState, 'created'); - expect(mockedState.mergeRequests).toEqual([]); + expect(mockedState.created.mergeRequests).toEqual([]); }); }); }); -- cgit v1.2.1 From c604c43782c5f2ac915f934d566f0502ae41f6d4 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 6 Jun 2018 05:29:52 -0500 Subject: fix broken specs --- .../projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb b/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb index d15391911c1..cb1b9e6f5fb 100644 --- a/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb +++ b/spec/views/projects/settings/ci_cd/_autodevops_form.html.haml_spec.rb @@ -12,7 +12,7 @@ describe 'projects/settings/ci_cd/_autodevops_form' do it 'shows warning message' do render - expect(rendered).to have_css('.settings-message') + expect(rendered).to have_css('.auto-devops-warning-message') expect(rendered).to have_text('Auto Review Apps and Auto Deploy need a domain name and a') expect(rendered).to have_link('Kubernetes cluster') end @@ -26,7 +26,7 @@ describe 'projects/settings/ci_cd/_autodevops_form' do it 'shows warning message' do render - expect(rendered).to have_css('.settings-message') + expect(rendered).to have_css('.auto-devops-warning-message') expect(rendered).to have_text('Auto Review Apps and Auto Deploy need a') expect(rendered).to have_link('Kubernetes cluster') end @@ -42,7 +42,7 @@ describe 'projects/settings/ci_cd/_autodevops_form' do it 'shows warning message' do render - expect(rendered).to have_css('.settings-message') + expect(rendered).to have_css('.auto-devops-warning-message') expect(rendered).to have_text('Auto Review Apps and Auto Deploy need a domain name to work correctly.') end end @@ -55,7 +55,7 @@ describe 'projects/settings/ci_cd/_autodevops_form' do it 'does not show warning message' do render - expect(rendered).not_to have_css('.settings-message') + expect(rendered).not_to have_css('.auto-devops-warning-message') end end end -- cgit v1.2.1 From 56efb9ee92cb96c6a378ae5d2f6510c7a870d896 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 6 Jun 2018 11:02:47 +0000 Subject: Adjust monitoring graphs to support widgets in EE --- spec/javascripts/monitoring/graph_spec.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/monitoring/graph_spec.js b/spec/javascripts/monitoring/graph_spec.js index 220228e5c08..a46a387a534 100644 --- a/spec/javascripts/monitoring/graph_spec.js +++ b/spec/javascripts/monitoring/graph_spec.js @@ -18,9 +18,7 @@ const createComponent = propsData => { }).$mount(); }; -const convertedMetrics = convertDatesMultipleSeries( - singleRowMetricsMultipleSeries, -); +const convertedMetrics = convertDatesMultipleSeries(singleRowMetricsMultipleSeries); describe('Graph', () => { beforeEach(() => { @@ -36,7 +34,7 @@ describe('Graph', () => { projectPath, }); - expect(component.$el.querySelector('.text-center').innerText.trim()).toBe( + expect(component.$el.querySelector('.prometheus-graph-title').innerText.trim()).toBe( component.graphData.title, ); }); @@ -52,9 +50,7 @@ describe('Graph', () => { }); const transformedHeight = `${component.graphHeight - 100}`; - expect(component.axisTransform.indexOf(transformedHeight)).not.toEqual( - -1, - ); + expect(component.axisTransform.indexOf(transformedHeight)).not.toEqual(-1); }); it('outerViewBox gets a width and height property based on the DOM size of the element', () => { -- cgit v1.2.1 From dfb0d45ddb0747f5b72e7188d930737d57dabc4c Mon Sep 17 00:00:00 2001 From: Shinya Maeda Date: Wed, 6 Jun 2018 20:18:32 +0900 Subject: Rename worker to ArchiveTracesCronWorker --- spec/workers/ci/archive_traces_cron_worker_spec.rb | 59 ++++++++++++++++++++++ .../ci/rescue_stale_live_trace_worker_spec.rb | 59 ---------------------- 2 files changed, 59 insertions(+), 59 deletions(-) create mode 100644 spec/workers/ci/archive_traces_cron_worker_spec.rb delete mode 100644 spec/workers/ci/rescue_stale_live_trace_worker_spec.rb (limited to 'spec') diff --git a/spec/workers/ci/archive_traces_cron_worker_spec.rb b/spec/workers/ci/archive_traces_cron_worker_spec.rb new file mode 100644 index 00000000000..9af51b7d4d8 --- /dev/null +++ b/spec/workers/ci/archive_traces_cron_worker_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe Ci::ArchiveTracesCronWorker do + subject { described_class.new.perform } + + before do + stub_feature_flags(ci_enable_live_trace: true) + end + + shared_examples_for 'archives trace' do + it do + subject + + build.reload + expect(build.job_artifacts_trace).to be_exist + end + end + + shared_examples_for 'does not archive trace' do + it do + subject + + build.reload + expect(build.job_artifacts_trace).to be_nil + end + end + + context 'when a job was succeeded' do + let!(:build) { create(:ci_build, :success, :trace_live) } + + it_behaves_like 'archives trace' + + context 'when archive raised an exception' do + let!(:build) { create(:ci_build, :success, :trace_artifact, :trace_live) } + let!(:build2) { create(:ci_build, :success, :trace_live) } + + it 'archives valid targets' do + expect(Rails.logger).to receive(:error).with("Failed to archive stale live trace. id: #{build.id} message: Already archived") + + subject + + build2.reload + expect(build2.job_artifacts_trace).to be_exist + end + end + end + + context 'when a job was cancelled' do + let!(:build) { create(:ci_build, :canceled, :trace_live) } + + it_behaves_like 'archives trace' + end + + context 'when a job is running' do + let!(:build) { create(:ci_build, :running, :trace_live) } + + it_behaves_like 'does not archive trace' + end +end diff --git a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb b/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb deleted file mode 100644 index 0e3fbe2d3a9..00000000000 --- a/spec/workers/ci/rescue_stale_live_trace_worker_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'spec_helper' - -describe Ci::RescueStaleLiveTraceWorker do - subject { described_class.new.perform } - - before do - stub_feature_flags(ci_enable_live_trace: true) - end - - shared_examples_for 'archives trace' do - it do - subject - - build.reload - expect(build.job_artifacts_trace).to be_exist - end - end - - shared_examples_for 'does not archive trace' do - it do - subject - - build.reload - expect(build.job_artifacts_trace).to be_nil - end - end - - context 'when a job was succeeded' do - let!(:build) { create(:ci_build, :success, :trace_live) } - - it_behaves_like 'archives trace' - - context 'when archive raised an exception' do - let!(:build) { create(:ci_build, :success, :trace_artifact, :trace_live) } - let!(:build2) { create(:ci_build, :success, :trace_live) } - - it 'archives valid targets' do - expect(Rails.logger).to receive(:error).with("Failed to archive stale live trace. id: #{build.id} message: Already archived") - - subject - - build2.reload - expect(build2.job_artifacts_trace).to be_exist - end - end - end - - context 'when a job was cancelled' do - let!(:build) { create(:ci_build, :canceled, :trace_live) } - - it_behaves_like 'archives trace' - end - - context 'when a job is running' do - let!(:build) { create(:ci_build, :running, :trace_live) } - - it_behaves_like 'does not archive trace' - end -end -- cgit v1.2.1 From 3b78b2d327ec00d201b74e74a81a9edb65a27a4c Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 6 Jun 2018 12:40:21 +0100 Subject: component specs --- .../ide/components/merge_requests/dropdown_spec.js | 47 ++++++++ .../ide/components/merge_requests/item_spec.js | 61 ++++++++++ .../ide/components/merge_requests/list_spec.js | 126 +++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 spec/javascripts/ide/components/merge_requests/dropdown_spec.js create mode 100644 spec/javascripts/ide/components/merge_requests/item_spec.js create mode 100644 spec/javascripts/ide/components/merge_requests/list_spec.js (limited to 'spec') diff --git a/spec/javascripts/ide/components/merge_requests/dropdown_spec.js b/spec/javascripts/ide/components/merge_requests/dropdown_spec.js new file mode 100644 index 00000000000..74884c9a362 --- /dev/null +++ b/spec/javascripts/ide/components/merge_requests/dropdown_spec.js @@ -0,0 +1,47 @@ +import Vue from 'vue'; +import { createStore } from '~/ide/stores'; +import Dropdown from '~/ide/components/merge_requests/dropdown.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { mergeRequests } from '../../mock_data'; + +describe('IDE merge requests dropdown', () => { + const Component = Vue.extend(Dropdown); + let vm; + + beforeEach(() => { + const store = createStore(); + + vm = createComponentWithStore(Component, store, { show: false }).$mount(); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('does not render tabs when show is false', () => { + expect(vm.$el.querySelector('.nav-links')).toBe(null); + }); + + describe('when show is true', () => { + beforeEach(done => { + vm.show = true; + vm.$store.state.mergeRequests.assigned.mergeRequests.push(mergeRequests[0]); + + vm.$nextTick(done); + }); + + it('renders tabs', () => { + expect(vm.$el.querySelector('.nav-links')).not.toBe(null); + }); + + it('renders count for assigned & created data', () => { + expect(vm.$el.querySelector('.nav-links a').textContent).toContain('Created by me'); + expect(vm.$el.querySelector('.nav-links a .badge').textContent).toContain('0'); + + expect(vm.$el.querySelectorAll('.nav-links a')[1].textContent).toContain('Assigned to me'); + expect( + vm.$el.querySelectorAll('.nav-links a')[1].querySelector('.badge').textContent, + ).toContain('1'); + }); + }); +}); diff --git a/spec/javascripts/ide/components/merge_requests/item_spec.js b/spec/javascripts/ide/components/merge_requests/item_spec.js new file mode 100644 index 00000000000..51c4cddef2f --- /dev/null +++ b/spec/javascripts/ide/components/merge_requests/item_spec.js @@ -0,0 +1,61 @@ +import Vue from 'vue'; +import Item from '~/ide/components/merge_requests/item.vue'; +import mountCompontent from '../../../helpers/vue_mount_component_helper'; + +describe('IDE merge request item', () => { + const Component = Vue.extend(Item); + let vm; + + beforeEach(() => { + vm = mountCompontent(Component, { + item: { + iid: 1, + projectPathWithNamespace: 'gitlab-org/gitlab-ce', + title: 'Merge request title', + }, + currentId: '1', + currentProjectId: 'gitlab-org/gitlab-ce', + }); + }); + + afterEach(() => { + vm.$destroy(); + }); + + it('renders merge requests data', () => { + expect(vm.$el.textContent).toContain('Merge request title'); + expect(vm.$el.textContent).toContain('gitlab-org/gitlab-ce!1'); + }); + + it('renders icon if ID matches currentId', () => { + expect(vm.$el.querySelector('.ic-mobile-issue-close')).not.toBe(null); + }); + + it('does not render icon if ID does not match currentId', done => { + vm.currentId = '2'; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.ic-mobile-issue-close')).toBe(null); + + done(); + }); + }); + + it('does not render icon if project ID does not match', done => { + vm.currentProjectId = 'test/test'; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.ic-mobile-issue-close')).toBe(null); + + done(); + }); + }); + + it('emits click event on click', () => { + spyOn(vm, '$emit'); + + vm.$el.click(); + + expect(vm.$emit).toHaveBeenCalledWith('click', vm.item); + }); +}); diff --git a/spec/javascripts/ide/components/merge_requests/list_spec.js b/spec/javascripts/ide/components/merge_requests/list_spec.js new file mode 100644 index 00000000000..f4b393778dc --- /dev/null +++ b/spec/javascripts/ide/components/merge_requests/list_spec.js @@ -0,0 +1,126 @@ +import Vue from 'vue'; +import store from '~/ide/stores'; +import List from '~/ide/components/merge_requests/list.vue'; +import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; +import { mergeRequests } from '../../mock_data'; +import { resetStore } from '../../helpers'; + +describe('IDE merge requests list', () => { + const Component = Vue.extend(List); + let vm; + + beforeEach(() => { + vm = createComponentWithStore(Component, store, { + type: 'created', + emptyText: 'empty text', + }); + + spyOn(vm, 'fetchMergeRequests'); + + vm.$mount(); + }); + + afterEach(() => { + vm.$destroy(); + + resetStore(vm.$store); + }); + + it('calls fetch on mounted', () => { + expect(vm.fetchMergeRequests).toHaveBeenCalledWith({ + type: 'created', + search: '', + }); + }); + + it('renders loading icon', done => { + vm.$store.state.mergeRequests.created.isLoading = true; + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.loading-container')).not.toBe(null); + + done(); + }); + }); + + it('renders empty text when no merge requests exist', () => { + expect(vm.$el.textContent).toContain('empty text'); + }); + + it('renders no search results text when search is not empty', done => { + vm.search = 'testing'; + + vm.$nextTick(() => { + expect(vm.$el.textContent).toContain('No merge requests found'); + + done(); + }); + }); + + describe('with merge requests', () => { + beforeEach(done => { + vm.$store.state.mergeRequests.created.mergeRequests.push({ + ...mergeRequests[0], + projectPathWithNamespace: 'gitlab-org/gitlab-ce', + }); + + vm.$nextTick(done); + }); + + it('renders list', () => { + expect(vm.$el.querySelectorAll('li').length).toBe(1); + expect(vm.$el.querySelector('li').textContent).toContain(mergeRequests[0].title); + }); + + it('calls openMergeRequest when clicking merge request', done => { + spyOn(vm, 'openMergeRequest'); + vm.$el.querySelector('li button').click(); + + vm.$nextTick(() => { + expect(vm.openMergeRequest).toHaveBeenCalledWith({ + projectPath: 'gitlab-org/gitlab-ce', + id: 1, + }); + + done(); + }); + }); + }); + + describe('focusSearch', () => { + it('focuses search input when loading is false', done => { + spyOn(vm.$refs.searchInput, 'focus'); + + vm.$store.state.mergeRequests.created.isLoading = false; + vm.focusSearch(); + + vm.$nextTick(() => { + expect(vm.$refs.searchInput.focus).toHaveBeenCalled(); + + done(); + }); + }); + }); + + describe('searchMergeRequests', () => { + beforeEach(() => { + spyOn(vm, 'loadMergeRequests'); + + jasmine.clock().install(); + }); + + afterEach(() => { + jasmine.clock().uninstall(); + }); + + it('calls loadMergeRequests on input in search field', () => { + const event = new Event('input'); + + vm.$el.querySelector('input').dispatchEvent(event); + + jasmine.clock().tick(300); + + expect(vm.loadMergeRequests).toHaveBeenCalled(); + }); + }); +}); -- cgit v1.2.1 From cfcc7043fe614cbc5fc82f3021a0c4cd8519e24b Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Tue, 22 May 2018 19:54:50 +0800 Subject: =?UTF-8?q?Rename=20=E2=80=9CDevelopers=20+=20Masters=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- spec/features/protected_branches_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb index 0c28a853b54..4c0f9971425 100644 --- a/spec/features/protected_branches_spec.rb +++ b/spec/features/protected_branches_spec.rb @@ -72,7 +72,7 @@ feature 'Protected Branches', :js do click_link 'No one' find(".js-allowed-to-push").click wait_for_requests - click_link 'Developers + Masters' + click_link 'Developers + Maintainers' end visit project_protected_branches_path(project) @@ -82,7 +82,7 @@ feature 'Protected Branches', :js do expect(page.find(".dropdown-toggle-text")).to have_content("No one") end page.within(".js-allowed-to-push") do - expect(page.find(".dropdown-toggle-text")).to have_content("Developers + Masters") + expect(page.find(".dropdown-toggle-text")).to have_content("Developers + Maintainers") end end end -- cgit v1.2.1 From 7c965a24f51ca93196c27880843a6d187ea063cc Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Tue, 22 May 2018 19:55:07 +0800 Subject: Fix spec --- spec/features/projects/settings/user_manages_group_links_spec.rb | 2 +- spec/features/projects/settings/user_manages_project_members_spec.rb | 2 +- spec/javascripts/notes/components/note_actions_spec.js | 4 ++-- spec/models/project_team_spec.rb | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/settings/user_manages_group_links_spec.rb b/spec/features/projects/settings/user_manages_group_links_spec.rb index fdf42797091..92ce2ca83c7 100644 --- a/spec/features/projects/settings/user_manages_group_links_spec.rb +++ b/spec/features/projects/settings/user_manages_group_links_spec.rb @@ -30,7 +30,7 @@ describe 'Projects > Settings > User manages group links' do click_link('Share with group') select2(group_market.id, from: '#link_group_id') - select('Master', from: 'link_group_access') + select('Maintainer', from: 'link_group_access') click_button('Share') diff --git a/spec/features/projects/settings/user_manages_project_members_spec.rb b/spec/features/projects/settings/user_manages_project_members_spec.rb index 8af95522165..d3003753ae6 100644 --- a/spec/features/projects/settings/user_manages_project_members_spec.rb +++ b/spec/features/projects/settings/user_manages_project_members_spec.rb @@ -62,7 +62,7 @@ describe 'Projects > Settings > User manages project members' do page.within('.project-members-groups') do expect(page).to have_content('OpenSource') - expect(first('.group_member')).to have_content('Master') + expect(first('.group_member')).to have_content('Maintainer') end end end diff --git a/spec/javascripts/notes/components/note_actions_spec.js b/spec/javascripts/notes/components/note_actions_spec.js index 1dfe890e05e..c9e549d2096 100644 --- a/spec/javascripts/notes/components/note_actions_spec.js +++ b/spec/javascripts/notes/components/note_actions_spec.js @@ -20,7 +20,7 @@ describe('issue_note_actions component', () => { beforeEach(() => { props = { - accessLevel: 'Master', + accessLevel: 'Maintainer', authorId: 26, canDelete: true, canEdit: true, @@ -67,7 +67,7 @@ describe('issue_note_actions component', () => { beforeEach(() => { store.dispatch('setUserData', {}); props = { - accessLevel: 'Master', + accessLevel: 'Maintainer', authorId: 26, canDelete: false, canEdit: false, diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index e07c522800a..9978f3e9566 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -179,14 +179,14 @@ describe ProjectTeam do end describe "#human_max_access" do - it 'returns Master role' do + it 'returns Maintainer role' do user = create(:user) group = create(:group) project = create(:project, namespace: group) group.add_master(user) - expect(project.team.human_max_access(user.id)).to eq 'Master' + expect(project.team.human_max_access(user.id)).to eq 'Maintainer' end it 'returns Owner role' do -- cgit v1.2.1 From a6c15c5b9750b3b6b16694974eab868a21b8683a Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Mon, 4 Jun 2018 10:25:38 +0900 Subject: change wording --- spec/lib/gitlab/checks/change_access_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/checks/change_access_spec.rb b/spec/lib/gitlab/checks/change_access_spec.rb index 48e9902027c..1cb8143a9e9 100644 --- a/spec/lib/gitlab/checks/change_access_spec.rb +++ b/spec/lib/gitlab/checks/change_access_spec.rb @@ -52,7 +52,7 @@ describe Gitlab::Checks::ChangeAccess do context 'with protected tag' do let!(:protected_tag) { create(:protected_tag, project: project, name: 'v*') } - context 'as master' do + context 'as maintainer' do before do project.add_master(user) end @@ -138,7 +138,7 @@ describe Gitlab::Checks::ChangeAccess do context 'if the user is not allowed to delete protected branches' do it 'raises an error' do - expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to delete protected branches from this project. Only a project master or owner can delete a protected branch.') + expect { subject.exec }.to raise_error(Gitlab::GitAccess::UnauthorizedError, 'You are not allowed to delete protected branches from this project. Only a project maintainer or owner can delete a protected branch.') end end -- cgit v1.2.1 From 748f8fef457f2795ab2592bf6041055cf613bb10 Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Mon, 4 Jun 2018 10:32:57 +0900 Subject: group runners --- spec/features/runners_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/features/runners_spec.rb b/spec/features/runners_spec.rb index 9ce7d538004..fe0b03a7e00 100644 --- a/spec/features/runners_spec.rb +++ b/spec/features/runners_spec.rb @@ -184,7 +184,7 @@ feature 'Runners' do given(:group) { create :group } - context 'as project and group master' do + context 'as project and group maintainer' do background do group.add_master(user) end @@ -197,13 +197,13 @@ feature 'Runners' do expect(page).to have_content 'This group does not provide any group Runners yet' - expect(page).to have_content 'Group masters can register group runners in the Group CI/CD settings' - expect(page).not_to have_content 'Ask your group master to setup a group Runner' + expect(page).to have_content 'Group maintainers can register group runners in the Group CI/CD settings' + expect(page).not_to have_content 'Ask your group maintainer to setup a group Runner' end end end - context 'as project master' do + context 'as project maintainer' do context 'project without a group' do given(:project) { create :project } @@ -223,8 +223,8 @@ feature 'Runners' do expect(page).to have_content 'This group does not provide any group Runners yet.' - expect(page).not_to have_content 'Group masters can register group runners in the Group CI/CD settings' - expect(page).to have_content 'Ask your group master to setup a group Runner.' + expect(page).not_to have_content 'Group maintainers can register group runners in the Group CI/CD settings' + expect(page).to have_content 'Ask your group maintainer to setup a group Runner.' end end -- cgit v1.2.1 From 9fa70462296c85deb48574bf3e3ceed0cb2dd493 Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Mon, 4 Jun 2018 12:50:28 +0900 Subject: fix lock spec --- spec/services/lfs/unlock_file_service_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/services/lfs/unlock_file_service_spec.rb b/spec/services/lfs/unlock_file_service_spec.rb index 4bea112b9c6..948401d7bdc 100644 --- a/spec/services/lfs/unlock_file_service_spec.rb +++ b/spec/services/lfs/unlock_file_service_spec.rb @@ -80,12 +80,12 @@ describe Lfs::UnlockFileService do result = subject.execute expect(result[:status]).to eq(:error) - expect(result[:message]).to match(/You must have master access/) + expect(result[:message]).to match(/You must have maintainer access/) expect(result[:http_status]).to eq(403) end end - context 'by a master user' do + context 'by a maintainer user' do let(:current_user) { master } let(:params) do { id: lock.id, -- cgit v1.2.1 From 51a9f71118e9cd4bec50b6a5872d035f219e4eaf Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 6 Jun 2018 15:21:13 +0200 Subject: Add a custom storage config instead of overwriting Otherwise the ApplicationSetting that is currently stored would be invalid as it specifies a storage that is not configured --- spec/requests/api/settings_spec.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/requests/api/settings_spec.rb b/spec/requests/api/settings_spec.rb index aead8978dd4..57adc3ca7a6 100644 --- a/spec/requests/api/settings_spec.rb +++ b/spec/requests/api/settings_spec.rb @@ -35,7 +35,9 @@ describe API::Settings, 'Settings' do context "custom repository storage type set in the config" do before do - storages = { 'custom' => 'tmp/tests/custom_repositories' } + # Add a possible storage to the config + storages = Gitlab.config.repositories.storages + .merge({ 'custom' => 'tmp/tests/custom_repositories' }) allow(Gitlab.config.repositories).to receive(:storages).and_return(storages) end -- cgit v1.2.1 From cc9468e4fa276cef5673750464889f2d2791a9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kim=20Carlb=C3=A4cker?= Date: Wed, 6 Jun 2018 14:28:03 +0000 Subject: Move GC/Repack to OptOut --- spec/workers/git_garbage_collect_worker_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index 74539a7e493..f44b4edc305 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -104,7 +104,7 @@ describe GitGarbageCollectWorker do it_should_behave_like 'flushing ref caches', true end - context "with Gitaly turned off", :skip_gitaly_mock do + context "with Gitaly turned off", :disable_gitaly do it_should_behave_like 'flushing ref caches', false end -- cgit v1.2.1 From e8f49b4bee8d803953b852685889a2912609ae84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Wed, 6 Jun 2018 16:42:18 +0000 Subject: Support LFS objects when creating a project by import --- spec/lib/gitlab/git/rev_list_spec.rb | 2 +- .../importer/lfs_object_importer_spec.rb | 23 ++++ .../importer/lfs_objects_importer_spec.rb | 94 +++++++++++++ .../importer/repository_importer_spec.rb | 3 +- spec/lib/gitlab/import_sources_spec.rb | 19 +++ spec/services/projects/import_service_spec.rb | 72 +++++++++- .../lfs_download_link_list_service_spec.rb | 102 ++++++++++++++ .../lfs_pointers/lfs_download_service_spec.rb | 69 ++++++++++ .../lfs_pointers/lfs_import_service_spec.rb | 146 +++++++++++++++++++++ .../projects/lfs_pointers/lfs_link_service_spec.rb | 33 +++++ .../stage/import_lfs_objects_worker_spec.rb | 28 ++++ .../stage/import_notes_worker_spec.rb | 2 +- 12 files changed, 589 insertions(+), 4 deletions(-) create mode 100644 spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb create mode 100644 spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb create mode 100644 spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb create mode 100644 spec/services/projects/lfs_pointers/lfs_download_service_spec.rb create mode 100644 spec/services/projects/lfs_pointers/lfs_import_service_spec.rb create mode 100644 spec/services/projects/lfs_pointers/lfs_link_service_spec.rb create mode 100644 spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index 95dc47e2a00..70e90659b0f 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -88,7 +88,7 @@ describe Gitlab::Git::RevList do context '#all_objects' do it 'fetches list of all pushed objects using rev-list' do - stub_popen_rev_list('--all', '--objects', output: "sha1\nsha2") + stub_popen_rev_list('--all', '--objects', '--filter=blob:limit=200', output: "sha1\nsha2") expect { |b| rev_list.all_objects(&b) }.to yield_with_args(%w[sha1 sha2]) end diff --git a/spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb b/spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb new file mode 100644 index 00000000000..4857f2afbe2 --- /dev/null +++ b/spec/lib/gitlab/github_import/importer/lfs_object_importer_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::Importer::LfsObjectImporter do + let(:project) { create(:project) } + let(:download_link) { "http://www.gitlab.com/lfs_objects/oid" } + + let(:github_lfs_object) do + Gitlab::GithubImport::Representation::LfsObject.new( + oid: 'oid', download_link: download_link + ) + end + + let(:importer) { described_class.new(github_lfs_object, project, nil) } + + describe '#execute' do + it 'calls the LfsDownloadService with the lfs object attributes' do + expect_any_instance_of(Projects::LfsPointers::LfsDownloadService) + .to receive(:execute).with('oid', download_link) + + importer.execute + end + end +end diff --git a/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb new file mode 100644 index 00000000000..5f5c6b803c0 --- /dev/null +++ b/spec/lib/gitlab/github_import/importer/lfs_objects_importer_spec.rb @@ -0,0 +1,94 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::Importer::LfsObjectsImporter do + let(:project) { double(:project, id: 4, import_source: 'foo/bar') } + let(:client) { double(:client) } + let(:download_link) { "http://www.gitlab.com/lfs_objects/oid" } + + let(:github_lfs_object) { ['oid', download_link] } + + describe '#parallel?' do + it 'returns true when running in parallel mode' do + importer = described_class.new(project, client) + expect(importer).to be_parallel + end + + it 'returns false when running in sequential mode' do + importer = described_class.new(project, client, parallel: false) + expect(importer).not_to be_parallel + end + end + + describe '#execute' do + context 'when running in parallel mode' do + it 'imports lfs objects in parallel' do + importer = described_class.new(project, client) + + expect(importer).to receive(:parallel_import) + + importer.execute + end + end + + context 'when running in sequential mode' do + it 'imports lfs objects in sequence' do + importer = described_class.new(project, client, parallel: false) + + expect(importer).to receive(:sequential_import) + + importer.execute + end + end + end + + describe '#sequential_import' do + it 'imports each lfs object in sequence' do + importer = described_class.new(project, client, parallel: false) + lfs_object_importer = double(:lfs_object_importer) + + allow(importer) + .to receive(:each_object_to_import) + .and_yield(['oid', download_link]) + + expect(Gitlab::GithubImport::Importer::LfsObjectImporter) + .to receive(:new) + .with( + an_instance_of(Gitlab::GithubImport::Representation::LfsObject), + project, + client + ) + .and_return(lfs_object_importer) + + expect(lfs_object_importer).to receive(:execute) + + importer.sequential_import + end + end + + describe '#parallel_import' do + it 'imports each lfs object in parallel' do + importer = described_class.new(project, client) + + allow(importer) + .to receive(:each_object_to_import) + .and_yield(github_lfs_object) + + expect(Gitlab::GithubImport::ImportLfsObjectWorker) + .to receive(:perform_async) + .with(project.id, an_instance_of(Hash), an_instance_of(String)) + + waiter = importer.parallel_import + + expect(waiter).to be_an_instance_of(Gitlab::JobWaiter) + expect(waiter.jobs_remaining).to eq(1) + end + end + + describe '#collection_options' do + it 'returns an empty Hash' do + importer = described_class.new(project, client) + + expect(importer.collection_options).to eq({}) + end + end +end diff --git a/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb b/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb index cc9e4b67e72..d8f01dcb76b 100644 --- a/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb @@ -14,7 +14,8 @@ describe Gitlab::GithubImport::Importer::RepositoryImporter do disk_path: 'foo', repository: repository, create_wiki: true, - import_state: import_state + import_state: import_state, + lfs_enabled?: true ) end diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb index f2fa315e3ec..10341486512 100644 --- a/spec/lib/gitlab/import_sources_spec.rb +++ b/spec/lib/gitlab/import_sources_spec.rb @@ -91,4 +91,23 @@ describe Gitlab::ImportSources do end end end + + describe 'imports_repository? checker' do + let(:allowed_importers) { %w[github gitlab_project] } + + it 'fails if any importer other than the allowed ones implements this method' do + current_importers = described_class.values.select { |kind| described_class.importer(kind).try(:imports_repository?) } + not_allowed_importers = current_importers - allowed_importers + + expect(not_allowed_importers).to be_empty, failure_message(not_allowed_importers) + end + + def failure_message(importers_class_names) + <<-MSG + It looks like the #{importers_class_names.join(', ')} importers implements its own way to import the repository. + That means that the lfs object download must be handled for each of them. You can use 'LfsImportService' and + 'LfsDownloadService' to implement it. After that, add the importer name to the list of allowed importers in this spec. + MSG + end + end end diff --git a/spec/services/projects/import_service_spec.rb b/spec/services/projects/import_service_spec.rb index 30c89ebd821..b3815045792 100644 --- a/spec/services/projects/import_service_spec.rb +++ b/spec/services/projects/import_service_spec.rb @@ -3,9 +3,17 @@ require 'spec_helper' describe Projects::ImportService do let!(:project) { create(:project) } let(:user) { project.creator } + let(:import_url) { 'http://www.gitlab.com/demo/repo.git' } + let(:oid_download_links) { { 'oid1' => "#{import_url}/gitlab-lfs/objects/oid1", 'oid2' => "#{import_url}/gitlab-lfs/objects/oid2" } } subject { described_class.new(project, user) } + before do + allow(project).to receive(:lfs_enabled?).and_return(true) + allow_any_instance_of(Projects::LfsPointers::LfsDownloadService).to receive(:execute) + allow_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute).and_return(oid_download_links) + end + describe '#async?' do it 'returns true for an asynchronous importer' do importer_class = double(:importer, async?: true) @@ -63,6 +71,15 @@ describe Projects::ImportService do expect(result[:status]).to eq :error expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - The repository could not be created." end + + context 'when repository creation succeeds' do + it 'does not download lfs files' do + expect_any_instance_of(Projects::LfsPointers::LfsImportService).not_to receive(:execute) + expect_any_instance_of(Projects::LfsPointers::LfsDownloadService).not_to receive(:execute) + + subject.execute + end + end end context 'with known url' do @@ -91,6 +108,15 @@ describe Projects::ImportService do expect(result[:status]).to eq :error end + + context 'when repository import scheduled' do + it 'does not download lfs objects' do + expect_any_instance_of(Projects::LfsPointers::LfsImportService).not_to receive(:execute) + expect_any_instance_of(Projects::LfsPointers::LfsDownloadService).not_to receive(:execute) + + subject.execute + end + end end context 'with a non Github repository' do @@ -99,9 +125,10 @@ describe Projects::ImportService do project.import_type = 'bitbucket' end - it 'succeeds if repository import is successfully' do + it 'succeeds if repository import is successfull' do expect_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_return(true) expect_any_instance_of(Gitlab::BitbucketImport::Importer).to receive(:execute).and_return(true) + expect_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute).and_return({}) result = subject.execute @@ -116,6 +143,29 @@ describe Projects::ImportService do expect(result[:status]).to eq :error expect(result[:message]).to eq "Error importing repository #{project.import_url} into #{project.full_path} - Failed to import the repository" end + + context 'when repository import scheduled' do + before do + allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_return(true) + allow(subject).to receive(:import_data) + end + + it 'downloads lfs objects if lfs_enabled is enabled for project' do + allow(project).to receive(:lfs_enabled?).and_return(true) + expect_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute).and_return(oid_download_links) + expect_any_instance_of(Projects::LfsPointers::LfsDownloadService).to receive(:execute).twice + + subject.execute + end + + it 'does not download lfs objects if lfs_enabled is not enabled for project' do + allow(project).to receive(:lfs_enabled?).and_return(false) + expect_any_instance_of(Projects::LfsPointers::LfsImportService).not_to receive(:execute) + expect_any_instance_of(Projects::LfsPointers::LfsDownloadService).not_to receive(:execute) + + subject.execute + end + end end end @@ -147,6 +197,26 @@ describe Projects::ImportService do expect(result[:status]).to eq :error end + + context 'when importer' do + it 'has a custom repository importer it does not download lfs objects' do + allow(Gitlab::GithubImport::ParallelImporter).to receive(:imports_repository?).and_return(true) + + expect_any_instance_of(Projects::LfsPointers::LfsImportService).not_to receive(:execute) + expect_any_instance_of(Projects::LfsPointers::LfsDownloadService).not_to receive(:execute) + + subject.execute + end + + it 'does not have a custom repository importer downloads lfs objects' do + allow(Gitlab::GithubImport::ParallelImporter).to receive(:imports_repository?).and_return(false) + + expect_any_instance_of(Projects::LfsPointers::LfsImportService).to receive(:execute).and_return(oid_download_links) + expect_any_instance_of(Projects::LfsPointers::LfsDownloadService).to receive(:execute) + + subject.execute + end + end end context 'with blocked import_URL' do diff --git a/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb new file mode 100644 index 00000000000..d7a2829d5f8 --- /dev/null +++ b/spec/services/projects/lfs_pointers/lfs_download_link_list_service_spec.rb @@ -0,0 +1,102 @@ +require 'spec_helper' + +describe Projects::LfsPointers::LfsDownloadLinkListService do + let(:import_url) { 'http://www.gitlab.com/demo/repo.git' } + let(:lfs_endpoint) { "#{import_url}/info/lfs/objects/batch" } + let!(:project) { create(:project, import_url: import_url) } + let(:new_oids) { { 'oid1' => 123, 'oid2' => 125 } } + let(:remote_uri) { URI.parse(lfs_endpoint) } + + let(:objects_response) do + body = new_oids.map do |oid, size| + { + 'oid' => oid, + 'size' => size, + 'actions' => { + 'download' => { 'href' => "#{import_url}/gitlab-lfs/objects/#{oid}" } + } + } + end + + Struct.new(:success?, :objects).new(true, body) + end + + let(:invalid_object_response) do + [ + 'oid' => 'whatever', + 'size' => 123 + ] + end + + subject { described_class.new(project, remote_uri: remote_uri) } + + before do + allow(project).to receive(:lfs_enabled?).and_return(true) + allow(Gitlab::HTTP).to receive(:post).and_return(objects_response) + end + + describe '#execute' do + it 'retrieves each download link of every non existent lfs object' do + subject.execute(new_oids).each do |oid, link| + expect(link).to eq "#{import_url}/gitlab-lfs/objects/#{oid}" + end + end + + context 'credentials' do + context 'when the download link and the lfs_endpoint have the same host' do + context 'when lfs_endpoint has credentials' do + let(:import_url) { 'http://user:password@www.gitlab.com/demo/repo.git' } + + it 'adds credentials to the download_link' do + result = subject.execute(new_oids) + + result.each do |oid, link| + expect(link.starts_with?('http://user:password@')).to be_truthy + end + end + end + + context 'when lfs_endpoint does not have any credentials' do + it 'does not add any credentials' do + result = subject.execute(new_oids) + + result.each do |oid, link| + expect(link.starts_with?('http://user:password@')).to be_falsey + end + end + end + end + + context 'when the download link and the lfs_endpoint have different hosts' do + let(:import_url_with_credentials) { 'http://user:password@www.otherdomain.com/demo/repo.git' } + let(:lfs_endpoint) { "#{import_url_with_credentials}/info/lfs/objects/batch" } + + it 'downloads without any credentials' do + result = subject.execute(new_oids) + + result.each do |oid, link| + expect(link.starts_with?('http://user:password@')).to be_falsey + end + end + end + end + end + + describe '#get_download_links' do + it 'raise errorif request fails' do + allow(Gitlab::HTTP).to receive(:post).and_return(Struct.new(:success?, :message).new(false, 'Failed request')) + + expect { subject.send(:get_download_links, new_oids) }.to raise_error(described_class::DownloadLinksError) + end + end + + describe '#parse_response_links' do + it 'does not add oid entry if href not found' do + expect(Rails.logger).to receive(:error).with("Link for Lfs Object with oid whatever not found or invalid.") + + result = subject.send(:parse_response_links, invalid_object_response) + + expect(result).to be_empty + end + end +end diff --git a/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb new file mode 100644 index 00000000000..6af5bfc7689 --- /dev/null +++ b/spec/services/projects/lfs_pointers/lfs_download_service_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe Projects::LfsPointers::LfsDownloadService do + let(:project) { create(:project) } + let(:oid) { '9e548e25631dd9ce6b43afd6359ab76da2819d6a5b474e66118c7819e1d8b3e8' } + let(:download_link) { "http://gitlab.com/#{oid}" } + let(:lfs_content) do + <<~HEREDOC + whatever + HEREDOC + end + + subject { described_class.new(project) } + + before do + allow(project).to receive(:lfs_enabled?).and_return(true) + WebMock.stub_request(:get, download_link).to_return(body: lfs_content) + end + + describe '#execute' do + context 'when file download succeeds' do + it 'a new lfs object is created' do + expect { subject.execute(oid, download_link) }.to change { LfsObject.count }.from(0).to(1) + end + + it 'has the same oid' do + subject.execute(oid, download_link) + + expect(LfsObject.first.oid).to eq oid + end + + it 'stores the content' do + subject.execute(oid, download_link) + + expect(File.read(LfsObject.first.file.file.file)).to eq lfs_content + end + end + + context 'when file download fails' do + it 'no lfs object is created' do + expect { subject.execute(oid, download_link) }.to change { LfsObject.count } + end + end + + context 'when credentials present' do + let(:download_link_with_credentials) { "http://user:password@gitlab.com/#{oid}" } + + before do + WebMock.stub_request(:get, download_link).with(headers: { 'Authorization' => 'Basic dXNlcjpwYXNzd29yZA==' }).to_return(body: lfs_content) + end + + it 'the request adds authorization headers' do + subject.execute(oid, download_link_with_credentials) + end + end + + context 'when an lfs object with the same oid already exists' do + before do + create(:lfs_object, oid: 'oid') + end + + it 'does not download the file' do + expect(subject).not_to receive(:download_and_save_file) + + subject.execute('oid', download_link) + end + end + end +end diff --git a/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb new file mode 100644 index 00000000000..5a75fb38dec --- /dev/null +++ b/spec/services/projects/lfs_pointers/lfs_import_service_spec.rb @@ -0,0 +1,146 @@ +require 'spec_helper' + +describe Projects::LfsPointers::LfsImportService do + let(:import_url) { 'http://www.gitlab.com/demo/repo.git' } + let(:default_endpoint) { "#{import_url}/info/lfs/objects/batch"} + let(:group) { create(:group, lfs_enabled: true)} + let!(:project) { create(:project, namespace: group, import_url: import_url, lfs_enabled: true) } + let!(:lfs_objects_project) { create_list(:lfs_objects_project, 2, project: project) } + let!(:existing_lfs_objects) { LfsObject.pluck(:oid, :size).to_h } + let(:oids) { { 'oid1' => 123, 'oid2' => 125 } } + let(:oid_download_links) { { 'oid1' => "#{import_url}/gitlab-lfs/objects/oid1", 'oid2' => "#{import_url}/gitlab-lfs/objects/oid2" } } + let(:all_oids) { existing_lfs_objects.merge(oids) } + let(:remote_uri) { URI.parse(lfs_endpoint) } + + subject { described_class.new(project) } + + before do + allow(project.repository).to receive(:lfsconfig_for).and_return(nil) + allow(Gitlab.config.lfs).to receive(:enabled).and_return(true) + allow_any_instance_of(Projects::LfsPointers::LfsListService).to receive(:execute).and_return(all_oids) + end + + describe '#execute' do + context 'when no lfs pointer is linked' do + before do + allow_any_instance_of(Projects::LfsPointers::LfsLinkService).to receive(:execute).and_return([]) + allow_any_instance_of(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:execute).and_return(oid_download_links) + expect(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:new).with(project, remote_uri: URI.parse(default_endpoint)).and_call_original + end + + it 'retrieves all lfs pointers in the project repository' do + expect_any_instance_of(Projects::LfsPointers::LfsListService).to receive(:execute) + + subject.execute + end + + it 'links existent lfs objects to the project' do + expect_any_instance_of(Projects::LfsPointers::LfsLinkService).to receive(:execute) + + subject.execute + end + + it 'retrieves the download links of non existent objects' do + expect_any_instance_of(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:execute).with(all_oids) + + subject.execute + end + end + + context 'when some lfs objects are linked' do + before do + allow_any_instance_of(Projects::LfsPointers::LfsLinkService).to receive(:execute).and_return(existing_lfs_objects.keys) + allow_any_instance_of(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:execute).and_return(oid_download_links) + end + + it 'retrieves the download links of non existent objects' do + expect_any_instance_of(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:execute).with(oids) + + subject.execute + end + end + + context 'when all lfs objects are linked' do + before do + allow_any_instance_of(Projects::LfsPointers::LfsLinkService).to receive(:execute).and_return(all_oids.keys) + allow_any_instance_of(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:execute) + end + + it 'retrieves no download links' do + expect_any_instance_of(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:execute).with({}).and_call_original + + expect(subject.execute).to be_empty + end + end + + context 'when lfsconfig file exists' do + before do + allow(project.repository).to receive(:lfsconfig_for).and_return("[lfs]\n\turl = #{lfs_endpoint}\n") + end + + context 'when url points to the same import url host' do + let(:lfs_endpoint) { "#{import_url}/different_endpoint" } + let(:service) { double } + + before do + allow(service).to receive(:execute) + end + it 'downloads lfs object using the new endpoint' do + expect(Projects::LfsPointers::LfsDownloadLinkListService).to receive(:new).with(project, remote_uri: remote_uri).and_return(service) + + subject.execute + end + + context 'when import url has credentials' do + let(:import_url) { 'http://user:password@www.gitlab.com/demo/repo.git'} + + it 'adds the credentials to the new endpoint' do + expect(Projects::LfsPointers::LfsDownloadLinkListService) + .to receive(:new).with(project, remote_uri: URI.parse("http://user:password@www.gitlab.com/demo/repo.git/different_endpoint")) + .and_return(service) + + subject.execute + end + + context 'when url has its own credentials' do + let(:lfs_endpoint) { "http://user1:password1@www.gitlab.com/demo/repo.git/different_endpoint" } + + it 'does not add the import url credentials' do + expect(Projects::LfsPointers::LfsDownloadLinkListService) + .to receive(:new).with(project, remote_uri: remote_uri) + .and_return(service) + + subject.execute + end + end + end + end + + context 'when url points to a third party service' do + let(:lfs_endpoint) { 'http://third_party_service.com/info/lfs/objects/' } + + it 'disables lfs from the project' do + expect(project.lfs_enabled?).to be_truthy + + subject.execute + + expect(project.lfs_enabled?).to be_falsey + end + + it 'does not download anything' do + expect_any_instance_of(Projects::LfsPointers::LfsListService).not_to receive(:execute) + + subject.execute + end + end + end + end + + describe '#default_endpoint_uri' do + let(:import_url) { 'http://www.gitlab.com/demo/repo' } + + it 'adds suffix .git if the url does not have it' do + expect(subject.send(:default_endpoint_uri).path).to match(/repo.git/) + end + end +end diff --git a/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb new file mode 100644 index 00000000000..b7b153655db --- /dev/null +++ b/spec/services/projects/lfs_pointers/lfs_link_service_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe Projects::LfsPointers::LfsLinkService do + let!(:project) { create(:project, lfs_enabled: true) } + let!(:lfs_objects_project) { create_list(:lfs_objects_project, 2, project: project) } + let(:new_oids) { { 'oid1' => 123, 'oid2' => 125 } } + let(:all_oids) { LfsObject.pluck(:oid, :size).to_h.merge(new_oids) } + let(:new_lfs_object) { create(:lfs_object) } + let(:new_oid_list) { all_oids.merge(new_lfs_object.oid => new_lfs_object.size) } + + subject { described_class.new(project) } + + before do + allow(project).to receive(:lfs_enabled?).and_return(true) + end + + describe '#execute' do + it 'links existing lfs objects to the project' do + expect(project.all_lfs_objects.count).to eq 2 + + linked = subject.execute(new_oid_list.keys) + + expect(project.all_lfs_objects.count).to eq 3 + expect(linked.size).to eq 3 + end + + it 'returns linked oids' do + linked = lfs_objects_project.map(&:lfs_object).map(&:oid) << new_lfs_object.oid + + expect(subject.execute(new_oid_list.keys)).to eq linked + end + end +end diff --git a/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb new file mode 100644 index 00000000000..b19884d7991 --- /dev/null +++ b/spec/workers/gitlab/github_import/stage/import_lfs_objects_worker_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::Stage::ImportLfsObjectsWorker do + let(:project) { create(:project) } + let(:worker) { described_class.new } + + describe '#import' do + it 'imports all the lfs objects' do + importer = double(:importer) + waiter = Gitlab::JobWaiter.new(2, '123') + + expect(Gitlab::GithubImport::Importer::LfsObjectsImporter) + .to receive(:new) + .with(project, nil) + .and_return(importer) + + expect(importer) + .to receive(:execute) + .and_return(waiter) + + expect(Gitlab::GithubImport::AdvanceStageWorker) + .to receive(:perform_async) + .with(project.id, { '123' => 2 }, :finish) + + worker.import(project) + end + end +end diff --git a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb index 098d2d55386..94cff9e4e80 100644 --- a/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb +++ b/spec/workers/gitlab/github_import/stage/import_notes_worker_spec.rb @@ -21,7 +21,7 @@ describe Gitlab::GithubImport::Stage::ImportNotesWorker do expect(Gitlab::GithubImport::AdvanceStageWorker) .to receive(:perform_async) - .with(project.id, { '123' => 2 }, :finish) + .with(project.id, { '123' => 2 }, :lfs_objects) worker.import(client, project) end -- cgit v1.2.1 From 78ae23045bae8a75775a11675afd5836fb8f318b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Wed, 6 Jun 2018 19:09:46 +0200 Subject: Reverse logic of manual and continuous deploy strategies --- spec/models/project_auto_devops_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 37cd1f571e5..040e76e28fc 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -69,11 +69,11 @@ describe ProjectAutoDevops do end end - context 'when deploy_strategy is continuous' do + context 'when deploy_strategy is manual' do let(:domain) { 'example.com' } before do - auto_devops.deploy_strategy = 'continuous' + auto_devops.deploy_strategy = 'manual' end it do -- cgit v1.2.1 From 86d39016a26f73e82437d38fcf723677b97c1c8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Wed, 6 Jun 2018 21:07:31 +0200 Subject: Moving rev-list lfs options to Lfschanges --- spec/lib/gitlab/git/rev_list_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index 70e90659b0f..95dc47e2a00 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -88,7 +88,7 @@ describe Gitlab::Git::RevList do context '#all_objects' do it 'fetches list of all pushed objects using rev-list' do - stub_popen_rev_list('--all', '--objects', '--filter=blob:limit=200', output: "sha1\nsha2") + stub_popen_rev_list('--all', '--objects', output: "sha1\nsha2") expect { |b| rev_list.all_objects(&b) }.to yield_with_args(%w[sha1 sha2]) end -- cgit v1.2.1 From 5d3abdf9a7c0260c708a46e2fd232b0490940f80 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Wed, 6 Jun 2018 00:47:53 -0700 Subject: Log response body to production_json.log when a controller responds with a 422 status We have a number of import errors occurring with 422 errors, and it's hard to determine why they are happening. This change will surface the errors in the log lines. Relates to #47365 --- spec/controllers/application_controller_spec.rb | 58 +++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'spec') diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 683c57c96f8..773bf25ed44 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -1,3 +1,4 @@ +# coding: utf-8 require 'spec_helper' describe ApplicationController do @@ -478,6 +479,63 @@ describe ApplicationController do end end + describe '#append_info_to_payload' do + controller(described_class) do + attr_reader :last_payload + + def index + render text: 'authenticated' + end + + def append_info_to_payload(payload) + super + + @last_payload = payload + end + end + + it 'does not log errors with a 200 response' do + get :index + + expect(controller.last_payload.has_key?(:response)).to be_falsey + end + + context '422 errors' do + it 'logs a response with a string' do + response = spy(ActionDispatch::Response, status: 422, body: 'Hello world', content_type: 'application/json') + allow(controller).to receive(:response).and_return(response) + get :index + + expect(controller.last_payload[:response]).to eq('Hello world') + end + + it 'logs a response with an array' do + body = ['I want', 'my hat back'] + response = spy(ActionDispatch::Response, status: 422, body: body, content_type: 'application/json') + allow(controller).to receive(:response).and_return(response) + get :index + + expect(controller.last_payload[:response]).to eq(body) + end + + it 'does not log a string with an empty body' do + response = spy(ActionDispatch::Response, status: 422, body: nil, content_type: 'application/json') + allow(controller).to receive(:response).and_return(response) + get :index + + expect(controller.last_payload.has_key?(:response)).to be_falsey + end + + it 'does not log an HTML body' do + response = spy(ActionDispatch::Response, status: 422, body: 'This is a test', content_type: 'application/html') + allow(controller).to receive(:response).and_return(response) + get :index + + expect(controller.last_payload.has_key?(:response)).to be_falsey + end + end + end + describe '#access_denied' do controller(described_class) do def index -- cgit v1.2.1 From 854c9636ec6aabd8941b31f0f2aa4e89c9c072ce Mon Sep 17 00:00:00 2001 From: Imre Farkas Date: Wed, 30 May 2018 12:12:42 +0200 Subject: Enforce UTF-8 encoding on user input in LogrageWithTimestamp formatter and filter out file content from logs --- spec/requests/api/commits_spec.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 8ad19e3f0f5..7e3277c4cab 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -247,6 +247,19 @@ describe API::Commits do ] } end + let!(:valid_utf8_c_params) do + { + branch: 'master', + commit_message: message, + actions: [ + { + action: 'create', + file_path: 'foo/bar/baz.txt', + content: 'puts 🦊' + } + ] + } + end it 'a new file in project repo' do post api(url, user), valid_c_params @@ -257,6 +270,15 @@ describe API::Commits do expect(json_response['committer_email']).to eq(user.email) end + it 'a new file with utf8 chars in project repo' do + post api(url, user), valid_utf8_c_params + + expect(response).to have_gitlab_http_status(201) + expect(json_response['title']).to eq(message) + expect(json_response['committer_name']).to eq(user.name) + expect(json_response['committer_email']).to eq(user.email) + end + it 'returns a 400 bad request if file exists' do post api(url, user), invalid_c_params -- cgit v1.2.1 From 38c2e480bfa180241e94e77c049b1f5256d83bcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mica=C3=ABl=20Bergeron?= Date: Wed, 6 Jun 2018 16:45:42 -0400 Subject: shave off 30% of the query count --- .../object_storage/migrate_uploads_worker_spec.rb | 50 ++++++++++++++++++---- 1 file changed, 41 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb index aed62f97448..18da0c6d39a 100644 --- a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb +++ b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb @@ -1,5 +1,7 @@ require 'spec_helper' +MIGRATION_QUERIES = 7 + describe ObjectStorage::MigrateUploadsWorker, :sidekiq do shared_context 'sanity_check! fails' do before do @@ -11,6 +13,13 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do let(:uploads) { Upload.all } let(:to_store) { ObjectStorage::Store::REMOTE } + def perform(uploads) + binding.pry + described_class.new.perform(uploads.ids, model_class.to_s, mounted_as, to_store) + rescue ObjectStorage::MigrateUploadsWorker::Report::MigrationFailures + # swallow + end + shared_examples "uploads migration worker" do describe '.enqueue!' do def enqueue! @@ -69,12 +78,6 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do end describe '#perform' do - def perform - described_class.new.perform(uploads.ids, model_class.to_s, mounted_as, to_store) - rescue ObjectStorage::MigrateUploadsWorker::Report::MigrationFailures - # swallow - end - shared_examples 'outputs correctly' do |success: 0, failures: 0| total = success + failures @@ -82,7 +85,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do it 'outputs the reports' do expect(Rails.logger).to receive(:info).with(%r{Migrated #{success}/#{total} files}) - perform + perform(uploads) end end @@ -90,7 +93,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do it 'outputs upload failures' do expect(Rails.logger).to receive(:warn).with(/Error .* I am a teapot/) - perform + perform(uploads) end end end @@ -98,7 +101,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do it_behaves_like 'outputs correctly', success: 10 it 'migrates files' do - perform + perform(uploads) expect(Upload.where(store: ObjectStorage::Store::LOCAL).count).to eq(0) end @@ -123,6 +126,18 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do end it_behaves_like "uploads migration worker" + + describe "limits N+1 queries" do + let!(:projects) { create_list(:project, 10, :with_avatar) } + + it do + query_count = ActiveRecord::QueryRecorder.new { perform(uploads) } + + more_projects = create_list(:project, 100, :with_avatar) + expected_queries_per_migration = MIGRATION_QUERIES * more_projects.count + expect { perform(Upload.all) }.not_to exceed_query_limit(query_count).with_threshold(expected_queries_per_migration) + end + end end context "for FileUploader" do @@ -140,5 +155,22 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do end it_behaves_like "uploads migration worker" + + describe "limits N+1 queries" do + let!(:projects) { create_list(:project, 10) } + + it do + query_count = ActiveRecord::QueryRecorder.new { perform(uploads) } + + more_projects = create_list(:project, 100) + more_projects.map do |project| + uploader = FileUploader.new(project) + uploader.store!(fixture_file_upload('spec/fixtures/doc_sample.txt')) + end + expected_queries_per_migration = MIGRATION_QUERIES * more_projects.count + + expect { perform(Upload.all) }.not_to exceed_query_limit(query_count).with_threshold(expected_queries_per_migration) + end + end end end -- cgit v1.2.1 From 164dbc6b77558e29fd9a1553048d314457dc6990 Mon Sep 17 00:00:00 2001 From: Annabel Gray Date: Thu, 7 Jun 2018 07:37:02 +0000 Subject: Resolve "Introduce new navigation themes in GitLab 11.0" --- spec/helpers/preferences_helper_spec.rb | 6 +++--- spec/lib/gitlab/themes_spec.rb | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index c9d2ec8a4ae..9940656fb68 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -31,9 +31,9 @@ describe PreferencesHelper do describe '#user_application_theme' do context 'with a user' do it "returns user's theme's css_class" do - stub_user(theme_id: 3) + stub_user(theme_id: 10) - expect(helper.user_application_theme).to eq 'ui_light' + expect(helper.user_application_theme).to eq 'ui-light' end it 'returns the default when id is invalid' do @@ -41,7 +41,7 @@ describe PreferencesHelper do allow(Gitlab.config.gitlab).to receive(:default_theme).and_return(1) - expect(helper.user_application_theme).to eq 'ui_indigo' + expect(helper.user_application_theme).to eq 'ui-indigo' end end diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb index ecacea6bb35..af2f4568017 100644 --- a/spec/lib/gitlab/themes_spec.rb +++ b/spec/lib/gitlab/themes_spec.rb @@ -5,16 +5,16 @@ describe Gitlab::Themes, lib: true do it 'returns a space-separated list of class names' do css = described_class.body_classes - expect(css).to include('ui_indigo') - expect(css).to include(' ui_dark ') - expect(css).to include(' ui_blue') + expect(css).to include('ui-indigo') + expect(css).to include('ui-dark ') + expect(css).to include('ui-blue') end end describe '.by_id' do it 'returns a Theme by its ID' do expect(described_class.by_id(1).name).to eq 'Indigo' - expect(described_class.by_id(3).name).to eq 'Light' + expect(described_class.by_id(10).name).to eq 'Light' end end -- cgit v1.2.1 From 0206476ae2a2d659fd0fb42338050253a9a91439 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 7 Jun 2018 12:14:27 +0100 Subject: Fix some N+1s when calculating notification recipients First N+1: we may have loaded a user's notification settings already, but not have loaded their sources. Because we're iterating through, we'd potentially load sources that are completely unrelated, just because they belong to this user. Second N+1: we do a separate query for each user who could be subscribed to or unsubcribed from the target. It's actually more efficient in this case to get all subscriptions at once, as we will need to check most of them. We can fix both by the slightly unpleasant means of checking IDs manually, rather than object equality. --- .../notification_recipient_service_spec.rb | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 spec/services/notification_recipient_service_spec.rb (limited to 'spec') diff --git a/spec/services/notification_recipient_service_spec.rb b/spec/services/notification_recipient_service_spec.rb new file mode 100644 index 00000000000..340d4585e0c --- /dev/null +++ b/spec/services/notification_recipient_service_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe NotificationRecipientService do + let(:service) { described_class } + let(:assignee) { create(:user) } + let(:project) { create(:project, :public) } + let(:other_projects) { create_list(:project, 5, :public) } + + describe '#build_new_note_recipients' do + let(:issue) { create(:issue, project: project, assignees: [assignee]) } + let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id) } + + def create_watcher + watcher = create(:user) + create(:notification_setting, project: project, user: watcher, level: :watch) + + other_projects.each do |other_project| + create(:notification_setting, project: other_project, user: watcher, level: :watch) + end + end + + it 'avoids N+1 queries' do + create_watcher + + service.build_new_note_recipients(note) + + control_count = ActiveRecord::QueryRecorder.new do + service.build_new_note_recipients(note) + end + + create_watcher + + expect { service.build_new_note_recipients(note) }.not_to exceed_query_limit(control_count) + end + end +end -- cgit v1.2.1 From 93c7976ae26370a6d65c3d5038323911592c20ce Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Thu, 7 Jun 2018 12:24:57 +0000 Subject: Restore navigation theme order --- spec/helpers/preferences_helper_spec.rb | 2 +- spec/lib/gitlab/themes_spec.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/helpers/preferences_helper_spec.rb b/spec/helpers/preferences_helper_spec.rb index 9940656fb68..363ebc88afd 100644 --- a/spec/helpers/preferences_helper_spec.rb +++ b/spec/helpers/preferences_helper_spec.rb @@ -31,7 +31,7 @@ describe PreferencesHelper do describe '#user_application_theme' do context 'with a user' do it "returns user's theme's css_class" do - stub_user(theme_id: 10) + stub_user(theme_id: 3) expect(helper.user_application_theme).to eq 'ui-light' end diff --git a/spec/lib/gitlab/themes_spec.rb b/spec/lib/gitlab/themes_spec.rb index af2f4568017..a8213988f70 100644 --- a/spec/lib/gitlab/themes_spec.rb +++ b/spec/lib/gitlab/themes_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::Themes, lib: true do css = described_class.body_classes expect(css).to include('ui-indigo') - expect(css).to include('ui-dark ') + expect(css).to include('ui-dark') expect(css).to include('ui-blue') end end @@ -14,7 +14,7 @@ describe Gitlab::Themes, lib: true do describe '.by_id' do it 'returns a Theme by its ID' do expect(described_class.by_id(1).name).to eq 'Indigo' - expect(described_class.by_id(10).name).to eq 'Light' + expect(described_class.by_id(3).name).to eq 'Light' end end -- cgit v1.2.1 From 616dd00abbd09e6ef550e2eb877ae9fe2b28812b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 7 Jun 2018 14:56:48 +0200 Subject: Add trait for manual deploy strategy --- spec/factories/project_auto_devops.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/factories/project_auto_devops.rb b/spec/factories/project_auto_devops.rb index a59087cd7eb..189d097d5e6 100644 --- a/spec/factories/project_auto_devops.rb +++ b/spec/factories/project_auto_devops.rb @@ -4,5 +4,9 @@ FactoryBot.define do enabled true domain "example.com" deploy_strategy :continuous + + trait :manual do + deploy_strategy :manual + end end end -- cgit v1.2.1 From 637b90db6edbd13d15289bf0d8d2c442d05442f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matija=20=C4=8Cupi=C4=87?= Date: Thu, 7 Jun 2018 14:58:09 +0200 Subject: Add spec for continuous deploy strategy --- spec/models/project_auto_devops_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'spec') diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 040e76e28fc..f9ee9fe98bd 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -82,6 +82,19 @@ describe ProjectAutoDevops do end end + context 'when deploy_strategy is continuous' do + let(:domain) { 'example.com' } + + before do + auto_devops.deploy_strategy = 'continuous' + end + + it do + expect(auto_devops.predefined_variables.map { |var| var[:key] }) + .not_to include("STAGING_ENABLED", "INCREMENTAL_ROLLOUT_ENABLED") + end + end + def domain_variable { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true } end -- cgit v1.2.1 From 435e661a2ec060c4b7349b26b506243c27e8cc30 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 7 Jun 2018 15:17:44 +0200 Subject: Introduce new keep-alive API entrypoint for CI job --- spec/requests/api/runner_spec.rb | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) (limited to 'spec') diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index c981a10ac38..c93612d7ada 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -849,6 +849,68 @@ describe API::Runner, :clean_gitlab_redis_shared_state do end end + describe 'POST /api/v4/jobs/:id/keep-alive' do + let(:job) { create(:ci_build, :running, :trace_live, runner_id: runner.id, pipeline: pipeline) } + let(:headers) { { API::Helpers::Runner::JOB_TOKEN_HEADER => job.token, 'Content-Type' => 'text/plain' } } + let(:update_interval) { 30.seconds } + + it 'returns correct response' do + keep_alive_job + + expect(response.status).to eq 200 + expect(response.header).to have_key 'Job-Status' + end + + it 'updates updated_at value' do + expect { keep_alive_job }.to change { job.updated_at } + end + + context 'when project for the build has been deleted' do + let(:job) do + create(:ci_build, :running, :trace_live, runner_id: runner.id, pipeline: pipeline) do |job| + job.project.update(pending_delete: true) + end + end + + it 'responds with forbidden' do + keep_alive_job + + expect(response.status).to eq(403) + end + end + + context 'when job has been canceled' do + before do + job.cancel + end + + it 'returns job-status=canceled header' do + keep_alive_job + + expect(response.status).to eq 200 + expect(response.header['Job-Status']).to eq('canceled') + end + end + + context 'when job has been errased' do + let(:job) { create(:ci_build, runner_id: runner.id, erased_at: Time.now) } + + it 'rresponds with forbidden' do + keep_alive_job + + expect(response.status).to eq 403 + end + end + + def keep_alive_job(token = job.token, **params) + new_params = params.merge(token: token) + Timecop.travel(job.updated_at + update_interval) do + post api("/jobs/#{job.id}/keep-alive"), new_params + job.reload + end + end + end + describe 'PATCH /api/v4/jobs/:id/trace' do let(:job) { create(:ci_build, :running, :trace_live, runner_id: runner.id, pipeline: pipeline) } let(:headers) { { API::Helpers::Runner::JOB_TOKEN_HEADER => job.token, 'Content-Type' => 'text/plain' } } -- cgit v1.2.1 From 02a2ca6ae4ab6f2b64ff00f5750a68e9371a4fb7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 7 Jun 2018 14:47:09 +0100 Subject: Fixes IDE button on merge requests not working with relative URL config Closes #46438 --- spec/javascripts/lib/utils/url_utility_spec.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 spec/javascripts/lib/utils/url_utility_spec.js (limited to 'spec') diff --git a/spec/javascripts/lib/utils/url_utility_spec.js b/spec/javascripts/lib/utils/url_utility_spec.js new file mode 100644 index 00000000000..8ed4950ee09 --- /dev/null +++ b/spec/javascripts/lib/utils/url_utility_spec.js @@ -0,0 +1,25 @@ +import { webIDEUrl } from '~/lib/utils/url_utility'; + +describe('URL utility', () => { + describe('webIDEUrl', () => { + describe('without relative_url_root', () => { + it('returns IDE path with route', () => { + expect(webIDEUrl('/gitlab-org/gitlab-ce/merge_requests/1')).toBe( + '/-/ide/project/gitlab-org/gitlab-ce/merge_requests/1', + ); + }); + }); + + describe('with relative_url_root', () => { + beforeEach(() => { + gon.relative_url_root = '/gitlab'; + }); + + it('returns IDE path with route', () => { + expect(webIDEUrl('/gitlab/gitlab-org/gitlab-ce/merge_requests/1')).toBe( + '/gitlab/-/ide/project/gitlab-org/gitlab-ce/merge_requests/1', + ); + }); + }); + }); +}); -- cgit v1.2.1 From 44975f8a5ad9c40c615f47f683fb46c94aa0e130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mica=C3=ABl=20Bergeron?= Date: Thu, 7 Jun 2018 10:01:47 -0400 Subject: shave off another 20% query --- spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb index 18da0c6d39a..ba01cfe53c5 100644 --- a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb +++ b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -MIGRATION_QUERIES = 7 +MIGRATION_QUERIES = 5 describe ObjectStorage::MigrateUploadsWorker, :sidekiq do shared_context 'sanity_check! fails' do @@ -14,7 +14,6 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do let(:to_store) { ObjectStorage::Store::REMOTE } def perform(uploads) - binding.pry described_class.new.perform(uploads.ids, model_class.to_s, mounted_as, to_store) rescue ObjectStorage::MigrateUploadsWorker::Report::MigrationFailures # swallow -- cgit v1.2.1 From 132db99a5b98daf7629f416ebb4ff817010cc0a9 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 7 Jun 2018 15:11:10 +0100 Subject: fixed karma --- spec/javascripts/lib/utils/url_utility_spec.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/lib/utils/url_utility_spec.js b/spec/javascripts/lib/utils/url_utility_spec.js index 8ed4950ee09..c7f4092911c 100644 --- a/spec/javascripts/lib/utils/url_utility_spec.js +++ b/spec/javascripts/lib/utils/url_utility_spec.js @@ -2,6 +2,10 @@ import { webIDEUrl } from '~/lib/utils/url_utility'; describe('URL utility', () => { describe('webIDEUrl', () => { + afterEach(() => { + gon.relative_url_root = ''; + }); + describe('without relative_url_root', () => { it('returns IDE path with route', () => { expect(webIDEUrl('/gitlab-org/gitlab-ce/merge_requests/1')).toBe( -- cgit v1.2.1 From cb6a16a2c6b15bbd51c02e74a6086ae33e83d3c8 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 7 Jun 2018 15:53:14 +0100 Subject: fixed more specs --- .../vue_mr_widget/components/mr_widget_header_spec.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js index 9b9c9656979..3d36e46d863 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js @@ -12,6 +12,7 @@ describe('MRWidgetHeader', () => { afterEach(() => { vm.$destroy(); + gon.relative_url_root = ''; }); describe('computed', () => { @@ -145,7 +146,16 @@ describe('MRWidgetHeader', () => { const button = vm.$el.querySelector('.js-web-ide'); expect(button.textContent.trim()).toEqual('Web IDE'); - expect(button.getAttribute('href')).toEqual('undefined/-/ide/projectabc'); + expect(button.getAttribute('href')).toEqual('/-/ide/projectabc'); + }); + + it('renders web ide button with relative URL', () => { + gon.relative_url_root = '/gitlab'; + + const button = vm.$el.querySelector('.js-web-ide'); + + expect(button.textContent.trim()).toEqual('Web IDE'); + expect(button.getAttribute('href')).toEqual('/-/ide/projectabc'); }); it('renders download dropdown with links', () => { -- cgit v1.2.1 From 6d165c740cecf6aff4c7ec0bbb962e7964c15f1b Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Tue, 5 Jun 2018 16:18:06 -0500 Subject: Make all uses of `fixture_file_upload` use relative paths --- spec/controllers/boards/issues_controller_spec.rb | 2 +- spec/controllers/groups/avatars_controller_spec.rb | 2 +- spec/controllers/import/gitlab_projects_controller_spec.rb | 2 +- spec/controllers/import/google_code_controller_spec.rb | 2 +- spec/controllers/profiles/avatars_controller_spec.rb | 2 +- spec/controllers/projects/avatars_controller_spec.rb | 2 +- spec/controllers/projects_controller_spec.rb | 4 ++-- spec/controllers/uploads_controller_spec.rb | 14 +++++++------- spec/factories/lfs_objects.rb | 2 +- spec/factories/notes.rb | 4 ++-- spec/features/commits_spec.rb | 2 +- .../merge_request/user_sees_mini_pipeline_graph_spec.rb | 4 ++-- spec/features/projects/jobs_spec.rb | 2 +- spec/features/projects/pages_spec.rb | 4 ++-- spec/lib/gitlab/import_export/avatar_saver_spec.rb | 2 +- spec/lib/gitlab/import_export/uploads_saver_spec.rb | 2 +- spec/models/ci/job_artifact_spec.rb | 4 ++-- spec/requests/api/projects_spec.rb | 4 ++-- spec/requests/api/runner_spec.rb | 4 ++-- spec/requests/api/users_spec.rb | 2 +- spec/requests/openid_connect_spec.rb | 2 +- spec/services/projects/fork_service_spec.rb | 2 +- .../projects/gitlab_projects_import_service_spec.rb | 2 +- spec/services/projects/participants_service_spec.rb | 2 +- spec/services/projects/update_pages_service_spec.rb | 10 +++++----- spec/services/upload_service_spec.rb | 10 +++++----- spec/support/rspec.rb | 2 ++ .../controllers/uploads_actions_shared_examples.rb | 4 ++-- spec/uploaders/attachment_uploader_spec.rb | 2 +- spec/uploaders/file_mover_spec.rb | 2 +- spec/uploaders/file_uploader_spec.rb | 2 +- spec/uploaders/job_artifact_uploader_spec.rb | 2 +- spec/uploaders/namespace_file_uploader_spec.rb | 2 +- spec/uploaders/object_storage_spec.rb | 2 +- spec/uploaders/personal_file_uploader_spec.rb | 2 +- spec/uploaders/records_uploads_spec.rb | 2 +- spec/uploaders/uploader_helper_spec.rb | 2 +- 37 files changed, 60 insertions(+), 58 deletions(-) (limited to 'spec') diff --git a/spec/controllers/boards/issues_controller_spec.rb b/spec/controllers/boards/issues_controller_spec.rb index dcb0faffbd4..e47ff8661a2 100644 --- a/spec/controllers/boards/issues_controller_spec.rb +++ b/spec/controllers/boards/issues_controller_spec.rb @@ -18,7 +18,7 @@ describe Boards::IssuesController do end describe 'GET index', :request_store do - let(:johndoe) { create(:user, avatar: fixture_file_upload(File.join(Rails.root, 'spec/fixtures/dk.png'))) } + let(:johndoe) { create(:user, avatar: fixture_file_upload(File.join('spec/fixtures/dk.png'))) } context 'with invalid board id' do it 'returns a not found 404 response' do diff --git a/spec/controllers/groups/avatars_controller_spec.rb b/spec/controllers/groups/avatars_controller_spec.rb index 506aeee7d2a..7feecd0c380 100644 --- a/spec/controllers/groups/avatars_controller_spec.rb +++ b/spec/controllers/groups/avatars_controller_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe Groups::AvatarsController do let(:user) { create(:user) } - let(:group) { create(:group, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let(:group) { create(:group, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) } before do group.add_owner(user) diff --git a/spec/controllers/import/gitlab_projects_controller_spec.rb b/spec/controllers/import/gitlab_projects_controller_spec.rb index 8759d3c0b97..d624659bce9 100644 --- a/spec/controllers/import/gitlab_projects_controller_spec.rb +++ b/spec/controllers/import/gitlab_projects_controller_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Import::GitlabProjectsController do set(:namespace) { create(:namespace) } set(:user) { namespace.owner } - let(:file) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } + let(:file) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') } before do sign_in(user) diff --git a/spec/controllers/import/google_code_controller_spec.rb b/spec/controllers/import/google_code_controller_spec.rb index 4241db6e771..0763492d88a 100644 --- a/spec/controllers/import/google_code_controller_spec.rb +++ b/spec/controllers/import/google_code_controller_spec.rb @@ -4,7 +4,7 @@ describe Import::GoogleCodeController do include ImportSpecHelper let(:user) { create(:user) } - let(:dump_file) { fixture_file_upload(Rails.root + 'spec/fixtures/GoogleCodeProjectHosting.json', 'application/json') } + let(:dump_file) { fixture_file_upload('spec/fixtures/GoogleCodeProjectHosting.json', 'application/json') } before do sign_in(user) diff --git a/spec/controllers/profiles/avatars_controller_spec.rb b/spec/controllers/profiles/avatars_controller_spec.rb index 4fa0462ccdf..909709e1103 100644 --- a/spec/controllers/profiles/avatars_controller_spec.rb +++ b/spec/controllers/profiles/avatars_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Profiles::AvatarsController do - let(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png")) } + let(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png")) } before do sign_in(user) diff --git a/spec/controllers/projects/avatars_controller_spec.rb b/spec/controllers/projects/avatars_controller_spec.rb index 6a41c4d23ea..acfa2730d94 100644 --- a/spec/controllers/projects/avatars_controller_spec.rb +++ b/spec/controllers/projects/avatars_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::AvatarsController do - let(:project) { create(:project, :repository, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let(:project) { create(:project, :repository, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) } let(:user) { create(:user) } before do diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 994da3cd159..5bd22ea803c 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -6,8 +6,8 @@ describe ProjectsController do let(:project) { create(:project) } let(:public_project) { create(:project, :public) } let(:user) { create(:user) } - let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } - let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } + let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') } + let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') } describe 'GET new' do context 'with an authenticated user' do diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 376b229ffc9..5892daa1a94 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -6,13 +6,13 @@ shared_examples 'content not cached without revalidation' do end describe UploadsController do - let!(:user) { create(:user, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let!(:user) { create(:user, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) } describe 'POST create' do let(:model) { 'personal_snippet' } let(:snippet) { create(:personal_snippet, :public) } - let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } - let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } + let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') } + let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') } context 'when a user does not have permissions to upload a file' do it "returns 401 when the user is not logged in" do @@ -205,7 +205,7 @@ describe UploadsController do end context "when viewing a project avatar" do - let!(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let!(:project) { create(:project, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) } context "when the project is public" do before do @@ -314,7 +314,7 @@ describe UploadsController do end context "when viewing a group avatar" do - let!(:group) { create(:group, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let!(:group) { create(:group, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) } context "when the group is public" do context "when not signed in" do @@ -521,7 +521,7 @@ describe UploadsController do context 'Appearance' do context 'when viewing a custom header logo' do - let!(:appearance) { create :appearance, header_logo: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } + let!(:appearance) { create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png', 'image/png') } context 'when not signed in' do it 'responds with status 200' do @@ -541,7 +541,7 @@ describe UploadsController do end context 'when viewing a custom logo' do - let!(:appearance) { create :appearance, logo: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } + let!(:appearance) { create :appearance, logo: fixture_file_upload('spec/fixtures/dk.png', 'image/png') } context 'when not signed in' do it 'responds with status 200' do diff --git a/spec/factories/lfs_objects.rb b/spec/factories/lfs_objects.rb index eaf3a4ed497..c909471bb55 100644 --- a/spec/factories/lfs_objects.rb +++ b/spec/factories/lfs_objects.rb @@ -7,7 +7,7 @@ FactoryBot.define do end trait :with_file do - file { fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "`/png") } + file { fixture_file_upload("spec/fixtures/dk.png", "`/png") } end # The uniqueness constraint means we can't use the correct OID for all LFS diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb index 40f3fa7d69b..9fdc3e616a6 100644 --- a/spec/factories/notes.rb +++ b/spec/factories/notes.rb @@ -130,11 +130,11 @@ FactoryBot.define do end trait :with_attachment do - attachment { fixture_file_upload(Rails.root.join( "spec/fixtures/dk.png"), "image/png") } + attachment { fixture_file_upload("spec/fixtures/dk.png", "image/png") } end trait :with_svg_attachment do - attachment { fixture_file_upload(Rails.root.join("spec/fixtures/unsanitized.svg"), "image/svg+xml") } + attachment { fixture_file_upload("spec/fixtures/unsanitized.svg", "image/svg+xml") } end transient do diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb index 62a2ec55b00..87fa3f60826 100644 --- a/spec/features/commits_spec.rb +++ b/spec/features/commits_spec.rb @@ -47,7 +47,7 @@ describe 'Commits' do context 'commit status is Ci Build' do let!(:build) { create(:ci_build, pipeline: pipeline) } - let(:artifacts_file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + let(:artifacts_file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } context 'when logged as developer' do before do diff --git a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb index fd1629746ef..d3104b448e0 100644 --- a/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb +++ b/spec/features/merge_request/user_sees_mini_pipeline_graph_spec.rb @@ -23,8 +23,8 @@ describe 'Merge request < User sees mini pipeline graph', :js do end context 'as json' do - let(:artifacts_file1) { fixture_file_upload(Rails.root.join('spec/fixtures/banana_sample.gif'), 'image/gif') } - let(:artifacts_file2) { fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } + let(:artifacts_file1) { fixture_file_upload(File.join('spec/fixtures/banana_sample.gif'), 'image/gif') } + let(:artifacts_file2) { fixture_file_upload(File.join('spec/fixtures/dk.png'), 'image/png') } before do create(:ci_build, :success, :trace_artifact, pipeline: pipeline, legacy_artifacts_file: artifacts_file1) diff --git a/spec/features/projects/jobs_spec.rb b/spec/features/projects/jobs_spec.rb index 9d1c4cbad8b..d2aaf60e72c 100644 --- a/spec/features/projects/jobs_spec.rb +++ b/spec/features/projects/jobs_spec.rb @@ -11,7 +11,7 @@ feature 'Jobs', :clean_gitlab_redis_shared_state do let(:job2) { create(:ci_build) } let(:artifacts_file) do - fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') + fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') end before do diff --git a/spec/features/projects/pages_spec.rb b/spec/features/projects/pages_spec.rb index bdd49f731c7..a2899ec0f48 100644 --- a/spec/features/projects/pages_spec.rb +++ b/spec/features/projects/pages_spec.rb @@ -314,8 +314,8 @@ feature 'Pages' do project: project, pipeline: pipeline, ref: 'HEAD', - legacy_artifacts_file: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip')), - legacy_artifacts_metadata: fixture_file_upload(Rails.root.join('spec/fixtures/pages.zip.meta')) + legacy_artifacts_file: fixture_file_upload(File.join('spec/fixtures/pages.zip')), + legacy_artifacts_metadata: fixture_file_upload(File.join('spec/fixtures/pages.zip.meta')) ) end diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb index f40d4bc2d08..2223f163177 100644 --- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ImportExport::AvatarSaver do let(:shared) { project.import_export_shared } let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" } - let(:project_with_avatar) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) } + let(:project_with_avatar) { create(:project, avatar: fixture_file_upload("spec/fixtures/dk.png", "image/png")) } let(:project) { create(:project) } before do diff --git a/spec/lib/gitlab/import_export/uploads_saver_spec.rb b/spec/lib/gitlab/import_export/uploads_saver_spec.rb index 1304d8fabfc..095687fa89d 100644 --- a/spec/lib/gitlab/import_export/uploads_saver_spec.rb +++ b/spec/lib/gitlab/import_export/uploads_saver_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Gitlab::ImportExport::UploadsSaver do describe 'bundle a project Git repo' do let(:export_path) { "#{Dir.tmpdir}/uploads_saver_spec" } - let(:file) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + let(:file) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } let(:shared) { project.import_export_shared } before do diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb index a3e119cbc27..efddd4e7662 100644 --- a/spec/models/ci/job_artifact_spec.rb +++ b/spec/models/ci/job_artifact_spec.rb @@ -76,12 +76,12 @@ describe Ci::JobArtifact do context 'updating the artifact file' do it 'updates the artifact size' do - artifact.update!(file: fixture_file_upload(File.join(Rails.root, 'spec/fixtures/dk.png'))) + artifact.update!(file: fixture_file_upload('spec/fixtures/dk.png')) expect(artifact.size).to eq(1062) end it 'updates the project statistics' do - expect { artifact.update!(file: fixture_file_upload(File.join(Rails.root, 'spec/fixtures/dk.png'))) } + expect { artifact.update!(file: fixture_file_upload('spec/fixtures/dk.png')) } .to change { artifact.project.statistics.reload.build_artifacts_size } .by(1062 - 106365) end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 9b7c3205c1f..99103039f77 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -518,7 +518,7 @@ describe API::Projects do end it 'uploads avatar for project a project' do - project = attributes_for(:project, avatar: fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif')) + project = attributes_for(:project, avatar: fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif')) post api('/projects', user), project @@ -777,7 +777,7 @@ describe API::Projects do end it "uploads the file and returns its info" do - post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") + post api("/projects/#{project.id}/uploads", user), file: fixture_file_upload("spec/fixtures/dk.png", "image/png") expect(response).to have_gitlab_http_status(201) expect(json_response['alt']).to eq("dk") diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index c981a10ac38..9b167a5ed23 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -1055,8 +1055,8 @@ describe API::Runner, :clean_gitlab_redis_shared_state do let(:jwt_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') } let(:headers) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => jwt_token } } let(:headers_with_token) { headers.merge(API::Helpers::Runner::JOB_TOKEN_HEADER => job.token) } - let(:file_upload) { fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } - let(:file_upload2) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', 'image/gif') } + let(:file_upload) { fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } + let(:file_upload2) { fixture_file_upload('spec/fixtures/dk.png', 'image/gif') } before do stub_artifacts_object_storage diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 05637eb0729..3377d67b644 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -512,7 +512,7 @@ describe API::Users do end it 'updates user with avatar' do - put api("/users/#{user.id}", admin), { avatar: fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') } + put api("/users/#{user.id}", admin), { avatar: fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') } user.reload diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb index be286c490fe..bcb8d6c2bfc 100644 --- a/spec/requests/openid_connect_spec.rb +++ b/spec/requests/openid_connect_spec.rb @@ -61,7 +61,7 @@ describe 'OpenID Connect requests' do email: private_email.email, public_email: public_email.email, website_url: 'https://example.com', - avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png") + avatar: fixture_file_upload('spec/fixtures/dk.png') ) end diff --git a/spec/services/projects/fork_service_spec.rb b/spec/services/projects/fork_service_spec.rb index a93f6f1ddc2..c15f5120b8a 100644 --- a/spec/services/projects/fork_service_spec.rb +++ b/spec/services/projects/fork_service_spec.rb @@ -8,7 +8,7 @@ describe Projects::ForkService do before do @from_user = create(:user) @from_namespace = @from_user.namespace - avatar = fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") + avatar = fixture_file_upload("spec/fixtures/dk.png", "image/png") @from_project = create(:project, :repository, creator_id: @from_user.id, diff --git a/spec/services/projects/gitlab_projects_import_service_spec.rb b/spec/services/projects/gitlab_projects_import_service_spec.rb index ee1a886f5d6..0a898e9b89b 100644 --- a/spec/services/projects/gitlab_projects_import_service_spec.rb +++ b/spec/services/projects/gitlab_projects_import_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Projects::GitlabProjectsImportService do set(:namespace) { create(:namespace) } let(:path) { 'test-path' } - let(:file) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } + let(:file) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') } let(:overwrite) { false } let(:import_params) { { namespace_id: namespace.id, path: path, file: file, overwrite: overwrite } } subject { described_class.new(namespace.owner, import_params) } diff --git a/spec/services/projects/participants_service_spec.rb b/spec/services/projects/participants_service_spec.rb index 0d18ceb8ff8..6040f9100f8 100644 --- a/spec/services/projects/participants_service_spec.rb +++ b/spec/services/projects/participants_service_spec.rb @@ -4,7 +4,7 @@ describe Projects::ParticipantsService do describe '#groups' do describe 'avatar_url' do let(:project) { create(:project, :public) } - let(:group) { create(:group, avatar: fixture_file_upload(Rails.root + 'spec/fixtures/dk.png')) } + let(:group) { create(:group, avatar: fixture_file_upload('spec/fixtures/dk.png')) } let(:user) { create(:user) } let!(:group_member) { create(:group_member, group: group, user: user) } diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb index 347ac13828c..35a9b744b10 100644 --- a/spec/services/projects/update_pages_service_spec.rb +++ b/spec/services/projects/update_pages_service_spec.rb @@ -4,11 +4,11 @@ describe Projects::UpdatePagesService do set(:project) { create(:project, :repository) } set(:pipeline) { create(:ci_pipeline, project: project, sha: project.commit('HEAD').sha) } set(:build) { create(:ci_build, pipeline: pipeline, ref: 'HEAD') } - let(:invalid_file) { fixture_file_upload(Rails.root + 'spec/fixtures/dk.png') } + let(:invalid_file) { fixture_file_upload('spec/fixtures/dk.png') } let(:extension) { 'zip' } - let(:file) { fixture_file_upload(Rails.root + "spec/fixtures/pages.#{extension}") } - let(:empty_file) { fixture_file_upload(Rails.root + "spec/fixtures/pages_empty.#{extension}") } + let(:file) { fixture_file_upload("spec/fixtures/pages.#{extension}") } + let(:empty_file) { fixture_file_upload("spec/fixtures/pages_empty.#{extension}") } let(:metadata) do filename = Rails.root + "spec/fixtures/pages.#{extension}.meta" fixture_file_upload(filename) if File.exist?(filename) @@ -196,8 +196,8 @@ describe Projects::UpdatePagesService do let(:metadata) { spy('metadata') } before do - file = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip') - metafile = fixture_file_upload(Rails.root + 'spec/fixtures/pages.zip.meta') + file = fixture_file_upload('spec/fixtures/pages.zip') + metafile = fixture_file_upload('spec/fixtures/pages.zip.meta') build.update_attributes(legacy_artifacts_file: file) build.update_attributes(legacy_artifacts_metadata: metafile) diff --git a/spec/services/upload_service_spec.rb b/spec/services/upload_service_spec.rb index 24f3a5c5ff0..9b232a52efa 100644 --- a/spec/services/upload_service_spec.rb +++ b/spec/services/upload_service_spec.rb @@ -9,7 +9,7 @@ describe UploadService do context 'for valid gif file' do before do - gif = fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif') + gif = fixture_file_upload('spec/fixtures/banana_sample.gif', 'image/gif') @link_to_file = upload_file(@project, gif) end @@ -21,7 +21,7 @@ describe UploadService do context 'for valid png file' do before do - png = fixture_file_upload(Rails.root + 'spec/fixtures/dk.png', + png = fixture_file_upload('spec/fixtures/dk.png', 'image/png') @link_to_file = upload_file(@project, png) end @@ -34,7 +34,7 @@ describe UploadService do context 'for valid jpg file' do before do - jpg = fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') + jpg = fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') @link_to_file = upload_file(@project, jpg) end @@ -46,7 +46,7 @@ describe UploadService do context 'for txt file' do before do - txt = fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') + txt = fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') @link_to_file = upload_file(@project, txt) end @@ -58,7 +58,7 @@ describe UploadService do context 'for too large a file' do before do - txt = fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') + txt = fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') allow(txt).to receive(:size) { 1000.megabytes.to_i } @link_to_file = upload_file(@project, txt) end diff --git a/spec/support/rspec.rb b/spec/support/rspec.rb index dffab22d8b5..54b8df7aa19 100644 --- a/spec/support/rspec.rb +++ b/spec/support/rspec.rb @@ -9,4 +9,6 @@ RSpec.configure do |config| config.include StubConfiguration config.include StubObjectStorage config.include StubENV + + config.fixture_path = Rails.root if defined?(Rails) end 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 ea7dbade171..bbbad86dcd5 100644 --- a/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb +++ b/spec/support/shared_examples/controllers/uploads_actions_shared_examples.rb @@ -1,7 +1,7 @@ shared_examples 'handle uploads' do let(:user) { create(:user) } - let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') } - let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') } + let(:jpg) { fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') } + let(:txt) { fixture_file_upload('spec/fixtures/doc_sample.txt', 'text/plain') } let(:secret) { FileUploader.generate_secret } let(:uploader_class) { FileUploader } diff --git a/spec/uploaders/attachment_uploader_spec.rb b/spec/uploaders/attachment_uploader_spec.rb index d302c14efb9..a9415854d25 100644 --- a/spec/uploaders/attachment_uploader_spec.rb +++ b/spec/uploaders/attachment_uploader_spec.rb @@ -26,7 +26,7 @@ describe AttachmentUploader do describe "#migrate!" do before do - uploader.store!(fixture_file_upload(Rails.root.join('spec/fixtures/doc_sample.txt'))) + uploader.store!(fixture_file_upload(File.join('spec/fixtures/doc_sample.txt'))) stub_uploads_object_storage end diff --git a/spec/uploaders/file_mover_spec.rb b/spec/uploaders/file_mover_spec.rb index 68b7e24776d..de29d0c943f 100644 --- a/spec/uploaders/file_mover_spec.rb +++ b/spec/uploaders/file_mover_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe FileMover do let(:filename) { 'banana_sample.gif' } - let(:file) { fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) } + let(:file) { fixture_file_upload(File.join('spec', 'fixtures', filename)) } let(:temp_file_path) { File.join('uploads/-/system/temp', 'secret55', filename) } let(:temp_description) do diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb index db2810bbe1d..59013a02938 100644 --- a/spec/uploaders/file_uploader_spec.rb +++ b/spec/uploaders/file_uploader_spec.rb @@ -89,7 +89,7 @@ describe FileUploader do describe "#migrate!" do before do - uploader.store!(fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'))) + uploader.store!(fixture_file_upload('spec/fixtures/dk.png')) stub_uploads_object_storage end diff --git a/spec/uploaders/job_artifact_uploader_spec.rb b/spec/uploaders/job_artifact_uploader_spec.rb index 42036d67f3d..179c94ec3bc 100644 --- a/spec/uploaders/job_artifact_uploader_spec.rb +++ b/spec/uploaders/job_artifact_uploader_spec.rb @@ -81,7 +81,7 @@ describe JobArtifactUploader do describe "#migrate!" do before do - uploader.store!(fixture_file_upload(Rails.root.join('spec/fixtures/trace/sample_trace'))) + uploader.store!(fixture_file_upload(File.join('spec/fixtures/trace/sample_trace'))) stub_artifacts_object_storage end diff --git a/spec/uploaders/namespace_file_uploader_spec.rb b/spec/uploaders/namespace_file_uploader_spec.rb index a8ba01d70b8..71fe2c353c0 100644 --- a/spec/uploaders/namespace_file_uploader_spec.rb +++ b/spec/uploaders/namespace_file_uploader_spec.rb @@ -28,7 +28,7 @@ describe NamespaceFileUploader do describe "#migrate!" do before do - uploader.store!(fixture_file_upload(Rails.root.join('spec/fixtures/doc_sample.txt'))) + uploader.store!(fixture_file_upload(File.join('spec/fixtures/doc_sample.txt'))) stub_uploads_object_storage end diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index 4503288e410..0bc5b6751b3 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -571,7 +571,7 @@ describe ObjectStorage do context 'when local file is used' do context 'when valid file is used' do let(:uploaded_file) do - fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') + fixture_file_upload('spec/fixtures/rails_sample.jpg', 'image/jpg') end it "properly caches the file" do diff --git a/spec/uploaders/personal_file_uploader_spec.rb b/spec/uploaders/personal_file_uploader_spec.rb index c70521d90dc..7700b14ce6b 100644 --- a/spec/uploaders/personal_file_uploader_spec.rb +++ b/spec/uploaders/personal_file_uploader_spec.rb @@ -45,7 +45,7 @@ describe PersonalFileUploader do describe "#migrate!" do before do - uploader.store!(fixture_file_upload(Rails.root.join('spec/fixtures/doc_sample.txt'))) + uploader.store!(fixture_file_upload('spec/fixtures/doc_sample.txt')) stub_uploads_object_storage end diff --git a/spec/uploaders/records_uploads_spec.rb b/spec/uploaders/records_uploads_spec.rb index 9a3e5d83e01..3592a11360d 100644 --- a/spec/uploaders/records_uploads_spec.rb +++ b/spec/uploaders/records_uploads_spec.rb @@ -16,7 +16,7 @@ describe RecordsUploads do end def upload_fixture(filename) - fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) + fixture_file_upload(File.join('spec', 'fixtures', filename)) end describe 'callbacks' do diff --git a/spec/uploaders/uploader_helper_spec.rb b/spec/uploaders/uploader_helper_spec.rb index c47f09adb6d..33da93cc9d0 100644 --- a/spec/uploaders/uploader_helper_spec.rb +++ b/spec/uploaders/uploader_helper_spec.rb @@ -12,7 +12,7 @@ describe UploaderHelper do end def upload_fixture(filename) - fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) + fixture_file_upload(File.join('spec', 'fixtures', filename)) end describe '#image_or_video?' do -- cgit v1.2.1 From b38c75b3dc2dc655377a1b4070cb6f5242594dbe Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 6 Jun 2018 16:26:00 -0500 Subject: Correct more usages of non-relative `fixture_file_upload` paths --- spec/features/projects/jobs/permissions_spec.rb | 3 +-- spec/helpers/emails_helper_spec.rb | 4 +--- spec/helpers/groups_helper_spec.rb | 8 ++++---- spec/requests/api/project_import_spec.rb | 2 +- spec/services/projects/update_pages_service_spec.rb | 2 +- spec/uploaders/gitlab_uploader_spec.rb | 2 +- spec/uploaders/job_artifact_uploader_spec.rb | 8 +++----- spec/uploaders/legacy_artifact_uploader_spec.rb | 3 +-- 8 files changed, 13 insertions(+), 19 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/jobs/permissions_spec.rb b/spec/features/projects/jobs/permissions_spec.rb index 31abadf9bd6..e9588daf37d 100644 --- a/spec/features/projects/jobs/permissions_spec.rb +++ b/spec/features/projects/jobs/permissions_spec.rb @@ -88,8 +88,7 @@ describe 'Project Jobs Permissions' do describe 'artifacts page' do context 'when recent job has artifacts available' do before do - artifacts = Rails.root.join('spec/fixtures/ci_build_artifacts.zip') - archive = fixture_file_upload(artifacts, 'application/zip') + archive = fixture_file_upload('spec/fixtures/ci_build_artifacts.zip') job.update_attributes(legacy_artifacts_file: archive) end diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb index 2390c1f3e5d..139387e0b24 100644 --- a/spec/helpers/emails_helper_spec.rb +++ b/spec/helpers/emails_helper_spec.rb @@ -47,9 +47,7 @@ describe EmailsHelper do describe '#header_logo' do context 'there is a brand item with a logo' do it 'returns the brand header logo' do - appearance = create :appearance, header_logo: fixture_file_upload( - Rails.root.join('spec/fixtures/dk.png') - ) + appearance = create :appearance, header_logo: fixture_file_upload('spec/fixtures/dk.png') expect(header_logo).to eq( %{Dk} diff --git a/spec/helpers/groups_helper_spec.rb b/spec/helpers/groups_helper_spec.rb index b48c252acd3..6c94bd4e504 100644 --- a/spec/helpers/groups_helper_spec.rb +++ b/spec/helpers/groups_helper_spec.rb @@ -4,9 +4,9 @@ describe GroupsHelper do include ApplicationHelper describe 'group_icon' do - avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') - it 'returns an url for the avatar' do + avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif') + group = create(:group) group.avatar = fixture_file_upload(avatar_file_path) group.save! @@ -17,9 +17,9 @@ describe GroupsHelper do end describe 'group_icon_url' do - avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') - it 'returns an url for the avatar' do + avatar_file_path = File.join('spec', 'fixtures', 'banana_sample.gif') + group = create(:group) group.avatar = fixture_file_upload(avatar_file_path) group.save! diff --git a/spec/requests/api/project_import_spec.rb b/spec/requests/api/project_import_spec.rb index f8c64f063af..97dffdc9233 100644 --- a/spec/requests/api/project_import_spec.rb +++ b/spec/requests/api/project_import_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe API::ProjectImport do let(:export_path) { "#{Dir.tmpdir}/project_export_spec" } let(:user) { create(:user) } - let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') } + let(:file) { File.join('spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') } let(:namespace) { create(:group) } before do allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) diff --git a/spec/services/projects/update_pages_service_spec.rb b/spec/services/projects/update_pages_service_spec.rb index 35a9b744b10..1bffeee6790 100644 --- a/spec/services/projects/update_pages_service_spec.rb +++ b/spec/services/projects/update_pages_service_spec.rb @@ -10,7 +10,7 @@ describe Projects::UpdatePagesService do let(:file) { fixture_file_upload("spec/fixtures/pages.#{extension}") } let(:empty_file) { fixture_file_upload("spec/fixtures/pages_empty.#{extension}") } let(:metadata) do - filename = Rails.root + "spec/fixtures/pages.#{extension}.meta" + filename = "spec/fixtures/pages.#{extension}.meta" fixture_file_upload(filename) if File.exist?(filename) end diff --git a/spec/uploaders/gitlab_uploader_spec.rb b/spec/uploaders/gitlab_uploader_spec.rb index 4fba122cce1..362f89424d4 100644 --- a/spec/uploaders/gitlab_uploader_spec.rb +++ b/spec/uploaders/gitlab_uploader_spec.rb @@ -62,7 +62,7 @@ describe GitlabUploader do expect(FileUtils).to receive(:mv).with(anything, /^#{subject.work_dir}/).and_call_original expect(FileUtils).to receive(:mv).with(/^#{subject.work_dir}/, /#{subject.cache_dir}/).and_call_original - fixture = Rails.root.join('spec', 'fixtures', 'rails_sample.jpg') + fixture = File.join('spec', 'fixtures', 'rails_sample.jpg') subject.cache!(fixture_file_upload(fixture)) expect(subject.file.path).to match(/#{subject.cache_dir}/) diff --git a/spec/uploaders/job_artifact_uploader_spec.rb b/spec/uploaders/job_artifact_uploader_spec.rb index 179c94ec3bc..026e4356ed6 100644 --- a/spec/uploaders/job_artifact_uploader_spec.rb +++ b/spec/uploaders/job_artifact_uploader_spec.rb @@ -29,8 +29,7 @@ describe JobArtifactUploader do context 'when trace is stored in File storage' do context 'when file exists' do let(:file) do - fixture_file_upload( - Rails.root.join('spec/fixtures/trace/sample_trace'), 'text/plain') + fixture_file_upload('spec/fixtures/trace/sample_trace', 'text/plain') end before do @@ -63,8 +62,7 @@ describe JobArtifactUploader do context 'file is stored in valid local_path' do let(:file) do - fixture_file_upload( - Rails.root.join('spec/fixtures/ci_build_artifacts.zip'), 'application/zip') + fixture_file_upload('spec/fixtures/ci_build_artifacts.zip', 'application/zip') end before do @@ -81,7 +79,7 @@ describe JobArtifactUploader do describe "#migrate!" do before do - uploader.store!(fixture_file_upload(File.join('spec/fixtures/trace/sample_trace'))) + uploader.store!(fixture_file_upload('spec/fixtures/trace/sample_trace')) stub_artifacts_object_storage end diff --git a/spec/uploaders/legacy_artifact_uploader_spec.rb b/spec/uploaders/legacy_artifact_uploader_spec.rb index eeb6fd90c9d..0589563b502 100644 --- a/spec/uploaders/legacy_artifact_uploader_spec.rb +++ b/spec/uploaders/legacy_artifact_uploader_spec.rb @@ -44,8 +44,7 @@ describe LegacyArtifactUploader do context 'file is stored in valid path' do let(:file) do - fixture_file_upload( - Rails.root.join('spec/fixtures/ci_build_artifacts.zip'), 'application/zip') + fixture_file_upload('spec/fixtures/ci_build_artifacts.zip', 'application/zip') end before do -- cgit v1.2.1 From 9f76632d80b5f1d9a47faa95f537e579b6ac41d6 Mon Sep 17 00:00:00 2001 From: Balasankar C Date: Thu, 7 Jun 2018 15:01:20 +0000 Subject: Add installation type to usage ping data --- spec/lib/gitlab/usage_data_spec.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb index a716e6f5434..22d921716aa 100644 --- a/spec/lib/gitlab/usage_data_spec.rb +++ b/spec/lib/gitlab/usage_data_spec.rb @@ -32,6 +32,7 @@ describe Gitlab::UsageData do mattermost_enabled edition version + installation_type uuid hostname signup @@ -156,6 +157,7 @@ describe Gitlab::UsageData do it "gathers license data" do expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid) expect(subject[:version]).to eq(Gitlab::VERSION) + expect(subject[:installation_type]).to eq(Gitlab::INSTALLATION_TYPE) expect(subject[:active_user_count]).to eq(User.active.count) expect(subject[:recorded_at]).to be_a(Time) end -- cgit v1.2.1 From 6afe6fa6bcb3bdb09bd49ba638a37af2a8c7a6ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 7 Jun 2018 17:23:38 +0200 Subject: Make Gitlab::CurrentSettings.current_application_settings return cached settings early if they exist without issuing any DB query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/lib/gitlab/current_settings_spec.rb | 143 +++++++++++++++++++------------ 1 file changed, 88 insertions(+), 55 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb index 19028495f52..55490f37ac7 100644 --- a/spec/lib/gitlab/current_settings_spec.rb +++ b/spec/lib/gitlab/current_settings_spec.rb @@ -5,6 +5,13 @@ describe Gitlab::CurrentSettings do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') end + shared_context 'with settings in cache' do + before do + create(:application_setting) + described_class.current_application_settings # warm the cache + end + end + describe '#current_application_settings', :use_clean_rails_memory_store_caching do it 'allows keys to be called directly' do db_settings = create(:application_setting, @@ -31,16 +38,29 @@ describe Gitlab::CurrentSettings do end context 'with DB unavailable' do - before do - # For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(false)` causes issues - # during the initialization phase of the test suite, so instead let's mock the internals of it - allow(ActiveRecord::Base.connection).to receive(:active?).and_return(false) + context 'and settings in cache' do + include_context 'with settings in cache' + + it 'fetches the settings from cache without issuing any query' do + expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0) + end end - it 'returns an in-memory ApplicationSetting object' do - expect(ApplicationSetting).not_to receive(:current) + context 'and no settings in cache' do + before do + # For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(false)` causes issues + # during the initialization phase of the test suite, so instead let's mock the internals of it + allow(ActiveRecord::Base.connection).to receive(:active?).and_return(false) + expect(ApplicationSetting).not_to receive(:current) + end - expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) + it 'returns an in-memory ApplicationSetting object' do + expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) + end + + it 'does not issue any query' do + expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0) + end end end @@ -52,73 +72,86 @@ describe Gitlab::CurrentSettings do ar_wrapped_defaults.slice(*::ApplicationSetting.defaults.keys) end - before do - # For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(true)` causes issues - # during the initialization phase of the test suite, so instead let's mock the internals of it - allow(ActiveRecord::Base.connection).to receive(:active?).and_return(true) - allow(ActiveRecord::Base.connection).to receive(:cached_table_exists?).with('application_settings').and_return(true) - end + context 'and settings in cache' do + include_context 'with settings in cache' - it 'creates default ApplicationSettings if none are present' do - settings = described_class.current_application_settings - - expect(settings).to be_a(ApplicationSetting) - expect(settings).to be_persisted - expect(settings).to have_attributes(settings_from_defaults) + it 'fetches the settings from cache' do + # For some reason, `allow(described_class).to receive(:connect_to_db?).and_return(true)` causes issues + # during the initialization phase of the test suite, so instead let's mock the internals of it + expect(ActiveRecord::Base.connection).not_to receive(:active?) + expect(ActiveRecord::Base.connection).not_to receive(:cached_table_exists?) + expect(ActiveRecord::Migrator).not_to receive(:needs_migration?) + expect(ActiveRecord::QueryRecorder.new { described_class.current_application_settings }.count).to eq(0) + end end - context 'with migrations pending' do + context 'and no settings in cache' do before do - expect(ActiveRecord::Migrator).to receive(:needs_migration?).and_return(true) + allow(ActiveRecord::Base.connection).to receive(:active?).and_return(true) + allow(ActiveRecord::Base.connection).to receive(:cached_table_exists?).with('application_settings').and_return(true) end - it 'returns an in-memory ApplicationSetting object' do + it 'creates default ApplicationSettings if none are present' do settings = described_class.current_application_settings - expect(settings).to be_a(Gitlab::FakeApplicationSettings) - expect(settings.sign_in_enabled?).to eq(settings.sign_in_enabled) - expect(settings.sign_up_enabled?).to eq(settings.sign_up_enabled) + expect(settings).to be_a(ApplicationSetting) + expect(settings).to be_persisted + expect(settings).to have_attributes(settings_from_defaults) end - it 'uses the existing database settings and falls back to defaults' do - db_settings = create(:application_setting, - home_page_url: 'http://mydomain.com', - signup_enabled: false) - settings = described_class.current_application_settings - app_defaults = ApplicationSetting.last - - expect(settings).to be_a(Gitlab::FakeApplicationSettings) - expect(settings.home_page_url).to eq(db_settings.home_page_url) - expect(settings.signup_enabled?).to be_falsey - expect(settings.signup_enabled).to be_falsey - - # Check that unspecified values use the defaults - settings.reject! { |key, _| [:home_page_url, :signup_enabled].include? key } - settings.each { |key, _| expect(settings[key]).to eq(app_defaults[key]) } + context 'with migrations pending' do + before do + expect(ActiveRecord::Migrator).to receive(:needs_migration?).and_return(true) + end + + it 'returns an in-memory ApplicationSetting object' do + settings = described_class.current_application_settings + + expect(settings).to be_a(Gitlab::FakeApplicationSettings) + expect(settings.sign_in_enabled?).to eq(settings.sign_in_enabled) + expect(settings.sign_up_enabled?).to eq(settings.sign_up_enabled) + end + + it 'uses the existing database settings and falls back to defaults' do + db_settings = create(:application_setting, + home_page_url: 'http://mydomain.com', + signup_enabled: false) + settings = described_class.current_application_settings + app_defaults = ApplicationSetting.last + + expect(settings).to be_a(Gitlab::FakeApplicationSettings) + expect(settings.home_page_url).to eq(db_settings.home_page_url) + expect(settings.signup_enabled?).to be_falsey + expect(settings.signup_enabled).to be_falsey + + # Check that unspecified values use the defaults + settings.reject! { |key, _| [:home_page_url, :signup_enabled].include? key } + settings.each { |key, _| expect(settings[key]).to eq(app_defaults[key]) } + end end - end - context 'when ApplicationSettings.current is present' do - it 'returns the existing application settings' do - expect(ApplicationSetting).to receive(:current).and_return(:current_settings) + context 'when ApplicationSettings.current is present' do + it 'returns the existing application settings' do + expect(ApplicationSetting).to receive(:current).and_return(:current_settings) - expect(described_class.current_application_settings).to eq(:current_settings) + expect(described_class.current_application_settings).to eq(:current_settings) + end end - end - context 'when the application_settings table does not exists' do - it 'returns an in-memory ApplicationSetting object' do - expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::StatementInvalid) + context 'when the application_settings table does not exists' do + it 'returns an in-memory ApplicationSetting object' do + expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::StatementInvalid) - expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) + expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) + end end - end - context 'when the application_settings table is not fully migrated' do - it 'returns an in-memory ApplicationSetting object' do - expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::UnknownAttributeError) + context 'when the application_settings table is not fully migrated' do + it 'returns an in-memory ApplicationSetting object' do + expect(ApplicationSetting).to receive(:create_from_defaults).and_raise(ActiveRecord::UnknownAttributeError) - expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) + expect(described_class.current_application_settings).to be_a(Gitlab::FakeApplicationSettings) + end end end end -- cgit v1.2.1 From 36c337647591d964b7ef1e1fc61fc64a930fb6f4 Mon Sep 17 00:00:00 2001 From: Gabriel Mazetto Date: Thu, 7 Jun 2018 15:40:44 +0000 Subject: Resolve "Hashed Storage: Make possible to migrate single project" --- spec/lib/gitlab/hashed_storage/migrator_spec.rb | 75 +++++++++++++++++++++++++ spec/tasks/gitlab/storage_rake_spec.rb | 45 ++++++++++++--- spec/workers/storage_migrator_worker_spec.rb | 25 ++++----- 3 files changed, 121 insertions(+), 24 deletions(-) create mode 100644 spec/lib/gitlab/hashed_storage/migrator_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/hashed_storage/migrator_spec.rb b/spec/lib/gitlab/hashed_storage/migrator_spec.rb new file mode 100644 index 00000000000..813ae43b4d3 --- /dev/null +++ b/spec/lib/gitlab/hashed_storage/migrator_spec.rb @@ -0,0 +1,75 @@ +require 'spec_helper' + +describe Gitlab::HashedStorage::Migrator do + describe '#bulk_schedule' do + it 'schedules job to StorageMigratorWorker' do + Sidekiq::Testing.fake! do + expect { subject.bulk_schedule(1, 5) }.to change(StorageMigratorWorker.jobs, :size).by(1) + end + end + end + + describe '#bulk_migrate' do + let(:projects) { create_list(:project, 2, :legacy_storage) } + let(:ids) { projects.map(&:id) } + + it 'enqueue jobs to ProjectMigrateHashedStorageWorker' do + Sidekiq::Testing.fake! do + expect { subject.bulk_migrate(ids.min, ids.max) }.to change(ProjectMigrateHashedStorageWorker.jobs, :size).by(2) + end + end + + it 'sets projects as read only' do + allow(ProjectMigrateHashedStorageWorker).to receive(:perform_async).twice + subject.bulk_migrate(ids.min, ids.max) + + projects.each do |project| + expect(project.reload.repository_read_only?).to be_truthy + end + end + + it 'rescues and log exceptions' do + allow_any_instance_of(Project).to receive(:migrate_to_hashed_storage!).and_raise(StandardError) + expect { subject.bulk_migrate(ids.min, ids.max) }.not_to raise_error + end + + it 'delegates each project in specified range to #migrate' do + projects.each do |project| + expect(subject).to receive(:migrate).with(project) + end + + subject.bulk_migrate(ids.min, ids.max) + end + end + + describe '#migrate' do + let(:project) { create(:project, :legacy_storage, :empty_repo) } + + it 'enqueues job to ProjectMigrateHashedStorageWorker' do + Sidekiq::Testing.fake! do + expect { subject.migrate(project) }.to change(ProjectMigrateHashedStorageWorker.jobs, :size).by(1) + end + end + + it 'rescues and log exceptions' do + allow(project).to receive(:migrate_to_hashed_storage!).and_raise(StandardError) + + expect { subject.migrate(project) }.not_to raise_error + end + + it 'sets project as read only' do + allow(ProjectMigrateHashedStorageWorker).to receive(:perform_async) + subject.migrate(project) + + expect(project.reload.repository_read_only?).to be_truthy + end + + it 'migrate project' do + Sidekiq::Testing.inline! do + subject.migrate(project) + end + + expect(project.reload.hashed_storage?(:attachments)).to be_truthy + end + end +end diff --git a/spec/tasks/gitlab/storage_rake_spec.rb b/spec/tasks/gitlab/storage_rake_spec.rb index 35e451b2f9a..233076ad6fa 100644 --- a/spec/tasks/gitlab/storage_rake_spec.rb +++ b/spec/tasks/gitlab/storage_rake_spec.rb @@ -1,6 +1,6 @@ require 'rake_helper' -describe 'gitlab:storage:*' do +describe 'rake gitlab:storage:*' do before do Rake.application.rake_require 'tasks/gitlab/storage' @@ -44,16 +44,18 @@ describe 'gitlab:storage:*' do end describe 'gitlab:storage:migrate_to_hashed' do + let(:task) { 'gitlab:storage:migrate_to_hashed' } + context '0 legacy projects' do it 'does nothing' do expect(StorageMigratorWorker).not_to receive(:perform_async) - run_rake_task('gitlab:storage:migrate_to_hashed') + run_rake_task(task) end end context '3 legacy projects' do - let(:projects) { create_list(:project, 3, storage_version: 0) } + let(:projects) { create_list(:project, 3, :legacy_storage) } context 'in batches of 1' do before do @@ -65,7 +67,7 @@ describe 'gitlab:storage:*' do expect(StorageMigratorWorker).to receive(:perform_async).with(project.id, project.id) end - run_rake_task('gitlab:storage:migrate_to_hashed') + run_rake_task(task) end end @@ -80,23 +82,48 @@ describe 'gitlab:storage:*' do expect(StorageMigratorWorker).to receive(:perform_async).with(first, last) end - run_rake_task('gitlab:storage:migrate_to_hashed') + run_rake_task(task) end end end + + context 'with same id in range' do + it 'displays message when project cant be found' do + stub_env('ID_FROM', 99999) + stub_env('ID_TO', 99999) + + expect { run_rake_task(task) }.to output(/There are no projects requiring storage migration with ID=99999/).to_stdout + end + + it 'displays a message when project exists but its already migrated' do + project = create(:project) + stub_env('ID_FROM', project.id) + stub_env('ID_TO', project.id) + + expect { run_rake_task(task) }.to output(/There are no projects requiring storage migration with ID=#{project.id}/).to_stdout + end + + it 'enqueues migration when project can be found' do + project = create(:project, :legacy_storage) + stub_env('ID_FROM', project.id) + stub_env('ID_TO', project.id) + + expect { run_rake_task(task) }.to output(/Enqueueing storage migration .* \(ID=#{project.id}\)/).to_stdout + end + end end describe 'gitlab:storage:legacy_projects' do it_behaves_like 'rake entities summary', 'projects', 'Legacy' do let(:task) { 'gitlab:storage:legacy_projects' } - let(:create_collection) { create_list(:project, 3, storage_version: 0) } + let(:create_collection) { create_list(:project, 3, :legacy_storage) } end end describe 'gitlab:storage:list_legacy_projects' do it_behaves_like 'rake listing entities', 'projects', 'Legacy' do let(:task) { 'gitlab:storage:list_legacy_projects' } - let(:create_collection) { create_list(:project, 3, storage_version: 0) } + let(:create_collection) { create_list(:project, 3, :legacy_storage) } end end @@ -133,7 +160,7 @@ describe 'gitlab:storage:*' do describe 'gitlab:storage:hashed_attachments' do it_behaves_like 'rake entities summary', 'attachments', 'Hashed' do let(:task) { 'gitlab:storage:hashed_attachments' } - let(:project) { create(:project, storage_version: 2) } + let(:project) { create(:project) } let(:create_collection) { create_list(:upload, 3, model: project) } end end @@ -141,7 +168,7 @@ describe 'gitlab:storage:*' do describe 'gitlab:storage:list_hashed_attachments' do it_behaves_like 'rake listing entities', 'attachments', 'Hashed' do let(:task) { 'gitlab:storage:list_hashed_attachments' } - let(:project) { create(:project, storage_version: 2) } + let(:project) { create(:project) } let(:create_collection) { create_list(:upload, 3, model: project) } end end diff --git a/spec/workers/storage_migrator_worker_spec.rb b/spec/workers/storage_migrator_worker_spec.rb index ff625164142..815432aacce 100644 --- a/spec/workers/storage_migrator_worker_spec.rb +++ b/spec/workers/storage_migrator_worker_spec.rb @@ -2,29 +2,24 @@ require 'spec_helper' describe StorageMigratorWorker do subject(:worker) { described_class.new } - let(:projects) { create_list(:project, 2, :legacy_storage) } + let(:projects) { create_list(:project, 2, :legacy_storage, :empty_repo) } + let(:ids) { projects.map(&:id) } describe '#perform' do - let(:ids) { projects.map(&:id) } + it 'delegates to MigratorService' do + expect_any_instance_of(Gitlab::HashedStorage::Migrator).to receive(:bulk_migrate).with(5, 10) - it 'enqueue jobs to ProjectMigrateHashedStorageWorker' do - expect(ProjectMigrateHashedStorageWorker).to receive(:perform_async).twice - - worker.perform(ids.min, ids.max) + worker.perform(5, 10) end - it 'sets projects as read only' do - allow(ProjectMigrateHashedStorageWorker).to receive(:perform_async).twice - worker.perform(ids.min, ids.max) + it 'migrates projects in the specified range' do + Sidekiq::Testing.inline! do + worker.perform(ids.min, ids.max) + end projects.each do |project| - expect(project.reload.repository_read_only?).to be_truthy + expect(project.reload.hashed_storage?(:attachments)).to be_truthy end end - - it 'rescues and log exceptions' do - allow_any_instance_of(Project).to receive(:migrate_to_hashed_storage!).and_raise(StandardError) - expect { worker.perform(ids.min, ids.max) }.not_to raise_error - end end end -- cgit v1.2.1 From 50872bcc242a582c7e3af25df4d32e1c3e0a28f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mica=C3=ABl=20Bergeron?= Date: Thu, 7 Jun 2018 11:06:04 -0400 Subject: fix the failing spec --- .../shared_examples/uploaders/object_storage_shared_examples.rb | 4 ++-- spec/uploaders/object_storage_spec.rb | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb index 6352f1527cd..1ecddc14d58 100644 --- a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb +++ b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb @@ -85,13 +85,13 @@ shared_examples "migrates" do |to_store:, from_store: nil| it 'does not execute migrate!' do expect(subject).not_to receive(:unsafe_migrate!) - expect { migrate(to) }.to raise_error('exclusive lease already taken') + expect { migrate(to) }.to raise_error(ObjectStorage::ExclusiveLeaseTaken) end it 'does not execute use_file' do expect(subject).not_to receive(:unsafe_use_file) - expect { subject.use_file }.to raise_error('exclusive lease already taken') + expect { subject.use_file }.to raise_error(ObjectStorage::ExclusiveLeaseTaken) end after do diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index 4503288e410..03386bf764f 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -321,7 +321,7 @@ describe ObjectStorage do when_file_is_in_use do expect(uploader).not_to receive(:unsafe_migrate!) - expect { uploader.migrate!(described_class::Store::REMOTE) }.to raise_error('exclusive lease already taken') + expect { uploader.migrate!(described_class::Store::REMOTE) }.to raise_error(ObjectStorage::ExclusiveLeaseTaken) end end @@ -329,7 +329,7 @@ describe ObjectStorage do when_file_is_in_use do expect(uploader).not_to receive(:unsafe_use_file) - expect { uploader.use_file }.to raise_error('exclusive lease already taken') + expect { uploader.use_file }.to raise_error(ObjectStorage::ExclusiveLeaseTaken) end end end -- cgit v1.2.1 From dd7a59bf94849f578ebc8f65aa7acbd0ed7c8f8e Mon Sep 17 00:00:00 2001 From: Kushal Pandya Date: Thu, 7 Jun 2018 21:38:27 +0530 Subject: Add timeframe helper methods --- spec/javascripts/datetime_utility_spec.js | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/datetime_utility_spec.js b/spec/javascripts/datetime_utility_spec.js index a8d09202154..e224ed46d18 100644 --- a/spec/javascripts/datetime_utility_spec.js +++ b/spec/javascripts/datetime_utility_spec.js @@ -149,23 +149,22 @@ describe('getSundays', () => { }); }); -describe('getTimeframeWindow', () => { - it('returns array of dates representing a timeframe based on provided length and date', () => { - const date = new Date(2018, 0, 1); +describe('getTimeframeWindowFrom', () => { + it('returns array of date objects upto provided length start with provided startDate', () => { + const startDate = new Date(2018, 0, 1); const mockTimeframe = [ - new Date(2017, 9, 1), - new Date(2017, 10, 1), - new Date(2017, 11, 1), new Date(2018, 0, 1), new Date(2018, 1, 1), - new Date(2018, 2, 31), + new Date(2018, 2, 1), + new Date(2018, 3, 1), + new Date(2018, 4, 31), ]; - const timeframe = datetimeUtility.getTimeframeWindow(6, date); - - expect(timeframe.length).toBe(6); + const timeframe = datetimeUtility.getTimeframeWindowFrom(startDate, 5); + expect(timeframe.length).toBe(5); timeframe.forEach((timeframeItem, index) => { - expect(timeframeItem.getFullYear() === mockTimeframe[index].getFullYear()).toBeTruthy(); - expect(timeframeItem.getMonth() === mockTimeframe[index].getMonth()).toBeTruthy(); + console.log(timeframeItem); + expect(timeframeItem.getFullYear() === mockTimeframe[index].getFullYear()).toBe(true); + expect(timeframeItem.getMonth() === mockTimeframe[index].getMonth()).toBe(true); expect(timeframeItem.getDate() === mockTimeframe[index].getDate()).toBeTruthy(); }); }); -- cgit v1.2.1 From a6a900256e194c28d8342db9c2d67df784877c14 Mon Sep 17 00:00:00 2001 From: Tomasz Maczukin Date: Thu, 7 Jun 2018 17:27:26 +0200 Subject: Change update entrypoint instead of adding new keep-alive one --- spec/requests/api/runner_spec.rb | 84 +++++++++++++--------------------------- 1 file changed, 26 insertions(+), 58 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb index c93612d7ada..57d238ff79b 100644 --- a/spec/requests/api/runner_spec.rb +++ b/spec/requests/api/runner_spec.rb @@ -816,6 +816,18 @@ describe API::Runner, :clean_gitlab_redis_shared_state do expect(job.reload.trace.raw).to eq 'BUILD TRACE' end + + context 'when running state is sent' do + it 'updates update_at value' do + expect { update_job_after_time }.to change { job.reload.updated_at } + end + end + + context 'when other state is sent' do + it "doesn't update update_at value" do + expect { update_job_after_time(20.minutes, state: 'success') }.not_to change { job.reload.updated_at } + end + end end context 'when job has been erased' do @@ -838,6 +850,7 @@ describe API::Runner, :clean_gitlab_redis_shared_state do update_job(state: 'success', trace: 'BUILD TRACE UPDATED') expect(response).to have_gitlab_http_status(403) + expect(response.header['Job-Status']).to eq 'failed' expect(job.trace.raw).to eq 'Job failed' expect(job).to be_failed end @@ -847,66 +860,10 @@ describe API::Runner, :clean_gitlab_redis_shared_state do new_params = params.merge(token: token) put api("/jobs/#{job.id}"), new_params end - end - - describe 'POST /api/v4/jobs/:id/keep-alive' do - let(:job) { create(:ci_build, :running, :trace_live, runner_id: runner.id, pipeline: pipeline) } - let(:headers) { { API::Helpers::Runner::JOB_TOKEN_HEADER => job.token, 'Content-Type' => 'text/plain' } } - let(:update_interval) { 30.seconds } - - it 'returns correct response' do - keep_alive_job - - expect(response.status).to eq 200 - expect(response.header).to have_key 'Job-Status' - end - - it 'updates updated_at value' do - expect { keep_alive_job }.to change { job.updated_at } - end - - context 'when project for the build has been deleted' do - let(:job) do - create(:ci_build, :running, :trace_live, runner_id: runner.id, pipeline: pipeline) do |job| - job.project.update(pending_delete: true) - end - end - - it 'responds with forbidden' do - keep_alive_job - - expect(response.status).to eq(403) - end - end - context 'when job has been canceled' do - before do - job.cancel - end - - it 'returns job-status=canceled header' do - keep_alive_job - - expect(response.status).to eq 200 - expect(response.header['Job-Status']).to eq('canceled') - end - end - - context 'when job has been errased' do - let(:job) { create(:ci_build, runner_id: runner.id, erased_at: Time.now) } - - it 'rresponds with forbidden' do - keep_alive_job - - expect(response.status).to eq 403 - end - end - - def keep_alive_job(token = job.token, **params) - new_params = params.merge(token: token) + def update_job_after_time(update_interval = 20.minutes, state = 'running') Timecop.travel(job.updated_at + update_interval) do - post api("/jobs/#{job.id}/keep-alive"), new_params - job.reload + update_job(job.token, state: state) end end end @@ -1041,6 +998,17 @@ describe API::Runner, :clean_gitlab_redis_shared_state do end end end + + context 'when the job is canceled' do + before do + job.cancel + patch_the_trace + end + + it 'receives status in header' do + expect(response.header['Job-Status']).to eq 'canceled' + end + end end context 'when Runner makes a force-patch' do -- cgit v1.2.1 From d64ab8df18db156ff44fb3c9f4ecef529c1c28e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Lu=C3=ADs?= Date: Thu, 7 Jun 2018 18:06:31 +0000 Subject: Resolve "Show `failure_reason` and improve failed jobs tab in pipeline detail view" --- spec/features/projects/pipelines/pipeline_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 35776a5f23b..ecc7cf84138 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -344,6 +344,16 @@ describe 'Pipeline', :js do it 'shows build failure logs' do expect(page).to have_content('4 examples, 1 failure') end + + it 'shows the failure reason' do + expect(page).to have_content('There is an unknown failure, please try again') + end + + it 'shows retry button for failed build' do + page.within(find('.build-failures', match: :first)) do + expect(page).to have_link('Retry') + end + end end context 'when missing build logs' do -- cgit v1.2.1 From 5370c442dfc0f1009b557cea9ce4dafbfe821569 Mon Sep 17 00:00:00 2001 From: Mayra Cabrera Date: Thu, 7 Jun 2018 18:09:14 +0000 Subject: Resolve "Automatically provide a Deploy Token to projects when Auto DevOps is enabled" --- spec/factories/project_auto_devops.rb | 4 ++ spec/models/project_auto_devops_spec.rb | 93 +++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) (limited to 'spec') diff --git a/spec/factories/project_auto_devops.rb b/spec/factories/project_auto_devops.rb index 5ce1988c76f..0e8b507f9ce 100644 --- a/spec/factories/project_auto_devops.rb +++ b/spec/factories/project_auto_devops.rb @@ -3,5 +3,9 @@ FactoryBot.define do project enabled true domain "example.com" + + trait :disabled do + enabled false + end end end diff --git a/spec/models/project_auto_devops_spec.rb b/spec/models/project_auto_devops_spec.rb index 7545c0797e9..4778bf4052b 100644 --- a/spec/models/project_auto_devops_spec.rb +++ b/spec/models/project_auto_devops_spec.rb @@ -71,4 +71,97 @@ describe ProjectAutoDevops do { key: 'AUTO_DEVOPS_DOMAIN', value: 'example.com', public: true } end end + + describe '#set_gitlab_deploy_token' do + let(:auto_devops) { build(:project_auto_devops, project: project) } + + context 'when the project is public' do + let(:project) { create(:project, :repository, :public) } + + it 'should not create a gitlab deploy token' do + expect do + auto_devops.save + end.not_to change { DeployToken.count } + end + end + + context 'when the project is internal' do + let(:project) { create(:project, :repository, :internal) } + + it 'should create a gitlab deploy token' do + expect do + auto_devops.save + end.to change { DeployToken.count }.by(1) + end + end + + context 'when the project is private' do + let(:project) { create(:project, :repository, :private) } + + it 'should create a gitlab deploy token' do + expect do + auto_devops.save + end.to change { DeployToken.count }.by(1) + end + end + + context 'when autodevops is enabled at project level' do + let(:project) { create(:project, :repository, :internal) } + let(:auto_devops) { build(:project_auto_devops, project: project) } + + it 'should create a deploy token' do + expect do + auto_devops.save + end.to change { DeployToken.count }.by(1) + end + end + + context 'when autodevops is enabled at instancel level' do + let(:project) { create(:project, :repository, :internal) } + let(:auto_devops) { build(:project_auto_devops, :disabled, project: project) } + + it 'should create a deploy token' do + allow(Gitlab::CurrentSettings).to receive(:auto_devops_enabled?).and_return(true) + + expect do + auto_devops.save + end.to change { DeployToken.count }.by(1) + end + end + + context 'when autodevops is disabled' do + let(:project) { create(:project, :repository, :internal) } + let(:auto_devops) { build(:project_auto_devops, :disabled, project: project) } + + it 'should not create a deploy token' do + expect do + auto_devops.save + end.not_to change { DeployToken.count } + end + end + + context 'when the project already has an active gitlab-deploy-token' do + let(:project) { create(:project, :repository, :internal) } + let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, projects: [project]) } + let(:auto_devops) { build(:project_auto_devops, project: project) } + + it 'should not create a deploy token' do + expect do + auto_devops.save + end.not_to change { DeployToken.count } + end + end + + context 'when the project already has a revoked gitlab-deploy-token' do + let(:project) { create(:project, :repository, :internal) } + let!(:deploy_token) { create(:deploy_token, :gitlab_deploy_token, :expired, projects: [project]) } + let(:auto_devops) { build(:project_auto_devops, project: project) } + + it 'should not create a deploy token' do + expect do + auto_devops.save + end.not_to change { DeployToken.count } + end + end + end end -- cgit v1.2.1 From afe5d7d56ee771dac6e4a97d23e69d678c03da2d Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Mon, 28 May 2018 15:43:46 -0300 Subject: Apply notification settings level of groups to all child objects --- spec/models/group_spec.rb | 24 ++++ spec/models/notification_recipient_spec.rb | 44 +++++++ spec/services/notification_service_spec.rb | 188 ++++++++++++++++++++++++----- 3 files changed, 227 insertions(+), 29 deletions(-) (limited to 'spec') diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index f83b52e8975..ff35be4a8e3 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -67,6 +67,30 @@ describe Group do end end + describe '#notification_settings', :nested_groups do + let(:user) { create(:user) } + let(:group) { create(:group) } + let(:sub_group) { create(:group, parent_id: group.id) } + + before do + group.add_developer(user) + sub_group.add_developer(user) + end + + it 'also gets notification settings from parent groups' do + expect(sub_group.notification_settings.size).to eq(2) + expect(sub_group.notification_settings).to include(group.notification_settings.first) + end + + context 'when sub group is deleted' do + it 'does not delete parent notification settings' do + expect do + sub_group.destroy + end.to change { NotificationSetting.count }.by(-1) + end + end + end + describe '#visibility_level_allowed_by_parent' do let(:parent) { create(:group, :internal) } let(:sub_group) { build(:group, parent_id: parent.id) } diff --git a/spec/models/notification_recipient_spec.rb b/spec/models/notification_recipient_spec.rb index eda0e1da835..13fe47799ed 100644 --- a/spec/models/notification_recipient_spec.rb +++ b/spec/models/notification_recipient_spec.rb @@ -13,4 +13,48 @@ describe NotificationRecipient do expect(recipient.has_access?).to be_falsy end + + context '#notification_setting' do + context 'for child groups', :nested_groups do + let!(:moved_group) { create(:group) } + let(:group) { create(:group) } + let(:sub_group_1) { create(:group, parent: group) } + let(:sub_group_2) { create(:group, parent: sub_group_1) } + let(:project) { create(:project, namespace: moved_group) } + + before do + sub_group_2.add_owner(user) + moved_group.add_owner(user) + Groups::TransferService.new(moved_group, user).execute(sub_group_2) + + moved_group.reload + end + + context 'when notification setting is global' do + before do + user.notification_settings_for(group).global! + user.notification_settings_for(sub_group_1).mention! + user.notification_settings_for(sub_group_2).global! + user.notification_settings_for(moved_group).global! + end + + it 'considers notification setting from the first parent without global setting' do + expect(subject.notification_setting.source).to eq(sub_group_1) + end + end + + context 'when notification setting is not global' do + before do + user.notification_settings_for(group).global! + user.notification_settings_for(sub_group_1).mention! + user.notification_settings_for(sub_group_2).watch! + user.notification_settings_for(moved_group).disabled! + end + + it 'considers notification setting from lowest group member in hierarchy' do + expect(subject.notification_setting.source).to eq(moved_group) + end + end + end + end end diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index 831678b949d..0eadc83bfe3 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -59,6 +59,20 @@ describe NotificationService, :mailer do should_email(participant) end + + context 'for subgroups', :nested_groups do + before do + build_group(project) + end + + it 'emails the participant' do + create(:note_on_issue, noteable: issuable, project_id: project.id, note: 'anything', author: @pg_participant) + + notification_trigger + + should_email_nested_group_user(@pg_participant) + end + end end shared_examples 'participating by assignee notification' do @@ -239,34 +253,56 @@ describe NotificationService, :mailer do end describe 'new note on issue in project that belongs to a group' do - let(:group) { create(:group) } - before do note.project.namespace_id = group.id - note.project.group.add_user(@u_watcher, GroupMember::MASTER) - note.project.group.add_user(@u_custom_global, GroupMember::MASTER) + group.add_user(@u_watcher, GroupMember::MASTER) + group.add_user(@u_custom_global, GroupMember::MASTER) note.project.save @u_watcher.notification_settings_for(note.project).participating! - @u_watcher.notification_settings_for(note.project.group).global! + @u_watcher.notification_settings_for(group).global! update_custom_notification(:new_note, @u_custom_global) reset_delivered_emails! end - it do - notification.new_note(note) + shared_examples 'new note notifications' do + it do + notification.new_note(note) + + should_email(note.noteable.author) + should_email(note.noteable.assignees.first) + should_email(@u_mentioned) + should_email(@u_custom_global) + should_not_email(@u_guest_custom) + should_not_email(@u_guest_watcher) + should_not_email(@u_watcher) + should_not_email(note.author) + should_not_email(@u_participating) + should_not_email(@u_disabled) + should_not_email(@u_lazy_participant) + end + end - should_email(note.noteable.author) - should_email(note.noteable.assignees.first) - should_email(@u_mentioned) - should_email(@u_custom_global) - should_not_email(@u_guest_custom) - should_not_email(@u_guest_watcher) - should_not_email(@u_watcher) - should_not_email(note.author) - should_not_email(@u_participating) - should_not_email(@u_disabled) - should_not_email(@u_lazy_participant) + let(:group) { create(:group) } + + it_behaves_like 'new note notifications' + + context 'which is a subgroup', :nested_groups do + let!(:parent) { create(:group) } + let!(:group) { create(:group, parent: parent) } + + it_behaves_like 'new note notifications' + + it 'overrides child objects with global level' do + user = create(:user) + parent.add_developer(user) + user.notification_settings_for(parent).watch! + reset_delivered_emails! + + notification.new_note(note) + + should_email(user) + end end end end @@ -301,6 +337,31 @@ describe NotificationService, :mailer do should_email(member) should_email(admin) end + + context 'on project that belongs to subgroup', :nested_groups do + let(:group_reporter) { create(:user) } + let(:group_guest) { create(:user) } + let(:parent_group) { create(:group) } + let(:child_group) { create(:group, parent: parent_group) } + let(:project) { create(:project, namespace: child_group) } + + context 'when user is group guest member' do + before do + parent_group.add_reporter(group_reporter) + parent_group.add_guest(group_guest) + group_guest.notification_settings_for(parent_group).watch! + group_reporter.notification_settings_for(parent_group).watch! + reset_delivered_emails! + end + + it 'does not email guest user' do + notification.new_note(note) + + should_email(group_reporter) + should_not_email(group_guest) + end + end + end end context 'issue note mention' do @@ -311,6 +372,7 @@ describe NotificationService, :mailer do before do build_team(note.project) + build_group(note.project) note.project.add_master(note.author) add_users_with_subscription(note.project, issue) reset_delivered_emails! @@ -336,10 +398,20 @@ describe NotificationService, :mailer do should_email(@u_guest_watcher) should_email(note.noteable.author) should_email(note.noteable.assignees.first) - should_not_email(note.author) + should_email_nested_group_user(@pg_watcher) should_email(@u_mentioned) - should_not_email(@u_disabled) should_email(@u_not_mentioned) + should_not_email(note.author) + should_not_email(@u_disabled) + should_not_email_nested_group_user(@pg_disabled) + end + + it 'notifies parent group members with mention level', :nested_groups do + note = create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: "@#{@pg_mention.username}") + + notification.new_note(note) + + should_email_nested_group_user(@pg_mention) end it 'filters out "mentioned in" notes' do @@ -352,17 +424,18 @@ describe NotificationService, :mailer do end context 'project snippet note' do - let(:project) { create(:project, :public) } + let!(:project) { create(:project, :public) } let(:snippet) { create(:project_snippet, project: project, author: create(:user)) } - let(:note) { create(:note_on_project_snippet, noteable: snippet, project_id: snippet.project.id, note: '@all mentioned') } + let(:note) { create(:note_on_project_snippet, noteable: snippet, project_id: project.id, note: '@all mentioned') } before do - build_team(note.project) + build_team(project) + build_group(project) # make sure these users can read the project snippet! project.add_guest(@u_guest_watcher) project.add_guest(@u_guest_custom) - + add_member_for_parent_group(@pg_watcher, project) note.project.add_master(note.author) reset_delivered_emails! end @@ -370,7 +443,6 @@ describe NotificationService, :mailer do describe '#new_note' do it 'notifies the team members' do notification.new_note(note) - # Notify all team members note.project.team.members.each do |member| # User with disabled notification should not be notified @@ -449,6 +521,7 @@ describe NotificationService, :mailer do before do build_team(note.project) + build_group(project) reset_delivered_emails! allow(note.noteable).to receive(:author).and_return(@u_committer) update_custom_notification(:new_note, @u_guest_custom, resource: project) @@ -463,11 +536,13 @@ describe NotificationService, :mailer do should_email(@u_guest_custom) should_email(@u_committer) should_email(@u_watcher) + should_email_nested_group_user(@pg_watcher) should_not_email(@u_mentioned) should_not_email(note.author) should_not_email(@u_participating) should_not_email(@u_disabled) should_not_email(@u_lazy_participant) + should_not_email_nested_group_user(@pg_disabled) end it do @@ -478,10 +553,12 @@ describe NotificationService, :mailer do should_email(@u_committer) should_email(@u_watcher) should_email(@u_mentioned) + should_email_nested_group_user(@pg_watcher) should_not_email(note.author) should_not_email(@u_participating) should_not_email(@u_disabled) should_not_email(@u_lazy_participant) + should_not_email_nested_group_user(@pg_disabled) end it do @@ -548,10 +625,13 @@ describe NotificationService, :mailer do should_email(@g_global_watcher) should_email(@g_watcher) should_email(@unsubscribed_mentioned) + should_email_nested_group_user(@pg_watcher) should_not_email(@u_mentioned) should_not_email(@u_participating) should_not_email(@u_disabled) should_not_email(@u_lazy_participant) + should_not_email_nested_group_user(@pg_disabled) + should_not_email_nested_group_user(@pg_mention) end it do @@ -1922,19 +2002,69 @@ describe NotificationService, :mailer do # Users in the project's group but not part of project's team # with different notification settings def build_group(project) - group = create(:group, :public) - project.group = group + group = create_nested_group + project.update(namespace_id: group.id) # Group member: global=disabled, group=watch - @g_watcher = create_user_with_notification(:watch, 'group_watcher', project.group) + @g_watcher ||= create_user_with_notification(:watch, 'group_watcher', project.group) @g_watcher.notification_settings_for(nil).disabled! # Group member: global=watch, group=global - @g_global_watcher = create_global_setting_for(create(:user), :watch) + @g_global_watcher ||= create_global_setting_for(create(:user), :watch) group.add_users([@g_watcher, @g_global_watcher], :master) + group end + # Creates a nested group only if supported + # to avoid errors on MySQL + def create_nested_group + if Group.supports_nested_groups? + parent_group = create(:group, :public) + child_group = create(:group, :public, parent: parent_group) + + # Parent group member: global=disabled, parent_group=watch, child_group=global + @pg_watcher ||= create_user_with_notification(:watch, 'parent_group_watcher', parent_group) + @pg_watcher.notification_settings_for(nil).disabled! + + # Parent group member: global=global, parent_group=disabled, child_group=global + @pg_disabled ||= create_user_with_notification(:disabled, 'parent_group_disabled', parent_group) + @pg_disabled.notification_settings_for(nil).global! + + # Parent group member: global=global, parent_group=mention, child_group=global + @pg_mention ||= create_user_with_notification(:mention, 'parent_group_mention', parent_group) + @pg_mention.notification_settings_for(nil).global! + + # Parent group member: global=global, parent_group=participating, child_group=global + @pg_participant ||= create_user_with_notification(:participating, 'parent_group_participant', parent_group) + @pg_mention.notification_settings_for(nil).global! + + child_group + else + create(:group, :public) + end + end + + def add_member_for_parent_group(user, project) + return unless Group.supports_nested_groups? + + project.reload + + project.group.parent.add_master(user) + end + + def should_email_nested_group_user(user, times: 1, recipients: email_recipients) + return unless Group.supports_nested_groups? + + should_email(user, times: 1, recipients: email_recipients) + end + + def should_not_email_nested_group_user(user, recipients: email_recipients) + return unless Group.supports_nested_groups? + + should_not_email(user, recipients: email_recipients) + end + def add_users_with_subscription(project, issuable) @subscriber = create :user @unsubscriber = create :user -- cgit v1.2.1 From b00b861863bd963224593846791ea0b6993d9b88 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Thu, 7 Jun 2018 15:46:25 -0500 Subject: Refactor schema_spec.rb for CE-EE parity and simplicity --- spec/migrations/active_record/schema_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/migrations/active_record/schema_spec.rb b/spec/migrations/active_record/schema_spec.rb index e132529d8d8..9d35b3cd642 100644 --- a/spec/migrations/active_record/schema_spec.rb +++ b/spec/migrations/active_record/schema_spec.rb @@ -5,7 +5,11 @@ require 'spec_helper' describe ActiveRecord::Schema do let(:latest_migration_timestamp) do - migrations = Dir[Rails.root.join('db', 'migrate', '*'), Rails.root.join('db', 'post_migrate', '*')] + migrations_paths = %w[db ee/db] + .product(%w[migrate post_migrate]) + .map { |path| Rails.root.join(*path, '*') } + + migrations = Dir[*migrations_paths] migrations.map { |migration| File.basename(migration).split('_').first.to_i }.max end -- cgit v1.2.1 From cf41aaba5ab9fb1d229807f77b2b77585d3550b0 Mon Sep 17 00:00:00 2001 From: Mario de la Ossa Date: Thu, 7 Jun 2018 20:54:24 +0000 Subject: Backport of "Add assignee lists to boards" --- spec/features/boards/boards_spec.rb | 2 +- spec/features/issues/form_spec.rb | 3 +++ spec/finders/group_members_finder_spec.rb | 12 ++++++++++++ spec/finders/members_finder_spec.rb | 12 ++++++++++++ spec/fixtures/api/schemas/list.json | 2 +- spec/javascripts/boards/board_card_spec.js | 2 +- spec/javascripts/boards/boards_store_spec.js | 2 +- spec/javascripts/boards/issue_card_spec.js | 2 +- spec/javascripts/boards/issue_spec.js | 2 +- spec/javascripts/boards/list_spec.js | 2 +- spec/javascripts/boards/modal_store_spec.js | 2 +- 11 files changed, 35 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/features/boards/boards_spec.rb b/spec/features/boards/boards_spec.rb index e414345ac23..f6e0dee28c6 100644 --- a/spec/features/boards/boards_spec.rb +++ b/spec/features/boards/boards_spec.rb @@ -150,7 +150,7 @@ describe 'Issue Boards', :js do click_button 'Add list' wait_for_requests - find('.dropdown-menu-close').click + find('.js-new-board-list').click page.within(find('.board:nth-child(2)')) do accept_confirm { find('.board-delete').click } diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 4625a50b8d9..2cb3ae08b0e 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -143,6 +143,9 @@ describe 'New/edit issue', :js do click_link label.title click_link label2.title end + + find('.js-issuable-form-dropdown.js-label-select').click + page.within '.js-label-select' do expect(page).to have_content label.title end diff --git a/spec/finders/group_members_finder_spec.rb b/spec/finders/group_members_finder_spec.rb index 9f285e28535..63e15b365a4 100644 --- a/spec/finders/group_members_finder_spec.rb +++ b/spec/finders/group_members_finder_spec.rb @@ -29,4 +29,16 @@ describe GroupMembersFinder, '#execute' do expect(result.to_a).to match_array([member1, member3, member4]) end + + it 'returns members for descendant groups if requested', :nested_groups do + member1 = group.add_master(user2) + member2 = group.add_master(user1) + nested_group.add_master(user2) + member3 = nested_group.add_master(user3) + member4 = nested_group.add_master(user4) + + result = described_class.new(group).execute(include_descendants: true) + + expect(result.to_a).to match_array([member1, member2, member3, member4]) + end end diff --git a/spec/finders/members_finder_spec.rb b/spec/finders/members_finder_spec.rb index 7bb1f45322e..2fc5299b0f4 100644 --- a/spec/finders/members_finder_spec.rb +++ b/spec/finders/members_finder_spec.rb @@ -19,4 +19,16 @@ describe MembersFinder, '#execute' do expect(result.to_a).to match_array([member1, member2, member3]) end + + it 'includes nested group members if asked', :nested_groups do + project = create(:project, namespace: group) + nested_group.request_access(user1) + member1 = group.add_master(user2) + member2 = nested_group.add_master(user3) + member3 = project.add_master(user4) + + result = described_class.new(project, user2).execute(include_descendants: true) + + expect(result.to_a).to match_array([member1, member2, member3]) + end end diff --git a/spec/fixtures/api/schemas/list.json b/spec/fixtures/api/schemas/list.json index 05922df6b81..b76ec115293 100644 --- a/spec/fixtures/api/schemas/list.json +++ b/spec/fixtures/api/schemas/list.json @@ -37,5 +37,5 @@ "title": { "type": "string" }, "position": { "type": ["integer", "null"] } }, - "additionalProperties": false + "additionalProperties": true } diff --git a/spec/javascripts/boards/board_card_spec.js b/spec/javascripts/boards/board_card_spec.js index 9b4db774b63..ad263791cd4 100644 --- a/spec/javascripts/boards/board_card_spec.js +++ b/spec/javascripts/boards/board_card_spec.js @@ -5,10 +5,10 @@ import Vue from 'vue'; import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; -import '~/boards/models/assignee'; import eventHub from '~/boards/eventhub'; import '~/vue_shared/models/label'; +import '~/vue_shared/models/assignee'; import '~/boards/models/list'; import '~/boards/stores/boards_store'; import boardCard from '~/boards/components/board_card.vue'; diff --git a/spec/javascripts/boards/boards_store_spec.js b/spec/javascripts/boards/boards_store_spec.js index 46fa10e1789..3f5ed4f3d07 100644 --- a/spec/javascripts/boards/boards_store_spec.js +++ b/spec/javascripts/boards/boards_store_spec.js @@ -7,9 +7,9 @@ import axios from '~/lib/utils/axios_utils'; import Cookies from 'js-cookie'; import '~/vue_shared/models/label'; +import '~/vue_shared/models/assignee'; import '~/boards/models/issue'; import '~/boards/models/list'; -import '~/boards/models/assignee'; import '~/boards/services/board_service'; import '~/boards/stores/boards_store'; import { listObj, listObjDuplicate, boardsMockInterceptor, mockBoardService } from './mock_data'; diff --git a/spec/javascripts/boards/issue_card_spec.js b/spec/javascripts/boards/issue_card_spec.js index abeef272c68..05acf903933 100644 --- a/spec/javascripts/boards/issue_card_spec.js +++ b/spec/javascripts/boards/issue_card_spec.js @@ -5,9 +5,9 @@ import Vue from 'vue'; import '~/vue_shared/models/label'; +import '~/vue_shared/models/assignee'; import '~/boards/models/issue'; import '~/boards/models/list'; -import '~/boards/models/assignee'; import '~/boards/stores/boards_store'; import '~/boards/components/issue_card_inner'; import { listObj } from './mock_data'; diff --git a/spec/javascripts/boards/issue_spec.js b/spec/javascripts/boards/issue_spec.js index d90f9a41231..db68096e3bd 100644 --- a/spec/javascripts/boards/issue_spec.js +++ b/spec/javascripts/boards/issue_spec.js @@ -3,9 +3,9 @@ import Vue from 'vue'; import '~/vue_shared/models/label'; +import '~/vue_shared/models/assignee'; import '~/boards/models/issue'; import '~/boards/models/list'; -import '~/boards/models/assignee'; import '~/boards/services/board_service'; import '~/boards/stores/boards_store'; import { mockBoardService } from './mock_data'; diff --git a/spec/javascripts/boards/list_spec.js b/spec/javascripts/boards/list_spec.js index d5d1139de15..ac8bbb8f2a8 100644 --- a/spec/javascripts/boards/list_spec.js +++ b/spec/javascripts/boards/list_spec.js @@ -6,9 +6,9 @@ import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import _ from 'underscore'; import '~/vue_shared/models/label'; +import '~/vue_shared/models/assignee'; import '~/boards/models/issue'; import '~/boards/models/list'; -import '~/boards/models/assignee'; import '~/boards/services/board_service'; import '~/boards/stores/boards_store'; import { listObj, listObjDuplicate, boardsMockInterceptor, mockBoardService } from './mock_data'; diff --git a/spec/javascripts/boards/modal_store_spec.js b/spec/javascripts/boards/modal_store_spec.js index 797693a21aa..a234c81fadf 100644 --- a/spec/javascripts/boards/modal_store_spec.js +++ b/spec/javascripts/boards/modal_store_spec.js @@ -1,9 +1,9 @@ /* global ListIssue */ import '~/vue_shared/models/label'; +import '~/vue_shared/models/assignee'; import '~/boards/models/issue'; import '~/boards/models/list'; -import '~/boards/models/assignee'; import Store from '~/boards/stores/modal_store'; describe('Modal store', () => { -- cgit v1.2.1 From ebf5f31d8c7e3381c16899ba8e64e569d3dfd3a3 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Fri, 8 Jun 2018 04:27:36 +0000 Subject: Set tooltips to have default boundary viewport --- spec/support/features/reportable_note_shared_examples.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/support/features/reportable_note_shared_examples.rb b/spec/support/features/reportable_note_shared_examples.rb index 836e5e7be23..b4c71d69119 100644 --- a/spec/support/features/reportable_note_shared_examples.rb +++ b/spec/support/features/reportable_note_shared_examples.rb @@ -1,6 +1,7 @@ require 'spec_helper' shared_examples 'reportable note' do |type| + include MobileHelpers include NotesHelper let(:comment) { find("##{ActionView::RecordIdentifier.dom_id(note)}") } @@ -39,6 +40,9 @@ shared_examples 'reportable note' do |type| end def open_dropdown(dropdown) + # make window wide enough that tooltip doesn't trigger horizontal scrollbar + resize_window(1200, 800) + dropdown.find('.more-actions-toggle').click dropdown.find('.dropdown-menu li', match: :first) end -- cgit v1.2.1 From 2729205b391c22eb3a15408580261456cc030530 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 7 Jun 2018 16:34:50 -0500 Subject: remove monacoLoader and import monaco directly within Editor class --- .../javascripts/ide/components/repo_editor_spec.js | 6 +----- .../ide/lib/common/model_manager_spec.js | 11 +++-------- spec/javascripts/ide/lib/common/model_spec.js | 17 ++++++---------- .../ide/lib/decorations/controller_spec.js | 19 +++++++----------- spec/javascripts/ide/lib/diff/controller_spec.js | 23 +++++++++------------- spec/javascripts/ide/lib/editor_spec.js | 16 +++++---------- spec/javascripts/ide/monaco_loader_spec.js | 15 -------------- 7 files changed, 31 insertions(+), 76 deletions(-) delete mode 100644 spec/javascripts/ide/monaco_loader_spec.js (limited to 'spec') diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js index d3f80e6f9c0..d318521d0a0 100644 --- a/spec/javascripts/ide/components/repo_editor_spec.js +++ b/spec/javascripts/ide/components/repo_editor_spec.js @@ -3,7 +3,6 @@ import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import store from '~/ide/stores'; import repoEditor from '~/ide/components/repo_editor.vue'; -import monacoLoader from '~/ide/monaco_loader'; import Editor from '~/ide/lib/editor'; import { activityBarViews } from '~/ide/constants'; import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; @@ -25,13 +24,10 @@ describe('RepoEditor', () => { f.tempFile = true; vm.$store.state.openFiles.push(f); Vue.set(vm.$store.state.entries, f.path, f); - vm.monaco = true; vm.$mount(); - monacoLoader(['vs/editor/editor.main'], () => { - setTimeout(done, 0); - }); + Vue.nextTick(() => setTimeout(done)); }); afterEach(() => { diff --git a/spec/javascripts/ide/lib/common/model_manager_spec.js b/spec/javascripts/ide/lib/common/model_manager_spec.js index c00d590c580..e3886f06f5a 100644 --- a/spec/javascripts/ide/lib/common/model_manager_spec.js +++ b/spec/javascripts/ide/lib/common/model_manager_spec.js @@ -1,18 +1,13 @@ -/* global monaco */ +import * as monaco from 'monaco-editor'; import eventHub from '~/ide/eventhub'; -import monacoLoader from '~/ide/monaco_loader'; import ModelManager from '~/ide/lib/common/model_manager'; import { file } from '../../helpers'; describe('Multi-file editor library model manager', () => { let instance; - beforeEach(done => { - monacoLoader(['vs/editor/editor.main'], () => { - instance = new ModelManager(monaco); - - done(); - }); + beforeEach(() => { + instance = new ModelManager(monaco); }); afterEach(() => { diff --git a/spec/javascripts/ide/lib/common/model_spec.js b/spec/javascripts/ide/lib/common/model_spec.js index c278bf92b08..ab753a7e5e2 100644 --- a/spec/javascripts/ide/lib/common/model_spec.js +++ b/spec/javascripts/ide/lib/common/model_spec.js @@ -1,23 +1,18 @@ -/* global monaco */ +import * as monaco from 'monaco-editor'; import eventHub from '~/ide/eventhub'; -import monacoLoader from '~/ide/monaco_loader'; import Model from '~/ide/lib/common/model'; import { file } from '../../helpers'; describe('Multi-file editor library model', () => { let model; - beforeEach(done => { + beforeEach(() => { spyOn(eventHub, '$on').and.callThrough(); - monacoLoader(['vs/editor/editor.main'], () => { - const f = file('path'); - f.mrChange = { diff: 'ABC' }; - f.baseRaw = 'test'; - model = new Model(monaco, f); - - done(); - }); + const f = file('path'); + f.mrChange = { diff: 'ABC' }; + f.baseRaw = 'test'; + model = new Model(monaco, f); }); afterEach(() => { diff --git a/spec/javascripts/ide/lib/decorations/controller_spec.js b/spec/javascripts/ide/lib/decorations/controller_spec.js index e1c4ca570b6..6f50056be73 100644 --- a/spec/javascripts/ide/lib/decorations/controller_spec.js +++ b/spec/javascripts/ide/lib/decorations/controller_spec.js @@ -1,6 +1,5 @@ -/* global monaco */ -import monacoLoader from '~/ide/monaco_loader'; -import editor from '~/ide/lib/editor'; +import * as monaco from 'monaco-editor'; +import Editor from '~/ide/lib/editor'; import DecorationsController from '~/ide/lib/decorations/controller'; import Model from '~/ide/lib/common/model'; import { file } from '../../helpers'; @@ -10,16 +9,12 @@ describe('Multi-file editor library decorations controller', () => { let controller; let model; - beforeEach(done => { - monacoLoader(['vs/editor/editor.main'], () => { - editorInstance = editor.create(monaco); - editorInstance.createInstance(document.createElement('div')); + beforeEach(() => { + editorInstance = Editor.create(); + editorInstance.createInstance(document.createElement('div')); - controller = new DecorationsController(editorInstance); - model = new Model(monaco, file('path')); - - done(); - }); + controller = new DecorationsController(editorInstance); + model = new Model(monaco, file('path')); }); afterEach(() => { diff --git a/spec/javascripts/ide/lib/diff/controller_spec.js b/spec/javascripts/ide/lib/diff/controller_spec.js index fd8ab3b4f1d..2438fb22036 100644 --- a/spec/javascripts/ide/lib/diff/controller_spec.js +++ b/spec/javascripts/ide/lib/diff/controller_spec.js @@ -1,6 +1,5 @@ -/* global monaco */ -import monacoLoader from '~/ide/monaco_loader'; -import editor from '~/ide/lib/editor'; +import * as monaco from 'monaco-editor'; +import Editor from '~/ide/lib/editor'; import ModelManager from '~/ide/lib/common/model_manager'; import DecorationsController from '~/ide/lib/decorations/controller'; import DirtyDiffController, { getDiffChangeType, getDecorator } from '~/ide/lib/diff/controller'; @@ -14,20 +13,16 @@ describe('Multi-file editor library dirty diff controller', () => { let decorationsController; let model; - beforeEach(done => { - monacoLoader(['vs/editor/editor.main'], () => { - editorInstance = editor.create(monaco); - editorInstance.createInstance(document.createElement('div')); + beforeEach(() => { + editorInstance = Editor.create(); + editorInstance.createInstance(document.createElement('div')); - modelManager = new ModelManager(monaco); - decorationsController = new DecorationsController(editorInstance); + modelManager = new ModelManager(monaco); + decorationsController = new DecorationsController(editorInstance); - model = modelManager.addModel(file('path')); + model = modelManager.addModel(file('path')); - controller = new DirtyDiffController(modelManager, decorationsController); - - done(); - }); + controller = new DirtyDiffController(modelManager, decorationsController); }); afterEach(() => { diff --git a/spec/javascripts/ide/lib/editor_spec.js b/spec/javascripts/ide/lib/editor_spec.js index b88a12264ca..cf867d021e6 100644 --- a/spec/javascripts/ide/lib/editor_spec.js +++ b/spec/javascripts/ide/lib/editor_spec.js @@ -1,6 +1,4 @@ -/* global monaco */ -import monacoLoader from '~/ide/monaco_loader'; -import editor from '~/ide/lib/editor'; +import Editor from '~/ide/lib/editor'; import { file } from '../helpers'; describe('Multi-file editor library', () => { @@ -8,18 +6,14 @@ describe('Multi-file editor library', () => { let el; let holder; - beforeEach(done => { + beforeEach(() => { el = document.createElement('div'); holder = document.createElement('div'); el.appendChild(holder); document.body.appendChild(el); - monacoLoader(['vs/editor/editor.main'], () => { - instance = editor.create(monaco); - - done(); - }); + instance = Editor.create(); }); afterEach(() => { @@ -29,11 +23,11 @@ describe('Multi-file editor library', () => { }); it('creates instance of editor', () => { - expect(editor.editorInstance).not.toBeNull(); + expect(Editor.editorInstance).not.toBeNull(); }); it('creates instance returns cached instance', () => { - expect(editor.create(monaco)).toEqual(instance); + expect(Editor.create()).toEqual(instance); }); describe('createInstance', () => { diff --git a/spec/javascripts/ide/monaco_loader_spec.js b/spec/javascripts/ide/monaco_loader_spec.js deleted file mode 100644 index 7ab315aa8c8..00000000000 --- a/spec/javascripts/ide/monaco_loader_spec.js +++ /dev/null @@ -1,15 +0,0 @@ -import monacoContext from 'monaco-editor/dev/vs/loader'; -import monacoLoader from '~/ide/monaco_loader'; - -describe('MonacoLoader', () => { - it('calls require.config and exports require', () => { - expect(monacoContext.require.getConfig()).toEqual( - jasmine.objectContaining({ - paths: { - vs: `${__webpack_public_path__}monaco-editor/vs`, // eslint-disable-line camelcase - }, - }), - ); - expect(monacoLoader).toBe(monacoContext.require); - }); -}); -- cgit v1.2.1 From 15993df1d6849bd487855cf4926e2e01e44e54df Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 7 Jun 2018 23:53:45 -0500 Subject: remove need to pass monaco around through DI --- spec/javascripts/ide/lib/common/model_manager_spec.js | 3 +-- spec/javascripts/ide/lib/common/model_spec.js | 5 ++--- spec/javascripts/ide/lib/decorations/controller_spec.js | 3 +-- spec/javascripts/ide/lib/diff/controller_spec.js | 6 +++--- 4 files changed, 7 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/lib/common/model_manager_spec.js b/spec/javascripts/ide/lib/common/model_manager_spec.js index e3886f06f5a..38ffa317e8e 100644 --- a/spec/javascripts/ide/lib/common/model_manager_spec.js +++ b/spec/javascripts/ide/lib/common/model_manager_spec.js @@ -1,4 +1,3 @@ -import * as monaco from 'monaco-editor'; import eventHub from '~/ide/eventhub'; import ModelManager from '~/ide/lib/common/model_manager'; import { file } from '../../helpers'; @@ -7,7 +6,7 @@ describe('Multi-file editor library model manager', () => { let instance; beforeEach(() => { - instance = new ModelManager(monaco); + instance = new ModelManager(); }); afterEach(() => { diff --git a/spec/javascripts/ide/lib/common/model_spec.js b/spec/javascripts/ide/lib/common/model_spec.js index ab753a7e5e2..f096e06f43c 100644 --- a/spec/javascripts/ide/lib/common/model_spec.js +++ b/spec/javascripts/ide/lib/common/model_spec.js @@ -1,4 +1,3 @@ -import * as monaco from 'monaco-editor'; import eventHub from '~/ide/eventhub'; import Model from '~/ide/lib/common/model'; import { file } from '../../helpers'; @@ -12,7 +11,7 @@ describe('Multi-file editor library model', () => { const f = file('path'); f.mrChange = { diff: 'ABC' }; f.baseRaw = 'test'; - model = new Model(monaco, f); + model = new Model(f); }); afterEach(() => { @@ -33,7 +32,7 @@ describe('Multi-file editor library model', () => { const f = file('path'); model.dispose(); - model = new Model(monaco, f, { + model = new Model(f, { ...f, content: '123 testing', }); diff --git a/spec/javascripts/ide/lib/decorations/controller_spec.js b/spec/javascripts/ide/lib/decorations/controller_spec.js index 6f50056be73..a112361e0d1 100644 --- a/spec/javascripts/ide/lib/decorations/controller_spec.js +++ b/spec/javascripts/ide/lib/decorations/controller_spec.js @@ -1,4 +1,3 @@ -import * as monaco from 'monaco-editor'; import Editor from '~/ide/lib/editor'; import DecorationsController from '~/ide/lib/decorations/controller'; import Model from '~/ide/lib/common/model'; @@ -14,7 +13,7 @@ describe('Multi-file editor library decorations controller', () => { editorInstance.createInstance(document.createElement('div')); controller = new DecorationsController(editorInstance); - model = new Model(monaco, file('path')); + model = new Model(file('path')); }); afterEach(() => { diff --git a/spec/javascripts/ide/lib/diff/controller_spec.js b/spec/javascripts/ide/lib/diff/controller_spec.js index 2438fb22036..96abd1dcd9e 100644 --- a/spec/javascripts/ide/lib/diff/controller_spec.js +++ b/spec/javascripts/ide/lib/diff/controller_spec.js @@ -1,4 +1,4 @@ -import * as monaco from 'monaco-editor'; +import { Range } from 'monaco-editor'; import Editor from '~/ide/lib/editor'; import ModelManager from '~/ide/lib/common/model_manager'; import DecorationsController from '~/ide/lib/decorations/controller'; @@ -17,7 +17,7 @@ describe('Multi-file editor library dirty diff controller', () => { editorInstance = Editor.create(); editorInstance.createInstance(document.createElement('div')); - modelManager = new ModelManager(monaco); + modelManager = new ModelManager(); decorationsController = new DecorationsController(editorInstance); model = modelManager.addModel(file('path')); @@ -165,7 +165,7 @@ describe('Multi-file editor library dirty diff controller', () => { [], [ { - range: new monaco.Range(1, 1, 1, 1), + range: new Range(1, 1, 1, 1), options: { isWholeLine: true, linesDecorationsClassName: 'dirty-diff dirty-diff-modified', -- cgit v1.2.1 From 4653820d37f89c2fabe74800ccce2d1f8420a7da Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 8 Jun 2018 00:09:59 -0500 Subject: refactor monaco-editor import and stop storing as class property within editor --- spec/javascripts/ide/lib/editor_spec.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/lib/editor_spec.js b/spec/javascripts/ide/lib/editor_spec.js index cf867d021e6..c1932284d53 100644 --- a/spec/javascripts/ide/lib/editor_spec.js +++ b/spec/javascripts/ide/lib/editor_spec.js @@ -1,3 +1,4 @@ +import { editor as monacoEditor } from 'monaco-editor'; import Editor from '~/ide/lib/editor'; import { file } from '../helpers'; @@ -32,11 +33,11 @@ describe('Multi-file editor library', () => { describe('createInstance', () => { it('creates editor instance', () => { - spyOn(instance.monaco.editor, 'create').and.callThrough(); + spyOn(monacoEditor, 'create').and.callThrough(); instance.createInstance(holder); - expect(instance.monaco.editor.create).toHaveBeenCalled(); + expect(monacoEditor.create).toHaveBeenCalled(); }); it('creates dirty diff controller', () => { @@ -54,11 +55,11 @@ describe('Multi-file editor library', () => { describe('createDiffInstance', () => { it('creates editor instance', () => { - spyOn(instance.monaco.editor, 'createDiffEditor').and.callThrough(); + spyOn(monacoEditor, 'createDiffEditor').and.callThrough(); instance.createDiffInstance(holder); - expect(instance.monaco.editor.createDiffEditor).toHaveBeenCalledWith(holder, { + expect(monacoEditor.createDiffEditor).toHaveBeenCalledWith(holder, { model: null, contextmenu: true, minimap: { -- cgit v1.2.1 From a904314941d42c41cab7760a154a1fcb3585dc27 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Fri, 8 Jun 2018 12:03:21 +0300 Subject: Use nip.io instead of xip.io for jupyter domain suggestion Signed-off-by: Dmitriy Zaporozhets --- spec/javascripts/clusters/stores/clusters_store_spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/javascripts/clusters/stores/clusters_store_spec.js b/spec/javascripts/clusters/stores/clusters_store_spec.js index 6854b016852..9e43552f740 100644 --- a/spec/javascripts/clusters/stores/clusters_store_spec.js +++ b/spec/javascripts/clusters/stores/clusters_store_spec.js @@ -110,7 +110,7 @@ describe('Clusters Store', () => { expect( store.state.applications.jupyter.hostname, - ).toEqual(`jupyter.${store.state.applications.ingress.externalIp}.xip.io`); + ).toEqual(`jupyter.${store.state.applications.ingress.externalIp}.nip.io`); }); }); }); -- cgit v1.2.1 From f413c4dd267f3a5906bf6c5b3c4eb3b45f8ac60a Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Fri, 8 Jun 2018 11:45:36 +0100 Subject: Fix NotificationRecipientService spec for EE EE checks a license, which needs RequestStore enabled to avoid N+1 queries. However, enabling RequestStore causes Gitaly to complain about N+1 invocations, which we really don't care about here. --- spec/services/notification_recipient_service_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/services/notification_recipient_service_spec.rb b/spec/services/notification_recipient_service_spec.rb index 340d4585e0c..7f536ce4e68 100644 --- a/spec/services/notification_recipient_service_spec.rb +++ b/spec/services/notification_recipient_service_spec.rb @@ -19,8 +19,8 @@ describe NotificationRecipientService do end end - it 'avoids N+1 queries' do - create_watcher + it 'avoids N+1 queries', :request_store do + Gitlab::GitalyClient.allow_n_plus_1_calls { create_watcher } service.build_new_note_recipients(note) @@ -28,7 +28,7 @@ describe NotificationRecipientService do service.build_new_note_recipients(note) end - create_watcher + Gitlab::GitalyClient.allow_n_plus_1_calls { create_watcher } expect { service.build_new_note_recipients(note) }.not_to exceed_query_limit(control_count) end -- cgit v1.2.1 From c22e51e8c1372e844aa3c4447ebea371d77d0c89 Mon Sep 17 00:00:00 2001 From: Athar Hameed Date: Fri, 8 Jun 2018 12:28:43 +0000 Subject: Resolve "Automatically created MR uses wrong target branch (when branching from Tag)" --- .../services/merge_requests/create_from_issue_service_spec.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/services/merge_requests/create_from_issue_service_spec.rb b/spec/services/merge_requests/create_from_issue_service_spec.rb index 38d84cf0ceb..b1882df732d 100644 --- a/spec/services/merge_requests/create_from_issue_service_spec.rb +++ b/spec/services/merge_requests/create_from_issue_service_spec.rb @@ -125,9 +125,14 @@ describe MergeRequests::CreateFromIssueService do end context 'when ref branch does not exist' do - it 'does not create a merge request' do - expect { described_class.new(project, user, issue_iid: issue.iid, ref: 'nobr').execute } - .not_to change { project.merge_requests.count } + subject { described_class.new(project, user, issue_iid: issue.iid, ref: 'no-such-branch').execute } + + it 'creates a merge request' do + expect { subject }.to change(project.merge_requests, :count).by(1) + end + + it 'sets the merge request target branch to the project default branch' do + expect(subject[:merge_request].target_branch).to eq(project.default_branch) end end end -- cgit v1.2.1 From 68cb1c2651fde0ae009beed10f81a74172ceeab1 Mon Sep 17 00:00:00 2001 From: Mark Chao Date: Fri, 8 Jun 2018 13:12:51 +0000 Subject: Revert rename allow collaboration column --- spec/lib/gitlab/import_export/safe_model_attributes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml index 4354dca25ea..0a1e3eb83d3 100644 --- a/spec/lib/gitlab/import_export/safe_model_attributes.yml +++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml @@ -170,7 +170,7 @@ MergeRequest: - last_edited_by_id - head_pipeline_id - discussion_locked -- allow_collaboration +- allow_maintainer_to_push MergeRequestDiff: - id - state -- cgit v1.2.1 From e1589a5c584acae83d97d41494616be1f3981da7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mica=C3=ABl=20Bergeron?= Date: Fri, 8 Jun 2018 10:51:59 -0400 Subject: apply feedback --- spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb index ba01cfe53c5..31d323626c5 100644 --- a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb +++ b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb @@ -129,7 +129,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do describe "limits N+1 queries" do let!(:projects) { create_list(:project, 10, :with_avatar) } - it do + it "to N*#{MIGRATION_QUERIES}" do query_count = ActiveRecord::QueryRecorder.new { perform(uploads) } more_projects = create_list(:project, 100, :with_avatar) @@ -158,7 +158,7 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do describe "limits N+1 queries" do let!(:projects) { create_list(:project, 10) } - it do + it "to N*#{MIGRATION_QUERIES}" do query_count = ActiveRecord::QueryRecorder.new { perform(uploads) } more_projects = create_list(:project, 100) -- cgit v1.2.1 From 3d713ac114085e091815aa486fb96905347c3002 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Fri, 8 Jun 2018 13:20:44 +0200 Subject: Users can accept terms during registration When a user checks the `accept` checkbox, we will track that acceptance as usual. That way they don't need to accept again after they complete the registration. When an unauthenticated user visits the `/-/users/terms` page, there is no button to accept, decline or continue. The 'current-user menu' is also hidden from the top bar. --- spec/controllers/registrations_controller_spec.rb | 21 ++++ spec/features/admin/admin_settings_spec.rb | 2 +- spec/features/users/signup_spec.rb | 21 +++- spec/features/users/terms_spec.rb | 143 ++++++++++++---------- 4 files changed, 118 insertions(+), 69 deletions(-) (limited to 'spec') diff --git a/spec/controllers/registrations_controller_spec.rb b/spec/controllers/registrations_controller_spec.rb index 346944fd5b0..898f3863008 100644 --- a/spec/controllers/registrations_controller_spec.rb +++ b/spec/controllers/registrations_controller_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe RegistrationsController do + include TermsHelper + describe '#create' do let(:user_params) { { user: { name: 'new_user', username: 'new_username', email: 'new@user.com', password: 'Any_password' } } } @@ -67,6 +69,25 @@ describe RegistrationsController do expect(flash[:notice]).to include 'Welcome! You have signed up successfully.' end end + + context 'when terms are enforced' do + before do + enforce_terms + end + + it 'redirects back with a notice when the checkbox was not checked' do + post :create, user_params + + expect(flash[:alert]).to match /you must accept our terms/i + end + + it 'creates the user with agreement when terms are accepted' do + post :create, user_params.merge(terms_opt_in: '1') + + expect(subject.current_user).to be_present + expect(subject.current_user.terms_accepted?).to be(true) + end + end end describe '#destroy' do diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index dc025d82937..e7aca94db66 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -94,7 +94,7 @@ feature 'Admin updates settings' do accept_terms(admin) page.within('.as-terms') do - check 'Require all users to accept Terms of Service when they access GitLab.' + check 'Require all users to accept Terms of Service and Privacy Policy when they access GitLab.' fill_in 'Terms of Service Agreement', with: 'Be nice!' click_button 'Save changes' end diff --git a/spec/features/users/signup_spec.rb b/spec/features/users/signup_spec.rb index b5bd5c505f2..b51ca5d130b 100644 --- a/spec/features/users/signup_spec.rb +++ b/spec/features/users/signup_spec.rb @@ -140,7 +140,7 @@ describe 'Signup' do enforce_terms end - it 'asks the user to accept terms before going to the dashboard' do + it 'requires the user to check the checkbox' do visit root_path fill_in 'new_user_name', with: new_user.name @@ -148,11 +148,24 @@ describe 'Signup' do fill_in 'new_user_email', with: new_user.email fill_in 'new_user_email_confirmation', with: new_user.email fill_in 'new_user_password', with: new_user.password - click_button "Register" - expect_to_be_on_terms_page + click_button 'Register' + + expect(current_path).to eq new_user_session_path + expect(page).to have_content(/you must accept our terms of service/i) + end + + it 'asks the user to accept terms before going to the dashboard' do + visit root_path + + fill_in 'new_user_name', with: new_user.name + fill_in 'new_user_username', with: new_user.username + fill_in 'new_user_email', with: new_user.email + fill_in 'new_user_email_confirmation', with: new_user.email + fill_in 'new_user_password', with: new_user.password + check :terms_opt_in - click_button 'Accept terms' + click_button "Register" expect(current_path).to eq dashboard_projects_path end diff --git a/spec/features/users/terms_spec.rb b/spec/features/users/terms_spec.rb index af407c52917..5b2e7605c4d 100644 --- a/spec/features/users/terms_spec.rb +++ b/spec/features/users/terms_spec.rb @@ -3,12 +3,10 @@ require 'spec_helper' describe 'Users > Terms' do include TermsHelper - let(:user) { create(:user) } let!(:term) { create(:term, terms: 'By accepting, you promise to be nice!') } before do stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') - sign_in(user) end it 'shows the terms' do @@ -17,102 +15,119 @@ describe 'Users > Terms' do expect(page).to have_content('By accepting, you promise to be nice!') end - context 'declining the terms' do - it 'returns the user to the app' do - visit terms_path + it 'does not show buttons to accept, decline or sign out', :aggregate_failures do + visit terms_path + + expect(page).not_to have_css('.footer-block') + expect(page).not_to have_content('Accept terms') + expect(page).not_to have_content('Decline and sign out') + expect(page).not_to have_content('Continue') + end - click_button 'Decline and sign out' + context 'when signed in' do + let(:user) { create(:user) } - expect(page).not_to have_content(term.terms) - expect(user.reload.terms_accepted?).to be(false) + before do + sign_in(user) end - end - context 'accepting the terms' do - it 'returns the user to the app' do - visit terms_path + context 'declining the terms' do + it 'returns the user to the app' do + visit terms_path - click_button 'Accept terms' + click_button 'Decline and sign out' - expect(page).not_to have_content(term.terms) - expect(user.reload.terms_accepted?).to be(true) + expect(page).not_to have_content(term.terms) + expect(user.reload.terms_accepted?).to be(false) + end end - end - context 'when the user has already accepted the terms' do - before do - accept_terms(user) + context 'accepting the terms' do + it 'returns the user to the app' do + visit terms_path + + click_button 'Accept terms' + + expect(page).not_to have_content(term.terms) + expect(user.reload.terms_accepted?).to be(true) + end end - it 'allows the user to continue to the app' do - visit terms_path + context 'when the user has already accepted the terms' do + before do + accept_terms(user) + end + + it 'allows the user to continue to the app' do + visit terms_path - expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}" + expect(page).to have_content "You have already accepted the Terms of Service as #{user.to_reference}" - click_link 'Continue' + click_link 'Continue' - expect(current_path).to eq(root_path) + expect(current_path).to eq(root_path) + end end - end - context 'terms were enforced while session is active', :js do - let(:project) { create(:project) } + context 'terms were enforced while session is active', :js do + let(:project) { create(:project) } - before do - project.add_developer(user) - end + before do + project.add_developer(user) + end - it 'redirects to terms and back to where the user was going' do - visit project_path(project) + it 'redirects to terms and back to where the user was going' do + visit project_path(project) - enforce_terms + enforce_terms - within('.nav-sidebar') do - click_link 'Issues' - end + within('.nav-sidebar') do + click_link 'Issues' + end - expect_to_be_on_terms_page + expect_to_be_on_terms_page - click_button('Accept terms') + click_button('Accept terms') - expect(current_path).to eq(project_issues_path(project)) - end + expect(current_path).to eq(project_issues_path(project)) + end - # Disabled until https://gitlab.com/gitlab-org/gitlab-ce/issues/37162 is solved properly - xit 'redirects back to the page the user was trying to save' do - visit new_project_issue_path(project) + # Disabled until https://gitlab.com/gitlab-org/gitlab-ce/issues/37162 is solved properly + xit 'redirects back to the page the user was trying to save' do + visit new_project_issue_path(project) - fill_in :issue_title, with: 'Hello world, a new issue' - fill_in :issue_description, with: "We don't want to lose what the user typed" + fill_in :issue_title, with: 'Hello world, a new issue' + fill_in :issue_description, with: "We don't want to lose what the user typed" - enforce_terms + enforce_terms - click_button 'Submit issue' + click_button 'Submit issue' - expect(current_path).to eq(terms_path) + expect(current_path).to eq(terms_path) - click_button('Accept terms') + click_button('Accept terms') - expect(current_path).to eq(new_project_issue_path(project)) - expect(find_field('issue_title').value).to eq('Hello world, a new issue') - expect(find_field('issue_description').value).to eq("We don't want to lose what the user typed") + expect(current_path).to eq(new_project_issue_path(project)) + expect(find_field('issue_title').value).to eq('Hello world, a new issue') + expect(find_field('issue_description').value).to eq("We don't want to lose what the user typed") + end end - end - context 'when the terms are enforced' do - before do - enforce_terms - end + context 'when the terms are enforced' do + before do + enforce_terms + end - context 'signing out', :js do - it 'allows the user to sign out without a response' do - visit terms_path + context 'signing out', :js do + it 'allows the user to sign out without a response' do + visit terms_path - find('.header-user-dropdown-toggle').click - click_link('Sign out') + find('.header-user-dropdown-toggle').click + click_link('Sign out') - expect(page).to have_content('Sign in') - expect(page).to have_content('Register') + expect(page).to have_content('Sign in') + expect(page).to have_content('Register') + end end end end -- cgit v1.2.1 From 7fcfe7ccab12e69d7f1d0130614c3dfa374f05d3 Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Sat, 9 Jun 2018 22:58:28 +0200 Subject: Fix conversion of integer into string in board spec In rails 5 controller specs, integers are converted to strings unless conte-type is set with `as: :json`: https://github.com/rails/rails/issues/26069 --- spec/controllers/boards/lists_controller_spec.rb | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/controllers/boards/lists_controller_spec.rb b/spec/controllers/boards/lists_controller_spec.rb index 71d45a22d91..57ccbf1d6b5 100644 --- a/spec/controllers/boards/lists_controller_spec.rb +++ b/spec/controllers/boards/lists_controller_spec.rb @@ -156,12 +156,18 @@ describe Boards::ListsController do def move(user:, board:, list:, position:) sign_in(user) - patch :update, namespace_id: project.namespace.to_param, - project_id: project, - board_id: board.to_param, - id: list.to_param, - list: { position: position }, - format: :json + params = { namespace_id: project.namespace.to_param, + project_id: project, + board_id: board.to_param, + id: list.to_param, + list: { position: position }, + format: :json } + + if Gitlab.rails5? + patch :update, params: params, as: :json + else + patch :update, params + end end end -- cgit v1.2.1 From 88808a1fd4f1b8ebfa90bf5a85cf618065140aa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20K=C3=A4mmerle?= Date: Mon, 11 Jun 2018 09:21:04 +0200 Subject: Replace ... with ellipsis in placeholders --- spec/javascripts/notes/components/comment_form_spec.js | 2 +- spec/javascripts/notes/components/note_app_spec.js | 4 ++-- spec/javascripts/notes/components/note_form_spec.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/notes/components/comment_form_spec.js b/spec/javascripts/notes/components/comment_form_spec.js index 224debbeff6..a7d1e4331eb 100644 --- a/spec/javascripts/notes/components/comment_form_spec.js +++ b/spec/javascripts/notes/components/comment_form_spec.js @@ -84,7 +84,7 @@ describe('issue_comment_form component', () => { it('should render textarea with placeholder', () => { expect( vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); it('should make textarea disabled while requesting', (done) => { diff --git a/spec/javascripts/notes/components/note_app_spec.js b/spec/javascripts/notes/components/note_app_spec.js index 0e792eee5e9..d494c63ff11 100644 --- a/spec/javascripts/notes/components/note_app_spec.js +++ b/spec/javascripts/notes/components/note_app_spec.js @@ -106,7 +106,7 @@ describe('note_app', () => { expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM'); expect( vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); it('should render form comment button as disabled', () => { @@ -129,7 +129,7 @@ describe('note_app', () => { expect(vm.$el.querySelector('.js-main-target-form').tagName).toEqual('FORM'); expect( vm.$el.querySelector('.js-main-target-form textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); }); diff --git a/spec/javascripts/notes/components/note_form_spec.js b/spec/javascripts/notes/components/note_form_spec.js index f841a408d09..413d4f69434 100644 --- a/spec/javascripts/notes/components/note_form_spec.js +++ b/spec/javascripts/notes/components/note_form_spec.js @@ -49,7 +49,7 @@ describe('issue_note_form component', () => { it('should render text area with placeholder', () => { expect( vm.$el.querySelector('textarea').getAttribute('placeholder'), - ).toEqual('Write a comment or drag your files here...'); + ).toEqual('Write a comment or drag your files here…'); }); it('should link to markdown docs', () => { -- cgit v1.2.1 From 927d2459cd6f36a314f6201db99610044ecd2fad Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Mon, 11 Jun 2018 13:06:29 +0300 Subject: Rename MrWidgetAuthorTime vue component --- .../vue_mr_widget/components/mr_widget_author_time_spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js index 6784b498c29..ef9def03db7 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js @@ -1,12 +1,12 @@ import Vue from 'vue'; -import authorTimeComponent from '~/vue_merge_request_widget/components/mr_widget_author_time.vue'; +import MrWidgetAuthorTime from '~/vue_merge_request_widget/components/mr_widget_author_time.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; -describe('MRWidgetAuthorTime', () => { +describe('MrWidgetAuthorTime', () => { let vm; beforeEach(() => { - const Component = Vue.extend(authorTimeComponent); + const Component = Vue.extend(MrWidgetAuthorTime); vm = mountComponent(Component, { actionText: 'Merged by', -- cgit v1.2.1 From ea8dc107729c06bbc15bfba21dd249611c376a19 Mon Sep 17 00:00:00 2001 From: "Jacob Vosmaer (GitLab)" Date: Mon, 11 Jun 2018 10:42:09 +0000 Subject: Don't use Gitlab::Utils.nlbr in Gitlab::Git --- spec/features/tags/master_deletes_tag_spec.rb | 4 ++-- spec/lib/gitlab/git/hook_spec.rb | 25 ++++++++++++++-------- spec/lib/gitlab/git/hooks_service_spec.rb | 8 +++---- spec/lib/gitlab/git/pre_receive_error_spec.rb | 9 ++++++++ .../gitlab/gitaly_client/operation_service_spec.rb | 4 ++-- spec/models/repository_spec.rb | 10 ++++----- .../merge_requests/ff_merge_service_spec.rb | 2 +- spec/services/merge_requests/merge_service_spec.rb | 2 +- spec/services/tags/create_service_spec.rb | 2 +- 9 files changed, 41 insertions(+), 25 deletions(-) create mode 100644 spec/lib/gitlab/git/pre_receive_error_spec.rb (limited to 'spec') diff --git a/spec/features/tags/master_deletes_tag_spec.rb b/spec/features/tags/master_deletes_tag_spec.rb index c0b4fa52526..9981bfa4609 100644 --- a/spec/features/tags/master_deletes_tag_spec.rb +++ b/spec/features/tags/master_deletes_tag_spec.rb @@ -38,7 +38,7 @@ feature 'Master deletes tag' do context 'when Gitaly operation_user_delete_tag feature is enabled' do before do allow_any_instance_of(Gitlab::GitalyClient::OperationService).to receive(:rm_tag) - .and_raise(Gitlab::Git::HooksService::PreReceiveError, 'Do not delete tags') + .and_raise(Gitlab::Git::PreReceiveError, 'Do not delete tags') end scenario 'shows the error message' do @@ -51,7 +51,7 @@ feature 'Master deletes tag' do context 'when Gitaly operation_user_delete_tag feature is disabled', :skip_gitaly_mock do before do allow_any_instance_of(Gitlab::Git::HooksService).to receive(:execute) - .and_raise(Gitlab::Git::HooksService::PreReceiveError, 'Do not delete tags') + .and_raise(Gitlab::Git::PreReceiveError, 'Do not delete tags') end scenario 'shows the error message' do diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb index 2fe1f5603ce..d9b3d0cf419 100644 --- a/spec/lib/gitlab/git/hook_spec.rb +++ b/spec/lib/gitlab/git/hook_spec.rb @@ -9,24 +9,31 @@ describe Gitlab::Git::Hook do end describe "#trigger" do - let(:project) { create(:project, :repository) } + set(:project) { create(:project, :repository) } let(:repository) { project.repository.raw_repository } let(:repo_path) { repository.path } + let(:hooks_dir) { File.join(repo_path, 'hooks') } let(:user) { create(:user) } let(:gl_id) { Gitlab::GlId.gl_id(user) } let(:gl_username) { user.username } def create_hook(name) - FileUtils.mkdir_p(File.join(repo_path, 'hooks')) - File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f| - f.write('exit 0') + FileUtils.mkdir_p(hooks_dir) + hook_path = File.join(hooks_dir, name) + File.open(hook_path, 'w', 0755) do |f| + f.write(<<~HOOK) + #!/bin/sh + exit 0 + HOOK end end def create_failing_hook(name) - FileUtils.mkdir_p(File.join(repo_path, 'hooks')) - File.open(File.join(repo_path, 'hooks', name), 'w', 0755) do |f| - f.write(<<-HOOK) + FileUtils.mkdir_p(hooks_dir) + hook_path = File.join(hooks_dir, name) + File.open(hook_path, 'w', 0755) do |f| + f.write(<<~HOOK) + #!/bin/sh echo 'regular message from the hook' echo 'error message from the hook' 1>&2 echo 'error message from the hook line 2' 1>&2 @@ -38,7 +45,7 @@ describe Gitlab::Git::Hook do ['pre-receive', 'post-receive', 'update'].each do |hook_name| context "when triggering a #{hook_name} hook" do context "when the hook is successful" do - let(:hook_path) { File.join(repo_path, 'hooks', hook_name) } + let(:hook_path) { File.join(hooks_dir, hook_name) } let(:gl_repository) { Gitlab::GlRepository.gl_repository(project, false) } let(:env) do { @@ -76,7 +83,7 @@ describe Gitlab::Git::Hook do status, errors = hook.trigger(gl_id, gl_username, blank, blank, ref) expect(status).to be false - expect(errors).to eq("error message from the hook
error message from the hook line 2
") + expect(errors).to eq("error message from the hook\nerror message from the hook line 2\n") end end end diff --git a/spec/lib/gitlab/git/hooks_service_spec.rb b/spec/lib/gitlab/git/hooks_service_spec.rb index 3ed3feb4c74..9337aa39e13 100644 --- a/spec/lib/gitlab/git/hooks_service_spec.rb +++ b/spec/lib/gitlab/git/hooks_service_spec.rb @@ -26,24 +26,24 @@ describe Gitlab::Git::HooksService, seed_helper: true do context 'when pre-receive hook failed' do it 'does not call post-receive hook' do - expect(service).to receive(:run_hook).with('pre-receive').and_return([false, '']) + expect(service).to receive(:run_hook).with('pre-receive').and_return([false, 'hello world']) expect(service).not_to receive(:run_hook).with('post-receive') expect do service.execute(user, repository, blankrev, newrev, ref) - end.to raise_error(Gitlab::Git::HooksService::PreReceiveError) + end.to raise_error(Gitlab::Git::PreReceiveError, 'hello world') end end context 'when update hook failed' do it 'does not call post-receive hook' do expect(service).to receive(:run_hook).with('pre-receive').and_return([true, nil]) - expect(service).to receive(:run_hook).with('update').and_return([false, '']) + expect(service).to receive(:run_hook).with('update').and_return([false, 'hello world']) expect(service).not_to receive(:run_hook).with('post-receive') expect do service.execute(user, repository, blankrev, newrev, ref) - end.to raise_error(Gitlab::Git::HooksService::PreReceiveError) + end.to raise_error(Gitlab::Git::PreReceiveError, 'hello world') end end end diff --git a/spec/lib/gitlab/git/pre_receive_error_spec.rb b/spec/lib/gitlab/git/pre_receive_error_spec.rb new file mode 100644 index 00000000000..1b8be62dec6 --- /dev/null +++ b/spec/lib/gitlab/git/pre_receive_error_spec.rb @@ -0,0 +1,9 @@ +require 'spec_helper' + +describe Gitlab::Git::PreReceiveError do + it 'makes its message HTML-friendly' do + ex = described_class.new("hello\nworld\n") + + expect(ex.message).to eq('hello
world
') + end +end diff --git a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb index 9fbdd73ee0e..9709f1f5646 100644 --- a/spec/lib/gitlab/gitaly_client/operation_service_spec.rb +++ b/spec/lib/gitlab/gitaly_client/operation_service_spec.rb @@ -48,7 +48,7 @@ describe Gitlab::GitalyClient::OperationService do .and_return(response) expect { subject }.to raise_error( - Gitlab::Git::HooksService::PreReceiveError, "something failed") + Gitlab::Git::PreReceiveError, "something failed") end end end @@ -85,7 +85,7 @@ describe Gitlab::GitalyClient::OperationService do .and_return(response) expect { subject }.to raise_error( - Gitlab::Git::HooksService::PreReceiveError, "something failed") + Gitlab::Git::PreReceiveError, "something failed") end end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index 7c0a1cd967c..b6df048d4ca 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -1195,7 +1195,7 @@ describe Repository do Gitlab::Git::OperationService.new(git_user, repository.raw_repository).with_branch('feature') do new_rev end - end.to raise_error(Gitlab::Git::HooksService::PreReceiveError) + end.to raise_error(Gitlab::Git::PreReceiveError) end end @@ -1938,13 +1938,13 @@ describe Repository do context 'when pre hooks failed' do before do allow_any_instance_of(Gitlab::GitalyClient::OperationService) - .to receive(:user_delete_branch).and_raise(Gitlab::Git::HooksService::PreReceiveError) + .to receive(:user_delete_branch).and_raise(Gitlab::Git::PreReceiveError) end it 'gets an error and does not delete the branch' do expect do repository.rm_branch(user, 'feature') - end.to raise_error(Gitlab::Git::HooksService::PreReceiveError) + end.to raise_error(Gitlab::Git::PreReceiveError) expect(repository.find_branch('feature')).not_to be_nil end @@ -1980,7 +1980,7 @@ describe Repository do expect do repository.rm_branch(user, 'feature') - end.to raise_error(Gitlab::Git::HooksService::PreReceiveError) + end.to raise_error(Gitlab::Git::PreReceiveError) end it 'does not delete the branch' do @@ -1988,7 +1988,7 @@ describe Repository do expect do repository.rm_branch(user, 'feature') - end.to raise_error(Gitlab::Git::HooksService::PreReceiveError) + end.to raise_error(Gitlab::Git::PreReceiveError) expect(repository.find_branch('feature')).not_to be_nil end end diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb index 5ef6365fcc9..28f56d19657 100644 --- a/spec/services/merge_requests/ff_merge_service_spec.rb +++ b/spec/services/merge_requests/ff_merge_service_spec.rb @@ -72,7 +72,7 @@ describe MergeRequests::FfMergeService do it 'logs and saves error if there is an PreReceiveError exception' do error_message = 'error message' - allow(service).to receive(:repository).and_raise(Gitlab::Git::HooksService::PreReceiveError, error_message) + allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, error_message) allow(service).to receive(:execute_hooks) service.execute(merge_request) diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb index dc30a9bccc1..ef2738ef504 100644 --- a/spec/services/merge_requests/merge_service_spec.rb +++ b/spec/services/merge_requests/merge_service_spec.rb @@ -226,7 +226,7 @@ describe MergeRequests::MergeService do it 'logs and saves error if there is an PreReceiveError exception' do error_message = 'error message' - allow(service).to receive(:repository).and_raise(Gitlab::Git::HooksService::PreReceiveError, error_message) + allow(service).to receive(:repository).and_raise(Gitlab::Git::PreReceiveError, error_message) allow(service).to receive(:execute_hooks) service.execute(merge_request) diff --git a/spec/services/tags/create_service_spec.rb b/spec/services/tags/create_service_spec.rb index e7e9080b6b0..0cbe57352be 100644 --- a/spec/services/tags/create_service_spec.rb +++ b/spec/services/tags/create_service_spec.rb @@ -41,7 +41,7 @@ describe Tags::CreateService do it 'returns an error' do expect(repository).to receive(:add_tag) .with(user, 'v1.1.0', 'master', 'Foo') - .and_raise(Gitlab::Git::HooksService::PreReceiveError, 'something went wrong') + .and_raise(Gitlab::Git::PreReceiveError, 'something went wrong') response = service.execute('v1.1.0', 'master', 'Foo') -- cgit v1.2.1 From 7469b58eafb2658542211479cd2e615203f94248 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 11 Jun 2018 11:42:47 +0100 Subject: Fix IDE pipelines eTagPoll not stopping Closes #47678 --- spec/javascripts/ide/components/pipelines/list_spec.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/components/pipelines/list_spec.js b/spec/javascripts/ide/components/pipelines/list_spec.js index 2bb5aa08c3b..68487733cb9 100644 --- a/spec/javascripts/ide/components/pipelines/list_spec.js +++ b/spec/javascripts/ide/components/pipelines/list_spec.js @@ -45,12 +45,15 @@ describe('IDE pipelines list', () => { setTimeout(done); }); - afterEach(() => { - vm.$store.dispatch('pipelines/stopPipelinePolling'); - vm.$store.dispatch('pipelines/clearEtagPoll'); - + afterEach(done => { vm.$destroy(); mock.restore(); + + vm.$store + .dispatch('pipelines/stopPipelinePolling') + .then(() => vm.$store.dispatch('pipelines/clearEtagPoll')) + .then(done) + .catch(done.fail); }); it('renders pipeline data', () => { -- cgit v1.2.1 From d5dae8e59a4097cb5f5be7405c793333683a2317 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Mon, 11 Jun 2018 12:08:30 +0100 Subject: fixed specs --- .../stores/modules/merge_requests/actions_spec.js | 47 +++++++++++++--------- 1 file changed, 29 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js index d178a44b76a..03ec08d05c3 100644 --- a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js @@ -199,28 +199,39 @@ describe('IDE merge requests actions', () => { }); it('commits reset mutations and actions', done => { - testAction( - openMergeRequest, - { projectPath: 'gitlab-org/gitlab-ce', id: '1' }, - mockedState, - [ - { type: 'CLEAR_PROJECTS' }, - { type: 'SET_CURRENT_MERGE_REQUEST', payload: '1' }, - { type: 'RESET_OPEN_FILES' }, - ], - [ - { type: 'pipelines/stopPipelinePolling' }, - { type: 'pipelines/clearEtagPoll' }, - { type: 'pipelines/resetLatestPipeline' }, - { type: 'setCurrentBranchId', payload: '' }, - ], - done, - ); + const commit = jasmine.createSpy(); + const dispatch = jasmine.createSpy().and.returnValue(Promise.resolve()); + openMergeRequest({ commit, dispatch }, { projectPath: 'gitlab-org/gitlab-ce', id: '1' }); + + setTimeout(() => { + expect(commit.calls.argsFor(0)).toEqual(['CLEAR_PROJECTS', null, { root: true }]); + expect(commit.calls.argsFor(1)).toEqual(['SET_CURRENT_MERGE_REQUEST', '1', { root: true }]); + expect(commit.calls.argsFor(2)).toEqual(['RESET_OPEN_FILES', null, { root: true }]); + + expect(dispatch.calls.argsFor(0)).toEqual([ + 'pipelines/resetLatestPipeline', + null, + { root: true }, + ]); + expect(dispatch.calls.argsFor(1)).toEqual(['setCurrentBranchId', '', { root: true }]); + expect(dispatch.calls.argsFor(2)).toEqual([ + 'pipelines/stopPipelinePolling', + null, + { root: true }, + ]); + expect(dispatch.calls.argsFor(3)).toEqual([ + 'pipelines/clearEtagPoll', + null, + { root: true }, + ]); + + done(); + }); }); it('pushes new route', () => { openMergeRequest( - { commit() {}, dispatch() {} }, + { commit() {}, dispatch: () => Promise.resolve() }, { projectPath: 'gitlab-org/gitlab-ce', id: '1' }, ); -- cgit v1.2.1 From d5e910710760cf8c189b3fc9629ff0874c1ee335 Mon Sep 17 00:00:00 2001 From: George Tsiolis Date: Mon, 11 Jun 2018 14:14:51 +0300 Subject: Update MrWidgetAuthorTime and MRWidgetMerged spec --- spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js | 2 +- .../vue_mr_widget/components/states/mr_widget_merged_spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js index ef9def03db7..10143402acf 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_author_time_spec.js @@ -34,7 +34,7 @@ describe('MrWidgetAuthorTime', () => { }); it('renders provided time', () => { - expect(vm.$el.querySelector('time').getAttribute('title')).toEqual('2017-03-23T23:02:00.807Z'); + expect(vm.$el.querySelector('time').getAttribute('data-original-title')).toEqual('2017-03-23T23:02:00.807Z'); expect(vm.$el.querySelector('time').textContent.trim()).toEqual('12 hours ago'); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js index adeea03481f..3e2fd71b5b8 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js @@ -186,7 +186,7 @@ describe('MRWidgetMerged', () => { it('should use mergedEvent mergedAt as tooltip title', () => { expect( - vm.$el.querySelector('time').getAttribute('title'), + vm.$el.querySelector('time').getAttribute('data-original-title'), ).toBe('Jan 24, 2018 1:02pm GMT+0000'); }); }); -- cgit v1.2.1 From 0f90c1fd730663fea30bd4d6368adbfbe752e001 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 11 Jun 2018 13:54:25 +0200 Subject: Don't use Rails.root.join for upload fixture paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/controllers/uploads_controller_spec.rb | 2 +- spec/lib/gitlab/favicon_spec.rb | 2 +- spec/models/project_services/jira_service_spec.rb | 2 +- spec/uploaders/favicon_uploader_spec.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb index 3230d7b438f..1df2c954893 100644 --- a/spec/controllers/uploads_controller_spec.rb +++ b/spec/controllers/uploads_controller_spec.rb @@ -562,7 +562,7 @@ describe UploadsController do end context 'original filename or a version filename must match' do - let!(:appearance) { create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png'), 'image/png') } + let!(:appearance) { create :appearance, favicon: fixture_file_upload('spec/fixtures/dk.png', 'image/png') } context 'has a valid filename on the original file' do it 'successfully returns the file' do diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb index fdc5c0180e4..08c4a474217 100644 --- a/spec/lib/gitlab/favicon_spec.rb +++ b/spec/lib/gitlab/favicon_spec.rb @@ -18,7 +18,7 @@ RSpec.describe Gitlab::Favicon, :request_store do end it 'uses the custom favicon if a favicon appearance is present' do - create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) + create :appearance, favicon: fixture_file_upload('spec/fixtures/dk.png') expect(described_class.main).to match %r{/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.png} end end diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index c3b4eb17a5c..b9f1c7dd5df 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -475,7 +475,7 @@ describe JiraService do end it 'includes returns the custom favicon' do - create :appearance, favicon: fixture_file_upload(Rails.root.join('spec/fixtures/dk.png')) + create :appearance, favicon: fixture_file_upload('spec/fixtures/dk.png') props = described_class.new.send(:build_remote_link_props, url: 'http://example.com', title: 'title') expect(props[:object][:icon][:url16x16]).to match %r{^http://localhost/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.png$} diff --git a/spec/uploaders/favicon_uploader_spec.rb b/spec/uploaders/favicon_uploader_spec.rb index db8a3207f4d..37deea8ab90 100644 --- a/spec/uploaders/favicon_uploader_spec.rb +++ b/spec/uploaders/favicon_uploader_spec.rb @@ -10,7 +10,7 @@ RSpec.describe FaviconUploader do end def upload_fixture(filename) - fixture_file_upload(Rails.root.join('spec', 'fixtures', filename)) + fixture_file_upload("spec/fixtures/#{filename}") end context 'versions' do -- cgit v1.2.1 From 1418afc2d6e7699f08a1fc5f33b78ea847ac1451 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Mon, 11 Jun 2018 13:29:37 +0000 Subject: Avoid checking the user format in every url validation --- spec/lib/gitlab/url_blocker_spec.rb | 46 +++++++++++++++++++++--------- spec/models/project_spec.rb | 11 ++++++-- spec/models/remote_mirror_spec.rb | 7 +++++ spec/validators/url_validator_spec.rb | 53 +++++++++++++++++++++++++++++++---- 4 files changed, 96 insertions(+), 21 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb index 81dbbb962dd..6f5f9938eca 100644 --- a/spec/lib/gitlab/url_blocker_spec.rb +++ b/spec/lib/gitlab/url_blocker_spec.rb @@ -58,20 +58,6 @@ describe Gitlab::UrlBlocker do end end - it 'returns true for a non-alphanumeric username' do - stub_resolv - - aggregate_failures do - expect(described_class).to be_blocked_url('ssh://-oProxyCommand=whoami@example.com/a') - - # The leading character here is a Unicode "soft hyphen" - expect(described_class).to be_blocked_url('ssh://­oProxyCommand=whoami@example.com/a') - - # Unicode alphanumerics are allowed - expect(described_class).not_to be_blocked_url('ssh://ğitlab@example.com/a') - end - end - it 'returns true for invalid URL' do expect(described_class.blocked_url?('http://:8080')).to be true end @@ -120,6 +106,38 @@ describe Gitlab::UrlBlocker do allow(Addrinfo).to receive(:getaddrinfo).and_call_original end end + + context 'when enforce_user is' do + before do + stub_resolv + end + + context 'false (default)' do + it 'does not block urls with a non-alphanumeric username' do + expect(described_class).not_to be_blocked_url('ssh://-oProxyCommand=whoami@example.com/a') + + # The leading character here is a Unicode "soft hyphen" + expect(described_class).not_to be_blocked_url('ssh://­oProxyCommand=whoami@example.com/a') + + # Unicode alphanumerics are allowed + expect(described_class).not_to be_blocked_url('ssh://ğitlab@example.com/a') + end + end + + context 'true' do + it 'blocks urls with a non-alphanumeric username' do + aggregate_failures do + expect(described_class).to be_blocked_url('ssh://-oProxyCommand=whoami@example.com/a', enforce_user: true) + + # The leading character here is a Unicode "soft hyphen" + expect(described_class).to be_blocked_url('ssh://­oProxyCommand=whoami@example.com/a', enforce_user: true) + + # Unicode alphanumerics are allowed + expect(described_class).not_to be_blocked_url('ssh://ğitlab@example.com/a', enforce_user: true) + end + end + end + end end # Resolv does not support resolving UTF-8 domain names diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 1a6ad3edd78..b9a9c4ebf42 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -238,20 +238,27 @@ describe Project do expect(project2.import_data).to be_nil end - it "does not allow blocked import_url localhost" do + it "does not allow import_url pointing to localhost" do project2 = build(:project, import_url: 'http://localhost:9000/t.git') expect(project2).to be_invalid expect(project2.errors[:import_url].first).to include('Requests to localhost are not allowed') end - it "does not allow blocked import_url port" do + it "does not allow import_url with invalid ports" do project2 = build(:project, import_url: 'http://github.com:25/t.git') expect(project2).to be_invalid expect(project2.errors[:import_url].first).to include('Only allowed ports are 22, 80, 443') end + it "does not allow import_url with invalid user" do + project2 = build(:project, import_url: 'http://$user:password@github.com/t.git') + + expect(project2).to be_invalid + expect(project2.errors[:import_url].first).to include('Username needs to start with an alphanumeric character') + end + describe 'project pending deletion' do let!(:project_pending_deletion) do create(:project, diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb index 1d94abe4195..4c086eeadfc 100644 --- a/spec/models/remote_mirror_spec.rb +++ b/spec/models/remote_mirror_spec.rb @@ -15,6 +15,13 @@ describe RemoteMirror do expect(remote_mirror).not_to be_valid end + + it 'does not allow url with an invalid user' do + remote_mirror = build(:remote_mirror, url: 'http://$user:password@invalid.invalid') + + expect(remote_mirror).to be_invalid + expect(remote_mirror.errors[:url].first).to include('Username needs to start with an alphanumeric character') + end end end diff --git a/spec/validators/url_validator_spec.rb b/spec/validators/url_validator_spec.rb index 2d719263fc8..93fe013d11c 100644 --- a/spec/validators/url_validator_spec.rb +++ b/spec/validators/url_validator_spec.rb @@ -50,13 +50,56 @@ describe UrlValidator do end end - context 'when ports is set' do - let(:validator) { described_class.new(attributes: [:link_url], ports: [443]) } + context 'when ports is' do + let(:validator) { described_class.new(attributes: [:link_url], ports: ports) } - it 'blocks urls with a different port' do - subject + context 'empty' do + let(:ports) { [] } - expect(badge.errors.empty?).to be false + it 'does not block any port' do + subject + + expect(badge.errors.empty?).to be true + end + end + + context 'set' do + let(:ports) { [443] } + + it 'blocks urls with a different port' do + subject + + expect(badge.errors.empty?).to be false + end + end + end + + context 'when enforce_user is' do + let(:url) { 'http://$user@example.com'} + let(:validator) { described_class.new(attributes: [:link_url], enforce_user: enforce_user) } + + context 'true' do + let(:enforce_user) { true } + + it 'checks user format' do + badge.link_url = url + + subject + + expect(badge.errors.empty?).to be false + end + end + + context 'false (default)' do + let(:enforce_user) { false } + + it 'does not check user format' do + badge.link_url = url + + subject + + expect(badge.errors.empty?).to be true + end end end end -- cgit v1.2.1 From 6defeb0a7d6928ad32d4d7a2fa35d0d71dbb9dea Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Sat, 9 Jun 2018 22:35:06 -0700 Subject: Expire Wiki content cache after importing a repository The cache state for Wikis that were imported via GitHub or Bitbucket does not appear to have been flushed after a successful import. Closes #47546 --- spec/lib/gitlab/github_import/sequential_importer_spec.rb | 1 - spec/models/project_spec.rb | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/github_import/sequential_importer_spec.rb b/spec/lib/gitlab/github_import/sequential_importer_spec.rb index 6089b0b751f..05d3243f806 100644 --- a/spec/lib/gitlab/github_import/sequential_importer_spec.rb +++ b/spec/lib/gitlab/github_import/sequential_importer_spec.rb @@ -30,7 +30,6 @@ describe Gitlab::GithubImport::SequentialImporter do expect(instance).to receive(:execute) end - expect(repository).to receive(:after_import) expect(importer.execute).to eq(true) end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 1a6ad3edd78..d385d617731 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3391,10 +3391,11 @@ describe Project do end describe '#after_import' do - let(:project) { build(:project) } + let(:project) { create(:project) } it 'runs the correct hooks' do expect(project.repository).to receive(:after_import) + expect(project.wiki.repository).to receive(:after_import) expect(project).to receive(:import_finish) expect(project).to receive(:update_project_counter_caches) expect(project).to receive(:remove_import_jid) -- cgit v1.2.1 From 698515313fe38fb3f85fdeec1efa15e2c8b54cfd Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Tue, 15 May 2018 12:25:51 +0200 Subject: Fixes rejected pushes from maintainers Before the push git would make a call to `/:namespace/:project/git-receive-pack`. This would perform an access check without a ref. So the `Project#branch_allows_maintainer_push?` would return false. This adjusts `Project#branch_allows_maintainer_push?` to return true when passing no branch name if there are merge requests open that would allow the user to push. The actual check then happens when a call to `/api/v4/internal/allowed` is made from a git hook. --- spec/models/project_spec.rb | 5 +++++ spec/requests/git_http_spec.rb | 17 +++++++++++++++++ 2 files changed, 22 insertions(+) (limited to 'spec') diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index b9a9c4ebf42..58928465f95 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -3658,6 +3658,11 @@ describe Project do .to be_truthy end + it 'allows access when there are merge requests open but no branch name is given' do + expect(project.branch_allows_collaboration?(user, nil)) + .to be_truthy + end + it 'does not allow guest users access' do guest = create(:user) target_project.add_guest(guest) diff --git a/spec/requests/git_http_spec.rb b/spec/requests/git_http_spec.rb index 2514dab1714..92fcfb65269 100644 --- a/spec/requests/git_http_spec.rb +++ b/spec/requests/git_http_spec.rb @@ -1,6 +1,7 @@ require "spec_helper" describe 'Git HTTP requests' do + include ProjectForksHelper include TermsHelper include GitHttpHelpers include WorkhorseHelpers @@ -305,6 +306,22 @@ describe 'Git HTTP requests' do expect(response.body).to eq(change_access_error(:push_code)) end end + + context 'when merge requests are open that allow maintainer access' do + let(:canonical_project) { create(:project, :public, :repository) } + let(:project) { fork_project(canonical_project, nil, repository: true) } + + before do + canonical_project.add_master(user) + create(:merge_request, + source_project: project, + target_project: canonical_project, + source_branch: 'fixes', + allow_collaboration: true) + end + + it_behaves_like 'pushes are allowed' + end end end -- cgit v1.2.1 From fe8261fdb201ece94f7e89b09d999a37311f4588 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Mon, 11 Jun 2018 12:44:08 -0300 Subject: Add Gitlab::SQL:CTE for easily building CTE statements --- spec/lib/gitlab/sql/cte_spec.rb | 42 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 spec/lib/gitlab/sql/cte_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/sql/cte_spec.rb b/spec/lib/gitlab/sql/cte_spec.rb new file mode 100644 index 00000000000..d6763c7b2e1 --- /dev/null +++ b/spec/lib/gitlab/sql/cte_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Gitlab::SQL::CTE, :postgresql do + describe '#to_arel' do + it 'generates an Arel relation for the CTE body' do + relation = User.where(id: 1) + cte = described_class.new(:cte_name, relation) + sql = cte.to_arel.to_sql + name = ActiveRecord::Base.connection.quote_table_name(:cte_name) + + sql1 = ActiveRecord::Base.connection.unprepared_statement do + relation.except(:order).to_sql + end + + expect(sql).to eq("#{name} AS (#{sql1})") + end + end + + describe '#alias_to' do + it 'returns an alias for the CTE' do + cte = described_class.new(:cte_name, nil) + table = Arel::Table.new(:kittens) + + source_name = ActiveRecord::Base.connection.quote_table_name(:cte_name) + alias_name = ActiveRecord::Base.connection.quote_table_name(:kittens) + + expect(cte.alias_to(table).to_sql).to eq("#{source_name} AS #{alias_name}") + end + end + + describe '#apply_to' do + it 'applies a CTE to an ActiveRecord::Relation' do + user = create(:user) + cte = described_class.new(:cte_name, User.where(id: user.id)) + + relation = cte.apply_to(User.all) + + expect(relation.to_sql).to match(/WITH .+cte_name/) + expect(relation.to_a).to eq(User.where(id: user.id).to_a) + end + end +end -- cgit v1.2.1 From 96ce4ed25c7633330f82439f1f9347f6eef8568a Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 11 Jun 2018 09:47:51 -0700 Subject: Work around limitations of expect_any_instance_of by stubbing Project.find --- spec/models/project_spec.rb | 6 +++++- spec/workers/repository_fork_worker_spec.rb | 11 ++++++++--- spec/workers/repository_import_worker_spec.rb | 15 ++++++++++----- 3 files changed, 23 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index d385d617731..adb6ea94ac7 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1726,7 +1726,11 @@ describe Project do .with(project.repository_storage, project.disk_path, project.import_url) .and_return(true) - expect_any_instance_of(Repository).to receive(:after_import) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + expect(Project).to receive(:find).with(project.id).twice.and_return(project) + expect(project.repository).to receive(:after_import) + .and_call_original + expect(project.wiki.repository).to receive(:after_import) .and_call_original end diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb index 4b3c1736ea0..ae4786389c7 100644 --- a/spec/workers/repository_fork_worker_spec.rb +++ b/spec/workers/repository_fork_worker_spec.rb @@ -55,10 +55,15 @@ describe RepositoryForkWorker do it 'flushes various caches' do expect_fork_repository.and_return(true) - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + expect(Project).to receive(:find).with(fork_project.id).and_return(fork_project) + expect(fork_project.repository).to receive(:expire_emptiness_caches) .and_call_original - - expect_any_instance_of(Repository).to receive(:expire_exists_cache) + expect(fork_project.repository).to receive(:expire_exists_cache) + .and_call_original + expect(fork_project.wiki.repository).to receive(:expire_emptiness_caches) + .and_call_original + expect(fork_project.wiki.repository).to receive(:expire_exists_cache) .and_call_original perform! diff --git a/spec/workers/repository_import_worker_spec.rb b/spec/workers/repository_import_worker_spec.rb index 84d1b38ef19..f0884ad0aff 100644 --- a/spec/workers/repository_import_worker_spec.rb +++ b/spec/workers/repository_import_worker_spec.rb @@ -22,8 +22,11 @@ describe RepositoryImportWorker do expect_any_instance_of(Projects::ImportService).to receive(:execute) .and_return({ status: :ok }) - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) - expect_any_instance_of(Project).to receive(:import_finish) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + expect(Project).to receive(:find).with(project.id).and_return(project) + expect(project.repository).to receive(:expire_emptiness_caches) + expect(project.wiki.repository).to receive(:expire_emptiness_caches) + expect(project).to receive(:import_finish) subject.perform(project.id) end @@ -34,9 +37,11 @@ describe RepositoryImportWorker do expect_any_instance_of(Projects::ImportService).to receive(:execute) .and_return({ status: :ok }) - expect_any_instance_of(Project).to receive(:after_import).and_call_original - expect_any_instance_of(Repository).to receive(:expire_emptiness_caches) - expect_any_instance_of(Project).to receive(:import_finish) + # Works around https://github.com/rspec/rspec-mocks/issues/910 + expect(Project).to receive(:find).with(project.id).and_return(project) + expect(project.repository).to receive(:expire_emptiness_caches) + expect(project.wiki.repository).to receive(:expire_emptiness_caches) + expect(project).to receive(:import_finish) subject.perform(project.id) end -- cgit v1.2.1 From 1756eea5316c9d1d4b6b8a9bb45d1d2425943f5c Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 11 Jun 2018 10:05:00 -0700 Subject: Fix Rubocop failure in spec/models/project_spec.rb --- spec/models/project_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index adb6ea94ac7..24c99a7929a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1727,7 +1727,7 @@ describe Project do .and_return(true) # Works around https://github.com/rspec/rspec-mocks/issues/910 - expect(Project).to receive(:find).with(project.id).twice.and_return(project) + expect(described_class).to receive(:find).with(project.id).twice.and_return(project) expect(project.repository).to receive(:after_import) .and_call_original expect(project.wiki.repository).to receive(:after_import) -- cgit v1.2.1 From 072f9224afded08cb1c93fa0e6c077928f60cca0 Mon Sep 17 00:00:00 2001 From: Stan Hu Date: Mon, 11 Jun 2018 12:06:25 -0700 Subject: Relax expectation in spec/models/project_spec.rb Multiple Sidekiq workers can run in the spec, causing `Project.find` to be run in different places. Instead of setting a fixed number of calls, just use `allow`. --- spec/models/project_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index a7a6d0bb09c..926365e409a 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1734,7 +1734,7 @@ describe Project do .and_return(true) # Works around https://github.com/rspec/rspec-mocks/issues/910 - expect(described_class).to receive(:find).with(project.id).twice.and_return(project) + allow(described_class).to receive(:find).with(project.id).and_return(project) expect(project.repository).to receive(:after_import) .and_call_original expect(project.wiki.repository).to receive(:after_import) -- cgit v1.2.1 From 79033a5f678c05c640d0b0cb7b53909ae2b5e221 Mon Sep 17 00:00:00 2001 From: "Marko, Peter" Date: Fri, 8 Jun 2018 20:37:19 +0200 Subject: Add id group api sorting option With introduction of subgroups, many groups may have the same name and/or path, thus further sorting options are necessary. Signed-off-by: Marko, Peter --- spec/requests/api/groups_spec.rb | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 7d923932309..2e7a5cbeca6 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -138,10 +138,12 @@ describe API::Groups do context "when using sorting" do let(:group3) { create(:group, name: "a#{group1.name}", path: "z#{group1.path}") } + let(:group4) { create(:group, name: "z#{group1.name}", path: "y#{group1.path}") } let(:response_groups) { json_response.map { |group| group['name'] } } before do group3.add_owner(user1) + group4.add_owner(user1) end it "sorts by name ascending by default" do @@ -150,7 +152,7 @@ describe API::Groups do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq([group3.name, group1.name]) + expect(response_groups).to eq([group3.name, group1.name, group4.name]) end it "sorts in descending order when passed" do @@ -159,16 +161,25 @@ describe API::Groups do expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq([group1.name, group3.name]) + expect(response_groups).to eq([group4.name, group1.name, group3.name]) end - it "sorts by the order_by param" do + it "sorts by path in order_by param" do get api("/groups", user1), order_by: "path" expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers expect(json_response).to be_an Array - expect(response_groups).to eq([group1.name, group3.name]) + expect(response_groups).to eq([group1.name, group4.name, group3.name]) + end + + it "sorts by id in the order_by param" do + get api("/groups", user1), order_by: "id" + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an Array + expect(response_groups).to eq([group1.name, group3.name, group4.name]) end end -- cgit v1.2.1 From c3f499e7c8656fa09b333b88950c70f7377f95f9 Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Fri, 8 Jun 2018 22:06:08 +0200 Subject: Use upload ID instead of model ID in lease key For FileUploaders it's possible that a model has many uploads and if lease key is created only from model id, it causes that the model's uploads can not be migrated in parallel because the exclusive lease key would be same for all uploads of the model. --- .../uploaders/object_storage_shared_examples.rb | 6 ++---- spec/uploaders/object_storage_spec.rb | 12 ++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb index 6352f1527cd..12f7d3ed92a 100644 --- a/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb +++ b/spec/support/shared_examples/uploaders/object_storage_shared_examples.rb @@ -76,10 +76,8 @@ shared_examples "migrates" do |to_store:, from_store: nil| end context 'when migrate! is occupied by another process' do - let(:exclusive_lease_key) { "object_storage_migrate:#{subject.model.class}:#{subject.model.id}" } - before do - @uuid = Gitlab::ExclusiveLease.new(exclusive_lease_key, timeout: 1.hour.to_i).try_obtain + @uuid = Gitlab::ExclusiveLease.new(subject.exclusive_lease_key, timeout: 1.hour.to_i).try_obtain end it 'does not execute migrate!' do @@ -95,7 +93,7 @@ shared_examples "migrates" do |to_store:, from_store: nil| end after do - Gitlab::ExclusiveLease.cancel(exclusive_lease_key, @uuid) + Gitlab::ExclusiveLease.cancel(subject.exclusive_lease_key, @uuid) end end diff --git a/spec/uploaders/object_storage_spec.rb b/spec/uploaders/object_storage_spec.rb index 0bc5b6751b3..902fc0bc030 100644 --- a/spec/uploaders/object_storage_spec.rb +++ b/spec/uploaders/object_storage_spec.rb @@ -332,6 +332,18 @@ describe ObjectStorage do expect { uploader.use_file }.to raise_error('exclusive lease already taken') end end + + it 'can still migrate other files of the same model' do + uploader2 = uploader_class.new(object, :file) + uploader2.upload = create(:upload) + uploader.upload = create(:upload) + + when_file_is_in_use do + expect(uploader2).to receive(:unsafe_migrate!) + + uploader2.migrate!(described_class::Store::REMOTE) + end + end end describe '#fog_credentials' do -- cgit v1.2.1 From 39ed07a816c9f732715b835bd363057a315f6ee7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Jun 2018 09:38:04 +0100 Subject: karma updates --- spec/javascripts/ide/components/commit_sidebar/list_item_spec.js | 1 + spec/javascripts/ide/components/commit_sidebar/list_spec.js | 1 + spec/javascripts/ide/components/repo_commit_section_spec.js | 1 + 3 files changed, 3 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js index cc7e0a3f26d..a732028158e 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js @@ -19,6 +19,7 @@ describe('Multi-file editor commit sidebar list item', () => { vm = createComponentWithStore(Component, store, { file: f, actionComponent: 'stage-button', + activeFileKey: `staged-${f.key}`, }).$mount(); }); diff --git a/spec/javascripts/ide/components/commit_sidebar/list_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_spec.js index 54625ef90f8..a37cbd5a596 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_spec.js @@ -17,6 +17,7 @@ describe('Multi-file editor commit sidebar list', () => { action: 'stageAllChanges', actionBtnText: 'stage all', itemActionComponent: 'stage-button', + activeFileKey: 'staged-testing', }); vm.$store.state.rightPanelCollapsed = false; diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js index 5e3e00a180b..0934c239a8e 100644 --- a/spec/javascripts/ide/components/repo_commit_section_spec.js +++ b/spec/javascripts/ide/components/repo_commit_section_spec.js @@ -98,6 +98,7 @@ describe('RepoCommitSection', () => { store.state.noChangesStateSvgPath = 'nochangessvg'; store.state.committedStateSvgPath = 'svg'; + vm.$destroy(); vm = createComponentWithStore(Component, store).$mount(); expect(vm.$el.querySelector('.js-empty-state').textContent.trim()).toContain('No changes'); -- cgit v1.2.1 From 6633fbef4e6c7adaca9b1f1633640f09c3bc90d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= Date: Sun, 20 May 2018 14:18:50 +0200 Subject: Add CI_{PIPELINE,JOB}_URL --- spec/models/ci/build_spec.rb | 3 +++ spec/models/ci/pipeline_spec.rb | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 0a0d7d3fea9..51b9b518117 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1548,7 +1548,9 @@ describe Ci::Build do let(:predefined_variables) do [ { key: 'CI_PIPELINE_ID', value: pipeline.id.to_s, public: true }, + { key: 'CI_PIPELINE_URL', value: project.web_url + "/pipelines/#{pipeline.id}", public: true }, { key: 'CI_JOB_ID', value: build.id.to_s, public: true }, + { key: 'CI_JOB_URL', value: project.web_url + "/-/jobs/#{build.id}", public: true }, { key: 'CI_JOB_TOKEN', value: build.token, public: false }, { key: 'CI_BUILD_ID', value: build.id.to_s, public: true }, { key: 'CI_BUILD_TOKEN', value: build.token, public: false }, @@ -2171,6 +2173,7 @@ describe Ci::Build do it 'does not return prohibited variables' do keys = %w[CI_JOB_ID + CI_JOB_URL CI_JOB_TOKEN CI_BUILD_ID CI_BUILD_TOKEN diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 2bae98dcbb8..a41657b53b7 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -194,7 +194,7 @@ describe Ci::Pipeline, :mailer do it 'does contains persisted variables' do keys = subject.map { |variable| variable[:key] } - expect(keys).to eq %w[CI_PIPELINE_ID] + expect(keys).to eq %w[CI_PIPELINE_ID CI_PIPELINE_URL] end end end -- cgit v1.2.1 From 00ced96c53f320240126f6497e75488eca81e973 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Jun 2018 11:46:00 +0100 Subject: added specs for is-active class added spec for openPendingTab in component --- .../ide/components/commit_sidebar/list_item_spec.js | 16 ++++++++++++++++ .../ide/components/repo_commit_section_spec.js | 9 +++++++++ 2 files changed, 25 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js index a732028158e..8f7cf24c22f 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js @@ -90,4 +90,20 @@ describe('Multi-file editor commit sidebar list item', () => { }); }); }); + + describe('is active', () => { + it('does not add active class when dont keys match', () => { + expect(vm.$el.classList).not.toContain('is-active'); + }); + + it('adds active class when keys match', done => { + vm.keyPrefix = 'staged'; + + vm.$nextTick(() => { + expect(vm.$el.classList).toContain('is-active'); + + done(); + }); + }); + }); }); diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js index 0934c239a8e..de00a372ed4 100644 --- a/spec/javascripts/ide/components/repo_commit_section_spec.js +++ b/spec/javascripts/ide/components/repo_commit_section_spec.js @@ -56,6 +56,8 @@ describe('RepoCommitSection', () => { vm.$store.state.entries[f.path] = f; }); + spyOn(vm, 'openPendingTab').and.callThrough(); + return vm.$mount(); } @@ -177,5 +179,12 @@ describe('RepoCommitSection', () => { expect(store.state.openFiles.length).toBe(1); expect(store.state.openFiles[0].pending).toBe(true); }); + + it('calls openPendingTab', () => { + expect(vm.openPendingTab).toHaveBeenCalledWith({ + file: vm.lastOpenedFile, + keyPrefix: 'unstaged', + }); + }); }); }); -- cgit v1.2.1 From b2cb0c6cbdd7ef46f68e824174df35356636b307 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Jun 2018 12:19:59 +0100 Subject: fixed eslint --- spec/javascripts/ide/components/repo_commit_section_spec.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js index de00a372ed4..531bcd6e540 100644 --- a/spec/javascripts/ide/components/repo_commit_section_spec.js +++ b/spec/javascripts/ide/components/repo_commit_section_spec.js @@ -56,9 +56,7 @@ describe('RepoCommitSection', () => { vm.$store.state.entries[f.path] = f; }); - spyOn(vm, 'openPendingTab').and.callThrough(); - - return vm.$mount(); + return vm; } beforeEach(done => { @@ -66,6 +64,10 @@ describe('RepoCommitSection', () => { vm = createComponent(); + spyOn(vm, 'openPendingTab').and.callThrough(); + + vm.$mount(); + spyOn(service, 'getTreeData').and.returnValue( Promise.resolve({ headers: { -- cgit v1.2.1 From 1292b99b742fd83438b011d3082662d354b3330e Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Tue, 12 Jun 2018 11:30:13 +0000 Subject: Resolve "[Rails5] `ActionView::MissingTemplate` in spec/features/projects/wiki/user_views_wiki_page_spec.rb" --- spec/routing/project_routing_spec.rb | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index e1b4e618092..56d93095a85 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -36,33 +36,36 @@ describe 'project routing' do shared_examples 'RESTful project resources' do let(:actions) { [:index, :create, :new, :edit, :show, :update, :destroy] } let(:controller_path) { controller } + let(:id) { { id: '1' } } + let(:format) { {} } # response format, e.g. { format: :html } + let(:params) { { namespace_id: 'gitlab', project_id: 'gitlabhq' } } it 'to #index' do - expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:index) + expect(get("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#index", params) if actions.include?(:index) end it 'to #create' do - expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:create) + expect(post("/gitlab/gitlabhq/#{controller_path}")).to route_to("projects/#{controller}#create", params) if actions.include?(:create) end it 'to #new' do - expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", namespace_id: 'gitlab', project_id: 'gitlabhq') if actions.include?(:new) + expect(get("/gitlab/gitlabhq/#{controller_path}/new")).to route_to("projects/#{controller}#new", params) if actions.include?(:new) end it 'to #edit' do - expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:edit) + expect(get("/gitlab/gitlabhq/#{controller_path}/1/edit")).to route_to("projects/#{controller}#edit", params.merge(**id, **format)) if actions.include?(:edit) end it 'to #show' do - expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:show) + expect(get("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#show", params.merge(**id, **format)) if actions.include?(:show) end it 'to #update' do - expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:update) + expect(put("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#update", params.merge(id)) if actions.include?(:update) end it 'to #destroy' do - expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') if actions.include?(:destroy) + expect(delete("/gitlab/gitlabhq/#{controller_path}/1")).to route_to("projects/#{controller}#destroy", params.merge(**id, **format)) if actions.include?(:destroy) end end @@ -150,12 +153,13 @@ describe 'project routing' do end it 'to #history' do - expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1') + expect(get('/gitlab/gitlabhq/wikis/1/history')).to route_to('projects/wikis#history', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1', format: :html) end it_behaves_like 'RESTful project resources' do let(:actions) { [:create, :edit, :show, :destroy] } let(:controller) { 'wikis' } + let(:format) { { format: :html } } end end -- cgit v1.2.1 From e4612df0e257a27b47986a9ee6aa77f68a9cd3ba Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 12 Jun 2018 13:29:43 +0200 Subject: Ensure MR diffs always exist in the PR importer In rare cases it could happen that an MR was created, but creating the MR diffs somehow failed (e.g. due to an error). This commit adds an additional check to make sure MR diffs are always present when importing GitHub pull requests. --- .../github_import/importer/pull_request_importer_spec.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb index 6686b7ce0b5..3422a1e82fc 100644 --- a/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer/pull_request_importer_spec.rb @@ -276,5 +276,17 @@ describe Gitlab::GithubImport::Importer::PullRequestImporter, :clean_gitlab_redi expect(diff.merge_request_diff_commits.exists?).to eq(true) end + + context 'when the merge request exists' do + it 'creates the merge request diffs if they do not yet exist' do + mr, _ = importer.create_merge_request + + mr.merge_request_diffs.delete_all + + importer.insert_git_data(mr, true) + + expect(mr.merge_request_diffs.exists?).to eq(true) + end + end end end -- cgit v1.2.1 From 9aad5ed0a23a6386bf48f166a6b07b3a41d9c2c1 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Mon, 11 Jun 2018 10:28:30 +0200 Subject: Fixes Microsoft Teams notifications for pipeline events Closes #42342 --- spec/lib/microsoft_teams/notifier_spec.rb | 2 +- spec/models/project_services/microsoft_teams_service_spec.rb | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/microsoft_teams/notifier_spec.rb b/spec/lib/microsoft_teams/notifier_spec.rb index 3035693812f..c9756544bd6 100644 --- a/spec/lib/microsoft_teams/notifier_spec.rb +++ b/spec/lib/microsoft_teams/notifier_spec.rb @@ -8,7 +8,7 @@ describe MicrosoftTeams::Notifier do let(:options) do { title: 'JohnDoe4/project2', - pretext: '[[JohnDoe4/project2](http://localhost/namespace2/gitlabhq)] Issue [#1 Awesome issue](http://localhost/namespace2/gitlabhq/issues/1) opened by user6', + summary: '[[JohnDoe4/project2](http://localhost/namespace2/gitlabhq)] Issue [#1 Awesome issue](http://localhost/namespace2/gitlabhq/issues/1) opened by user6', activity: { title: 'Issue opened by user6', subtitle: 'in [JohnDoe4/project2](http://localhost/namespace2/gitlabhq)', diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb index 8d9ee96227f..3351c6280b4 100644 --- a/spec/models/project_services/microsoft_teams_service_spec.rb +++ b/spec/models/project_services/microsoft_teams_service_spec.rb @@ -225,10 +225,15 @@ describe MicrosoftTeamsService do it 'calls Microsoft Teams API for pipeline events' do data = Gitlab::DataBuilder::Pipeline.build(pipeline) + data[:markdown] = true chat_service.execute(data) - expect(WebMock).to have_requested(:post, webhook_url).once + message = ChatMessage::PipelineMessage.new(data) + + expect(WebMock).to have_requested(:post, webhook_url) + .with(body: hash_including({ summary: message.summary })) + .once end end -- cgit v1.2.1 From ab93f7cc7912e0f07cf5ac4de95afdabffad5138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Tue, 12 Jun 2018 12:31:10 +0000 Subject: Bumping gitlab-gollum-lib and gitlab-gollum-rugged_adapter --- spec/lib/gitlab/git/wiki_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb index 722d697c28e..35b06b14620 100644 --- a/spec/lib/gitlab/git/wiki_spec.rb +++ b/spec/lib/gitlab/git/wiki_spec.rb @@ -25,6 +25,22 @@ describe Gitlab::Git::Wiki do end end + describe '#delete_page', :skip_gitaly_mock do + after do + destroy_page('page1') + end + + it 'only removes the page with the same path' do + create_page('page1', 'content') + create_page('*', 'content') + + subject.delete_page('*', commit_details('whatever')) + + expect(subject.pages.count).to eq 1 + expect(subject.pages.first.title).to eq 'page1' + end + end + def create_page(name, content) subject.write_page(name, :markdown, content, commit_details(name)) end -- cgit v1.2.1 From f376347f24f24efc157d80de63381dd22d060630 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Tue, 5 Jun 2018 17:58:28 +0200 Subject: Find and mark more Git disk access locations, part 2 --- spec/factories/projects.rb | 12 --- spec/lib/gitlab/diff/file_spec.rb | 4 +- spec/lib/gitlab/git/blob_spec.rb | 14 ++- spec/lib/gitlab/git/branch_spec.rb | 4 +- spec/lib/gitlab/git/commit_spec.rb | 17 +++- spec/lib/gitlab/git/diff_spec.rb | 6 +- spec/lib/gitlab/git/gitlab_projects_spec.rb | 112 ++++++++++----------- spec/lib/gitlab/git/hook_spec.rb | 7 ++ spec/lib/gitlab/git/index_spec.rb | 7 ++ .../import_export/merge_request_parser_spec.rb | 4 +- spec/lib/gitlab/shell_spec.rb | 72 ++++++++++--- spec/services/git_tag_push_service_spec.rb | 4 +- .../services/merge_requests/squash_service_spec.rb | 4 +- .../services/projects/after_import_service_spec.rb | 8 +- spec/services/projects/destroy_service_spec.rb | 6 +- .../migrate_repository_service_spec.rb | 6 +- spec/spec_helper.rb | 13 --- spec/support/helpers/test_env.rb | 10 ++ spec/tasks/gitlab/gitaly_rake_spec.rb | 4 +- spec/tasks/gitlab/shell_rake_spec.rb | 8 +- spec/workers/git_garbage_collect_worker_spec.rb | 8 +- spec/workers/project_destroy_worker_spec.rb | 6 +- spec/workers/repository_fork_worker_spec.rb | 3 + 23 files changed, 214 insertions(+), 125 deletions(-) (limited to 'spec') diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 16e025618a6..f6b05bac0e8 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -151,11 +151,6 @@ FactoryBot.define do trait :empty_repo do after(:create) do |project| raise "Failed to create repository!" unless project.create_repository - - # We delete hooks so that gitlab-shell will not try to authenticate with - # an API that isn't running - project.gitlab_shell.rm_directory(project.repository_storage, - File.join("#{project.disk_path}.git", 'hooks')) end end @@ -180,13 +175,6 @@ FactoryBot.define do trait :wiki_repo do after(:create) do |project| raise 'Failed to create wiki repository!' unless project.create_wiki - - # We delete hooks so that gitlab-shell will not try to authenticate with - # an API that isn't running - project.gitlab_shell.rm_directory( - project.repository_storage, - File.join("#{project.wiki.repository.disk_path}.git", "hooks") - ) end end diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb index f0e83ccfc7a..5dfbb8e71f8 100644 --- a/spec/lib/gitlab/diff/file_spec.rb +++ b/spec/lib/gitlab/diff/file_spec.rb @@ -79,7 +79,9 @@ describe Gitlab::Diff::File do let(:diffs) { commit.diffs } before do - info_dir_path = File.join(project.repository.path_to_repo, 'info') + info_dir_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + File.join(project.repository.path_to_repo, 'info') + end FileUtils.mkdir(info_dir_path) unless File.exist?(info_dir_path) File.write(File.join(info_dir_path, 'attributes'), "*.md -diff\n") diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb index 94eaf86ef80..6015086f002 100644 --- a/spec/lib/gitlab/git/blob_spec.rb +++ b/spec/lib/gitlab/git/blob_spec.rb @@ -149,7 +149,9 @@ describe Gitlab::Git::Blob, seed_helper: true do it 'limits the size of a large file' do blob_size = Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE + 1 buffer = Array.new(blob_size, 0) - rugged_blob = Rugged::Blob.from_buffer(repository.rugged, buffer.join('')) + rugged_blob = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Rugged::Blob.from_buffer(repository.rugged, buffer.join('')) + end blob = Gitlab::Git::Blob.raw(repository, rugged_blob) expect(blob.size).to eq(blob_size) @@ -164,7 +166,9 @@ describe Gitlab::Git::Blob, seed_helper: true do context 'when sha references a tree' do it 'returns nil' do - tree = repository.rugged.rev_parse('master^{tree}') + tree = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged.rev_parse('master^{tree}') + end blob = Gitlab::Git::Blob.raw(repository, tree.oid) @@ -278,7 +282,11 @@ describe Gitlab::Git::Blob, seed_helper: true do end describe '.batch_lfs_pointers' do - let(:tree_object) { repository.rugged.rev_parse('master^{tree}') } + let(:tree_object) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged.rev_parse('master^{tree}') + end + end let(:non_lfs_blob) do Gitlab::Git::Blob.find( diff --git a/spec/lib/gitlab/git/branch_spec.rb b/spec/lib/gitlab/git/branch_spec.rb index a19155ed5b0..ec1a684cfbc 100644 --- a/spec/lib/gitlab/git/branch_spec.rb +++ b/spec/lib/gitlab/git/branch_spec.rb @@ -69,7 +69,9 @@ describe Gitlab::Git::Branch, seed_helper: true do Gitlab::Git.committer_hash(email: user.email, name: user.name) end let(:params) do - parents = [repository.rugged.head.target] + parents = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + [repository.rugged.head.target] + end tree = parents.first.tree { diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 89be8a1b7f2..5af982c7a54 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -4,12 +4,15 @@ describe Gitlab::Git::Commit, seed_helper: true do let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') } let(:commit) { described_class.find(repository, SeedRepo::Commit::ID) } let(:rugged_commit) do - repository.rugged.lookup(SeedRepo::Commit::ID) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged.lookup(SeedRepo::Commit::ID) + end end - describe "Commit info" do before do - repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged + repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged + end @committer = { email: 'mike@smith.com', @@ -58,7 +61,9 @@ describe Gitlab::Git::Commit, seed_helper: true do after do # Erase the new commit so other tests get the original repo - repo = Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged + repo = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '').rugged + end repo.references.update("refs/heads/master", SeedRepo::LastCommit::ID) end end @@ -115,7 +120,9 @@ describe Gitlab::Git::Commit, seed_helper: true do describe '.find' do it "should return first head commit if without params" do expect(described_class.last(repository).id).to eq( - repository.rugged.head.target.oid + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged.head.target.oid + end ) end diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb index 4a7b06003fc..3bb0b5be15b 100644 --- a/spec/lib/gitlab/git/diff_spec.rb +++ b/spec/lib/gitlab/git/diff_spec.rb @@ -27,8 +27,10 @@ EOT too_large: false } - @rugged_diff = repository.rugged.diff("5937ac0a7beb003549fc5fd26fc247adbce4a52e^", "5937ac0a7beb003549fc5fd26fc247adbce4a52e", paths: - [".gitmodules"]).patches.first + @rugged_diff = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + repository.rugged.diff("5937ac0a7beb003549fc5fd26fc247adbce4a52e^", "5937ac0a7beb003549fc5fd26fc247adbce4a52e", paths: + [".gitmodules"]).patches.first + end end describe '.new' do diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb index 8b715d717c1..f5d8503c30c 100644 --- a/spec/lib/gitlab/git/gitlab_projects_spec.rb +++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb @@ -5,6 +5,13 @@ describe Gitlab::Git::GitlabProjects do TestEnv.clean_test_path end + around do |example| + # TODO move this spec to gitaly-ruby. GitlabProjects is not used in gitlab-ce + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + let(:project) { create(:project, :repository) } if $VERBOSE @@ -190,36 +197,30 @@ describe Gitlab::Git::GitlabProjects do end end - context 'when Gitaly import_repository feature is enabled' do - it_behaves_like 'importing repository' - end + describe 'logging' do + it 'imports a repo' do + message = "Importing project from <#{import_url}> to <#{tmp_repo_path}>." + expect(logger).to receive(:info).with(message) - context 'when Gitaly import_repository feature is disabled', :disable_gitaly do - describe 'logging' do - it 'imports a repo' do - message = "Importing project from <#{import_url}> to <#{tmp_repo_path}>." - expect(logger).to receive(:info).with(message) - - subject - end + subject end + end - context 'timeout' do - it 'does not import a repo' do - stub_spawn_timeout(cmd, timeout, nil) + context 'timeout' do + it 'does not import a repo' do + stub_spawn_timeout(cmd, timeout, nil) - message = "Importing project from <#{import_url}> to <#{tmp_repo_path}> failed." - expect(logger).to receive(:error).with(message) + message = "Importing project from <#{import_url}> to <#{tmp_repo_path}> failed." + expect(logger).to receive(:error).with(message) - is_expected.to be_falsy + is_expected.to be_falsy - expect(gl_projects.output).to eq("Timed out\n") - expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy - end + expect(gl_projects.output).to eq("Timed out\n") + expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy end - - it_behaves_like 'importing repository' end + + it_behaves_like 'importing repository' end describe '#fork_repository' do @@ -232,9 +233,6 @@ describe Gitlab::Git::GitlabProjects do before do FileUtils.mkdir_p(dest_repos_path) - - # Undo spec_helper stub that deletes hooks - allow_any_instance_of(described_class).to receive(:fork_repository).and_call_original end after do @@ -258,51 +256,45 @@ describe Gitlab::Git::GitlabProjects do end end - context 'when Gitaly fork_repository feature is enabled' do - it_behaves_like 'forking a repository' - end - - context 'when Gitaly fork_repository feature is disabled', :disable_gitaly do - it_behaves_like 'forking a repository' + it_behaves_like 'forking a repository' - # We seem to be stuck to having only one working Gitaly storage in tests, changing - # that is not very straight-forward so I'm leaving this test here for now till - # https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed. - context 'different storages' do - let(:dest_repos) { 'alternative' } - let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), dest_repos) } + # We seem to be stuck to having only one working Gitaly storage in tests, changing + # that is not very straight-forward so I'm leaving this test here for now till + # https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed. + context 'different storages' do + let(:dest_repos) { 'alternative' } + let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), dest_repos) } - before do - stub_storage_settings(dest_repos => { 'path' => dest_repos_path }) - end + before do + stub_storage_settings(dest_repos => { 'path' => dest_repos_path }) + end - it 'forks the repo' do - is_expected.to be_truthy + it 'forks the repo' do + is_expected.to be_truthy - expect(File.exist?(dest_repo)).to be_truthy - expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy - expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy - end + expect(File.exist?(dest_repo)).to be_truthy + expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy + expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy end + end - describe 'log messages' do - describe 'successful fork' do - it do - message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>." - expect(logger).to receive(:info).with(message) + describe 'log messages' do + describe 'successful fork' do + it do + message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>." + expect(logger).to receive(:info).with(message) - subject - end + subject end + end - describe 'failed fork due existing destination' do - it do - FileUtils.mkdir_p(dest_repo) - message = "fork-repository failed: destination repository <#{dest_repo}> already exists." - expect(logger).to receive(:error).with(message) + describe 'failed fork due existing destination' do + it do + FileUtils.mkdir_p(dest_repo) + message = "fork-repository failed: destination repository <#{dest_repo}> already exists." + expect(logger).to receive(:error).with(message) - subject - end + subject end end end diff --git a/spec/lib/gitlab/git/hook_spec.rb b/spec/lib/gitlab/git/hook_spec.rb index 2fe1f5603ce..c8a5052200c 100644 --- a/spec/lib/gitlab/git/hook_spec.rb +++ b/spec/lib/gitlab/git/hook_spec.rb @@ -8,6 +8,13 @@ describe Gitlab::Git::Hook do allow_any_instance_of(described_class).to receive(:trigger).and_call_original end + around do |example| + # TODO move hook tests to gitaly-ruby. Hook will disappear from gitlab-ce + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + describe "#trigger" do let(:project) { create(:project, :repository) } let(:repository) { project.repository.raw_repository } diff --git a/spec/lib/gitlab/git/index_spec.rb b/spec/lib/gitlab/git/index_spec.rb index 73fbc6a6afa..16e6bd35449 100644 --- a/spec/lib/gitlab/git/index_spec.rb +++ b/spec/lib/gitlab/git/index_spec.rb @@ -8,6 +8,13 @@ describe Gitlab::Git::Index, seed_helper: true do index.read_tree(repository.lookup('master').tree) end + around do |example| + # TODO move these specs to gitaly-ruby. The Index class will disappear from gitlab-ce + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + example.run + end + end + describe '#create' do let(:options) do { diff --git a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb index b793636c4d6..68eaa70e6b6 100644 --- a/spec/lib/gitlab/import_export/merge_request_parser_spec.rb +++ b/spec/lib/gitlab/import_export/merge_request_parser_spec.rb @@ -19,7 +19,9 @@ describe Gitlab::ImportExport::MergeRequestParser do end after do - FileUtils.rm_rf(project.repository.path_to_repo) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + FileUtils.rm_rf(project.repository.path_to_repo) + end end it 'has a source branch' do diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb index 14eae22a2ec..155e1663298 100644 --- a/spec/lib/gitlab/shell_spec.rb +++ b/spec/lib/gitlab/shell_spec.rb @@ -498,16 +498,34 @@ describe Gitlab::Shell do ) end - it 'returns true when the command succeeds' do - expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { true } + context 'with gitaly' do + it 'returns true when the command succeeds' do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository) + .with(repository.raw_repository) { :gitaly_response_object } + + is_expected.to be_truthy + end + + it 'return false when the command fails' do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository) + .with(repository.raw_repository) { raise GRPC::BadStatus, 'bla' } - is_expected.to be_truthy + is_expected.to be_falsy + end end - it 'return false when the command fails' do - expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { false } + context 'without gitaly', :disable_gitaly do + it 'returns true when the command succeeds' do + expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { true } - is_expected.to be_falsy + is_expected.to be_truthy + end + + it 'return false when the command fails' do + expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { false } + + is_expected.to be_falsy + end end end @@ -662,21 +680,43 @@ describe Gitlab::Shell do describe '#import_repository' do let(:import_url) { 'https://gitlab.com/gitlab-org/gitlab-ce.git' } - it 'returns true when the command succeeds' do - expect(gitlab_projects).to receive(:import_project).with(import_url, timeout) { true } + context 'with gitaly' do + it 'returns true when the command succeeds' do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:import_repository).with(import_url) - result = gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) + result = gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) - expect(result).to be_truthy + expect(result).to be_truthy + end + + it 'raises an exception when the command fails' do + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:import_repository) + .with(import_url) { raise GRPC::BadStatus, 'bla' } + expect_any_instance_of(Gitlab::Shell::GitalyGitlabProjects).to receive(:output) { 'error'} + + expect do + gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) + end.to raise_error(Gitlab::Shell::Error, "error") + end end - it 'raises an exception when the command fails' do - allow(gitlab_projects).to receive(:output) { 'error' } - expect(gitlab_projects).to receive(:import_project) { false } + context 'without gitaly', :disable_gitaly do + it 'returns true when the command succeeds' do + expect(gitlab_projects).to receive(:import_project).with(import_url, timeout) { true } - expect do - gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) - end.to raise_error(Gitlab::Shell::Error, "error") + result = gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) + + expect(result).to be_truthy + end + + it 'raises an exception when the command fails' do + allow(gitlab_projects).to receive(:output) { 'error' } + expect(gitlab_projects).to receive(:import_project) { false } + + expect do + gitlab_shell.import_repository(project.repository_storage, project.disk_path, import_url) + end.to raise_error(Gitlab::Shell::Error, "error") + end end end end diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb index 33405d7a7ec..92159e1e372 100644 --- a/spec/services/git_tag_push_service_spec.rb +++ b/spec/services/git_tag_push_service_spec.rb @@ -118,7 +118,9 @@ describe GitTagPushService do before do # Create the lightweight tag - project.repository.raw_repository.rugged.tags.create(tag_name, newrev) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.raw_repository.rugged.tags.create(tag_name, newrev) + end # Clear tag list cache project.repository.expire_tags_cache diff --git a/spec/services/merge_requests/squash_service_spec.rb b/spec/services/merge_requests/squash_service_spec.rb index bd884787425..ded17fa92a4 100644 --- a/spec/services/merge_requests/squash_service_spec.rb +++ b/spec/services/merge_requests/squash_service_spec.rb @@ -63,7 +63,9 @@ describe MergeRequests::SquashService do end it 'has the same diff as the merge request, but a different SHA' do - rugged = project.repository.rugged + rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.rugged + end mr_diff = rugged.diff(merge_request.diff_base_sha, merge_request.diff_head_sha) squash_diff = rugged.diff(merge_request.diff_start_sha, squash_sha) diff --git a/spec/services/projects/after_import_service_spec.rb b/spec/services/projects/after_import_service_spec.rb index c6678fc1f5c..cd52bc88f4c 100644 --- a/spec/services/projects/after_import_service_spec.rb +++ b/spec/services/projects/after_import_service_spec.rb @@ -32,7 +32,7 @@ describe Projects::AfterImportService do end it 'removes refs/pull/**/*' do - expect(repository.rugged.references.map(&:name)) + expect(rugged.references.map(&:name)) .not_to include(%r{\Arefs/pull/}) end end @@ -46,10 +46,14 @@ describe Projects::AfterImportService do end it "does not remove refs/#{name}/tmp" do - expect(repository.rugged.references.map(&:name)) + expect(rugged.references.map(&:name)) .to include("refs/#{name}/tmp") end end end + + def rugged + Gitlab::GitalyClient::StorageSettings.allow_disk_access { repository.rugged } + end end end diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index b63f409579e..38660ad7a01 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -5,7 +5,11 @@ describe Projects::DestroyService do let!(:user) { create(:user) } let!(:project) { create(:project, :repository, namespace: user.namespace) } - let!(:path) { project.repository.path_to_repo } + let!(:path) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.path_to_repo + end + end let!(:remove_path) { path.sub(/\.git\Z/, "+#{project.id}+deleted.git") } let!(:async) { false } # execute or async_execute diff --git a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb index 7dca81eb59e..ed4930313c5 100644 --- a/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb +++ b/spec/services/projects/hashed_storage/migrate_repository_service_spec.rb @@ -37,7 +37,11 @@ describe Projects::HashedStorage::MigrateRepositoryService do it 'writes project full path to .git/config' do service.execute - expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path + rugged_config = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.rugged.config['gitlab.fullpath'] + end + + expect(rugged_config).to eq project.full_path end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index e093444121a..8417b340de5 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -107,19 +107,6 @@ RSpec.configure do |config| end config.before(:example) do - # Skip pre-receive hook check so we can use the web editor and merge. - allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil]) - - allow_any_instance_of(Gitlab::Git::GitlabProjects).to receive(:fork_repository).and_wrap_original do |m, *args| - m.call(*args) - - shard_name, repository_relative_path = args - # We can't leave the hooks in place after a fork, as those would fail in tests - # The "internal" API is not available - Gitlab::Shell.new.rm_directory(shard_name, - File.join(repository_relative_path, 'hooks')) - end - # Enable all features by default for testing allow(Feature).to receive(:enabled?) { true } end diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index 1fef50a52ec..05a8e6206ae 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -135,6 +135,16 @@ module TestEnv install_dir: Gitlab.config.gitlab_shell.path, version: Gitlab::Shell.version_required, task: 'gitlab:shell:install') + + create_fake_git_hooks + end + + def create_fake_git_hooks + # gitlab-shell hooks don't work in our test environment because they try to make internal API calls + hooks_dir = File.join(Gitlab.config.gitlab_shell.path, 'hooks') + %w[pre-receive post-receive update].each do |hook| + File.open(File.join(hooks_dir, hook), 'w', 0755) { |f| f.puts '#!/bin/sh' } + end end def setup_gitaly diff --git a/spec/tasks/gitlab/gitaly_rake_spec.rb b/spec/tasks/gitlab/gitaly_rake_spec.rb index 1e507c0236e..4545226d78c 100644 --- a/spec/tasks/gitlab/gitaly_rake_spec.rb +++ b/spec/tasks/gitlab/gitaly_rake_spec.rb @@ -134,7 +134,9 @@ describe 'gitlab:gitaly namespace rake task' do parsed_output = TomlRB.parse(expected_output) config.each do |name, params| - expect(parsed_output['storage']).to include({ 'name' => name, 'path' => params.legacy_disk_path }) + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + expect(parsed_output['storage']).to include({ 'name' => name, 'path' => params.legacy_disk_path }) + end end end end diff --git a/spec/tasks/gitlab/shell_rake_spec.rb b/spec/tasks/gitlab/shell_rake_spec.rb index 4a756c5742d..0ed5d3e27b9 100644 --- a/spec/tasks/gitlab/shell_rake_spec.rb +++ b/spec/tasks/gitlab/shell_rake_spec.rb @@ -7,11 +7,17 @@ describe 'gitlab:shell rake tasks' do stub_warn_user_is_not_gitlab end + after do + TestEnv.create_fake_git_hooks + end + describe 'install task' do it 'invokes create_hooks task' do expect(Rake::Task['gitlab:shell:create_hooks']).to receive(:invoke) - storages = Gitlab.config.repositories.storages.values.map(&:legacy_disk_path) + storages = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Gitlab.config.repositories.storages.values.map(&:legacy_disk_path) + end expect(Kernel).to receive(:system).with('bin/install', *storages).and_call_original expect(Kernel).to receive(:system).with('bin/compile').and_call_original diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index f44b4edc305..807d1b8c084 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -218,7 +218,9 @@ describe GitGarbageCollectWorker do # Create a new commit on a random new branch def create_objects(project) - rugged = project.repository.rugged + rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.rugged + end old_commit = rugged.branches.first.target new_commit_sha = Rugged::Commit.create( rugged, @@ -237,7 +239,9 @@ describe GitGarbageCollectWorker do end def packs(project) - Dir["#{project.repository.path_to_repo}/objects/pack/*.pack"] + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + Dir["#{project.repository.path_to_repo}/objects/pack/*.pack"] + end end def packed_refs(project) diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb index f19c9dff941..42e1d86e3bb 100644 --- a/spec/workers/project_destroy_worker_spec.rb +++ b/spec/workers/project_destroy_worker_spec.rb @@ -2,7 +2,11 @@ require 'spec_helper' describe ProjectDestroyWorker do let(:project) { create(:project, :repository, pending_delete: true) } - let(:path) { project.repository.path_to_repo } + let(:path) do + Gitlab::GitalyClient::StorageSettings.allow_disk_access do + project.repository.path_to_repo + end + end subject { described_class.new } diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb index 4b3c1736ea0..f5f1b60ace8 100644 --- a/spec/workers/repository_fork_worker_spec.rb +++ b/spec/workers/repository_fork_worker_spec.rb @@ -89,6 +89,9 @@ describe RepositoryForkWorker do it_behaves_like 'RepositoryForkWorker performing' it 'logs a message about forking with old-style arguments' do + allow(subject).to receive(:gitlab_shell).and_return(shell) + expect(shell).to receive(:fork_repository) { true } + allow(Rails.logger).to receive(:info).with(anything) # To compensate for other logs expect(Rails.logger).to receive(:info).with("Project #{fork_project.id} is being forked using old-style arguments.") -- cgit v1.2.1 From 1801b7fd20b6732a8381878147943f32f564dc18 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Jun 2018 13:53:13 +0100 Subject: Fixed IDE jobs empty state showing when loading Closes #47766 --- spec/javascripts/ide/components/jobs/detail_spec.js | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'spec') diff --git a/spec/javascripts/ide/components/jobs/detail_spec.js b/spec/javascripts/ide/components/jobs/detail_spec.js index 641ba06f653..8f8d4b9709e 100644 --- a/spec/javascripts/ide/components/jobs/detail_spec.js +++ b/spec/javascripts/ide/components/jobs/detail_spec.js @@ -62,6 +62,11 @@ describe('IDE jobs detail view', () => { expect(vm.$el.querySelector('.build-loader-animation').style.display).toBe(''); }); + it('hides output when loading', () => { + expect(vm.$el.querySelector('.bash')).not.toBe(null); + expect(vm.$el.querySelector('.bash').style.display).toBe('none'); + }); + it('hide loading icon when isLoading is false', done => { vm.$store.state.pipelines.detailJob.isLoading = false; -- cgit v1.2.1 From 423fcb476e64c96d7945af8d9fca65aa6db20314 Mon Sep 17 00:00:00 2001 From: Murat Dogan Date: Tue, 12 Jun 2018 13:04:01 +0000 Subject: mergeError message has been binded using v-html directive --- .../states/mr_widget_failed_to_merge_spec.js | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js index a0a74648328..8de99fd3c96 100644 --- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js +++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_failed_to_merge_spec.js @@ -6,6 +6,7 @@ import mountComponent from 'spec/helpers/vue_mount_component_helper'; describe('MRWidgetFailedToMerge', () => { const dummyIntervalId = 1337; let Component; + let mr; let vm; beforeEach(() => { @@ -13,10 +14,11 @@ describe('MRWidgetFailedToMerge', () => { spyOn(eventHub, '$emit'); spyOn(window, 'setInterval').and.returnValue(dummyIntervalId); spyOn(window, 'clearInterval').and.stub(); + mr = { + mergeError: 'Merge error happened', + }; vm = mountComponent(Component, { - mr: { - mergeError: 'Merge error happened.', - }, + mr, }); }); @@ -44,6 +46,19 @@ describe('MRWidgetFailedToMerge', () => { expect(vm.timerText).toEqual('Refreshing in a second to show the updated status...'); }); }); + + describe('mergeError', () => { + it('removes forced line breaks', done => { + mr.mergeError = 'contains
line breaks
'; + + Vue.nextTick() + .then(() => { + expect(vm.mergeError).toBe('contains line breaks'); + }) + .then(done) + .catch(done.fail); + }); + }); }); describe('created', () => { @@ -103,7 +118,7 @@ describe('MRWidgetFailedToMerge', () => { it('renders given error', () => { expect(vm.$el.querySelector('.has-error-message').textContent.trim()).toEqual( - 'Merge error happened..', + 'Merge error happened.', ); }); -- cgit v1.2.1 From 404ef05002e067d057dabafb4945d79a49d028bc Mon Sep 17 00:00:00 2001 From: Leonid Batizhevskii Date: Wed, 6 Jun 2018 15:15:35 +0300 Subject: Added with_statsoption for GET /projects/:id/repository/commits --- .../schemas/public_api/v4/commit/with_stats.json | 14 ++++++++++++++ .../schemas/public_api/v4/commits_with_stats.json | 4 ++++ spec/requests/api/commits_spec.rb | 21 +++++++++++++++++++-- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 spec/fixtures/api/schemas/public_api/v4/commit/with_stats.json create mode 100644 spec/fixtures/api/schemas/public_api/v4/commits_with_stats.json (limited to 'spec') diff --git a/spec/fixtures/api/schemas/public_api/v4/commit/with_stats.json b/spec/fixtures/api/schemas/public_api/v4/commit/with_stats.json new file mode 100644 index 00000000000..3b5dd547e69 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commit/with_stats.json @@ -0,0 +1,14 @@ +{ + "type": "object", + "allOf": [ + { "$ref": "basic.json" }, + { + "required" : [ + "stats" + ], + "properties": { + "stats": { "$ref": "../commit_stats.json" } + } + } + ] +} diff --git a/spec/fixtures/api/schemas/public_api/v4/commits_with_stats.json b/spec/fixtures/api/schemas/public_api/v4/commits_with_stats.json new file mode 100644 index 00000000000..23511123ce4 --- /dev/null +++ b/spec/fixtures/api/schemas/public_api/v4/commits_with_stats.json @@ -0,0 +1,4 @@ +{ + "type": "array", + "items": { "$ref": "commit/with_stats.json" } +} diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb index 8ad19e3f0f5..fc0c8fdceb8 100644 --- a/spec/requests/api/commits_spec.rb +++ b/spec/requests/api/commits_spec.rb @@ -18,14 +18,14 @@ describe API::Commits do describe 'GET /projects/:id/repository/commits' do let(:route) { "/projects/#{project_id}/repository/commits" } - shared_examples_for 'project commits' do + shared_examples_for 'project commits' do |schema: 'public_api/v4/commits'| it "returns project commits" do commit = project.repository.commit get api(route, current_user) expect(response).to have_gitlab_http_status(200) - expect(response).to match_response_schema('public_api/v4/commits') + expect(response).to match_response_schema(schema) expect(json_response.first['id']).to eq(commit.id) expect(json_response.first['committer_name']).to eq(commit.committer_name) expect(json_response.first['committer_email']).to eq(commit.committer_email) @@ -161,6 +161,23 @@ describe API::Commits do end end + context 'with_stats optional parameter' do + let(:project) { create(:project, :public, :repository) } + + it_behaves_like 'project commits', schema: 'public_api/v4/commits_with_stats' do + let(:route) { "/projects/#{project_id}/repository/commits?with_stats=true" } + + it 'include commits details' do + commit = project.repository.commit + get api(route, current_user) + + expect(json_response.first['stats']['additions']).to eq(commit.stats.additions) + expect(json_response.first['stats']['deletions']).to eq(commit.stats.deletions) + expect(json_response.first['stats']['total']).to eq(commit.stats.total) + end + end + end + context 'with pagination params' do let(:page) { 1 } let(:per_page) { 5 } -- cgit v1.2.1 From 3d42bab71ad293c99d029dfb4f0c9aa0378643d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mica=C3=ABl=20Bergeron?= Date: Tue, 12 Jun 2018 11:22:35 -0400 Subject: apply feedback --- .../object_storage/migrate_uploads_worker_spec.rb | 34 +++++++++------------- 1 file changed, 14 insertions(+), 20 deletions(-) (limited to 'spec') diff --git a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb index 31d323626c5..da490cb02af 100644 --- a/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb +++ b/spec/uploaders/workers/object_storage/migrate_uploads_worker_spec.rb @@ -1,7 +1,5 @@ require 'spec_helper' -MIGRATION_QUERIES = 5 - describe ObjectStorage::MigrateUploadsWorker, :sidekiq do shared_context 'sanity_check! fails' do before do @@ -127,13 +125,12 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do it_behaves_like "uploads migration worker" describe "limits N+1 queries" do - let!(:projects) { create_list(:project, 10, :with_avatar) } - - it "to N*#{MIGRATION_QUERIES}" do + it "to N*5" do query_count = ActiveRecord::QueryRecorder.new { perform(uploads) } - more_projects = create_list(:project, 100, :with_avatar) - expected_queries_per_migration = MIGRATION_QUERIES * more_projects.count + more_projects = create_list(:project, 3, :with_avatar) + + expected_queries_per_migration = 5 * more_projects.count expect { perform(Upload.all) }.not_to exceed_query_limit(query_count).with_threshold(expected_queries_per_migration) end end @@ -144,30 +141,27 @@ describe ObjectStorage::MigrateUploadsWorker, :sidekiq do let(:secret) { SecureRandom.hex } let(:mounted_as) { nil } + def upload_file(project) + uploader = FileUploader.new(project) + uploader.store!(fixture_file_upload('spec/fixtures/doc_sample.txt')) + end + before do stub_uploads_object_storage(FileUploader) - projects.map do |project| - uploader = FileUploader.new(project) - uploader.store!(fixture_file_upload('spec/fixtures/doc_sample.txt')) - end + projects.map(&method(:upload_file)) end it_behaves_like "uploads migration worker" describe "limits N+1 queries" do - let!(:projects) { create_list(:project, 10) } - - it "to N*#{MIGRATION_QUERIES}" do + it "to N*5" do query_count = ActiveRecord::QueryRecorder.new { perform(uploads) } - more_projects = create_list(:project, 100) - more_projects.map do |project| - uploader = FileUploader.new(project) - uploader.store!(fixture_file_upload('spec/fixtures/doc_sample.txt')) - end - expected_queries_per_migration = MIGRATION_QUERIES * more_projects.count + more_projects = create_list(:project, 3) + more_projects.map(&method(:upload_file)) + expected_queries_per_migration = 5 * more_projects.count expect { perform(Upload.all) }.not_to exceed_query_limit(query_count).with_threshold(expected_queries_per_migration) end end -- cgit v1.2.1 From 7530e4ec86a686dede8eb8535fd231c1a75d3659 Mon Sep 17 00:00:00 2001 From: Mario de la Ossa Date: Tue, 12 Jun 2018 14:35:45 -0600 Subject: Fix Banzai reference for milestones belonging to parent groups --- spec/lib/banzai/filter/milestone_reference_filter_spec.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb index f8fa9b2d13d..91d4a60ba95 100644 --- a/spec/lib/banzai/filter/milestone_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/milestone_reference_filter_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' describe Banzai::Filter::MilestoneReferenceFilter do include FilterSpecHelper - let(:group) { create(:group, :public) } + let(:parent_group) { create(:group, :public) } + let(:group) { create(:group, :public, parent: parent_group) } let(:project) { create(:project, :public, group: group) } it 'requires project context' do @@ -340,6 +341,13 @@ describe Banzai::Filter::MilestoneReferenceFilter do expect(doc.css('a')).to be_empty end + + it 'supports parent group references', :nested_groups do + milestone.update!(group: parent_group) + + doc = reference_filter("See #{reference}") + expect(doc.css('a').first.text).to eq(milestone.name) + end end context 'group context' do -- cgit v1.2.1 From 379a6a709a55f952133354febddf97854c2d5d4d Mon Sep 17 00:00:00 2001 From: Mario de la Ossa Date: Tue, 12 Jun 2018 16:40:16 -0600 Subject: Sidebar Milestone - Fix wrong URL when selecting a parent group milestone --- .../api/schemas/public_api/v4/milestones.json | 3 ++- spec/lib/gitlab/url_builder_spec.rb | 25 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/fixtures/api/schemas/public_api/v4/milestones.json b/spec/fixtures/api/schemas/public_api/v4/milestones.json index c3c42b6ee60..448e97d6c85 100644 --- a/spec/fixtures/api/schemas/public_api/v4/milestones.json +++ b/spec/fixtures/api/schemas/public_api/v4/milestones.json @@ -13,7 +13,8 @@ "created_at": { "type": "date" }, "updated_at": { "type": "date" }, "start_date": { "type": "date" }, - "due_date": { "type": "date" } + "due_date": { "type": "date" }, + "web_url": { "type": "string" } }, "required": [ "id", "iid", "title", "description", "state", diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb index b81749cf428..9f495a5d50b 100644 --- a/spec/lib/gitlab/url_builder_spec.rb +++ b/spec/lib/gitlab/url_builder_spec.rb @@ -22,6 +22,31 @@ describe Gitlab::UrlBuilder do end end + context 'when passing a Milestone' do + let(:group) { create(:group) } + let(:project) { create(:project, :public, namespace: group) } + + context 'belonging to a project' do + it 'returns a proper URL' do + milestone = create(:milestone, project: project) + + url = described_class.build(milestone) + + expect(url).to eq "#{Settings.gitlab['url']}/#{milestone.project.full_path}/milestones/#{milestone.iid}" + end + end + + context 'belonging to a group' do + it 'returns a proper URL' do + milestone = create(:milestone, group: group) + + url = described_class.build(milestone) + + expect(url).to eq "#{Settings.gitlab['url']}/groups/#{milestone.group.full_path}/-/milestones/#{milestone.iid}" + end + end + end + context 'when passing a MergeRequest' do it 'returns a proper URL' do merge_request = build_stubbed(:merge_request, iid: 42) -- cgit v1.2.1 From df45623b3455193395d523bc88deee87b5f6d56f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Javier=20L=C3=B3pez?= Date: Wed, 13 Jun 2018 08:25:01 +0000 Subject: Restoring user v3 endpoint --- spec/requests/api/users_spec.rb | 73 ++++++++++++---------- .../api/scopes/read_user_shared_examples.rb | 10 +-- 2 files changed, 45 insertions(+), 38 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 3377d67b644..a97c3f3461a 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -1123,58 +1123,63 @@ describe API::Users do describe "GET /user" do let(:personal_access_token) { create(:personal_access_token, user: user).token } - context 'with regular user' do - context 'with personal access token' do - it 'returns 403 without private token when sudo is defined' do - get api("/user?private_token=#{personal_access_token}&sudo=123") + shared_examples 'get user info' do |version| + context 'with regular user' do + context 'with personal access token' do + it 'returns 403 without private token when sudo is defined' do + get api("/user?private_token=#{personal_access_token}&sudo=123", version: version) - expect(response).to have_gitlab_http_status(403) + expect(response).to have_gitlab_http_status(403) + end end - end - it 'returns current user without private token when sudo not defined' do - get api("/user", user) + it 'returns current user without private token when sudo not defined' do + get api("/user", user, version: version) - expect(response).to have_gitlab_http_status(200) - expect(response).to match_response_schema('public_api/v4/user/public') - expect(json_response['id']).to eq(user.id) - end + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/user/public') + expect(json_response['id']).to eq(user.id) + end - context "scopes" do - let(:path) { "/user" } - let(:api_call) { method(:api) } + context "scopes" do + let(:path) { "/user" } + let(:api_call) { method(:api) } - include_examples 'allows the "read_user" scope' + include_examples 'allows the "read_user" scope', version + end end - end - context 'with admin' do - let(:admin_personal_access_token) { create(:personal_access_token, user: admin).token } + context 'with admin' do + let(:admin_personal_access_token) { create(:personal_access_token, user: admin).token } - context 'with personal access token' do - it 'returns 403 without private token when sudo defined' do - get api("/user?private_token=#{admin_personal_access_token}&sudo=#{user.id}") + context 'with personal access token' do + it 'returns 403 without private token when sudo defined' do + get api("/user?private_token=#{admin_personal_access_token}&sudo=#{user.id}", version: version) - expect(response).to have_gitlab_http_status(403) - end + expect(response).to have_gitlab_http_status(403) + end - it 'returns initial current user without private token but with is_admin when sudo not defined' do - get api("/user?private_token=#{admin_personal_access_token}") + it 'returns initial current user without private token but with is_admin when sudo not defined' do + get api("/user?private_token=#{admin_personal_access_token}", version: version) - expect(response).to have_gitlab_http_status(200) - expect(response).to match_response_schema('public_api/v4/user/admin') - expect(json_response['id']).to eq(admin.id) + expect(response).to have_gitlab_http_status(200) + expect(response).to match_response_schema('public_api/v4/user/admin') + expect(json_response['id']).to eq(admin.id) + end end end - end - context 'with unauthenticated user' do - it "returns 401 error if user is unauthenticated" do - get api("/user") + context 'with unauthenticated user' do + it "returns 401 error if user is unauthenticated" do + get api("/user", version: version) - expect(response).to have_gitlab_http_status(401) + expect(response).to have_gitlab_http_status(401) + end end end + + it_behaves_like 'get user info', 'v3' + it_behaves_like 'get user info', 'v4' end describe "GET /user/keys" do diff --git a/spec/support/api/scopes/read_user_shared_examples.rb b/spec/support/api/scopes/read_user_shared_examples.rb index 06ae8792c61..d7cef137989 100644 --- a/spec/support/api/scopes/read_user_shared_examples.rb +++ b/spec/support/api/scopes/read_user_shared_examples.rb @@ -1,10 +1,12 @@ -shared_examples_for 'allows the "read_user" scope' do +shared_examples_for 'allows the "read_user" scope' do |api_version| + let(:version) { api_version || 'v4' } + context 'for personal access tokens' do context 'when the requesting token has the "api" scope' do let(:token) { create(:personal_access_token, scopes: ['api'], user: user) } it 'returns a "200" response' do - get api_call.call(path, user, personal_access_token: token) + get api_call.call(path, user, personal_access_token: token, version: version) expect(response).to have_gitlab_http_status(200) end @@ -14,7 +16,7 @@ shared_examples_for 'allows the "read_user" scope' do let(:token) { create(:personal_access_token, scopes: ['read_user'], user: user) } it 'returns a "200" response' do - get api_call.call(path, user, personal_access_token: token) + get api_call.call(path, user, personal_access_token: token, version: version) expect(response).to have_gitlab_http_status(200) end @@ -28,7 +30,7 @@ shared_examples_for 'allows the "read_user" scope' do end it 'returns a "403" response' do - get api_call.call(path, user, personal_access_token: token) + get api_call.call(path, user, personal_access_token: token, version: version) expect(response).to have_gitlab_http_status(403) end -- cgit v1.2.1 From 9a37ef438e52fd33bb592f1b5cf637ecc2bb962d Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Wed, 13 Jun 2018 19:39:47 +1100 Subject: [Rails5] Fix `storage_counter` helper Since rails 5 beta 2 support of petabytes and exabytes were added to the `number_to_human*` methods. See https://github.com/rails/rails/pull/22759 So for rails5 the comma separator gets shown for big numbers (EBs). --- spec/helpers/storage_helper_spec.rb | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/helpers/storage_helper_spec.rb b/spec/helpers/storage_helper_spec.rb index 4627a1e1872..c580b78c908 100644 --- a/spec/helpers/storage_helper_spec.rb +++ b/spec/helpers/storage_helper_spec.rb @@ -1,21 +1,25 @@ -require 'spec_helper' +require "spec_helper" describe StorageHelper do - describe '#storage_counter' do - it 'formats bytes to one decimal place' do - expect(helper.storage_counter(1.23.megabytes)).to eq '1.2 MB' + describe "#storage_counter" do + it "formats bytes to one decimal place" do + expect(helper.storage_counter(1.23.megabytes)).to eq("1.2 MB") end - it 'does not add decimals for sizes < 1 MB' do - expect(helper.storage_counter(23.5.kilobytes)).to eq '24 KB' + it "does not add decimals for sizes < 1 MB" do + expect(helper.storage_counter(23.5.kilobytes)).to eq("24 KB") end - it 'does not add decimals for zeroes' do - expect(helper.storage_counter(2.megabytes)).to eq '2 MB' + it "does not add decimals for zeroes" do + expect(helper.storage_counter(2.megabytes)).to eq("2 MB") end - it 'uses commas as thousands separator' do - expect(helper.storage_counter(100_000_000_000_000_000)).to eq '90,949.5 TB' + it "uses commas as thousands separator" do + if Gitlab.rails5? + expect(helper.storage_counter(100_000_000_000_000_000_000_000)).to eq("86,736.2 EB") + else + expect(helper.storage_counter(100_000_000_000_000_000)).to eq("90,949.5 TB") + end end end end -- cgit v1.2.1 From 9d9d952c1172e2b68bd4537a0ce05f96eae7b340 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Wed, 13 Jun 2018 10:10:24 +0100 Subject: moved strings into constants file --- spec/javascripts/ide/components/commit_sidebar/list_spec.js | 1 + 1 file changed, 1 insertion(+) (limited to 'spec') diff --git a/spec/javascripts/ide/components/commit_sidebar/list_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_spec.js index a37cbd5a596..6fb52378386 100644 --- a/spec/javascripts/ide/components/commit_sidebar/list_spec.js +++ b/spec/javascripts/ide/components/commit_sidebar/list_spec.js @@ -18,6 +18,7 @@ describe('Multi-file editor commit sidebar list', () => { actionBtnText: 'stage all', itemActionComponent: 'stage-button', activeFileKey: 'staged-testing', + keyPrefix: 'staged', }); vm.$store.state.rightPanelCollapsed = false; -- cgit v1.2.1 From cf22366d79e2a3a332de3d7729c14dcffe45cd98 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 12 Jun 2018 14:12:39 +0100 Subject: Resets state correctly when switching to merge request in IDE Closes #47763 --- spec/javascripts/ide/components/repo_editor_spec.js | 11 +++++++++++ .../ide/stores/modules/merge_requests/actions_spec.js | 13 +++++++------ .../ide/stores/modules/pipelines/actions_spec.js | 17 +++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) (limited to 'spec') diff --git a/spec/javascripts/ide/components/repo_editor_spec.js b/spec/javascripts/ide/components/repo_editor_spec.js index d318521d0a0..2256deb7dac 100644 --- a/spec/javascripts/ide/components/repo_editor_spec.js +++ b/spec/javascripts/ide/components/repo_editor_spec.js @@ -315,6 +315,17 @@ describe('RepoEditor', () => { done(); }); }); + + it('calls updateDimensions when rightPane is updated', done => { + vm.$store.state.rightPane = 'testing'; + + vm.$nextTick(() => { + expect(vm.editor.updateDimensions).toHaveBeenCalled(); + expect(vm.editor.updateDiffView).toHaveBeenCalled(); + + done(); + }); + }); }); describe('show tabs', () => { diff --git a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js index 03ec08d05c3..fa4c18931e5 100644 --- a/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/merge_requests/actions_spec.js @@ -208,18 +208,19 @@ describe('IDE merge requests actions', () => { expect(commit.calls.argsFor(1)).toEqual(['SET_CURRENT_MERGE_REQUEST', '1', { root: true }]); expect(commit.calls.argsFor(2)).toEqual(['RESET_OPEN_FILES', null, { root: true }]); - expect(dispatch.calls.argsFor(0)).toEqual([ - 'pipelines/resetLatestPipeline', + expect(dispatch.calls.argsFor(0)).toEqual(['setCurrentBranchId', '', { root: true }]); + expect(dispatch.calls.argsFor(1)).toEqual([ + 'pipelines/stopPipelinePolling', null, { root: true }, ]); - expect(dispatch.calls.argsFor(1)).toEqual(['setCurrentBranchId', '', { root: true }]); - expect(dispatch.calls.argsFor(2)).toEqual([ - 'pipelines/stopPipelinePolling', + expect(dispatch.calls.argsFor(2)).toEqual(['setRightPane', null, { root: true }]); + expect(dispatch.calls.argsFor(3)).toEqual([ + 'pipelines/resetLatestPipeline', null, { root: true }, ]); - expect(dispatch.calls.argsFor(3)).toEqual([ + expect(dispatch.calls.argsFor(4)).toEqual([ 'pipelines/clearEtagPoll', null, { root: true }, diff --git a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js index f2f8e780cd1..f47e69d6e5b 100644 --- a/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js +++ b/spec/javascripts/ide/stores/modules/pipelines/actions_spec.js @@ -18,6 +18,7 @@ import actions, { receiveJobTraceError, receiveJobTraceSuccess, fetchJobTrace, + resetLatestPipeline, } from '~/ide/stores/modules/pipelines/actions'; import state from '~/ide/stores/modules/pipelines/state'; import * as types from '~/ide/stores/modules/pipelines/mutation_types'; @@ -416,4 +417,20 @@ describe('IDE pipelines actions', () => { }); }); }); + + describe('resetLatestPipeline', () => { + it('commits reset mutations', done => { + testAction( + resetLatestPipeline, + null, + mockedState, + [ + { type: types.RECEIVE_LASTEST_PIPELINE_SUCCESS, payload: null }, + { type: types.SET_DETAIL_JOB, payload: null }, + ], + [], + done, + ); + }); + }); }); -- cgit v1.2.1 From 8a23bcc9bc0f7ab453ee09d41a9407d40d57ba4c Mon Sep 17 00:00:00 2001 From: Tim Zallmann Date: Wed, 13 Jun 2018 09:35:52 +0000 Subject: Image Diff Viewing + Download Diff Viewing --- spec/javascripts/fixtures/images/green_box.png | Bin 0 -> 1306 bytes spec/javascripts/fixtures/images/red_box.png | Bin 0 -> 1305 bytes spec/javascripts/ide/stores/mutations/file_spec.js | 47 ++++++ spec/javascripts/test_constants.js | 3 + .../content_viewer/content_viewer_spec.js | 10 +- .../components/diff_viewer/diff_viewer_spec.js | 70 ++++++++ .../diff_viewer/viewers/image_diff_viewer_spec.js | 185 +++++++++++++++++++++ .../components/lib/utils/dom_utils_spec.js | 13 ++ 8 files changed, 323 insertions(+), 5 deletions(-) create mode 100644 spec/javascripts/fixtures/images/green_box.png create mode 100644 spec/javascripts/fixtures/images/red_box.png create mode 100644 spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js create mode 100644 spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js create mode 100644 spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js (limited to 'spec') diff --git a/spec/javascripts/fixtures/images/green_box.png b/spec/javascripts/fixtures/images/green_box.png new file mode 100644 index 00000000000..cd1ff9f9ade Binary files /dev/null and b/spec/javascripts/fixtures/images/green_box.png differ diff --git a/spec/javascripts/fixtures/images/red_box.png b/spec/javascripts/fixtures/images/red_box.png new file mode 100644 index 00000000000..73b2927da0f Binary files /dev/null and b/spec/javascripts/fixtures/images/red_box.png differ diff --git a/spec/javascripts/ide/stores/mutations/file_spec.js b/spec/javascripts/ide/stores/mutations/file_spec.js index e83961fcedc..52f83be8e8c 100644 --- a/spec/javascripts/ide/stores/mutations/file_spec.js +++ b/spec/javascripts/ide/stores/mutations/file_spec.js @@ -152,6 +152,53 @@ describe('IDE store file mutations', () => { expect(localFile.mrChange.diff).toBe('ABC'); }); + + it('has diffMode replaced by default', () => { + mutations.SET_FILE_MERGE_REQUEST_CHANGE(localState, { + file: localFile, + mrChange: { + diff: 'ABC', + }, + }); + + expect(localFile.mrChange.diffMode).toBe('replaced'); + }); + + it('has diffMode new', () => { + mutations.SET_FILE_MERGE_REQUEST_CHANGE(localState, { + file: localFile, + mrChange: { + diff: 'ABC', + new_file: true, + }, + }); + + expect(localFile.mrChange.diffMode).toBe('new'); + }); + + it('has diffMode deleted', () => { + mutations.SET_FILE_MERGE_REQUEST_CHANGE(localState, { + file: localFile, + mrChange: { + diff: 'ABC', + deleted_file: true, + }, + }); + + expect(localFile.mrChange.diffMode).toBe('deleted'); + }); + + it('has diffMode renamed', () => { + mutations.SET_FILE_MERGE_REQUEST_CHANGE(localState, { + file: localFile, + mrChange: { + diff: 'ABC', + renamed_file: true, + }, + }); + + expect(localFile.mrChange.diffMode).toBe('renamed'); + }); }); describe('DISCARD_FILE_CHANGES', () => { diff --git a/spec/javascripts/test_constants.js b/spec/javascripts/test_constants.js index df59195e9f6..a820dd2d09c 100644 --- a/spec/javascripts/test_constants.js +++ b/spec/javascripts/test_constants.js @@ -2,3 +2,6 @@ export const FIXTURES_PATH = '/base/spec/javascripts/fixtures'; export const TEST_HOST = 'http://test.host'; export const DUMMY_IMAGE_URL = `${FIXTURES_PATH}/one_white_pixel.png`; + +export const GREEN_BOX_IMAGE_URL = `${FIXTURES_PATH}/images/green_box.png`; +export const RED_BOX_IMAGE_URL = `${FIXTURES_PATH}/images/red_box.png`; diff --git a/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js b/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js index 383f0cd29ea..e2c34508b0d 100644 --- a/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js +++ b/spec/javascripts/vue_shared/components/content_viewer/content_viewer_spec.js @@ -3,6 +3,7 @@ import MockAdapter from 'axios-mock-adapter'; import axios from '~/lib/utils/axios_utils'; import contentViewer from '~/vue_shared/components/content_viewer/content_viewer.vue'; import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import { GREEN_BOX_IMAGE_URL } from 'spec/test_constants'; describe('ContentViewer', () => { let vm; @@ -41,12 +42,12 @@ describe('ContentViewer', () => { it('renders image preview', done => { createComponent({ - path: 'test.jpg', + path: GREEN_BOX_IMAGE_URL, fileSize: 1024, }); setTimeout(() => { - expect(vm.$el.querySelector('.image_file img').getAttribute('src')).toBe('test.jpg'); + expect(vm.$el.querySelector('.image_file img').getAttribute('src')).toBe(GREEN_BOX_IMAGE_URL); done(); }); @@ -59,9 +60,8 @@ describe('ContentViewer', () => { }); setTimeout(() => { - expect(vm.$el.querySelector('.file-info').textContent.trim()).toContain( - 'test.abc (1.00 KiB)', - ); + expect(vm.$el.querySelector('.file-info').textContent.trim()).toContain('test.abc'); + expect(vm.$el.querySelector('.file-info').textContent.trim()).toContain('(1.00 KiB)'); expect(vm.$el.querySelector('.btn.btn-default').textContent.trim()).toContain('Download'); done(); diff --git a/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js b/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js new file mode 100644 index 00000000000..71d9145bf22 --- /dev/null +++ b/spec/javascripts/vue_shared/components/diff_viewer/diff_viewer_spec.js @@ -0,0 +1,70 @@ +import Vue from 'vue'; +import diffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import { GREEN_BOX_IMAGE_URL, RED_BOX_IMAGE_URL } from 'spec/test_constants'; + +describe('DiffViewer', () => { + let vm; + + function createComponent(props) { + const DiffViewer = Vue.extend(diffViewer); + vm = mountComponent(DiffViewer, props); + } + + afterEach(() => { + vm.$destroy(); + }); + + it('renders image diff', done => { + window.gon = { + relative_url_root: '', + }; + + createComponent({ + diffMode: 'replaced', + newPath: GREEN_BOX_IMAGE_URL, + newSha: 'ABC', + oldPath: RED_BOX_IMAGE_URL, + oldSha: 'DEF', + projectPath: '', + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.deleted .image_file img').getAttribute('src')).toBe( + `//raw/DEF/${RED_BOX_IMAGE_URL}`, + ); + + expect(vm.$el.querySelector('.added .image_file img').getAttribute('src')).toBe( + `//raw/ABC/${GREEN_BOX_IMAGE_URL}`, + ); + + done(); + }); + }); + + it('renders fallback download diff display', done => { + createComponent({ + diffMode: 'replaced', + newPath: 'test.abc', + newSha: 'ABC', + oldPath: 'testold.abc', + oldSha: 'DEF', + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.deleted .file-info').textContent.trim()).toContain( + 'testold.abc', + ); + expect(vm.$el.querySelector('.deleted .btn.btn-default').textContent.trim()).toContain( + 'Download', + ); + + expect(vm.$el.querySelector('.added .file-info').textContent.trim()).toContain('test.abc'); + expect(vm.$el.querySelector('.added .btn.btn-default').textContent.trim()).toContain( + 'Download', + ); + + done(); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js b/spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js new file mode 100644 index 00000000000..b878286ae3f --- /dev/null +++ b/spec/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer_spec.js @@ -0,0 +1,185 @@ +import Vue from 'vue'; +import imageDiffViewer from '~/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue'; +import mountComponent from 'spec/helpers/vue_mount_component_helper'; +import { GREEN_BOX_IMAGE_URL, RED_BOX_IMAGE_URL } from 'spec/test_constants'; + +describe('ImageDiffViewer', () => { + let vm; + + function createComponent(props) { + const ImageDiffViewer = Vue.extend(imageDiffViewer); + vm = mountComponent(ImageDiffViewer, props); + } + + const triggerEvent = (eventName, el = vm.$el, clientX = 0) => { + const event = document.createEvent('MouseEvents'); + event.initMouseEvent( + eventName, + true, + true, + window, + 1, + clientX, + 0, + clientX, + 0, + false, + false, + false, + false, + 0, + null, + ); + + el.dispatchEvent(event); + }; + + const dragSlider = (sliderElement, dragPixel = 20) => { + triggerEvent('mousedown', sliderElement); + triggerEvent('mousemove', document.body, dragPixel); + triggerEvent('mouseup', document.body); + }; + + afterEach(() => { + vm.$destroy(); + }); + + it('renders image diff for replaced', done => { + createComponent({ + diffMode: 'replaced', + newPath: GREEN_BOX_IMAGE_URL, + oldPath: RED_BOX_IMAGE_URL, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.added .image_file img').getAttribute('src')).toBe( + GREEN_BOX_IMAGE_URL, + ); + expect(vm.$el.querySelector('.deleted .image_file img').getAttribute('src')).toBe( + RED_BOX_IMAGE_URL, + ); + + expect(vm.$el.querySelector('.view-modes-menu li.active').textContent.trim()).toBe('2-up'); + expect(vm.$el.querySelector('.view-modes-menu li:nth-child(2)').textContent.trim()).toBe( + 'Swipe', + ); + expect(vm.$el.querySelector('.view-modes-menu li:nth-child(3)').textContent.trim()).toBe( + 'Onion skin', + ); + + done(); + }); + }); + + it('renders image diff for new', done => { + createComponent({ + diffMode: 'new', + newPath: GREEN_BOX_IMAGE_URL, + oldPath: '', + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.added .image_file img').getAttribute('src')).toBe( + GREEN_BOX_IMAGE_URL, + ); + + done(); + }); + }); + + it('renders image diff for deleted', done => { + createComponent({ + diffMode: 'deleted', + newPath: '', + oldPath: RED_BOX_IMAGE_URL, + }); + + setTimeout(() => { + expect(vm.$el.querySelector('.deleted .image_file img').getAttribute('src')).toBe( + RED_BOX_IMAGE_URL, + ); + + done(); + }); + }); + + describe('swipeMode', () => { + beforeEach(done => { + createComponent({ + diffMode: 'replaced', + newPath: GREEN_BOX_IMAGE_URL, + oldPath: RED_BOX_IMAGE_URL, + }); + + setTimeout(() => { + done(); + }); + }); + + it('switches to Swipe Mode', done => { + vm.$el.querySelector('.view-modes-menu li:nth-child(2)').click(); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.view-modes-menu li.active').textContent.trim()).toBe('Swipe'); + done(); + }); + }); + + it('drag handler is working', done => { + vm.$el.querySelector('.view-modes-menu li:nth-child(2)').click(); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.swipe-bar').style.left).toBe('1px'); + expect(vm.$el.querySelector('.top-handle')).not.toBeNull(); + + dragSlider(vm.$el.querySelector('.swipe-bar'), 40); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.swipe-bar').style.left).toBe('-20px'); + done(); + }); + }); + }); + }); + + describe('onionSkin', () => { + beforeEach(done => { + createComponent({ + diffMode: 'replaced', + newPath: GREEN_BOX_IMAGE_URL, + oldPath: RED_BOX_IMAGE_URL, + }); + + setTimeout(() => { + done(); + }); + }); + + it('switches to Onion Skin Mode', done => { + vm.$el.querySelector('.view-modes-menu li:nth-child(3)').click(); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.view-modes-menu li.active').textContent.trim()).toBe( + 'Onion skin', + ); + done(); + }); + }); + + it('has working drag handler', done => { + vm.$el.querySelector('.view-modes-menu li:nth-child(3)').click(); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.dragger').style.left).toBe('100px'); + + dragSlider(vm.$el.querySelector('.dragger')); + + vm.$nextTick(() => { + expect(vm.$el.querySelector('.dragger').style.left).toBe('20px'); + expect(vm.$el.querySelector('.added.frame').style.opacity).toBe('0.2'); + done(); + }); + }); + }); + }); +}); diff --git a/spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js b/spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js new file mode 100644 index 00000000000..2388660b0c2 --- /dev/null +++ b/spec/javascripts/vue_shared/components/lib/utils/dom_utils_spec.js @@ -0,0 +1,13 @@ +import * as domUtils from '~/vue_shared/components/lib/utils/dom_utils'; + +describe('domUtils', () => { + describe('pixeliseValue', () => { + it('should add px to a given Number', () => { + expect(domUtils.pixeliseValue(12)).toEqual('12px'); + }); + + it('should not add px to 0', () => { + expect(domUtils.pixeliseValue(0)).toEqual(''); + }); + }); +}); -- cgit v1.2.1 From 1721bbcb013eed3c98c81d615087dd79dddb65be Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 13 Jun 2018 10:23:57 +0000 Subject: Resolve "Quick actions are case sensitive" --- spec/lib/gitlab/quick_actions/extractor_spec.rb | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/quick_actions/extractor_spec.rb b/spec/lib/gitlab/quick_actions/extractor_spec.rb index f7c288f2393..0166f6c2ee0 100644 --- a/spec/lib/gitlab/quick_actions/extractor_spec.rb +++ b/spec/lib/gitlab/quick_actions/extractor_spec.rb @@ -182,6 +182,14 @@ describe Gitlab::QuickActions::Extractor do expect(msg).to eq "hello\nworld" end + it 'extracts command case insensitive' do + msg = %(hello\n/PoWer @user.name %9.10 ~"bar baz.2"\nworld) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['power', '@user.name %9.10 ~"bar baz.2"']] + expect(msg).to eq "hello\nworld" + end + it 'does not extract noop commands' do msg = %(hello\nworld\n/reopen\n/noop_command) msg, commands = extractor.extract_commands(msg) @@ -206,6 +214,14 @@ describe Gitlab::QuickActions::Extractor do expect(msg).to eq "hello\nworld\nthis is great? SHRUG" end + it 'extracts and performs substitution commands case insensitive' do + msg = %(hello\nworld\n/reOpen\n/sHRuG this is great?) + msg, commands = extractor.extract_commands(msg) + + expect(commands).to eq [['reopen'], ['shrug', 'this is great?']] + expect(msg).to eq "hello\nworld\nthis is great? SHRUG" + end + it 'extracts and performs substitution commands with comments' do msg = %(hello\nworld\n/reopen\n/substitution wow this is a thing.) msg, commands = extractor.extract_commands(msg) -- cgit v1.2.1 From 4077d4f735ed40b7a62baa35464677813c3b6784 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 13 Jun 2018 10:28:27 +0000 Subject: Resolve "Provide ability to retrieve `visibility` level via Snippets API" --- spec/fixtures/api/schemas/public_api/v4/snippets.json | 1 + spec/requests/api/snippets_spec.rb | 3 +++ 2 files changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/fixtures/api/schemas/public_api/v4/snippets.json b/spec/fixtures/api/schemas/public_api/v4/snippets.json index e37e9704649..d13d703e063 100644 --- a/spec/fixtures/api/schemas/public_api/v4/snippets.json +++ b/spec/fixtures/api/schemas/public_api/v4/snippets.json @@ -8,6 +8,7 @@ "title": { "type": "string" }, "file_name": { "type": ["string", "null"] }, "description": { "type": ["string", "null"] }, + "visibility": { "type": "string" }, "web_url": { "type": "string" }, "created_at": { "type": "date" }, "updated_at": { "type": "date" }, diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb index b3e253befc6..c5456977b60 100644 --- a/spec/requests/api/snippets_spec.rb +++ b/spec/requests/api/snippets_spec.rb @@ -20,6 +20,7 @@ describe API::Snippets do private_snippet.id) expect(json_response.last).to have_key('web_url') expect(json_response.last).to have_key('raw_url') + expect(json_response.last).to have_key('visibility') end it 'hides private snippets from regular user' do @@ -112,6 +113,7 @@ describe API::Snippets do expect(json_response['title']).to eq(snippet.title) expect(json_response['description']).to eq(snippet.description) expect(json_response['file_name']).to eq(snippet.file_name) + expect(json_response['visibility']).to eq(snippet.visibility) end it 'returns 404 for invalid snippet id' do @@ -142,6 +144,7 @@ describe API::Snippets do expect(json_response['title']).to eq(params[:title]) expect(json_response['description']).to eq(params[:description]) expect(json_response['file_name']).to eq(params[:file_name]) + expect(json_response['visibility']).to eq(params[:visibility]) end it 'returns 400 for missing parameters' do -- cgit v1.2.1 From 6d902e07d908769a909db0bf93d84f5be28720af Mon Sep 17 00:00:00 2001 From: Jan Provaznik Date: Wed, 13 Jun 2018 13:21:12 +0200 Subject: Fix shoulda-matchers in Rails 5 Backports a fix for https://github.com/thoughtbot/shoulda-matchers/issues/913. This can be removed once new shoulda-matchers version is released. --- spec/support/shoulda/matchers/rails_shim.rb | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 spec/support/shoulda/matchers/rails_shim.rb (limited to 'spec') diff --git a/spec/support/shoulda/matchers/rails_shim.rb b/spec/support/shoulda/matchers/rails_shim.rb new file mode 100644 index 00000000000..8d70598beb5 --- /dev/null +++ b/spec/support/shoulda/matchers/rails_shim.rb @@ -0,0 +1,27 @@ +# monkey patch which fixes serialization matcher in Rails 5 +# https://github.com/thoughtbot/shoulda-matchers/issues/913 +# This can be removed when a new version of shoulda-matchers +# is released +module Shoulda + module Matchers + class RailsShim + def self.serialized_attributes_for(model) + if defined?(::ActiveRecord::Type::Serialized) + # Rails 5+ + serialized_columns = model.columns.select do |column| + model.type_for_attribute(column.name).is_a?( + ::ActiveRecord::Type::Serialized + ) + end + + serialized_columns.inject({}) do |hash, column| # rubocop:disable Style/EachWithObject + hash[column.name.to_s] = model.type_for_attribute(column.name).coder + hash + end + else + model.serialized_attributes + end + end + end + end +end -- cgit v1.2.1 From 5ba9279c5039615fd797beab273f3c1aeb642dd0 Mon Sep 17 00:00:00 2001 From: Jan Date: Wed, 13 Jun 2018 12:42:36 +0000 Subject: Resolve "Add `/confidential` quick action for issues" --- .../issues/user_uses_slash_commands_spec.rb | 36 ++++++++++++++++++++++ .../quick_actions/interpret_service_spec.rb | 18 +++++++++++ 2 files changed, 54 insertions(+) (limited to 'spec') diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb index fd0aa6cf3a3..dacca494755 100644 --- a/spec/features/issues/user_uses_slash_commands_spec.rb +++ b/spec/features/issues/user_uses_slash_commands_spec.rb @@ -153,6 +153,42 @@ feature 'Issues > User uses quick actions', :js do end end + describe 'make issue confidential' do + let(:issue) { create(:issue, project: project) } + let(:original_issue) { create(:issue, project: project) } + + context 'when the current user can update issues' do + it 'does not create a note, and marks the issue as confidential' do + add_note("/confidential") + + expect(page).not_to have_content "/confidential" + expect(page).to have_content 'Commands applied' + expect(page).to have_content "made the issue confidential" + + expect(issue.reload).to be_confidential + end + end + + context 'when the current user cannot update the issue' do + let(:guest) { create(:user) } + before do + project.add_guest(guest) + gitlab_sign_out + sign_in(guest) + visit project_issue_path(project, issue) + end + + it 'does not create a note, and does not mark the issue as confidential' do + add_note("/confidential") + + expect(page).not_to have_content 'Commands applied' + expect(page).not_to have_content "made the issue confidential" + + expect(issue.reload).not_to be_confidential + end + end + end + describe 'move the issue to another project' do let(:issue) { create(:issue, project: project) } diff --git a/spec/services/quick_actions/interpret_service_spec.rb b/spec/services/quick_actions/interpret_service_spec.rb index bd835a1fca6..743e281183e 100644 --- a/spec/services/quick_actions/interpret_service_spec.rb +++ b/spec/services/quick_actions/interpret_service_spec.rb @@ -323,6 +323,14 @@ describe QuickActions::InterpretService do end end + shared_examples 'confidential command' do + it 'marks issue as confidential if content contains /confidential' do + _, updates = service.execute(content, issuable) + + expect(updates).to eq(confidential: true) + end + end + shared_examples 'shrug command' do it 'appends ¯\_(ツ)_/¯ to the comment' do new_content, _ = service.execute(content, issuable) @@ -774,6 +782,11 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end + it_behaves_like 'confidential command' do + let(:content) { '/confidential' } + let(:issuable) { issue } + end + context '/copy_metadata command' do let(:todo_label) { create(:label, project: project, title: 'To Do') } let(:inreview_label) { create(:label, project: project, title: 'In Review') } @@ -918,6 +931,11 @@ describe QuickActions::InterpretService do let(:issuable) { issue } end + it_behaves_like 'empty command' do + let(:content) { '/confidential' } + let(:issuable) { issue } + end + it_behaves_like 'empty command' do let(:content) { '/duplicate #{issue.to_reference}' } let(:issuable) { issue } -- cgit v1.2.1 From e4a9b0771abdcd4e478cfc763ca7fcecc99ae505 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 13 Jun 2018 15:23:34 +0200 Subject: ListCommitByOid isn't called with an empty batch Batching commits for performance improvements, might lead to empty batches being used. This isn't the case yet, but to guard against this in future cases, a guard clause is added. --- spec/lib/gitlab/git/commit_spec.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb index 5af982c7a54..ae69a362dda 100644 --- a/spec/lib/gitlab/git/commit_spec.rb +++ b/spec/lib/gitlab/git/commit_spec.rb @@ -421,6 +421,16 @@ describe Gitlab::Git::Commit, seed_helper: true do end end + describe '#batch_by_oid' do + context 'when oids is empty' do + it 'makes no Gitaly request' do + expect(Gitlab::GitalyClient).not_to receive(:call) + + described_class.batch_by_oid(repository, []) + end + end + end + shared_examples 'extracting commit signature' do context 'when the commit is signed' do let(:commit_id) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } -- cgit v1.2.1 From 0e2577229d8e12fdb02a156fcc6672ebc6bb3f5d Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 13 Jun 2018 16:36:43 +0200 Subject: Move GC RPCs to mandatory Closes https://gitlab.com/gitlab-org/gitaly/issues/354 --- spec/workers/git_garbage_collect_worker_spec.rb | 117 +++++++++--------------- 1 file changed, 45 insertions(+), 72 deletions(-) (limited to 'spec') diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb index 807d1b8c084..e39dec556fc 100644 --- a/spec/workers/git_garbage_collect_worker_spec.rb +++ b/spec/workers/git_garbage_collect_worker_spec.rb @@ -11,36 +11,63 @@ describe GitGarbageCollectWorker do subject { described_class.new } describe "#perform" do - shared_examples 'flushing ref caches' do |gitaly| - context 'with active lease_uuid' do + context 'with active lease_uuid' do + before do + allow(subject).to receive(:get_lease_uuid).and_return(lease_uuid) + end + + it "flushes ref caches when the task if 'gc'" do + expect(subject).to receive(:renew_lease).with(lease_key, lease_uuid).and_call_original + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect) + .and_return(nil) + expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original + expect_any_instance_of(Repository).to receive(:branch_names).and_call_original + expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original + expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original + + subject.perform(project.id, :gc, lease_key, lease_uuid) + end + end + + context 'with different lease than the active one' do + before do + allow(subject).to receive(:get_lease_uuid).and_return(SecureRandom.uuid) + end + + it 'returns silently' do + expect_any_instance_of(Repository).not_to receive(:after_create_branch).and_call_original + expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original + expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original + + subject.perform(project.id, :gc, lease_key, lease_uuid) + end + end + + context 'with no active lease' do + before do + allow(subject).to receive(:get_lease_uuid).and_return(false) + end + + context 'when is able to get the lease' do before do - allow(subject).to receive(:get_lease_uuid).and_return(lease_uuid) + allow(subject).to receive(:try_obtain_lease).and_return(SecureRandom.uuid) end it "flushes ref caches when the task if 'gc'" do - expect(subject).to receive(:renew_lease).with(lease_key, lease_uuid).and_call_original - expect(subject).to receive(:command).with(:gc).and_return([:the, :command]) - - if gitaly - expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect) - .and_return(nil) - else - expect(Gitlab::Popen).to receive(:popen) - .with([:the, :command], project.repository.path_to_repo).and_return(["", 0]) - end - + expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect) + .and_return(nil) expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original expect_any_instance_of(Repository).to receive(:branch_names).and_call_original expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original - subject.perform(project.id, :gc, lease_key, lease_uuid) + subject.perform(project.id) end end - context 'with different lease than the active one' do + context 'when no lease can be obtained' do before do - allow(subject).to receive(:get_lease_uuid).and_return(SecureRandom.uuid) + expect(subject).to receive(:try_obtain_lease).and_return(false) end it 'returns silently' do @@ -49,63 +76,9 @@ describe GitGarbageCollectWorker do expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original - subject.perform(project.id, :gc, lease_key, lease_uuid) + subject.perform(project.id) end end - - context 'with no active lease' do - before do - allow(subject).to receive(:get_lease_uuid).and_return(false) - end - - context 'when is able to get the lease' do - before do - allow(subject).to receive(:try_obtain_lease).and_return(SecureRandom.uuid) - end - - it "flushes ref caches when the task if 'gc'" do - expect(subject).to receive(:command).with(:gc).and_return([:the, :command]) - - if gitaly - expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:garbage_collect) - .and_return(nil) - else - expect(Gitlab::Popen).to receive(:popen) - .with([:the, :command], project.repository.path_to_repo).and_return(["", 0]) - end - - expect_any_instance_of(Repository).to receive(:after_create_branch).and_call_original - expect_any_instance_of(Repository).to receive(:branch_names).and_call_original - expect_any_instance_of(Repository).to receive(:has_visible_content?).and_call_original - expect_any_instance_of(Gitlab::Git::Repository).to receive(:has_visible_content?).and_call_original - - subject.perform(project.id) - end - end - - context 'when no lease can be obtained' do - before do - expect(subject).to receive(:try_obtain_lease).and_return(false) - end - - it 'returns silently' do - expect(subject).not_to receive(:command) - expect_any_instance_of(Repository).not_to receive(:after_create_branch).and_call_original - expect_any_instance_of(Repository).not_to receive(:branch_names).and_call_original - expect_any_instance_of(Repository).not_to receive(:has_visible_content?).and_call_original - - subject.perform(project.id) - end - end - end - end - - context "with Gitaly turned on" do - it_should_behave_like 'flushing ref caches', true - end - - context "with Gitaly turned off", :disable_gitaly do - it_should_behave_like 'flushing ref caches', false end context "repack_full" do -- cgit v1.2.1 From f195a7436d8848cccc8888f2de047547fa9eb94f Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Wed, 13 Jun 2018 16:44:59 +0200 Subject: RawBlame only called through Gitaly Closes https://gitlab.com/gitlab-org/gitaly/issues/376 --- spec/lib/gitlab/git/blame_spec.rb | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/git/blame_spec.rb b/spec/lib/gitlab/git/blame_spec.rb index 793228701cf..ba790b717ae 100644 --- a/spec/lib/gitlab/git/blame_spec.rb +++ b/spec/lib/gitlab/git/blame_spec.rb @@ -7,7 +7,7 @@ describe Gitlab::Git::Blame, seed_helper: true do Gitlab::Git::Blame.new(repository, SeedRepo::Commit::ID, "CONTRIBUTING.md") end - shared_examples 'blaming a file' do + describe 'blaming a file' do context "each count" do it do data = [] @@ -68,12 +68,4 @@ describe Gitlab::Git::Blame, seed_helper: true do end end end - - context 'when Gitaly blame feature is enabled' do - it_behaves_like 'blaming a file' - end - - context 'when Gitaly blame feature is disabled', :skip_gitaly_mock do - it_behaves_like 'blaming a file' - end end -- cgit v1.2.1 From 7fe92d998125d3dc8be3544346de8dbd5c64b240 Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Wed, 13 Jun 2018 16:05:55 +0200 Subject: Render access denied without message The `errors/access_denied` page should not fail to render when no message is provided. When accessing something as a sessionless user, we should also display the terms message if possible. --- spec/controllers/application_controller_spec.rb | 10 ++++++++++ spec/views/errors/access_denied.html.haml_spec.rb | 7 +++++++ 2 files changed, 17 insertions(+) create mode 100644 spec/views/errors/access_denied.html.haml_spec.rb (limited to 'spec') diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 773bf25ed44..fbafb4a4de8 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -458,6 +458,8 @@ describe ApplicationController do end context 'for sessionless users' do + render_views + before do sign_out user end @@ -468,6 +470,14 @@ describe ApplicationController do expect(response).to have_gitlab_http_status(403) end + it 'renders the error message when the format was html' do + get :index, + private_token: create(:personal_access_token, user: user).token, + format: :html + + expect(response.body).to have_content /accept the terms of service/i + end + it 'renders a 200 when the sessionless user accepted the terms' do accept_terms(user) diff --git a/spec/views/errors/access_denied.html.haml_spec.rb b/spec/views/errors/access_denied.html.haml_spec.rb new file mode 100644 index 00000000000..bde2f6f0169 --- /dev/null +++ b/spec/views/errors/access_denied.html.haml_spec.rb @@ -0,0 +1,7 @@ +require 'spec_helper' + +describe 'errors/access_denied' do + it 'does not fail to render when there is no message provided' do + expect { render }.not_to raise_error + end +end -- cgit v1.2.1 From b6996837ea992a98018caa0210f10ae6f3bcc9c0 Mon Sep 17 00:00:00 2001 From: Jasper Maes Date: Wed, 13 Jun 2018 17:35:39 +0200 Subject: Rails5 fix stack level too deep --- spec/controllers/application_controller_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 773bf25ed44..b35b220b440 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -502,7 +502,7 @@ describe ApplicationController do context '422 errors' do it 'logs a response with a string' do - response = spy(ActionDispatch::Response, status: 422, body: 'Hello world', content_type: 'application/json') + response = spy(ActionDispatch::Response, status: 422, body: 'Hello world', content_type: 'application/json', cookies: {}) allow(controller).to receive(:response).and_return(response) get :index @@ -511,7 +511,7 @@ describe ApplicationController do it 'logs a response with an array' do body = ['I want', 'my hat back'] - response = spy(ActionDispatch::Response, status: 422, body: body, content_type: 'application/json') + response = spy(ActionDispatch::Response, status: 422, body: body, content_type: 'application/json', cookies: {}) allow(controller).to receive(:response).and_return(response) get :index @@ -519,7 +519,7 @@ describe ApplicationController do end it 'does not log a string with an empty body' do - response = spy(ActionDispatch::Response, status: 422, body: nil, content_type: 'application/json') + response = spy(ActionDispatch::Response, status: 422, body: nil, content_type: 'application/json', cookies: {}) allow(controller).to receive(:response).and_return(response) get :index @@ -527,7 +527,7 @@ describe ApplicationController do end it 'does not log an HTML body' do - response = spy(ActionDispatch::Response, status: 422, body: 'This is a test', content_type: 'application/html') + response = spy(ActionDispatch::Response, status: 422, body: 'This is a test', content_type: 'application/html', cookies: {}) allow(controller).to receive(:response).and_return(response) get :index -- cgit v1.2.1 From 71e0d33e74fb5c571032be641130105fd3f6a4b6 Mon Sep 17 00:00:00 2001 From: Jasper Maes Date: Wed, 13 Jun 2018 17:48:27 +0200 Subject: Rails5 ActionController::ParameterMissing: param is missing or the value is empty: application_setting --- spec/controllers/admin/application_settings_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/controllers/admin/application_settings_controller_spec.rb b/spec/controllers/admin/application_settings_controller_spec.rb index b4fc2aa326f..9d10d725ff3 100644 --- a/spec/controllers/admin/application_settings_controller_spec.rb +++ b/spec/controllers/admin/application_settings_controller_spec.rb @@ -73,7 +73,7 @@ describe Admin::ApplicationSettingsController do end it 'updates the restricted_visibility_levels when empty array is passed' do - put :update, application_setting: { restricted_visibility_levels: [] } + put :update, application_setting: { restricted_visibility_levels: [""] } expect(response).to redirect_to(admin_application_settings_path) expect(ApplicationSetting.current.restricted_visibility_levels).to be_empty -- cgit v1.2.1 From 6a0178d8324964489654eb26fbefcb90bbcd1147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20D=C3=A1vila?= Date: Wed, 13 Jun 2018 11:57:18 -0500 Subject: Invalidate cache with project details when repository is updated The partial using this cache key was showing stale information due to the cache not being invalidated. --- spec/helpers/projects_helper_spec.rb | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'spec') diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index d372e58f63d..815b4035114 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -90,6 +90,10 @@ describe ProjectsHelper do expect(helper.project_list_cache_key(project)).to include(project.cache_key) end + it "includes the last activity date" do + expect(helper.project_list_cache_key(project)).to include(project.last_activity_date) + end + it "includes the controller name" do expect(helper.controller).to receive(:controller_name).and_return("testcontroller") -- cgit v1.2.1 From 2f40fb456bbc99fa4d3816696dd9ac612a21482c Mon Sep 17 00:00:00 2001 From: Michael Kozono Date: Wed, 13 Jun 2018 17:11:43 +0000 Subject: Add support for verifying remote uploads, artifacts, and LFS objects in check rake tasks --- spec/lib/gitlab/verify/job_artifacts_spec.rb | 29 +++++++++++++++++++++++++--- spec/lib/gitlab/verify/lfs_objects_spec.rb | 25 +++++++++++++++--------- spec/lib/gitlab/verify/uploads_spec.rb | 27 ++++++++++++++++---------- 3 files changed, 59 insertions(+), 22 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/verify/job_artifacts_spec.rb b/spec/lib/gitlab/verify/job_artifacts_spec.rb index ec490bdfde2..6e916a56564 100644 --- a/spec/lib/gitlab/verify/job_artifacts_spec.rb +++ b/spec/lib/gitlab/verify/job_artifacts_spec.rb @@ -21,15 +21,38 @@ describe Gitlab::Verify::JobArtifacts do FileUtils.rm_f(artifact.file.path) expect(failures.keys).to contain_exactly(artifact) - expect(failure).to be_a(Errno::ENOENT) - expect(failure.to_s).to include(artifact.file.path) + expect(failure).to include('No such file or directory') + expect(failure).to include(artifact.file.path) end it 'fails artifacts with a mismatched checksum' do File.truncate(artifact.file.path, 0) expect(failures.keys).to contain_exactly(artifact) - expect(failure.to_s).to include('Checksum mismatch') + expect(failure).to include('Checksum mismatch') + end + + context 'with remote files' do + let(:file) { double(:file) } + + before do + stub_artifacts_object_storage + artifact.update!(file_store: ObjectStorage::Store::REMOTE) + expect(CarrierWave::Storage::Fog::File).to receive(:new).and_return(file) + end + + it 'passes artifacts in object storage that exist' do + expect(file).to receive(:exists?).and_return(true) + + expect(failures).to eq({}) + end + + it 'fails artifacts in object storage that do not exist' do + expect(file).to receive(:exists?).and_return(false) + + expect(failures.keys).to contain_exactly(artifact) + expect(failure).to include('Remote object does not exist') + end end end end diff --git a/spec/lib/gitlab/verify/lfs_objects_spec.rb b/spec/lib/gitlab/verify/lfs_objects_spec.rb index 0f890e2c7ce..2feaedd6f14 100644 --- a/spec/lib/gitlab/verify/lfs_objects_spec.rb +++ b/spec/lib/gitlab/verify/lfs_objects_spec.rb @@ -21,30 +21,37 @@ describe Gitlab::Verify::LfsObjects do FileUtils.rm_f(lfs_object.file.path) expect(failures.keys).to contain_exactly(lfs_object) - expect(failure).to be_a(Errno::ENOENT) - expect(failure.to_s).to include(lfs_object.file.path) + expect(failure).to include('No such file or directory') + expect(failure).to include(lfs_object.file.path) end it 'fails LFS objects with a mismatched oid' do File.truncate(lfs_object.file.path, 0) expect(failures.keys).to contain_exactly(lfs_object) - expect(failure.to_s).to include('Checksum mismatch') + expect(failure).to include('Checksum mismatch') end context 'with remote files' do + let(:file) { double(:file) } + before do stub_lfs_object_storage + lfs_object.update!(file_store: ObjectStorage::Store::REMOTE) + expect(CarrierWave::Storage::Fog::File).to receive(:new).and_return(file) end - it 'skips LFS objects in object storage' do - local_failure = create(:lfs_object) - create(:lfs_object, :object_storage) + it 'passes LFS objects in object storage that exist' do + expect(file).to receive(:exists?).and_return(true) + + expect(failures).to eq({}) + end - failures = {} - described_class.new(batch_size: 10).run_batches { |_, failed| failures.merge!(failed) } + it 'fails LFS objects in object storage that do not exist' do + expect(file).to receive(:exists?).and_return(false) - expect(failures.keys).to contain_exactly(local_failure) + expect(failures.keys).to contain_exactly(lfs_object) + expect(failure).to include('Remote object does not exist') end end end diff --git a/spec/lib/gitlab/verify/uploads_spec.rb b/spec/lib/gitlab/verify/uploads_spec.rb index 85768308edc..296866d3319 100644 --- a/spec/lib/gitlab/verify/uploads_spec.rb +++ b/spec/lib/gitlab/verify/uploads_spec.rb @@ -23,37 +23,44 @@ describe Gitlab::Verify::Uploads do FileUtils.rm_f(upload.absolute_path) expect(failures.keys).to contain_exactly(upload) - expect(failure).to be_a(Errno::ENOENT) - expect(failure.to_s).to include(upload.absolute_path) + expect(failure).to include('No such file or directory') + expect(failure).to include(upload.absolute_path) end it 'fails uploads with a mismatched checksum' do upload.update!(checksum: 'something incorrect') expect(failures.keys).to contain_exactly(upload) - expect(failure.to_s).to include('Checksum mismatch') + expect(failure).to include('Checksum mismatch') end it 'fails uploads with a missing precalculated checksum' do upload.update!(checksum: '') expect(failures.keys).to contain_exactly(upload) - expect(failure.to_s).to include('Checksum missing') + expect(failure).to include('Checksum missing') end context 'with remote files' do + let(:file) { double(:file) } + before do stub_uploads_object_storage(AvatarUploader) + upload.update!(store: ObjectStorage::Store::REMOTE) + expect(CarrierWave::Storage::Fog::File).to receive(:new).and_return(file) end - it 'skips uploads in object storage' do - local_failure = create(:upload) - create(:upload, :object_storage) + it 'passes uploads in object storage that exist' do + expect(file).to receive(:exists?).and_return(true) + + expect(failures).to eq({}) + end - failures = {} - described_class.new(batch_size: 10).run_batches { |_, failed| failures.merge!(failed) } + it 'fails uploads in object storage that do not exist' do + expect(file).to receive(:exists?).and_return(false) - expect(failures.keys).to contain_exactly(local_failure) + expect(failures.keys).to contain_exactly(upload) + expect(failure).to include('Remote object does not exist') end end end -- cgit v1.2.1 From fa29bc2899193c5c5d8f92b54d8ade1a4230c84e Mon Sep 17 00:00:00 2001 From: Winnie Hellmann Date: Wed, 13 Jun 2018 22:48:59 +0000 Subject: Fix branch name encoding for dropdown on issue page --- .../create_merge_request_dropdown_spec.js | 67 ++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 spec/javascripts/create_merge_request_dropdown_spec.js (limited to 'spec') diff --git a/spec/javascripts/create_merge_request_dropdown_spec.js b/spec/javascripts/create_merge_request_dropdown_spec.js new file mode 100644 index 00000000000..b229765a8c5 --- /dev/null +++ b/spec/javascripts/create_merge_request_dropdown_spec.js @@ -0,0 +1,67 @@ +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; +import CreateMergeRequestDropdown from '~/create_merge_request_dropdown'; +import { TEST_HOST } from 'spec/test_constants'; + +describe('CreateMergeRequestDropdown', () => { + let axiosMock; + let dropdown; + + beforeEach(() => { + axiosMock = new MockAdapter(axios); + + setFixtures(` +
+
+
+
+
+
+
+
+
+
+
+ `); + + const dummyElement = document.getElementById('dummy-wrapper-element'); + dropdown = new CreateMergeRequestDropdown(dummyElement); + dropdown.refsPath = `${TEST_HOST}/dummy/refs?search=`; + }); + + afterEach(() => { + axiosMock.restore(); + }); + + describe('getRef', () => { + it('escapes branch names correctly', done => { + const endpoint = `${dropdown.refsPath}contains%23hash`; + spyOn(axios, 'get').and.callThrough(); + axiosMock.onGet(endpoint).replyOnce({}); + + dropdown + .getRef('contains#hash') + .then(() => { + expect(axios.get).toHaveBeenCalledWith(endpoint); + }) + .then(done) + .catch(done.fail); + }); + }); + + describe('updateCreatePaths', () => { + it('escapes branch names correctly', () => { + dropdown.createBranchPath = `${TEST_HOST}/branches?branch_name=some-branch&issue=42`; + dropdown.createMrPath = `${TEST_HOST}/create_merge_request?branch_name=some-branch&ref=master`; + + dropdown.updateCreatePaths('branch', 'contains#hash'); + + expect(dropdown.createBranchPath).toBe( + `${TEST_HOST}/branches?branch_name=contains%23hash&issue=42`, + ); + expect(dropdown.createMrPath).toBe( + `${TEST_HOST}/create_merge_request?branch_name=contains%23hash&ref=master`, + ); + }); + }); +}); -- cgit v1.2.1 From 202bd2da16942ca8c9b667b10c75025a0c95980d Mon Sep 17 00:00:00 2001 From: James Edwards-Jones Date: Thu, 14 Jun 2018 09:02:32 +1000 Subject: Backport InternalRedirect#sanitize_redirect --- .../controllers/concerns/internal_redirect_spec.rb | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'spec') diff --git a/spec/controllers/concerns/internal_redirect_spec.rb b/spec/controllers/concerns/internal_redirect_spec.rb index a0ee13b2352..7e23b56356e 100644 --- a/spec/controllers/concerns/internal_redirect_spec.rb +++ b/spec/controllers/concerns/internal_redirect_spec.rb @@ -54,6 +54,31 @@ describe InternalRedirect do end end + describe '#sanitize_redirect' do + let(:valid_path) { '/hello/world?hello=world' } + let(:valid_url) { "http://test.host#{valid_path}" } + + it 'returns `nil` for invalid paths' do + invalid_path = '//not/valid' + + expect(controller.sanitize_redirect(invalid_path)).to eq nil + end + + it 'returns `nil` for invalid urls' do + input = 'http://test.host:3000/invalid' + + expect(controller.sanitize_redirect(input)).to eq nil + end + + it 'returns input for valid paths' do + expect(controller.sanitize_redirect(valid_path)).to eq valid_path + end + + it 'returns path for valid urls' do + expect(controller.sanitize_redirect(valid_url)).to eq valid_path + end + end + describe '#host_allowed?' do it 'allows uris with the same host and port' do expect(controller.host_allowed?(URI('http://test.host/test'))).to be(true) -- cgit v1.2.1 From fa36101a7fc8679d98198942f15dd6285673594d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarka=20Kadlecov=C3=A1?= Date: Tue, 5 Jun 2018 11:29:33 +0200 Subject: Use data_source_exists? instead of table_exists? Use data_source_exists? where possible instead of table_exists? in order to be Rails5 compatible --- .../background_migration/populate_untracked_uploads_spec.rb | 2 +- spec/lib/gitlab/database_spec.rb | 9 +++++++-- spec/support/helpers/migrations_helpers.rb | 4 ---- 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb index 0d2074eed22..0dee683350f 100644 --- a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb +++ b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb @@ -114,7 +114,7 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, :sidekiq, :migra it 'does not drop the temporary tracking table after processing the batch, if there are still untracked rows' do subject.perform(1, untracked_files_for_uploads.last.id - 1) - expect(ActiveRecord::Base.connection.table_exists?(:untracked_files_for_uploads)).to be_truthy + expect(ActiveRecord::Base.connection.data_source_exists?(:untracked_files_for_uploads)).to be_truthy end it 'drops the temporary tracking table after processing the batch, if there are no untracked rows left' do diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index 8ac36ae8bab..8bb246aa4bd 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -314,8 +314,13 @@ describe Gitlab::Database do describe '.cached_table_exists?' do it 'only retrieves data once per table' do - expect(ActiveRecord::Base.connection).to receive(:table_exists?).with(:projects).once.and_call_original - expect(ActiveRecord::Base.connection).to receive(:table_exists?).with(:bogus_table_name).once.and_call_original + if Gitlab.rails5? + expect(ActiveRecord::Base.connection).to receive(:data_source_exists?).with(:projects).once.and_call_original + expect(ActiveRecord::Base.connection).to receive(:data_source_exists?).with(:bogus_table_name).once.and_call_original + else + expect(ActiveRecord::Base.connection).to receive(:table_exists?).with(:projects).once.and_call_original + expect(ActiveRecord::Base.connection).to receive(:table_exists?).with(:bogus_table_name).once.and_call_original + end 2.times do expect(described_class.cached_table_exists?(:projects)).to be_truthy diff --git a/spec/support/helpers/migrations_helpers.rb b/spec/support/helpers/migrations_helpers.rb index 84abec75c26..0bc235701eb 100644 --- a/spec/support/helpers/migrations_helpers.rb +++ b/spec/support/helpers/migrations_helpers.rb @@ -10,10 +10,6 @@ module MigrationsHelpers ActiveRecord::Migrator.migrations_paths end - def table_exists?(name) - ActiveRecord::Base.connection.table_exists?(name) - end - def migrations ActiveRecord::Migrator.migrations(migrations_paths) end -- cgit v1.2.1 From 4fc46007479784997a90e3b648fd5d4b3ff897ec Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Thu, 14 Jun 2018 09:56:16 +0200 Subject: Default branch detection happens through Gitaly Migration: https://gitlab.com/gitlab-org/gitaly/issues/220 --- spec/lib/gitlab/git/repository_spec.rb | 51 ---------------------------------- 1 file changed, 51 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 1744db1b17e..9cc7a0d79dc 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -77,17 +77,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end describe '#root_ref' do - context 'with gitaly disabled' do - before do - allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) - end - - it 'calls #discover_default_branch' do - expect(repository).to receive(:discover_default_branch) - repository.root_ref - end - end - it 'returns UTF-8' do expect(repository.root_ref).to be_utf8 end @@ -153,46 +142,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - describe "#discover_default_branch" do - let(:master) { 'master' } - let(:feature) { 'feature' } - let(:feature2) { 'feature2' } - - around do |example| - # discover_default_branch will be moved to gitaly-ruby - Gitlab::GitalyClient::StorageSettings.allow_disk_access do - example.run - end - end - - it "returns 'master' when master exists" do - expect(repository).to receive(:branch_names).at_least(:once).and_return([feature, master]) - expect(repository.discover_default_branch).to eq('master') - end - - it "returns non-master when master exists but default branch is set to something else" do - File.write(File.join(repository_path, 'HEAD'), 'ref: refs/heads/feature') - expect(repository).to receive(:branch_names).at_least(:once).and_return([feature, master]) - expect(repository.discover_default_branch).to eq('feature') - File.write(File.join(repository_path, 'HEAD'), 'ref: refs/heads/master') - end - - it "returns a non-master branch when only one exists" do - expect(repository).to receive(:branch_names).at_least(:once).and_return([feature]) - expect(repository.discover_default_branch).to eq('feature') - end - - it "returns a non-master branch when more than one exists and master does not" do - expect(repository).to receive(:branch_names).at_least(:once).and_return([feature, feature2]) - expect(repository.discover_default_branch).to eq('feature') - end - - it "returns nil when no branch exists" do - expect(repository).to receive(:branch_names).at_least(:once).and_return([]) - expect(repository.discover_default_branch).to be_nil - end - end - describe '#branch_names' do subject { repository.branch_names } -- cgit v1.2.1 From 89ab32c6b20b9a0e8cde9d7f28759db8f53c7ffb Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Thu, 14 Jun 2018 10:25:28 +0200 Subject: Branches are fully migrated to Gitaly Closes: https://gitlab.com/gitlab-org/gitaly/issues/389 --- spec/lib/gitlab/git/repository_spec.rb | 18 ------------------ 1 file changed, 18 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb index 9cc7a0d79dc..9de7724e34e 100644 --- a/spec/lib/gitlab/git/repository_spec.rb +++ b/spec/lib/gitlab/git/repository_spec.rb @@ -1344,24 +1344,6 @@ describe Gitlab::Git::Repository, seed_helper: true do end end - # With Gitaly enabled, Gitaly just doesn't return deleted branches. - context 'with deleted branch with Gitaly disabled' do - before do - allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) - end - - it 'returns no results' do - ref = double() - allow(ref).to receive(:name) { 'bad-branch' } - allow(ref).to receive(:target) { raise Rugged::ReferenceError } - branches = double() - allow(branches).to receive(:each) { [ref].each } - allow(repository_rugged).to receive(:branches) { branches } - - expect(subject).to be_empty - end - end - it_behaves_like 'wrapping gRPC errors', Gitlab::GitalyClient::RefService, :branches end -- cgit v1.2.1 From f79410fe1772798d7fa1b288880e14e806483c3c Mon Sep 17 00:00:00 2001 From: Brett Walker Date: Thu, 14 Jun 2018 08:30:16 +0000 Subject: enable CommonMark as the default --- spec/features/markdown/copy_as_gfm_spec.rb | 9 +++- spec/features/markdown/markdown_spec.rb | 55 +++++++++++++++++------ spec/features/task_lists_spec.rb | 45 ++++++++++++++++--- spec/fixtures/markdown.md.erb | 10 ++++- spec/helpers/markup_helper_spec.rb | 2 +- spec/javascripts/shortcuts_issuable_spec.js | 2 +- spec/lib/banzai/filter/markdown_filter_spec.rb | 4 +- spec/models/concerns/cache_markdown_field_spec.rb | 10 ++--- 8 files changed, 106 insertions(+), 31 deletions(-) (limited to 'spec') diff --git a/spec/features/markdown/copy_as_gfm_spec.rb b/spec/features/markdown/copy_as_gfm_spec.rb index 4d897f09b57..05228e27963 100644 --- a/spec/features/markdown/copy_as_gfm_spec.rb +++ b/spec/features/markdown/copy_as_gfm_spec.rb @@ -502,6 +502,13 @@ describe 'Copy as GFM', :js do 1. Numbered lists GFM + # list item followed by an HR + <<-GFM.strip_heredoc, + - list item + + ----- + GFM + '# Heading', '## Heading', '### Heading', @@ -515,8 +522,6 @@ describe 'Copy as GFM', :js do '~~Strikethrough~~', - '2^2', - '-----', # table diff --git a/spec/features/markdown/markdown_spec.rb b/spec/features/markdown/markdown_spec.rb index c86ba8c50a5..cac8a5068ec 100644 --- a/spec/features/markdown/markdown_spec.rb +++ b/spec/features/markdown/markdown_spec.rb @@ -44,7 +44,7 @@ describe 'GitLab Markdown', :aggregate_failures do # Shared behavior that all pipelines should exhibit shared_examples 'all pipelines' do - it 'includes Redcarpet extensions' do + it 'includes extensions' do aggregate_failures 'does not parse emphasis inside of words' do expect(doc.to_html).not_to match('foobarbaz') end @@ -72,10 +72,6 @@ describe 'GitLab Markdown', :aggregate_failures do aggregate_failures 'parses strikethroughs' do expect(doc).to have_selector(%{del:contains("and this text doesn't")}) end - - aggregate_failures 'parses superscript' do - expect(doc).to have_selector('sup', count: 2) - end end it 'includes SanitizationFilter' do @@ -123,16 +119,24 @@ describe 'GitLab Markdown', :aggregate_failures do expect(doc).to have_selector('details summary:contains("collapsible")') end - aggregate_failures 'permits style attribute in th elements' do - expect(doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center' - expect(doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right' - expect(doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left' + aggregate_failures 'permits align attribute in th elements' do + expect(doc.at_css('th:contains("Header")')['align']).to eq 'center' + expect(doc.at_css('th:contains("Row")')['align']).to eq 'right' + expect(doc.at_css('th:contains("Example")')['align']).to eq 'left' end - aggregate_failures 'permits style attribute in td elements' do - expect(doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center' - expect(doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right' - expect(doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left' + aggregate_failures 'permits align attribute in td elements' do + expect(doc.at_css('td:contains("Foo")')['align']).to eq 'center' + expect(doc.at_css('td:contains("Bar")')['align']).to eq 'right' + expect(doc.at_css('td:contains("Baz")')['align']).to eq 'left' + end + + aggregate_failures 'permits superscript elements' do + expect(doc).to have_selector('sup', count: 2) + end + + aggregate_failures 'permits subscript elements' do + expect(doc).to have_selector('sub', count: 3) end aggregate_failures 'removes `rel` attribute from links' do @@ -320,6 +324,31 @@ describe 'GitLab Markdown', :aggregate_failures do end end + context 'Redcarpet documents' do + before do + allow_any_instance_of(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet') + @html = markdown(@feat.raw_markdown) + end + + it 'processes certain elements differently' do + aggregate_failures 'parses superscript' do + expect(doc).to have_selector('sup', count: 3) + end + + aggregate_failures 'permits style attribute in th elements' do + expect(doc.at_css('th:contains("Header")')['style']).to eq 'text-align: center' + expect(doc.at_css('th:contains("Row")')['style']).to eq 'text-align: right' + expect(doc.at_css('th:contains("Example")')['style']).to eq 'text-align: left' + end + + aggregate_failures 'permits style attribute in td elements' do + expect(doc.at_css('td:contains("Foo")')['style']).to eq 'text-align: center' + expect(doc.at_css('td:contains("Bar")')['style']).to eq 'text-align: right' + expect(doc.at_css('td:contains("Baz")')['style']).to eq 'text-align: left' + end + end + end + # Fake a `current_user` helper def current_user @feat.user diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb index 2dc3c5e3927..f37d8998045 100644 --- a/spec/features/task_lists_spec.rb +++ b/spec/features/task_lists_spec.rb @@ -36,7 +36,7 @@ feature 'Task Lists' do MARKDOWN end - let(:nested_tasks_markdown) do + let(:nested_tasks_markdown_redcarpet) do <<-EOT.strip_heredoc - [ ] Task a - [x] Task a.1 @@ -49,6 +49,19 @@ feature 'Task Lists' do EOT end + let(:nested_tasks_markdown) do + <<-EOT.strip_heredoc + - [ ] Task a + - [x] Task a.1 + - [ ] Task a.2 + - [ ] Task b + + 1. [ ] Task 1 + 1. [ ] Task 1.1 + 1. [x] Task 1.2 + EOT + end + before do Warden.test_mode! @@ -141,13 +154,11 @@ feature 'Task Lists' do end end - describe 'nested tasks', :js do - let(:issue) { create(:issue, description: nested_tasks_markdown, author: user, project: project) } - + shared_examples 'shared nested tasks' do before do + allow(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet') visit_issue(project, issue) end - it 'renders' do expect(page).to have_selector('ul.task-list', count: 2) expect(page).to have_selector('li.task-list-item', count: 7) @@ -171,6 +182,30 @@ feature 'Task Lists' do expect(page).to have_content('marked the task Task 1.1 as complete') end end + + describe 'nested tasks', :js do + context 'with Redcarpet' do + let(:issue) { create(:issue, description: nested_tasks_markdown_redcarpet, author: user, project: project) } + + before do + allow_any_instance_of(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('Redcarpet') + visit_issue(project, issue) + end + + it_behaves_like 'shared nested tasks' + end + + context 'with CommonMark' do + let(:issue) { create(:issue, description: nested_tasks_markdown, author: user, project: project) } + + before do + allow_any_instance_of(Banzai::Filter::MarkdownFilter).to receive(:engine).and_return('CommonMark') + visit_issue(project, issue) + end + + it_behaves_like 'shared nested tasks' + end + end end describe 'for Notes' do diff --git a/spec/fixtures/markdown.md.erb b/spec/fixtures/markdown.md.erb index da32a46675f..e5d01c3bd03 100644 --- a/spec/fixtures/markdown.md.erb +++ b/spec/fixtures/markdown.md.erb @@ -43,8 +43,14 @@ This text says this, ~~and this text doesn't~~. ### Superscript -This is my 1^(st) time using superscript in Markdown. Now this is my -2^(nd). +This is my 1(st) time using superscript in Markdown. Now this is my +2(nd). + +Redcarpet supports this superscript syntax ( x^2 ). + +### Subscript + +This (C6H12O6) is an example of subscripts in Markdown. ### Next step diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb index c0dc9293397..1a720aae55c 100644 --- a/spec/helpers/markup_helper_spec.rb +++ b/spec/helpers/markup_helper_spec.rb @@ -298,7 +298,7 @@ describe MarkupHelper do it 'preserves code color scheme' do object = create_object("```ruby\ndef test\n 'hello world'\nend\n```") - expected = "\n
" \
+        expected = "
" \
           "def test...\n" \
           "
" diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index d73608ed0ed..b10d8be6781 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -66,7 +66,7 @@ describe('ShortcutsIssuable', function () { }); describe('with a multi-line selection', () => { it('quotes the selected lines as a group', () => { - stubSelection('

Selected line one.

\n\n

Selected line two.

\n\n

Selected line three.

'); + stubSelection('

Selected line one.

\n

Selected line two.

\n

Selected line three.

'); this.shortcut.replyWithSelectedText(true); expect($(this.selector).val()).toBe('> Selected line one.\n>\n> Selected line two.\n>\n> Selected line three.\n\n'); }); diff --git a/spec/lib/banzai/filter/markdown_filter_spec.rb b/spec/lib/banzai/filter/markdown_filter_spec.rb index 00c407d1b69..ab14d77d552 100644 --- a/spec/lib/banzai/filter/markdown_filter_spec.rb +++ b/spec/lib/banzai/filter/markdown_filter_spec.rb @@ -7,13 +7,13 @@ describe Banzai::Filter::MarkdownFilter do it 'adds language to lang attribute when specified' do result = filter("```html\nsome code\n```") - expect(result).to start_with("\n
")
+      expect(result).to start_with("
")
     end
 
     it 'does not add language to lang attribute when not specified' do
       result = filter("```\nsome code\n```")
 
-      expect(result).to start_with("\n
")
+      expect(result).to start_with("
")
     end
   end
 end
diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb
index b3797c1fb46..2d75422ee68 100644
--- a/spec/models/concerns/cache_markdown_field_spec.rb
+++ b/spec/models/concerns/cache_markdown_field_spec.rb
@@ -156,7 +156,7 @@ describe CacheMarkdownField do
     end
 
     it { expect(thing.foo_html).to eq(updated_html) }
-    it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION) }
+    it { expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION) }
   end
 
   describe '#cached_html_up_to_date?' do
@@ -234,7 +234,7 @@ describe CacheMarkdownField do
 
     it 'returns default version when version is nil' do
       thing.cached_markdown_version = nil
-      is_expected.to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
+      is_expected.to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
     end
   end
 
@@ -261,7 +261,7 @@ describe CacheMarkdownField do
       thing.cached_markdown_version = nil
       thing.refresh_markdown_cache
 
-      expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
+      expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
     end
   end
 
@@ -346,7 +346,7 @@ describe CacheMarkdownField do
 
         expect(thing.foo_html).to eq(updated_html)
         expect(thing.baz_html).to eq(updated_html)
-        expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
+        expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
       end
     end
 
@@ -366,7 +366,7 @@ describe CacheMarkdownField do
 
         expect(thing.foo_html).to eq(updated_html)
         expect(thing.baz_html).to eq(updated_html)
-        expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_REDCARPET_VERSION)
+        expect(thing.cached_markdown_version).to eq(CacheMarkdownField::CACHE_COMMONMARK_VERSION)
       end
     end
   end
-- 
cgit v1.2.1


From 3ed4a1b3aadd50b47181312b49911d2a770c4c82 Mon Sep 17 00:00:00 2001
From: Zeger-Jan van de Weg 
Date: Thu, 14 Jun 2018 10:31:24 +0200
Subject: HasLocalBranches check is done by Gitaly only

Closes https://gitlab.com/gitlab-org/gitaly/issues/217
---
 spec/lib/gitlab/git/repository_spec.rb | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 9de7724e34e..5bae99101e6 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -425,7 +425,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
   end
 
   describe '#has_local_branches?' do
-    shared_examples 'check for local branches' do
+    context 'check for local branches' do
       it { expect(repository.has_local_branches?).to eq(true) }
 
       context 'mutable' do
@@ -459,14 +459,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
         end
       end
     end
-
-    context 'with gitaly' do
-      it_behaves_like 'check for local branches'
-    end
-
-    context 'without gitaly', :skip_gitaly_mock do
-      it_behaves_like 'check for local branches'
-    end
   end
 
   describe "#delete_branch" do
-- 
cgit v1.2.1


From 946a982748f93bc09f2f3c8092f9e8c757e8115f Mon Sep 17 00:00:00 2001
From: Eric Eastwood 
Date: Wed, 13 Jun 2018 14:18:08 -0500
Subject: Fix flakey user comment on issue test race condition

---
 spec/features/projects/issues/user_comments_on_issue_spec.rb | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/features/projects/issues/user_comments_on_issue_spec.rb b/spec/features/projects/issues/user_comments_on_issue_spec.rb
index c45fdc7642f..353f487485d 100644
--- a/spec/features/projects/issues/user_comments_on_issue_spec.rb
+++ b/spec/features/projects/issues/user_comments_on_issue_spec.rb
@@ -31,11 +31,14 @@ describe "User comments on issue", :js do
     end
 
     it "adds comment with code block" do
-      comment = "```\nCommand [1]: /usr/local/bin/git , see [text](doc/text)\n```"
+      code_block_content = "Command [1]: /usr/local/bin/git , see [text](doc/text)"
+      comment = "```\n#{code_block_content}\n```"
 
       add_note(comment)
 
-      expect(page).to have_content(comment)
+      wait_for_requests
+
+      expect(page.find('pre code').text).to eq code_block_content
     end
   end
 
-- 
cgit v1.2.1


From aef29d00fea11938587dceeb7a9abb2cb6afa74f Mon Sep 17 00:00:00 2001
From: Eric Eastwood 
Date: Wed, 13 Jun 2018 17:09:50 -0500
Subject: Fix flakey move slash command with unauthorized project

---
 spec/features/issues/user_uses_slash_commands_spec.rb | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/features/issues/user_uses_slash_commands_spec.rb b/spec/features/issues/user_uses_slash_commands_spec.rb
index dacca494755..17818beb947 100644
--- a/spec/features/issues/user_uses_slash_commands_spec.rb
+++ b/spec/features/issues/user_uses_slash_commands_spec.rb
@@ -226,7 +226,9 @@ feature 'Issues > User uses quick actions', :js do
         it 'does not move the issue' do
           add_note("/move #{project_unauthorized.full_path}")
 
-          expect(page).not_to have_content 'Commands applied'
+          wait_for_requests
+
+          expect(page).to have_content 'Commands applied'
           expect(issue.reload).to be_open
         end
       end
-- 
cgit v1.2.1


From 9c3e9fe2c099a0fc251a8c8e15e4846cd1d946e5 Mon Sep 17 00:00:00 2001
From: Eric Eastwood 
Date: Thu, 14 Jun 2018 00:05:05 -0500
Subject: Fix flakey time-sensitive remove deploy key spec

---
 spec/features/projects/deploy_keys_spec.rb | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/features/projects/deploy_keys_spec.rb b/spec/features/projects/deploy_keys_spec.rb
index 43a23c42f83..1552a3512dd 100644
--- a/spec/features/projects/deploy_keys_spec.rb
+++ b/spec/features/projects/deploy_keys_spec.rb
@@ -22,7 +22,8 @@ describe 'Project deploy keys', :js do
 
         accept_confirm { find('.ic-remove').click() }
 
-        expect(page).not_to have_selector('.fa-spinner', count: 0)
+        wait_for_requests
+
         expect(page).to have_selector('.deploy-key', count: 0)
       end
     end
-- 
cgit v1.2.1


From 56b64e8b2fa5ca7024fade404f0d73cdd5a9aec2 Mon Sep 17 00:00:00 2001
From: Lin Jen-Shin 
Date: Thu, 14 Jun 2018 19:03:24 +0800
Subject: We don't need to pass lib: true as in EE

---
 spec/lib/banzai/filter/image_lazy_load_filter_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
index c19de7b784a..41f957c4e00 100644
--- a/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
+++ b/spec/lib/banzai/filter/image_lazy_load_filter_spec.rb
@@ -1,6 +1,6 @@
 require 'spec_helper'
 
-describe Banzai::Filter::ImageLazyLoadFilter, lib: true do
+describe Banzai::Filter::ImageLazyLoadFilter do
   include FilterSpecHelper
 
   def image(path)
-- 
cgit v1.2.1


From 5cf5680f9c8ce251570efce7dd4c348fb68efccf Mon Sep 17 00:00:00 2001
From: "Jacob Vosmaer (GitLab)" 
Date: Thu, 14 Jun 2018 11:18:25 +0000
Subject: Deny repository disk access in development and test

---
 spec/controllers/projects_controller_spec.rb               | 12 +++++++++---
 spec/helpers/projects_helper_spec.rb                       |  6 +++++-
 spec/lib/gitlab/git_access_wiki_spec.rb                    |  4 +++-
 spec/migrations/migrate_process_commit_worker_jobs_spec.rb |  6 +++++-
 ...urn_nested_groups_into_regular_groups_for_mysql_spec.rb |  8 ++++++--
 spec/models/project_spec.rb                                | 14 ++++++++++----
 spec/models/project_wiki_spec.rb                           |  6 +++++-
 spec/models/remote_mirror_spec.rb                          |  4 +++-
 spec/requests/api/internal_spec.rb                         |  1 -
 spec/services/projects/create_service_spec.rb              |  5 ++++-
 spec/support/gitaly.rb                                     |  2 +-
 spec/workers/repository_remove_remote_worker_spec.rb       |  4 +++-
 12 files changed, 54 insertions(+), 18 deletions(-)

(limited to 'spec')

diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb
index 5bd22ea803c..705b30f0130 100644
--- a/spec/controllers/projects_controller_spec.rb
+++ b/spec/controllers/projects_controller_spec.rb
@@ -296,16 +296,22 @@ describe ProjectsController do
     shared_examples_for 'updating a project' do
       context 'when only renaming a project path' do
         it "sets the repository to the right path after a rename" do
-          original_repository_path = project.repository.path
+          original_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            project.repository.path
+          end
 
           expect { update_project path: 'renamed_path' }
             .to change { project.reload.path }
           expect(project.path).to include 'renamed_path'
 
+          assign_repository_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            assigns(:repository).path
+          end
+
           if project.hashed_storage?(:repository)
-            expect(assigns(:repository).path).to eq(original_repository_path)
+            expect(assign_repository_path).to eq(original_repository_path)
           else
-            expect(assigns(:repository).path).to include(project.path)
+            expect(assign_repository_path).to include(project.path)
           end
 
           expect(response).to have_gitlab_http_status(302)
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 815b4035114..5cf9e9e8f12 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -280,7 +280,11 @@ describe ProjectsHelper do
 
   describe '#sanitizerepo_repo_path' do
     let(:project) { create(:project, :repository) }
-    let(:storage_path) { Gitlab.config.repositories.storages.default.legacy_disk_path }
+    let(:storage_path) do
+      Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        Gitlab.config.repositories.storages.default.legacy_disk_path
+      end
+    end
 
     before do
       allow(Settings.shared).to receive(:[]).with('path').and_return('/base/repo/export/path')
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 730ede99fc9..9c6c9fe13bf 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -52,7 +52,9 @@ describe Gitlab::GitAccessWiki do
       context 'when the wiki repository does not exist' do
         it 'returns not found' do
           wiki_repo = project.wiki.repository
-          FileUtils.rm_rf(wiki_repo.path)
+          Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+            FileUtils.rm_rf(wiki_repo.path)
+          end
 
           # Sanity check for rm_rf
           expect(wiki_repo.exists?).to eq(false)
diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
index 4ee1d255fbd..ac34efa4f9d 100644
--- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
+++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
@@ -6,7 +6,11 @@ require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_
 describe MigrateProcessCommitWorkerJobs do
   let(:project) { create(:project, :legacy_storage, :repository) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
   let(:user) { create(:user) } # rubocop:disable RSpec/FactoriesInMigrationSpecs
-  let(:commit) { project.commit.raw.rugged_commit }
+  let(:commit) do
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.commit.raw.rugged_commit
+    end
+  end
 
   describe 'Project' do
     describe 'find_including_path' do
diff --git a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
index 560409f08de..5f5ba426d69 100644
--- a/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
+++ b/spec/migrations/turn_nested_groups_into_regular_groups_for_mysql_spec.rb
@@ -49,10 +49,14 @@ describe TurnNestedGroupsIntoRegularGroupsForMysql do
     end
 
     it 'renames the repository of any projects' do
-      expect(updated_project.repository.path)
+      repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+        updated_project.repository.path
+      end
+
+      expect(repo_path)
         .to end_with("#{parent_group.name}-#{child_group.name}/#{updated_project.path}.git")
 
-      expect(File.directory?(updated_project.repository.path)).to eq(true)
+      expect(File.directory?(repo_path)).to eq(true)
     end
 
     it 'creates a redirect route for renamed projects' do
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 585cf7aab44..bc9cce6b0c3 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2943,7 +2943,7 @@ describe Project do
 
         project.rename_repo
 
-        expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path)
+        expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
       end
     end
 
@@ -3104,7 +3104,7 @@ describe Project do
       it 'updates project full path in .git/config' do
         project.rename_repo
 
-        expect(project.repository.rugged.config['gitlab.fullpath']).to eq(project.full_path)
+        expect(rugged_config['gitlab.fullpath']).to eq(project.full_path)
       end
     end
 
@@ -3525,13 +3525,13 @@ describe Project do
     it 'writes full path in .git/config when key is missing' do
       project.write_repository_config
 
-      expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
+      expect(rugged_config['gitlab.fullpath']).to eq project.full_path
     end
 
     it 'updates full path in .git/config when key is present' do
       project.write_repository_config(gl_full_path: 'old/path')
 
-      expect { project.write_repository_config }.to change { project.repository.rugged.config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
+      expect { project.write_repository_config }.to change { rugged_config['gitlab.fullpath'] }.from('old/path').to(project.full_path)
     end
 
     it 'does not raise an error with an empty repository' do
@@ -3817,4 +3817,10 @@ describe Project do
       let(:uploader_class) { AttachmentUploader }
     end
   end
+
+  def rugged_config
+    Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.repository.rugged.config
+    end
+  end
 end
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index f1142832f1a..a3c20b3b3c1 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -188,7 +188,11 @@ describe ProjectWiki do
       before do
         subject.wiki # Make sure the wiki repo exists
 
-        BareRepoOperations.new(subject.repository.path_to_repo).commit_file(image, 'image.png')
+        repo_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          subject.repository.path_to_repo
+        end
+
+        BareRepoOperations.new(repo_path).commit_file(image, 'image.png')
       end
 
       it 'returns the latest version of the file if it exists' do
diff --git a/spec/models/remote_mirror_spec.rb b/spec/models/remote_mirror_spec.rb
index 4c086eeadfc..3597b080021 100644
--- a/spec/models/remote_mirror_spec.rb
+++ b/spec/models/remote_mirror_spec.rb
@@ -74,7 +74,9 @@ describe RemoteMirror do
 
         mirror.update_attribute(:url, 'http://foo:baz@test.com')
 
-        config = repo.raw_repository.rugged.config
+        config = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+          repo.raw_repository.rugged.config
+        end
         expect(config["remote.#{mirror.remote_name}.url"]).to eq('http://foo:baz@test.com')
       end
 
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index bc32372d3a9..a56b913198c 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -522,7 +522,6 @@ describe API::Internal do
 
     context 'the project path was changed' do
       let(:project) { create(:project, :repository, :legacy_storage) }
-      let!(:old_path_to_repo) { project.repository.path_to_repo }
       let!(:repository) { project.repository }
 
       before do
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index a8f003b1073..e8cbf84e3be 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -272,8 +272,11 @@ describe Projects::CreateService, '#execute' do
 
   it 'writes project full path to .git/config' do
     project = create_project(user, opts)
+    rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.repository.rugged
+    end
 
-    expect(project.repository.rugged.config['gitlab.fullpath']).to eq project.full_path
+    expect(rugged.config['gitlab.fullpath']).to eq project.full_path
   end
 
   def create_project(user, opts)
diff --git a/spec/support/gitaly.rb b/spec/support/gitaly.rb
index 5a1dd44bc9d..614aaa73693 100644
--- a/spec/support/gitaly.rb
+++ b/spec/support/gitaly.rb
@@ -9,7 +9,7 @@ RSpec.configure do |config|
       # Use 'and_wrap_original' to make sure the arguments are valid
       allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_wrap_original do |m, *args|
         m.call(*args)
-        !Gitlab::GitalyClient::EXPLICIT_OPT_IN_REQUIRED.include?(args.first)
+        !Gitlab::GitalyClient.explicit_opt_in_required.include?(args.first)
       end
     end
   end
diff --git a/spec/workers/repository_remove_remote_worker_spec.rb b/spec/workers/repository_remove_remote_worker_spec.rb
index f22d7c1d073..5968c5da3c9 100644
--- a/spec/workers/repository_remove_remote_worker_spec.rb
+++ b/spec/workers/repository_remove_remote_worker_spec.rb
@@ -44,7 +44,9 @@ describe RepositoryRemoveRemoteWorker do
   end
 
   def create_remote_branch(remote_name, branch_name, target)
-    rugged = project.repository.rugged
+    rugged = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
+      project.repository.rugged
+    end
     rugged.references.create("refs/remotes/#{remote_name}/#{branch_name}", target.id)
   end
 end
-- 
cgit v1.2.1


From cc4541e1b2bc4a946d34c689464ec88ac7320963 Mon Sep 17 00:00:00 2001
From: Lin Jen-Shin 
Date: Thu, 14 Jun 2018 21:33:35 +0800
Subject: Port route helper from EE to CE

---
 spec/spec_helper.rb | 1 +
 1 file changed, 1 insertion(+)

(limited to 'spec')

diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 8417b340de5..dac609e2545 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -87,6 +87,7 @@ RSpec.configure do |config|
   config.include LiveDebugger, :js
   config.include MigrationsHelpers, :migration
   config.include RedisHelpers
+  config.include Rails.application.routes.url_helpers, type: :routing
 
   if ENV['CI']
     # This includes the first try, i.e. tests will be run 4 times before failing.
-- 
cgit v1.2.1


From 30ef25452182cb9a956f895595cf0cd4afc51c57 Mon Sep 17 00:00:00 2001
From: Phil Hughes 
Date: Wed, 13 Jun 2018 09:44:14 +0100
Subject: fixed hover styling caused by dropdown fixed karma specs added
 CHANGELOG item

---
 .../ide/components/commit_sidebar/list_spec.js       |  1 +
 .../components/commit_sidebar/stage_button_spec.js   |  2 +-
 .../ide/components/repo_commit_section_spec.js       | 20 ++++++++++++--------
 3 files changed, 14 insertions(+), 9 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/ide/components/commit_sidebar/list_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_spec.js
index 6fb52378386..b994488af87 100644
--- a/spec/javascripts/ide/components/commit_sidebar/list_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/list_spec.js
@@ -16,6 +16,7 @@ describe('Multi-file editor commit sidebar list', () => {
       iconName: 'staged',
       action: 'stageAllChanges',
       actionBtnText: 'stage all',
+      actionBtnIcon: 'history',
       itemActionComponent: 'stage-button',
       activeFileKey: 'staged-testing',
       keyPrefix: 'staged',
diff --git a/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js b/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js
index 6bf8710bda7..a5b906da8a1 100644
--- a/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/stage_button_spec.js
@@ -39,7 +39,7 @@ describe('IDE stage file button', () => {
   });
 
   it('calls store with discard button', () => {
-    vm.$el.querySelectorAll('.btn')[1].click();
+    vm.$el.querySelector('.dropdown-menu button').click();
 
     expect(vm.discardFileChanges).toHaveBeenCalledWith(f.path);
   });
diff --git a/spec/javascripts/ide/components/repo_commit_section_spec.js b/spec/javascripts/ide/components/repo_commit_section_spec.js
index 531bcd6e540..6bf309fb4bf 100644
--- a/spec/javascripts/ide/components/repo_commit_section_spec.js
+++ b/spec/javascripts/ide/components/repo_commit_section_spec.js
@@ -111,7 +111,7 @@ describe('RepoCommitSection', () => {
   });
 
   it('renders a commit section', () => {
-    const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list li')];
+    const changedFileElements = [...vm.$el.querySelectorAll('.multi-file-commit-list > li')];
     const allFiles = vm.$store.state.changedFiles.concat(vm.$store.state.stagedFiles);
 
     expect(changedFileElements.length).toEqual(4);
@@ -140,22 +140,26 @@ describe('RepoCommitSection', () => {
     vm.$el.querySelector('.multi-file-discard-btn .btn').click();
 
     Vue.nextTick(() => {
-      expect(vm.$el.querySelector('.ide-commit-list-container').querySelectorAll('li').length).toBe(
-        1,
-      );
+      expect(
+        vm.$el
+          .querySelector('.ide-commit-list-container')
+          .querySelectorAll('.multi-file-commit-list > li').length,
+      ).toBe(1);
 
       done();
     });
   });
 
   it('discards a single file', done => {
-    vm.$el.querySelectorAll('.multi-file-discard-btn .btn')[1].click();
+    vm.$el.querySelector('.multi-file-discard-btn .dropdown-menu button').click();
 
     Vue.nextTick(() => {
       expect(vm.$el.querySelector('.ide-commit-list-container').textContent).not.toContain('file1');
-      expect(vm.$el.querySelector('.ide-commit-list-container').querySelectorAll('li').length).toBe(
-        1,
-      );
+      expect(
+        vm.$el
+          .querySelector('.ide-commit-list-container')
+          .querySelectorAll('.multi-file-commit-list > li').length,
+      ).toBe(1);
 
       done();
     });
-- 
cgit v1.2.1


From a2bfb820021f05a51ffaa96a3ef7cc87dc1cf6b2 Mon Sep 17 00:00:00 2001
From: Phil Hughes 
Date: Wed, 13 Jun 2018 10:59:51 +0100
Subject: fixed sidebar list spec

---
 spec/javascripts/ide/components/commit_sidebar/list_spec.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/javascripts/ide/components/commit_sidebar/list_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_spec.js
index b994488af87..b786be55019 100644
--- a/spec/javascripts/ide/components/commit_sidebar/list_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/list_spec.js
@@ -43,7 +43,7 @@ describe('Multi-file editor commit sidebar list', () => {
     });
 
     it('renders list', () => {
-      expect(vm.$el.querySelectorAll('li').length).toBe(1);
+      expect(vm.$el.querySelectorAll('.multi-file-commit-list > li').length).toBe(1);
     });
   });
 
-- 
cgit v1.2.1


From f454f1ab5ab69de51ad4ae8cb620782e48fc0541 Mon Sep 17 00:00:00 2001
From: Phil Hughes 
Date: Wed, 13 Jun 2018 12:24:48 +0100
Subject: fixed karma spec

---
 spec/javascripts/ide/components/commit_sidebar/list_item_spec.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
index 8f7cf24c22f..bf96170f703 100644
--- a/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
+++ b/spec/javascripts/ide/components/commit_sidebar/list_item_spec.js
@@ -93,14 +93,14 @@ describe('Multi-file editor commit sidebar list item', () => {
 
   describe('is active', () => {
     it('does not add active class when dont keys match', () => {
-      expect(vm.$el.classList).not.toContain('is-active');
+      expect(vm.$el.querySelector('.is-active')).toBe(null);
     });
 
     it('adds active class when keys match', done => {
       vm.keyPrefix = 'staged';
 
       vm.$nextTick(() => {
-        expect(vm.$el.classList).toContain('is-active');
+        expect(vm.$el.querySelector('.is-active')).not.toBe(null);
 
         done();
       });
-- 
cgit v1.2.1


From 4d098451c3830a13e7ae3a9615d87dbc1f73ceec Mon Sep 17 00:00:00 2001
From: Annabel Gray 
Date: Thu, 14 Jun 2018 16:34:58 +0000
Subject: Resolve "Performance bar Gitaly modal is hard to read"

---
 spec/javascripts/vue_shared/components/gl_modal_spec.js | 8 ++++++++
 1 file changed, 8 insertions(+)

(limited to 'spec')

diff --git a/spec/javascripts/vue_shared/components/gl_modal_spec.js b/spec/javascripts/vue_shared/components/gl_modal_spec.js
index 23be8d93b81..e4737714312 100644
--- a/spec/javascripts/vue_shared/components/gl_modal_spec.js
+++ b/spec/javascripts/vue_shared/components/gl_modal_spec.js
@@ -208,6 +208,14 @@ describe('GlModal', () => {
       expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-lg')).toEqual(true);
     });
 
+    it('should render modal-xl', () => {
+      vm = mountComponent(modalComponent, {
+        modalSize: 'xl',
+      });
+
+      expect(vm.$el.querySelector('.modal-dialog').classList.contains('modal-xl')).toEqual(true);
+    });
+
     it('should not add modal size classes when md size is passed', () => {
       vm = mountComponent(modalComponent, {
         modalSize: 'md',
-- 
cgit v1.2.1


From 2126f8f38e6df1da4afec169343303facdde339a Mon Sep 17 00:00:00 2001
From: Eric Eastwood 
Date: Wed, 13 Jun 2018 23:43:21 -0500
Subject: Fix flakey user/assignee autocomplete dropdown

Related to https://gitlab.com/gitlab-org/gitlab-ce/issues/38664

This previously worked because, it would assert the correct names
in the full list and then wait for the list to go blank for the NOT assertion

Example failure, https://gitlab.com/gitlab-org/gitlab-ee/-/jobs/74649299
---
 .../issues/filtered_search/dropdown_assignee_spec.rb   | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

(limited to 'spec')

diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index cbd0949c192..4fc55acc6bf 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -79,23 +79,21 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'filters by name' do
-      filtered_search.send_keys('j')
+      input_filtered_search('jac', submit: false, extra_space: false)
 
-      expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_john.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_jacob.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_no_content(user.name)
     end
 
     it 'filters by case insensitive name' do
-      filtered_search.send_keys('J')
+      input_filtered_search('JAC', submit: false, extra_space: false)
 
-      expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_john.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_jacob.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_no_content(user.name)
     end
 
     it 'filters by username with symbol' do
-      filtered_search.send_keys('@ot')
+      input_filtered_search('@ott', submit: false, extra_space: false)
 
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_jacob.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user.name)
@@ -103,7 +101,7 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'filters by case insensitive username with symbol' do
-      filtered_search.send_keys('@OT')
+      input_filtered_search('@OTT', submit: false, extra_space: false)
 
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_jacob.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user.name)
@@ -111,7 +109,9 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'filters by username without symbol' do
-      filtered_search.send_keys('ot')
+      filtered_search.send_keys('ott')
+
+      wait_for_requests
 
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_jacob.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user.name)
@@ -119,7 +119,9 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'filters by case insensitive username without symbol' do
-      filtered_search.send_keys('OT')
+      filtered_search.send_keys('OTT')
+
+      wait_for_requests
 
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_jacob.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user.name)
-- 
cgit v1.2.1


From 9201e42a224dcb97dcca18ca7d8ea79c746220c5 Mon Sep 17 00:00:00 2001
From: Eric Eastwood 
Date: Thu, 14 Jun 2018 12:15:19 -0500
Subject: Update dropdown_assignee_spec with filtered_search_helpers

---
 .../filtered_search/dropdown_assignee_spec.rb      | 37 +++++++++++-----------
 1 file changed, 18 insertions(+), 19 deletions(-)

(limited to 'spec')

diff --git a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
index 4fc55acc6bf..c8115db9212 100644
--- a/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_assignee_spec.rb
@@ -31,7 +31,7 @@ describe 'Dropdown assignee', :js do
 
   describe 'behavior' do
     it 'opens when the search bar has assignee:' do
-      filtered_search.set('assignee:')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
 
       expect(page).to have_css(js_dropdown_assignee, visible: true)
     end
@@ -44,6 +44,7 @@ describe 'Dropdown assignee', :js do
 
     it 'should show loading indicator when opened' do
       slow_requests do
+        # We aren't using `input_filtered_search` because we want to see the loading indicator
         filtered_search.set('assignee:')
 
         expect(page).to have_css('#js-dropdown-assignee .filter-dropdown-loading', visible: true)
@@ -51,19 +52,19 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'should hide loading indicator when loaded' do
-      filtered_search.set('assignee:')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
 
       expect(find(js_dropdown_assignee)).not_to have_css('.filter-dropdown-loading')
     end
 
     it 'should load all the assignees when opened' do
-      filtered_search.set('assignee:')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
 
       expect(dropdown_assignee_size).to eq(4)
     end
 
     it 'shows current user at top of dropdown' do
-      filtered_search.set('assignee:')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
 
       expect(filter_dropdown.first('.filter-dropdown-item')).to have_content(user.name)
     end
@@ -71,7 +72,7 @@ describe 'Dropdown assignee', :js do
 
   describe 'filtering' do
     before do
-      filtered_search.set('assignee:')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
 
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_john.name)
       expect(find("#{js_dropdown_assignee} .filter-dropdown")).to have_content(user_jacob.name)
@@ -109,7 +110,7 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'filters by username without symbol' do
-      filtered_search.send_keys('ott')
+      input_filtered_search('ott', submit: false, extra_space: false)
 
       wait_for_requests
 
@@ -119,7 +120,7 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'filters by case insensitive username without symbol' do
-      filtered_search.send_keys('OTT')
+      input_filtered_search('OTT', submit: false, extra_space: false)
 
       wait_for_requests
 
@@ -131,7 +132,7 @@ describe 'Dropdown assignee', :js do
 
   describe 'selecting from dropdown' do
     before do
-      filtered_search.set('assignee:')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
     end
 
     it 'fills in the assignee username when the assignee has not been filtered' do
@@ -145,7 +146,7 @@ describe 'Dropdown assignee', :js do
     end
 
     it 'fills in the assignee username when the assignee has been filtered' do
-      filtered_search.send_keys('roo')
+      input_filtered_search('roo', submit: false, extra_space: false)
       click_assignee(user.name)
 
       wait_for_requests
@@ -167,7 +168,7 @@ describe 'Dropdown assignee', :js do
   describe 'selecting from dropdown without Ajax call' do
     before do
       Gitlab::Testing::RequestBlockerMiddleware.block_requests!
-      filtered_search.set('assignee:')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
     end
 
     after do
@@ -185,31 +186,31 @@ describe 'Dropdown assignee', :js do
 
   describe 'input has existing content' do
     it 'opens assignee dropdown with existing search term' do
-      filtered_search.set('searchTerm assignee:')
+      input_filtered_search('searchTerm assignee:', submit: false, extra_space: false)
 
       expect(page).to have_css(js_dropdown_assignee, visible: true)
     end
 
     it 'opens assignee dropdown with existing author' do
-      filtered_search.set('author:@user assignee:')
+      input_filtered_search('author:@user assignee:', submit: false, extra_space: false)
 
       expect(page).to have_css(js_dropdown_assignee, visible: true)
     end
 
     it 'opens assignee dropdown with existing label' do
-      filtered_search.set('label:~bug assignee:')
+      input_filtered_search('label:~bug assignee:', submit: false, extra_space: false)
 
       expect(page).to have_css(js_dropdown_assignee, visible: true)
     end
 
     it 'opens assignee dropdown with existing milestone' do
-      filtered_search.set('milestone:%v1.0 assignee:')
+      input_filtered_search('milestone:%v1.0 assignee:', submit: false, extra_space: false)
 
       expect(page).to have_css(js_dropdown_assignee, visible: true)
     end
 
     it 'opens assignee dropdown with existing my-reaction' do
-      filtered_search.set('my-reaction:star assignee:')
+      input_filtered_search('my-reaction:star assignee:', submit: false, extra_space: false)
 
       expect(page).to have_css(js_dropdown_assignee, visible: true)
     end
@@ -217,8 +218,7 @@ describe 'Dropdown assignee', :js do
 
   describe 'caching requests' do
     it 'caches requests after the first load' do
-      filtered_search.set('assignee')
-      filtered_search.send_keys(':')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
       initial_size = dropdown_assignee_size
 
       expect(initial_size).to be > 0
@@ -226,8 +226,7 @@ describe 'Dropdown assignee', :js do
       new_user = create(:user)
       project.add_master(new_user)
       find('.filtered-search-box .clear-search').click
-      filtered_search.set('assignee')
-      filtered_search.send_keys(':')
+      input_filtered_search('assignee:', submit: false, extra_space: false)
 
       expect(dropdown_assignee_size).to eq(initial_size)
     end
-- 
cgit v1.2.1


From 26fcf83308ba1388423fe6afd536bf433d327a76 Mon Sep 17 00:00:00 2001
From: Clement Ho 
Date: Thu, 14 Jun 2018 17:35:15 +0000
Subject: Resolve "Placeholder note renders the user name in a new line"

---
 spec/javascripts/notes_spec.js | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js
index 648fb3e9bd3..acbf23e2007 100644
--- a/spec/javascripts/notes_spec.js
+++ b/spec/javascripts/notes_spec.js
@@ -974,7 +974,7 @@ import timeoutPromise from './helpers/set_timeout_promise_helper';
         ).toBeFalsy();
         expect(
           $tempNoteHeader
-            .find('.d-none.d-sm-block')
+            .find('.d-none.d-sm-inline-block')
             .text()
             .trim(),
         ).toEqual(currentUserFullname);
@@ -1020,7 +1020,7 @@ import timeoutPromise from './helpers/set_timeout_promise_helper';
         const $tempNoteHeader = $tempNote.find('.note-header');
         expect(
           $tempNoteHeader
-            .find('.d-none.d-sm-block')
+            .find('.d-none.d-sm-inline-block')
             .text()
             .trim(),
         ).toEqual('Foo <script>alert("XSS")</script>');
-- 
cgit v1.2.1


From 3b2a909ac22b7ac559062973dbd1c951fae3ed43 Mon Sep 17 00:00:00 2001
From: Tim Zallmann 
Date: Thu, 14 Jun 2018 19:37:16 +0200
Subject: Makes the html attribute in the json output optional with the option
 html_render=false

---
 spec/controllers/projects/blob_controller_spec.rb | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

(limited to 'spec')

diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 00a7df6ccc8..fff363bca7a 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -55,6 +55,24 @@ describe Projects::BlobController do
           expect(json_response).to have_key 'raw_path'
         end
       end
+
+      context "html_render=false" do
+        let(:id) { 'master/README.md' }
+
+        before do
+          get(:show,
+              namespace_id: project.namespace,
+              project_id: project,
+              id: id,
+              format: :json,
+              html_render: false)
+        end
+
+        it do
+          expect(response).to be_ok
+          expect(json_response).note_to have_key 'html'
+        end
+      end
     end
 
     context 'with tree path' do
-- 
cgit v1.2.1


From 2fec4183368aebf848e3014598081948ddce49ca Mon Sep 17 00:00:00 2001
From: Mario de la Ossa 
Date: Thu, 14 Jun 2018 11:40:35 -0600
Subject: ChatNotificationService - fix sending tag notifications when "only
 default branch" enabled

---
 ...ack_mattermost_notifications_shared_examples.rb | 81 +++++++++++++++++-----
 1 file changed, 64 insertions(+), 17 deletions(-)

(limited to 'spec')

diff --git a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb
index 2228e872926..7c34c7b4977 100644
--- a/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb
+++ b/spec/support/shared_examples/slack_mattermost_notifications_shared_examples.rb
@@ -245,6 +245,70 @@ RSpec.shared_examples 'slack or mattermost notifications' do
     end
   end
 
+  describe 'Push events' do
+    let(:user) { create(:user) }
+    let(:project) { create(:project, :repository, creator: user) }
+
+    before do
+      allow(chat_service).to receive_messages(
+        project: project,
+        service_hook: true,
+        webhook: webhook_url
+      )
+
+      WebMock.stub_request(:post, webhook_url)
+    end
+
+    context 'only notify for the default branch' do
+      context 'when enabled' do
+        before do
+          chat_service.notify_only_default_branch = true
+        end
+
+        it 'does not notify push events if they are not for the default branch' do
+          ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}test"
+          push_sample_data = Gitlab::DataBuilder::Push.build(project, user, nil, nil, ref, [])
+
+          chat_service.execute(push_sample_data)
+
+          expect(WebMock).not_to have_requested(:post, webhook_url)
+        end
+
+        it 'notifies about push events for the default branch' do
+          push_sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
+
+          chat_service.execute(push_sample_data)
+
+          expect(WebMock).to have_requested(:post, webhook_url).once
+        end
+
+        it 'still notifies about pushed tags' do
+          ref = "#{Gitlab::Git::TAG_REF_PREFIX}test"
+          push_sample_data = Gitlab::DataBuilder::Push.build(project, user, nil, nil, ref, [])
+
+          chat_service.execute(push_sample_data)
+
+          expect(WebMock).to have_requested(:post, webhook_url).once
+        end
+      end
+
+      context 'when disabled' do
+        before do
+          chat_service.notify_only_default_branch = false
+        end
+
+        it 'notifies about all push events' do
+          ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}test"
+          push_sample_data = Gitlab::DataBuilder::Push.build(project, user, nil, nil, ref, [])
+
+          chat_service.execute(push_sample_data)
+
+          expect(WebMock).to have_requested(:post, webhook_url).once
+        end
+      end
+    end
+  end
+
   describe "Note events" do
     let(:user) { create(:user) }
     let(:project) { create(:project, :repository, creator: user) }
@@ -394,23 +458,6 @@ RSpec.shared_examples 'slack or mattermost notifications' do
 
           expect(result).to be_falsy
         end
-
-        it 'does not notify push events if they are not for the default branch' do
-          ref = "#{Gitlab::Git::BRANCH_REF_PREFIX}test"
-          push_sample_data = Gitlab::DataBuilder::Push.build(project, user, nil, nil, ref, [])
-
-          chat_service.execute(push_sample_data)
-
-          expect(WebMock).not_to have_requested(:post, webhook_url)
-        end
-
-        it 'notifies about push events for the default branch' do
-          push_sample_data = Gitlab::DataBuilder::Push.build_sample(project, user)
-
-          chat_service.execute(push_sample_data)
-
-          expect(WebMock).to have_requested(:post, webhook_url).once
-        end
       end
 
       context 'when disabled' do
-- 
cgit v1.2.1


From 24068596ee0ab7d5a02e5aef49dc19c58ac84e40 Mon Sep 17 00:00:00 2001
From: Tim Zallmann 
Date: Thu, 14 Jun 2018 20:46:53 +0200
Subject: Fixed linting error with trailing space in rb

---
 spec/controllers/projects/blob_controller_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index fff363bca7a..a543f626bb0 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -70,7 +70,7 @@ describe Projects::BlobController do
 
         it do
           expect(response).to be_ok
-          expect(json_response).note_to have_key 'html'
+          expect(json_response).not_to have_key 'html'
         end
       end
     end
-- 
cgit v1.2.1


From cf01719d6e5a511adae61cd10ef0f82228747c24 Mon Sep 17 00:00:00 2001
From: Annabel Gray 
Date: Thu, 14 Jun 2018 20:22:56 +0000
Subject: Resolve ""Click to expand" link in collapsed diffs should be blue"

---
 spec/features/projects/diffs/diff_show_spec.rb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/features/projects/diffs/diff_show_spec.rb b/spec/features/projects/diffs/diff_show_spec.rb
index c1307ab640f..9bfcb1e816a 100644
--- a/spec/features/projects/diffs/diff_show_spec.rb
+++ b/spec/features/projects/diffs/diff_show_spec.rb
@@ -166,8 +166,7 @@ feature 'Diff file viewer', :js do
 
     context 'expanding the diff' do
       before do
-        # We can't use `click_link` because the "link" doesn't have an `href`.
-        find('a.click-to-expand').click
+        click_button 'Click to expand it.'
 
         wait_for_requests
       end
-- 
cgit v1.2.1


From c84a470bab08abce2ac9ad268e57c1c90fb7755e Mon Sep 17 00:00:00 2001
From: Jan Provaznik 
Date: Thu, 14 Jun 2018 23:21:12 +0200
Subject: Fix queue_name in Rails 5

In Rails 5 DeliveryJob.queue_name may return Proc (probably
if block is used for queue name definition). Instance method
takes handles this already and returns string as expected.
---
 spec/workers/every_sidekiq_worker_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/workers/every_sidekiq_worker_spec.rb b/spec/workers/every_sidekiq_worker_spec.rb
index 9e3b99b3502..2106959e23c 100644
--- a/spec/workers/every_sidekiq_worker_spec.rb
+++ b/spec/workers/every_sidekiq_worker_spec.rb
@@ -13,7 +13,7 @@ describe 'Every Sidekiq worker' do
     file_worker_queues = Gitlab::SidekiqConfig.worker_queues.to_set
 
     worker_queues = Gitlab::SidekiqConfig.workers.map(&:queue).to_set
-    worker_queues << ActionMailer::DeliveryJob.queue_name
+    worker_queues << ActionMailer::DeliveryJob.new.queue_name
     worker_queues << 'default'
 
     missing_from_file = worker_queues - file_worker_queues
-- 
cgit v1.2.1


From f1955962d91eb25a847553b2900068cd9487d0be Mon Sep 17 00:00:00 2001
From: Jasper Maes 
Date: Fri, 15 Jun 2018 07:57:35 +0200
Subject: Rails5 fix update_attribute usage not causing a save

---
 spec/controllers/projects/imports_controller_spec.rb | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'spec')

diff --git a/spec/controllers/projects/imports_controller_spec.rb b/spec/controllers/projects/imports_controller_spec.rb
index 011843baffc..812833cc86b 100644
--- a/spec/controllers/projects/imports_controller_spec.rb
+++ b/spec/controllers/projects/imports_controller_spec.rb
@@ -29,7 +29,7 @@ describe Projects::ImportsController do
 
       context 'when import is in progress' do
         before do
-          project.update_attribute(:import_status, :started)
+          project.update_attributes(import_status: :started)
         end
 
         it 'renders template' do
@@ -47,7 +47,7 @@ describe Projects::ImportsController do
 
       context 'when import failed' do
         before do
-          project.update_attribute(:import_status, :failed)
+          project.update_attributes(import_status: :failed)
         end
 
         it 'redirects to new_namespace_project_import_path' do
@@ -59,7 +59,7 @@ describe Projects::ImportsController do
 
       context 'when import finished' do
         before do
-          project.update_attribute(:import_status, :finished)
+          project.update_attributes(import_status: :finished)
         end
 
         context 'when project is a fork' do
@@ -108,7 +108,7 @@ describe Projects::ImportsController do
 
       context 'when import never happened' do
         before do
-          project.update_attribute(:import_status, :none)
+          project.update_attributes(import_status: :none)
         end
 
         it 'redirects to namespace_project_path' do
-- 
cgit v1.2.1


From 4ac381a565eb1b3e7ebaec443889c6a7138fdfd0 Mon Sep 17 00:00:00 2001
From: Tim Zallmann 
Date: Fri, 15 Jun 2018 09:08:21 +0200
Subject: Changed the query string parameter to a string

---
 spec/controllers/projects/blob_controller_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index a543f626bb0..f47593aad72 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -65,7 +65,7 @@ describe Projects::BlobController do
               project_id: project,
               id: id,
               format: :json,
-              html_render: false)
+              html_render: 'false')
         end
 
         it do
-- 
cgit v1.2.1


From 242039e4e12b90495fcddfbb250d9540f3a6f95a Mon Sep 17 00:00:00 2001
From: Shinya Maeda 
Date: Fri, 15 Jun 2018 17:20:25 +0900
Subject: Fix "[Rails5] '-1' is not a valid data_store"

---
 spec/models/ci/build_trace_chunk_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb
index cbcf1e55979..6213a203d6a 100644
--- a/spec/models/ci/build_trace_chunk_spec.rb
+++ b/spec/models/ci/build_trace_chunk_spec.rb
@@ -57,7 +57,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
 
     context 'when data_store is others' do
       before do
-        build_trace_chunk.send(:write_attribute, :data_store, -1)
+        build_trace_chunk.send(:write_attribute, :data_store, 999)
       end
 
       it { expect { subject }.to raise_error('Unsupported data store') }
-- 
cgit v1.2.1


From d4540c6131ba036df45463604925217756dac28f Mon Sep 17 00:00:00 2001
From: Shinya Maeda 
Date: Fri, 15 Jun 2018 18:20:46 +0900
Subject: Remove unexpected data store test suite

---
 spec/models/ci/build_trace_chunk_spec.rb | 8 --------
 1 file changed, 8 deletions(-)

(limited to 'spec')

diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb
index 6213a203d6a..b5a6d959ccb 100644
--- a/spec/models/ci/build_trace_chunk_spec.rb
+++ b/spec/models/ci/build_trace_chunk_spec.rb
@@ -54,14 +54,6 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
 
       it { is_expected.to eq('Sample data in db') }
     end
-
-    context 'when data_store is others' do
-      before do
-        build_trace_chunk.send(:write_attribute, :data_store, 999)
-      end
-
-      it { expect { subject }.to raise_error('Unsupported data store') }
-    end
   end
 
   describe '#set_data' do
-- 
cgit v1.2.1


From fbc749a96e07dd1b1b5760cfe376b5b7838181f0 Mon Sep 17 00:00:00 2001
From: Douwe Maan 
Date: Fri, 15 Jun 2018 09:42:56 +0000
Subject: Reuse viewer param and move logic to blob controller

---
 spec/controllers/projects/blob_controller_spec.rb | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index f47593aad72..9e696e9cb29 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -56,7 +56,7 @@ describe Projects::BlobController do
         end
       end
 
-      context "html_render=false" do
+      context "with viewer=none" do
         let(:id) { 'master/README.md' }
 
         before do
@@ -65,12 +65,13 @@ describe Projects::BlobController do
               project_id: project,
               id: id,
               format: :json,
-              html_render: 'false')
+              viewer: 'none')
         end
 
         it do
           expect(response).to be_ok
           expect(json_response).not_to have_key 'html'
+          expect(json_response).to have_key 'raw_path'
         end
       end
     end
-- 
cgit v1.2.1


From 9d735dc27c09f0d9ce50711dbf99ddd8514f75b9 Mon Sep 17 00:00:00 2001
From: "Marko, Peter" 
Date: Thu, 14 Jun 2018 23:45:17 +0200
Subject: Ensure ordering for group sorting tests

Instead of manually creating list to compare the test result,
use system sort to assure no errors are introduced.

Signed-off-by: Marko, Peter 
---
 spec/requests/api/groups_spec.rb | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'spec')

diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 2e7a5cbeca6..f5218ebfac2 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -152,7 +152,7 @@ describe API::Groups do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(response_groups).to eq([group3.name, group1.name, group4.name])
+        expect(response_groups).to eq(Group.visible_to_user(user1).order(:name).pluck(:name))
       end
 
       it "sorts in descending order when passed" do
@@ -161,7 +161,7 @@ describe API::Groups do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(response_groups).to eq([group4.name, group1.name, group3.name])
+        expect(response_groups).to eq(Group.visible_to_user(user1).order(name: :desc).pluck(:name))
       end
 
       it "sorts by path in order_by param" do
@@ -170,7 +170,7 @@ describe API::Groups do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(response_groups).to eq([group1.name, group4.name, group3.name])
+        expect(response_groups).to eq(Group.visible_to_user(user1).order(:path).pluck(:name))
       end
 
       it "sorts by id in the order_by param" do
@@ -179,7 +179,7 @@ describe API::Groups do
         expect(response).to have_gitlab_http_status(200)
         expect(response).to include_pagination_headers
         expect(json_response).to be_an Array
-        expect(response_groups).to eq([group1.name, group3.name, group4.name])
+        expect(response_groups).to eq(Group.visible_to_user(user1).order(:id).pluck(:name))
       end
     end
 
-- 
cgit v1.2.1


From e906be2f683f6170a5ee1d5b5f104ab0e08062d1 Mon Sep 17 00:00:00 2001
From: Phil Hughes 
Date: Thu, 7 Jun 2018 17:19:35 +0100
Subject: IDE sends last commit ID when committing changes

Closes #46192
---
 .../ide/stores/modules/commit/actions_spec.js      | 101 ++++++---------------
 spec/javascripts/ide/stores/utils_spec.js          |  60 ++++++++++++
 2 files changed, 90 insertions(+), 71 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
index a2869ff378b..45101304a4c 100644
--- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
@@ -108,77 +108,6 @@ describe('IDE commit module actions', () => {
     });
   });
 
-  describe('checkCommitStatus', () => {
-    beforeEach(() => {
-      store.state.currentProjectId = 'abcproject';
-      store.state.currentBranchId = 'master';
-      store.state.projects.abcproject = {
-        branches: {
-          master: {
-            workingReference: '1',
-          },
-        },
-      };
-    });
-
-    it('calls service', done => {
-      spyOn(service, 'getBranchData').and.returnValue(
-        Promise.resolve({
-          data: {
-            commit: { id: '123' },
-          },
-        }),
-      );
-
-      store
-        .dispatch('commit/checkCommitStatus')
-        .then(() => {
-          expect(service.getBranchData).toHaveBeenCalledWith('abcproject', 'master');
-
-          done();
-        })
-        .catch(done.fail);
-    });
-
-    it('returns true if current ref does not equal returned ID', done => {
-      spyOn(service, 'getBranchData').and.returnValue(
-        Promise.resolve({
-          data: {
-            commit: { id: '123' },
-          },
-        }),
-      );
-
-      store
-        .dispatch('commit/checkCommitStatus')
-        .then(val => {
-          expect(val).toBeTruthy();
-
-          done();
-        })
-        .catch(done.fail);
-    });
-
-    it('returns false if current ref equals returned ID', done => {
-      spyOn(service, 'getBranchData').and.returnValue(
-        Promise.resolve({
-          data: {
-            commit: { id: '1' },
-          },
-        }),
-      );
-
-      store
-        .dispatch('commit/checkCommitStatus')
-        .then(val => {
-          expect(val).toBeFalsy();
-
-          done();
-        })
-        .catch(done.fail);
-    });
-  });
-
   describe('updateFilesAfterCommit', () => {
     const data = {
       id: '123',
@@ -314,6 +243,9 @@ describe('IDE commit module actions', () => {
         ...file('changed'),
         type: 'blob',
         active: true,
+        lastCommit: {
+          id: '123456789',
+        },
       };
       store.state.stagedFiles.push(f);
       store.state.changedFiles = [
@@ -366,6 +298,7 @@ describe('IDE commit module actions', () => {
                   file_path: jasmine.anything(),
                   content: jasmine.anything(),
                   encoding: jasmine.anything(),
+                  last_commit_id: undefined,
                 },
               ],
               start_branch: 'master',
@@ -376,6 +309,32 @@ describe('IDE commit module actions', () => {
           .catch(done.fail);
       });
 
+      it('sends lastCommit ID when not creating new branch', done => {
+        store.state.commit.commitAction = '1';
+
+        store
+          .dispatch('commit/commitChanges')
+          .then(() => {
+            expect(service.commit).toHaveBeenCalledWith('abcproject', {
+              branch: jasmine.anything(),
+              commit_message: 'testing 123',
+              actions: [
+                {
+                  action: 'update',
+                  file_path: jasmine.anything(),
+                  content: jasmine.anything(),
+                  encoding: jasmine.anything(),
+                  last_commit_id: '123456789',
+                },
+              ],
+              start_branch: undefined,
+            });
+
+            done();
+          })
+          .catch(done.fail);
+      });
+
       it('sets last Commit Msg', done => {
         store
           .dispatch('commit/commitChanges')
diff --git a/spec/javascripts/ide/stores/utils_spec.js b/spec/javascripts/ide/stores/utils_spec.js
index f38ac6dd82f..3f06f287ba9 100644
--- a/spec/javascripts/ide/stores/utils_spec.js
+++ b/spec/javascripts/ide/stores/utils_spec.js
@@ -1,4 +1,5 @@
 import * as utils from '~/ide/stores/utils';
+import { file } from '../helpers';
 
 describe('Multi-file store utils', () => {
   describe('setPageTitle', () => {
@@ -63,4 +64,63 @@ describe('Multi-file store utils', () => {
       expect(foundEntry).toBeUndefined();
     });
   });
+
+  describe('createCommitPayload', () => {
+    it('returns API payload', () => {
+      const state = {
+        commitMessage: 'commit message',
+      };
+      const rootState = {
+        stagedFiles: [
+          {
+            ...file('staged'),
+            path: 'staged',
+            content: 'updated file content',
+            lastCommit: {
+              id: '123456789',
+            },
+          },
+          {
+            ...file('newFile'),
+            path: 'added',
+            tempFile: true,
+            content: 'new file content',
+            base64: true,
+            lastCommit: {
+              id: '123456789',
+            },
+          },
+        ],
+        currentBranchId: 'master',
+      };
+      const payload = utils.createCommitPayload({
+        branch: 'master',
+        newBranch: false,
+        state,
+        rootState,
+      });
+
+      expect(payload).toEqual({
+        branch: 'master',
+        commit_message: 'commit message',
+        actions: [
+          {
+            action: 'update',
+            file_path: 'staged',
+            content: 'updated file content',
+            encoding: 'text',
+            last_commit_id: '123456789',
+          },
+          {
+            action: 'create',
+            file_path: 'added',
+            content: 'new file content',
+            encoding: 'base64',
+            last_commit_id: '123456789',
+          },
+        ],
+        start_branch: undefined,
+      });
+    });
+  });
 });
-- 
cgit v1.2.1


From 3530274b13ec4f20731f9f98ea94dabe1494072d Mon Sep 17 00:00:00 2001
From: Phil Hughes 
Date: Fri, 15 Jun 2018 11:12:13 +0100
Subject: only return last_commit_sha in the JSON

---
 spec/javascripts/ide/stores/modules/commit/actions_spec.js | 4 +---
 spec/javascripts/ide/stores/utils_spec.js                  | 8 ++------
 2 files changed, 3 insertions(+), 9 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/ide/stores/modules/commit/actions_spec.js b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
index 45101304a4c..133ad627f34 100644
--- a/spec/javascripts/ide/stores/modules/commit/actions_spec.js
+++ b/spec/javascripts/ide/stores/modules/commit/actions_spec.js
@@ -243,9 +243,7 @@ describe('IDE commit module actions', () => {
         ...file('changed'),
         type: 'blob',
         active: true,
-        lastCommit: {
-          id: '123456789',
-        },
+        lastCommitSha: '123456789',
       };
       store.state.stagedFiles.push(f);
       store.state.changedFiles = [
diff --git a/spec/javascripts/ide/stores/utils_spec.js b/spec/javascripts/ide/stores/utils_spec.js
index 3f06f287ba9..a7bd443af51 100644
--- a/spec/javascripts/ide/stores/utils_spec.js
+++ b/spec/javascripts/ide/stores/utils_spec.js
@@ -76,9 +76,7 @@ describe('Multi-file store utils', () => {
             ...file('staged'),
             path: 'staged',
             content: 'updated file content',
-            lastCommit: {
-              id: '123456789',
-            },
+            lastCommitSha: '123456789',
           },
           {
             ...file('newFile'),
@@ -86,9 +84,7 @@ describe('Multi-file store utils', () => {
             tempFile: true,
             content: 'new file content',
             base64: true,
-            lastCommit: {
-              id: '123456789',
-            },
+            lastCommitSha: '123456789',
           },
         ],
         currentBranchId: 'master',
-- 
cgit v1.2.1


From 5fc3b8a08d9264eedbf886c45b4ef7b418df380d Mon Sep 17 00:00:00 2001
From: Douwe Maan 
Date: Fri, 15 Jun 2018 12:28:23 +0200
Subject: Remove FaviconUploader favicon_main version

See https://gitlab.com/gitlab-org/gitlab-ce/issues/47677 for more information
---
 spec/controllers/uploads_controller_spec.rb       | 17 -------------
 spec/lib/gitlab/favicon_spec.rb                   |  2 +-
 spec/models/project_services/jira_service_spec.rb |  2 +-
 spec/uploaders/favicon_uploader_spec.rb           | 29 -----------------------
 4 files changed, 2 insertions(+), 48 deletions(-)
 delete mode 100644 spec/uploaders/favicon_uploader_spec.rb

(limited to 'spec')

diff --git a/spec/controllers/uploads_controller_spec.rb b/spec/controllers/uploads_controller_spec.rb
index 1df2c954893..eb94d395a9e 100644
--- a/spec/controllers/uploads_controller_spec.rb
+++ b/spec/controllers/uploads_controller_spec.rb
@@ -580,23 +580,6 @@ describe UploadsController do
           expect(response).to have_gitlab_http_status(404)
         end
       end
-
-      context 'has a valid filename on the version file' do
-        it 'successfully returns the file' do
-          get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'favicon_main_dk.png'
-
-          expect(response).to have_gitlab_http_status(200)
-          expect(response.header['Content-Disposition']).to end_with 'filename="favicon_main_dk.png"'
-        end
-      end
-
-      context 'has an invalid filename on the version file' do
-        it 'returns a 404' do
-          get :show, model: 'appearance', mounted_as: 'favicon', id: appearance.id, filename: 'favicon_bogusversion_dk.png'
-
-          expect(response).to have_gitlab_http_status(404)
-        end
-      end
     end
   end
 end
diff --git a/spec/lib/gitlab/favicon_spec.rb b/spec/lib/gitlab/favicon_spec.rb
index 08c4a474217..f36111a4946 100644
--- a/spec/lib/gitlab/favicon_spec.rb
+++ b/spec/lib/gitlab/favicon_spec.rb
@@ -19,7 +19,7 @@ RSpec.describe Gitlab::Favicon, :request_store do
 
     it 'uses the custom favicon if a favicon appearance is present' do
       create :appearance, favicon: fixture_file_upload('spec/fixtures/dk.png')
-      expect(described_class.main).to match %r{/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.png}
+      expect(described_class.main).to match %r{/uploads/-/system/appearance/favicon/\d+/dk.png}
     end
   end
 
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index b9f1c7dd5df..6c637533c6b 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -478,7 +478,7 @@ describe JiraService do
       create :appearance, favicon: fixture_file_upload('spec/fixtures/dk.png')
 
       props = described_class.new.send(:build_remote_link_props, url: 'http://example.com', title: 'title')
-      expect(props[:object][:icon][:url16x16]).to match %r{^http://localhost/uploads/-/system/appearance/favicon/\d+/favicon_main_dk.png$}
+      expect(props[:object][:icon][:url16x16]).to match %r{^http://localhost/uploads/-/system/appearance/favicon/\d+/dk.png$}
     end
   end
 end
diff --git a/spec/uploaders/favicon_uploader_spec.rb b/spec/uploaders/favicon_uploader_spec.rb
deleted file mode 100644
index 37deea8ab90..00000000000
--- a/spec/uploaders/favicon_uploader_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require 'spec_helper'
-
-RSpec.describe FaviconUploader do
-  include CarrierWave::Test::Matchers
-
-  let(:uploader) { described_class.new(build_stubbed(:user)) }
-
-  after do
-    uploader.remove!
-  end
-
-  def upload_fixture(filename)
-    fixture_file_upload("spec/fixtures/#{filename}")
-  end
-
-  context 'versions' do
-    before do
-      uploader.store!(upload_fixture('dk.png'))
-    end
-
-    it 'has the correct format' do
-      expect(uploader.favicon_main).to be_format('png')
-    end
-
-    it 'has the correct dimensions' do
-      expect(uploader.favicon_main).to have_dimensions(32, 32)
-    end
-  end
-end
-- 
cgit v1.2.1


From d304f883520277334339bf2be1dd20c53a51dc16 Mon Sep 17 00:00:00 2001
From: Sean McGivern 
Date: Fri, 15 Jun 2018 13:29:55 +0100
Subject: Expose a clean_backtrace method from Gitlab::Profiler

This method makes it easier for other parts of the app to get clean backtraces,
as well as console users.
---
 spec/lib/gitlab/profiler_spec.rb | 45 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 45 insertions(+)

(limited to 'spec')

diff --git a/spec/lib/gitlab/profiler_spec.rb b/spec/lib/gitlab/profiler_spec.rb
index 548eb28fe4d..4059188fba1 100644
--- a/spec/lib/gitlab/profiler_spec.rb
+++ b/spec/lib/gitlab/profiler_spec.rb
@@ -135,6 +135,51 @@ describe Gitlab::Profiler do
     end
   end
 
+  describe '.clean_backtrace' do
+    it 'uses the Rails backtrace cleaner' do
+      backtrace = []
+
+      expect(Rails.backtrace_cleaner).to receive(:clean).with(backtrace)
+
+      described_class.clean_backtrace(backtrace)
+    end
+
+    it 'removes lines from IGNORE_BACKTRACES' do
+      backtrace = [
+        "lib/gitlab/gitaly_client.rb:294:in `block (2 levels) in migrate'",
+        "lib/gitlab/gitaly_client.rb:331:in `allow_n_plus_1_calls'",
+        "lib/gitlab/gitaly_client.rb:280:in `block in migrate'",
+        "lib/gitlab/metrics/influx_db.rb:103:in `measure'",
+        "lib/gitlab/gitaly_client.rb:278:in `migrate'",
+        "lib/gitlab/git/repository.rb:1451:in `gitaly_migrate'",
+        "lib/gitlab/git/commit.rb:66:in `find'",
+        "app/models/repository.rb:1047:in `find_commit'",
+        "lib/gitlab/metrics/instrumentation.rb:159:in `block in find_commit'",
+        "lib/gitlab/metrics/method_call.rb:36:in `measure'",
+        "lib/gitlab/metrics/instrumentation.rb:159:in `find_commit'",
+        "app/models/repository.rb:113:in `commit'",
+        "lib/gitlab/i18n.rb:50:in `with_locale'",
+        "lib/gitlab/middleware/multipart.rb:95:in `call'",
+        "lib/gitlab/request_profiler/middleware.rb:14:in `call'",
+        "ee/lib/gitlab/database/load_balancing/rack_middleware.rb:37:in `call'",
+        "ee/lib/gitlab/jira/middleware.rb:15:in `call'"
+      ]
+
+      expect(described_class.clean_backtrace(backtrace))
+        .to eq([
+                 "lib/gitlab/gitaly_client.rb:294:in `block (2 levels) in migrate'",
+                 "lib/gitlab/gitaly_client.rb:331:in `allow_n_plus_1_calls'",
+                 "lib/gitlab/gitaly_client.rb:280:in `block in migrate'",
+                 "lib/gitlab/gitaly_client.rb:278:in `migrate'",
+                 "lib/gitlab/git/repository.rb:1451:in `gitaly_migrate'",
+                 "lib/gitlab/git/commit.rb:66:in `find'",
+                 "app/models/repository.rb:1047:in `find_commit'",
+                 "app/models/repository.rb:113:in `commit'",
+                 "ee/lib/gitlab/jira/middleware.rb:15:in `call'"
+               ])
+    end
+  end
+
   describe '.with_custom_logger' do
     context 'when the logger is set' do
       it 'uses the replacement logger for the duration of the block' do
-- 
cgit v1.2.1


From 9403b1d951c47aca67d2bac1369b86c125c5119d Mon Sep 17 00:00:00 2001
From: Bob Van Landuyt 
Date: Thu, 14 Jun 2018 15:06:53 +0200
Subject: Allow querying a single MR within a project

This allows the user to get a single MR nested in a GraphQL project
query.

Since we need the full path and the iid anyway, this makes more sense
than having a root query that needs the full path as well.
---
 .../resolvers/merge_request_resolver_spec.rb       | 23 ++------
 spec/graphql/types/project_type_spec.rb            |  9 ++++
 spec/graphql/types/query_type_spec.rb              | 16 +-----
 .../api/graphql/merge_request_query_spec.rb        | 49 -----------------
 spec/requests/api/graphql/project_query_spec.rb    | 63 +++++++++++++++++++---
 spec/support/helpers/graphql_helpers.rb            | 15 ++++--
 spec/support/matchers/graphql_matchers.rb          |  6 +++
 7 files changed, 89 insertions(+), 92 deletions(-)
 delete mode 100644 spec/requests/api/graphql/merge_request_query_spec.rb

(limited to 'spec')

diff --git a/spec/graphql/resolvers/merge_request_resolver_spec.rb b/spec/graphql/resolvers/merge_request_resolver_spec.rb
index af015533209..73993b3a039 100644
--- a/spec/graphql/resolvers/merge_request_resolver_spec.rb
+++ b/spec/graphql/resolvers/merge_request_resolver_spec.rb
@@ -10,49 +10,36 @@ describe Resolvers::MergeRequestResolver do
   set(:other_project) { create(:project, :repository) }
   set(:other_merge_request) { create(:merge_request, source_project: other_project, target_project: other_project) }
 
-  let(:full_path) { project.full_path }
   let(:iid_1) { merge_request_1.iid }
   let(:iid_2) { merge_request_2.iid }
 
-  let(:other_full_path) { other_project.full_path }
   let(:other_iid) { other_merge_request.iid }
 
   describe '#resolve' do
     it 'batch-resolves merge requests by target project full path and IID' do
-      path = full_path # avoid database query
-
       result = batch(max_queries: 2) do
-        [resolve_mr(path, iid_1), resolve_mr(path, iid_2)]
+        [resolve_mr(project, iid_1), resolve_mr(project, iid_2)]
       end
 
       expect(result).to contain_exactly(merge_request_1, merge_request_2)
     end
 
     it 'can batch-resolve merge requests from different projects' do
-      path = project.full_path # avoid database queries
-      other_path = other_full_path
-
       result = batch(max_queries: 3) do
-        [resolve_mr(path, iid_1), resolve_mr(path, iid_2), resolve_mr(other_path, other_iid)]
+        [resolve_mr(project, iid_1), resolve_mr(project, iid_2), resolve_mr(other_project, other_iid)]
       end
 
       expect(result).to contain_exactly(merge_request_1, merge_request_2, other_merge_request)
     end
 
     it 'resolves an unknown iid to nil' do
-      result = batch { resolve_mr(full_path, -1) }
-
-      expect(result).to be_nil
-    end
-
-    it 'resolves a known iid for an unknown full_path to nil' do
-      result = batch { resolve_mr('unknown/project', iid_1) }
+      result = batch { resolve_mr(project, -1) }
 
       expect(result).to be_nil
     end
   end
 
-  def resolve_mr(full_path, iid)
-    resolve(described_class, args: { full_path: full_path, iid: iid })
+  def resolve_mr(project, iid)
+    resolve(described_class, obj: project, args: { iid: iid })
   end
 end
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index e0f89105b86..b4eeca2e3f1 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -2,4 +2,13 @@ require 'spec_helper'
 
 describe GitlabSchema.types['Project'] do
   it { expect(described_class.graphql_name).to eq('Project') }
+
+  describe 'nested merge request' do
+    it { expect(described_class).to have_graphql_field(:merge_request) }
+
+    it 'authorizes the merge request' do
+      expect(described_class.fields['mergeRequest'])
+        .to  require_graphql_authorizations(:read_merge_request)
+    end
+  end
 end
diff --git a/spec/graphql/types/query_type_spec.rb b/spec/graphql/types/query_type_spec.rb
index 8488252fd59..e1df6f9811d 100644
--- a/spec/graphql/types/query_type_spec.rb
+++ b/spec/graphql/types/query_type_spec.rb
@@ -5,7 +5,7 @@ describe GitlabSchema.types['Query'] do
     expect(described_class.graphql_name).to eq('Query')
   end
 
-  it { is_expected.to have_graphql_fields(:project, :merge_request, :echo) }
+  it { is_expected.to have_graphql_fields(:project, :echo) }
 
   describe 'project field' do
     subject { described_class.fields['project'] }
@@ -20,18 +20,4 @@ describe GitlabSchema.types['Query'] do
       is_expected.to require_graphql_authorizations(:read_project)
     end
   end
-
-  describe 'merge_request field' do
-    subject { described_class.fields['mergeRequest'] }
-
-    it 'finds MRs by project and IID' do
-      is_expected.to have_graphql_arguments(:full_path, :iid)
-      is_expected.to have_graphql_type(Types::MergeRequestType)
-      is_expected.to have_graphql_resolver(Resolvers::MergeRequestResolver)
-    end
-
-    it 'authorizes with read_merge_request' do
-      is_expected.to require_graphql_authorizations(:read_merge_request)
-    end
-  end
 end
diff --git a/spec/requests/api/graphql/merge_request_query_spec.rb b/spec/requests/api/graphql/merge_request_query_spec.rb
deleted file mode 100644
index 12b1d5d18a2..00000000000
--- a/spec/requests/api/graphql/merge_request_query_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require 'spec_helper'
-
-describe 'getting merge request information' do
-  include GraphqlHelpers
-
-  let(:project) { create(:project, :repository) }
-  let(:merge_request) { create(:merge_request, source_project: project) }
-  let(:current_user) { create(:user) }
-
-  let(:query) do
-    attributes = {
-      'fullPath' => merge_request.project.full_path,
-      'iid' => merge_request.iid
-    }
-    graphql_query_for('mergeRequest',  attributes)
-  end
-
-  context 'when the user has access to the merge request' do
-    before do
-      project.add_developer(current_user)
-      post_graphql(query, current_user: current_user)
-    end
-
-    it 'returns the merge request' do
-      expect(graphql_data['mergeRequest']).not_to be_nil
-    end
-
-    # This is a field coming from the `MergeRequestPresenter`
-    it 'includes a web_url' do
-      expect(graphql_data['mergeRequest']['webUrl']).to be_present
-    end
-
-    it_behaves_like 'a working graphql query'
-  end
-
-  context 'when the user does not have access to the merge request' do
-    before do
-      post_graphql(query, current_user: current_user)
-    end
-
-    it 'returns an empty field' do
-      post_graphql(query, current_user: current_user)
-
-      expect(graphql_data['mergeRequest']).to be_nil
-    end
-
-    it_behaves_like 'a working graphql query'
-  end
-end
diff --git a/spec/requests/api/graphql/project_query_spec.rb b/spec/requests/api/graphql/project_query_spec.rb
index 8196bcfa87c..796ffc9d569 100644
--- a/spec/requests/api/graphql/project_query_spec.rb
+++ b/spec/requests/api/graphql/project_query_spec.rb
@@ -13,27 +13,76 @@ describe 'getting project information' do
   context 'when the user has access to the project' do
     before do
       project.add_developer(current_user)
-      post_graphql(query, current_user: current_user)
     end
 
     it 'includes the project' do
+      post_graphql(query, current_user: current_user)
+
       expect(graphql_data['project']).not_to be_nil
     end
 
-    it_behaves_like 'a working graphql query'
-  end
+    it_behaves_like 'a working graphql query' do
+      before do
+        post_graphql(query, current_user: current_user)
+      end
+    end
 
-  context 'when the user does not have access to the project' do
-    before do
-      post_graphql(query, current_user: current_user)
+    context 'when requesting a nested merge request' do
+      let(:merge_request) { create(:merge_request, source_project: project) }
+      let(:merge_request_graphql_data) { graphql_data['project']['mergeRequest'] }
+
+      let(:query) do
+        graphql_query_for(
+          'project',
+          { 'fullPath' => project.full_path },
+          query_graphql_field('mergeRequest', iid: merge_request.iid)
+        )
+      end
+
+      it_behaves_like 'a working graphql query' do
+        before do
+          post_graphql(query, current_user: current_user)
+        end
+      end
+
+      it 'contains merge request information' do
+        post_graphql(query, current_user: current_user)
+
+        expect(merge_request_graphql_data).not_to be_nil
+      end
+
+      # This is a field coming from the `MergeRequestPresenter`
+      it 'includes a web_url' do
+        post_graphql(query, current_user: current_user)
+
+        expect(merge_request_graphql_data['webUrl']).to be_present
+      end
+
+      context 'when the user does not have access to the merge request' do
+        let(:project) { create(:project, :public, :repository) }
+
+        it 'returns nil' do
+          project.project_feature.update!(merge_requests_access_level: ProjectFeature::PRIVATE)
+
+          post_graphql(query)
+
+          expect(merge_request_graphql_data).to be_nil
+        end
+      end
     end
+  end
 
+  context 'when the user does not have access to the project' do
     it 'returns an empty field' do
       post_graphql(query, current_user: current_user)
 
       expect(graphql_data['project']).to be_nil
     end
 
-    it_behaves_like 'a working graphql query'
+    it_behaves_like 'a working graphql query' do
+      before do
+        post_graphql(query, current_user: current_user)
+      end
+    end
   end
 end
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 30ff9a1196a..0930b9da368 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -34,14 +34,20 @@ module GraphqlHelpers
   end
 
   def graphql_query_for(name, attributes = {}, fields = nil)
+    <<~QUERY
+    {
+      #{query_graphql_field(name, attributes, fields)}
+    }
+    QUERY
+  end
+
+  def query_graphql_field(name, attributes = {}, fields = nil)
     fields ||= all_graphql_fields_for(name.classify)
     attributes = attributes_to_graphql(attributes)
     <<~QUERY
-    {
       #{name}(#{attributes}) {
         #{fields}
       }
-    }
     QUERY
   end
 
@@ -50,12 +56,15 @@ module GraphqlHelpers
     return "" unless type
 
     type.fields.map do |name, field|
+      # We can't guess arguments, so skip fields that require them
+      next if field.arguments.any?
+
       if scalar?(field)
         name
       else
         "#{name} { #{all_graphql_fields_for(field_type(field))} }"
       end
-    end.join("\n")
+    end.compact.join("\n")
   end
 
   def attributes_to_graphql(attributes)
diff --git a/spec/support/matchers/graphql_matchers.rb b/spec/support/matchers/graphql_matchers.rb
index ba7a1c8cde0..d23cbaf4beb 100644
--- a/spec/support/matchers/graphql_matchers.rb
+++ b/spec/support/matchers/graphql_matchers.rb
@@ -13,6 +13,12 @@ RSpec::Matchers.define :have_graphql_fields do |*expected|
   end
 end
 
+RSpec::Matchers.define :have_graphql_field do |field_name|
+  match do |kls|
+    expect(kls.fields.keys).to include(GraphqlHelpers.fieldnamerize(field_name))
+  end
+end
+
 RSpec::Matchers.define :have_graphql_arguments do |*expected|
   include GraphqlHelpers
 
-- 
cgit v1.2.1


From ca065e493e7a62f22cb330659e75f8567fa6131f Mon Sep 17 00:00:00 2001
From: Bob Van Landuyt 
Date: Mon, 7 May 2018 16:04:11 +0200
Subject: Forbids combining named and unnamed variables in `gitlab.pot`

This would break with an argument error when interpolating using
`sprintf` in ruby.
---
 spec/lib/gitlab/i18n/po_linter_spec.rb | 102 ++++++++++++++++++++-------------
 1 file changed, 62 insertions(+), 40 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/i18n/po_linter_spec.rb b/spec/lib/gitlab/i18n/po_linter_spec.rb
index 3a962ba7f22..9bbd51fe212 100644
--- a/spec/lib/gitlab/i18n/po_linter_spec.rb
+++ b/spec/lib/gitlab/i18n/po_linter_spec.rb
@@ -5,6 +5,25 @@ describe Gitlab::I18n::PoLinter do
   let(:linter) { described_class.new(po_path) }
   let(:po_path) { 'spec/fixtures/valid.po' }
 
+  def fake_translation(id:, translation:, plural_id: nil, plurals: [])
+    data = { msgid: id, msgid_plural: plural_id }
+
+    if plural_id
+      [translation, *plurals].each_with_index do |plural, index|
+        allow(FastGettext::Translation).to receive(:n_).with(plural_id, index).and_return(plural)
+        data.merge!("msgstr[#{index}]" => plural)
+      end
+    else
+      allow(FastGettext::Translation).to receive(:_).with(id).and_return(translation)
+      data[:msgstr] = translation
+    end
+
+    Gitlab::I18n::TranslationEntry.new(
+      data,
+      plurals.size + 1
+    )
+  end
+
   describe '#errors' do
     it 'only calls validation once' do
       expect(linter).to receive(:validate_po).once.and_call_original
@@ -155,9 +174,8 @@ describe Gitlab::I18n::PoLinter do
 
   describe '#validate_entries' do
     it 'keeps track of errors for entries' do
-      fake_invalid_entry = Gitlab::I18n::TranslationEntry.new(
-        { msgid: "Hello %{world}", msgstr: "Bonjour %{monde}" }, 2
-      )
+      fake_invalid_entry = fake_translation(id: "Hello %{world}",
+                                            translation: "Bonjour %{monde}")
       allow(linter).to receive(:translation_entries) { [fake_invalid_entry] }
 
       expect(linter).to receive(:validate_entry)
@@ -177,6 +195,7 @@ describe Gitlab::I18n::PoLinter do
       expect(linter).to receive(:validate_newlines).with([], fake_entry)
       expect(linter).to receive(:validate_number_of_plurals).with([], fake_entry)
       expect(linter).to receive(:validate_unescaped_chars).with([], fake_entry)
+      expect(linter).to receive(:validate_translation).with([], fake_entry)
 
       linter.validate_entry(fake_entry)
     end
@@ -201,13 +220,12 @@ describe Gitlab::I18n::PoLinter do
   end
 
   describe '#validate_variables' do
-    it 'validates both signular and plural in a pluralized string when the entry has a singular' do
-      pluralized_entry = Gitlab::I18n::TranslationEntry.new(
-        { msgid: 'Hello %{world}',
-          msgid_plural: 'Hello all %{world}',
-          'msgstr[0]' => 'Bonjour %{world}',
-          'msgstr[1]' => 'Bonjour tous %{world}' },
-        2
+    it 'validates both singular and plural in a pluralized string when the entry has a singular' do
+      pluralized_entry = fake_translation(
+        id: 'Hello %{world}',
+        translation: 'Bonjour %{world}',
+        plural_id: 'Hello all %{world}',
+        plurals: ['Bonjour tous %{world}']
       )
 
       expect(linter).to receive(:validate_variables_in_message)
@@ -221,11 +239,10 @@ describe Gitlab::I18n::PoLinter do
     end
 
     it 'only validates plural when there is no separate singular' do
-      pluralized_entry = Gitlab::I18n::TranslationEntry.new(
-        { msgid: 'Hello %{world}',
-          msgid_plural: 'Hello all %{world}',
-          'msgstr[0]' => 'Bonjour %{world}' },
-        1
+      pluralized_entry = fake_translation(
+        id: 'Hello %{world}',
+        translation: 'Bonjour %{world}',
+        plural_id: 'Hello all %{world}'
       )
 
       expect(linter).to receive(:validate_variables_in_message)
@@ -235,10 +252,7 @@ describe Gitlab::I18n::PoLinter do
     end
 
     it 'validates the message variables' do
-      entry = Gitlab::I18n::TranslationEntry.new(
-        { msgid: 'Hello', msgstr: 'Bonjour' },
-        2
-      )
+      entry = fake_translation(id: 'Hello', translation: 'Bonjour')
 
       expect(linter).to receive(:validate_variables_in_message)
                           .with([], 'Hello', 'Bonjour')
@@ -251,21 +265,34 @@ describe Gitlab::I18n::PoLinter do
     it 'detects when a variables are used incorrectly' do
       errors = []
 
-      expected_errors = [' is missing: [%{hello}]',
-                         ' is using unknown variables: [%{world}]',
-                         'is combining multiple unnamed variables']
+      expected_errors = ['<%d hello %{world} %s> is missing: [%{hello}]',
+                         '<%d hello %{world} %s> is using unknown variables: [%{world}]',
+                         'is combining multiple unnamed variables',
+                         'is combining named variables with unnamed variables']
 
-      linter.validate_variables_in_message(errors, '%{hello} world %d', 'hello %{world} %d')
+      linter.validate_variables_in_message(errors, '%d %{hello} world %s', '%d hello %{world} %s')
 
       expect(errors).to include(*expected_errors)
     end
+
+    it 'does not allow combining 1 `%d` unnamed variable with named variables' do
+      errors = []
+
+      linter.validate_variables_in_message(errors,
+                                           '%{type} detected %d vulnerability',
+                                           '%{type} detecteerde %d kwetsbaarheid')
+
+      expect(errors).not_to be_empty
+    end
   end
 
   describe '#validate_translation' do
+    let(:entry) { fake_translation(id: 'Hello %{world}', translation: 'Bonjour %{world}') }
+
     it 'succeeds with valid variables' do
       errors = []
 
-      linter.validate_translation(errors, 'Hello %{world}',  ['%{world}'])
+      linter.validate_translation(errors, entry)
 
       expect(errors).to be_empty
     end
@@ -275,43 +302,38 @@ describe Gitlab::I18n::PoLinter do
 
       expect(FastGettext::Translation).to receive(:_) { raise 'broken' }
 
-      linter.validate_translation(errors, 'Hello', [])
+      linter.validate_translation(errors, entry)
 
-      expect(errors).to include('Failure translating to en with []: broken')
+      expect(errors).to include('Failure translating to en: broken')
     end
 
     it 'adds an error message when translating fails when translating with context' do
+      entry = fake_translation(id: 'Tests|Hello', translation: 'broken')
       errors = []
 
       expect(FastGettext::Translation).to receive(:s_) { raise 'broken' }
 
-      linter.validate_translation(errors, 'Tests|Hello', [])
+      linter.validate_translation(errors, entry)
 
-      expect(errors).to include('Failure translating to en with []: broken')
+      expect(errors).to include('Failure translating to en: broken')
     end
 
     it "adds an error when trying to translate with incorrect variables when using unnamed variables" do
+      entry = fake_translation(id: 'Hello %s', translation: 'Hello %d')
       errors = []
 
-      linter.validate_translation(errors, 'Hello %d', ['%s'])
+      linter.validate_translation(errors, entry)
 
-      expect(errors.first).to start_with("Failure translating to en with")
+      expect(errors.first).to start_with("Failure translating to en")
     end
 
     it "adds an error when trying to translate with named variables when unnamed variables are expected" do
+      entry = fake_translation(id: 'Hello %s', translation: 'Hello %{thing}')
       errors = []
 
-      linter.validate_translation(errors, 'Hello %d', ['%{world}'])
-
-      expect(errors.first).to start_with("Failure translating to en with")
-    end
-
-    it 'adds an error when translated with incorrect variables using named variables' do
-      errors = []
-
-      linter.validate_translation(errors, 'Hello %{thing}', ['%d'])
+      linter.validate_translation(errors, entry)
 
-      expect(errors.first).to start_with("Failure translating to en with")
+      expect(errors.first).to start_with("Failure translating to en")
     end
   end
 
-- 
cgit v1.2.1


From 3b5ce6945dee059717855962271245bbb29f24e1 Mon Sep 17 00:00:00 2001
From: Bob Van Landuyt 
Date: Mon, 7 May 2018 17:56:18 +0200
Subject: Validate PO-variable usage in message ids

That way we can detect incorrect usage before the strings are added to
Crowdin for translation
---
 spec/lib/gitlab/i18n/po_linter_spec.rb | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

(limited to 'spec')

diff --git a/spec/lib/gitlab/i18n/po_linter_spec.rb b/spec/lib/gitlab/i18n/po_linter_spec.rb
index 9bbd51fe212..045916e6dc2 100644
--- a/spec/lib/gitlab/i18n/po_linter_spec.rb
+++ b/spec/lib/gitlab/i18n/po_linter_spec.rb
@@ -220,6 +220,10 @@ describe Gitlab::I18n::PoLinter do
   end
 
   describe '#validate_variables' do
+    before do
+      allow(linter).to receive(:validate_variables_in_message).and_call_original
+    end
+
     it 'validates both singular and plural in a pluralized string when the entry has a singular' do
       pluralized_entry = fake_translation(
         id: 'Hello %{world}',
@@ -259,6 +263,24 @@ describe Gitlab::I18n::PoLinter do
 
       linter.validate_variables([], entry)
     end
+
+    it 'validates variable usage in message ids' do
+      entry = fake_translation(
+        id: 'Hello %{world}',
+        translation: 'Bonjour %{world}',
+        plural_id: 'Hello all %{world}',
+        plurals: ['Bonjour tous %{world}']
+      )
+
+      expect(linter).to receive(:validate_variables_in_message)
+                          .with([], 'Hello %{world}', 'Hello %{world}')
+                          .and_call_original
+      expect(linter).to receive(:validate_variables_in_message)
+                          .with([], 'Hello all %{world}', 'Hello all %{world}')
+                          .and_call_original
+
+      linter.validate_variables([], entry)
+    end
   end
 
   describe '#validate_variables_in_message' do
-- 
cgit v1.2.1


From 17fc178cb5a68be787cb3fa243aed4cf1abb24a3 Mon Sep 17 00:00:00 2001
From: Bob Van Landuyt 
Date: Mon, 14 May 2018 15:28:39 +0200
Subject: Correctly translate all forms in tests

---
 spec/lib/gitlab/i18n/metadata_entry_spec.rb    |  6 +--
 spec/lib/gitlab/i18n/po_linter_spec.rb         | 73 +++++++++++++++++++++-----
 spec/lib/gitlab/i18n/translation_entry_spec.rb |  6 +--
 3 files changed, 65 insertions(+), 20 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/i18n/metadata_entry_spec.rb b/spec/lib/gitlab/i18n/metadata_entry_spec.rb
index ab71d6454a9..a399517cc04 100644
--- a/spec/lib/gitlab/i18n/metadata_entry_spec.rb
+++ b/spec/lib/gitlab/i18n/metadata_entry_spec.rb
@@ -1,7 +1,7 @@
 require 'spec_helper'
 
 describe Gitlab::I18n::MetadataEntry do
-  describe '#expected_plurals' do
+  describe '#expected_forms' do
     it 'returns the number of plurals' do
       data = {
         msgid: "",
@@ -22,7 +22,7 @@ describe Gitlab::I18n::MetadataEntry do
       }
       entry = described_class.new(data)
 
-      expect(entry.expected_plurals).to eq(2)
+      expect(entry.expected_forms).to eq(2)
     end
 
     it 'returns 0 for the POT-metadata' do
@@ -45,7 +45,7 @@ describe Gitlab::I18n::MetadataEntry do
       }
       entry = described_class.new(data)
 
-      expect(entry.expected_plurals).to eq(0)
+      expect(entry.expected_forms).to eq(0)
     end
   end
 end
diff --git a/spec/lib/gitlab/i18n/po_linter_spec.rb b/spec/lib/gitlab/i18n/po_linter_spec.rb
index 045916e6dc2..3dbc23d2aaf 100644
--- a/spec/lib/gitlab/i18n/po_linter_spec.rb
+++ b/spec/lib/gitlab/i18n/po_linter_spec.rb
@@ -1,20 +1,22 @@
 require 'spec_helper'
 require 'simple_po_parser'
 
+# Disabling this cop to allow for multi-language examples in comments
+# rubocop:disable Style/AsciiComments
 describe Gitlab::I18n::PoLinter do
   let(:linter) { described_class.new(po_path) }
   let(:po_path) { 'spec/fixtures/valid.po' }
 
-  def fake_translation(id:, translation:, plural_id: nil, plurals: [])
-    data = { msgid: id, msgid_plural: plural_id }
+  def fake_translation(msgid:, translation:, plural_id: nil, plurals: [])
+    data = { msgid: msgid, msgid_plural: plural_id }
 
     if plural_id
       [translation, *plurals].each_with_index do |plural, index|
-        allow(FastGettext::Translation).to receive(:n_).with(plural_id, index).and_return(plural)
+        allow(FastGettext::Translation).to receive(:n_).with(msgid, plural_id, index).and_return(plural)
         data.merge!("msgstr[#{index}]" => plural)
       end
     else
-      allow(FastGettext::Translation).to receive(:_).with(id).and_return(translation)
+      allow(FastGettext::Translation).to receive(:_).with(msgid).and_return(translation)
       data[:msgstr] = translation
     end
 
@@ -174,7 +176,7 @@ describe Gitlab::I18n::PoLinter do
 
   describe '#validate_entries' do
     it 'keeps track of errors for entries' do
-      fake_invalid_entry = fake_translation(id: "Hello %{world}",
+      fake_invalid_entry = fake_translation(msgid: "Hello %{world}",
                                             translation: "Bonjour %{monde}")
       allow(linter).to receive(:translation_entries) { [fake_invalid_entry] }
 
@@ -204,7 +206,7 @@ describe Gitlab::I18n::PoLinter do
   describe '#validate_number_of_plurals' do
     it 'validates when there are an incorrect number of translations' do
       fake_metadata = double
-      allow(fake_metadata).to receive(:expected_plurals).and_return(2)
+      allow(fake_metadata).to receive(:expected_forms).and_return(2)
       allow(linter).to receive(:metadata_entry).and_return(fake_metadata)
 
       fake_entry = Gitlab::I18n::TranslationEntry.new(
@@ -226,7 +228,7 @@ describe Gitlab::I18n::PoLinter do
 
     it 'validates both singular and plural in a pluralized string when the entry has a singular' do
       pluralized_entry = fake_translation(
-        id: 'Hello %{world}',
+        msgid: 'Hello %{world}',
         translation: 'Bonjour %{world}',
         plural_id: 'Hello all %{world}',
         plurals: ['Bonjour tous %{world}']
@@ -244,7 +246,7 @@ describe Gitlab::I18n::PoLinter do
 
     it 'only validates plural when there is no separate singular' do
       pluralized_entry = fake_translation(
-        id: 'Hello %{world}',
+        msgid: 'Hello %{world}',
         translation: 'Bonjour %{world}',
         plural_id: 'Hello all %{world}'
       )
@@ -256,7 +258,7 @@ describe Gitlab::I18n::PoLinter do
     end
 
     it 'validates the message variables' do
-      entry = fake_translation(id: 'Hello', translation: 'Bonjour')
+      entry = fake_translation(msgid: 'Hello', translation: 'Bonjour')
 
       expect(linter).to receive(:validate_variables_in_message)
                           .with([], 'Hello', 'Bonjour')
@@ -266,7 +268,7 @@ describe Gitlab::I18n::PoLinter do
 
     it 'validates variable usage in message ids' do
       entry = fake_translation(
-        id: 'Hello %{world}',
+        msgid: 'Hello %{world}',
         translation: 'Bonjour %{world}',
         plural_id: 'Hello all %{world}',
         plurals: ['Bonjour tous %{world}']
@@ -309,7 +311,7 @@ describe Gitlab::I18n::PoLinter do
   end
 
   describe '#validate_translation' do
-    let(:entry) { fake_translation(id: 'Hello %{world}', translation: 'Bonjour %{world}') }
+    let(:entry) { fake_translation(msgid: 'Hello %{world}', translation: 'Bonjour %{world}') }
 
     it 'succeeds with valid variables' do
       errors = []
@@ -330,7 +332,7 @@ describe Gitlab::I18n::PoLinter do
     end
 
     it 'adds an error message when translating fails when translating with context' do
-      entry = fake_translation(id: 'Tests|Hello', translation: 'broken')
+      entry = fake_translation(msgid: 'Tests|Hello', translation: 'broken')
       errors = []
 
       expect(FastGettext::Translation).to receive(:s_) { raise 'broken' }
@@ -341,7 +343,7 @@ describe Gitlab::I18n::PoLinter do
     end
 
     it "adds an error when trying to translate with incorrect variables when using unnamed variables" do
-      entry = fake_translation(id: 'Hello %s', translation: 'Hello %d')
+      entry = fake_translation(msgid: 'Hello %s', translation: 'Hello %d')
       errors = []
 
       linter.validate_translation(errors, entry)
@@ -350,13 +352,55 @@ describe Gitlab::I18n::PoLinter do
     end
 
     it "adds an error when trying to translate with named variables when unnamed variables are expected" do
-      entry = fake_translation(id: 'Hello %s', translation: 'Hello %{thing}')
+      entry = fake_translation(msgid: 'Hello %s', translation: 'Hello %{thing}')
       errors = []
 
       linter.validate_translation(errors, entry)
 
       expect(errors.first).to start_with("Failure translating to en")
     end
+
+    it 'tests translation for all given forms' do
+      # Fake a language that has 3 forms to translate
+      fake_metadata = double
+      allow(fake_metadata).to receive(:forms_to_test).and_return(3)
+      allow(linter).to receive(:metadata_entry).and_return(fake_metadata)
+      entry = fake_translation(
+        msgid: '%d exception',
+        translation: '%d uitzondering',
+        plural_id: '%d exceptions',
+        plurals: ['%d uitzonderingen', '%d uitzonderingetjes']
+      )
+
+      # Make each count use a different index
+      allow(linter).to receive(:index_for_pluralization).with(0).and_return(0)
+      allow(linter).to receive(:index_for_pluralization).with(1).and_return(1)
+      allow(linter).to receive(:index_for_pluralization).with(2).and_return(2)
+
+      expect(FastGettext::Translation).to receive(:n_).with('%d exception', '%d exceptions', 0).and_call_original
+      expect(FastGettext::Translation).to receive(:n_).with('%d exception', '%d exceptions', 1).and_call_original
+      expect(FastGettext::Translation).to receive(:n_).with('%d exception', '%d exceptions', 2).and_call_original
+
+      linter.validate_translation([], entry)
+    end
+  end
+
+  describe '#numbers_covering_all_plurals' do
+    it 'can correctly find all required numbers to translate to Polish' do
+      # Polish used as an example with 3 different forms:
+      # 0, all plurals except the ones ending in 2,3,4: Kotów
+      # 1: Kot
+      # 2-3-4: Koty
+      # So translating with [0, 1, 2] will give us all different posibilities
+      fake_metadata = double
+      allow(fake_metadata).to receive(:forms_to_test).and_return(4)
+      allow(linter).to receive(:metadata_entry).and_return(fake_metadata)
+      allow(linter).to receive(:locale).and_return('pl_PL')
+
+      numbers = linter.numbers_covering_all_plurals
+
+      expect(numbers).to contain_exactly(0, 1, 2)
+    end
   end
 
   describe '#fill_in_variables' do
@@ -380,3 +424,4 @@ describe Gitlab::I18n::PoLinter do
     end
   end
 end
+# rubocop:enable Style/AsciiComments
diff --git a/spec/lib/gitlab/i18n/translation_entry_spec.rb b/spec/lib/gitlab/i18n/translation_entry_spec.rb
index f68bc8feff9..b301e6ea443 100644
--- a/spec/lib/gitlab/i18n/translation_entry_spec.rb
+++ b/spec/lib/gitlab/i18n/translation_entry_spec.rb
@@ -109,7 +109,7 @@ describe Gitlab::I18n::TranslationEntry do
       data = { msgid: %w(hello world) }
       entry = described_class.new(data, 2)
 
-      expect(entry.msgid_contains_newlines?).to be_truthy
+      expect(entry.msgid_has_multiple_lines?).to be_truthy
     end
   end
 
@@ -118,7 +118,7 @@ describe Gitlab::I18n::TranslationEntry do
       data = { msgid_plural: %w(hello world) }
       entry = described_class.new(data, 2)
 
-      expect(entry.plural_id_contains_newlines?).to be_truthy
+      expect(entry.plural_id_has_multiple_lines?).to be_truthy
     end
   end
 
@@ -127,7 +127,7 @@ describe Gitlab::I18n::TranslationEntry do
       data = { msgstr: %w(hello world) }
       entry = described_class.new(data, 2)
 
-      expect(entry.translations_contain_newlines?).to be_truthy
+      expect(entry.translations_have_multiple_lines?).to be_truthy
     end
   end
 
-- 
cgit v1.2.1


From 564c819b3deec8617f87d59f904c0364b031e05c Mon Sep 17 00:00:00 2001
From: Clement Ho 
Date: Fri, 15 Jun 2018 09:39:27 -0500
Subject: Fix specs

---
 spec/features/labels_hierarchy_spec.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb
index 4700ada1aae..5573148f8bc 100644
--- a/spec/features/labels_hierarchy_spec.rb
+++ b/spec/features/labels_hierarchy_spec.rb
@@ -34,7 +34,7 @@ feature 'Labels Hierarchy', :js, :nested_groups do
 
         wait_for_requests
 
-        expect(page).to have_selector('span.badge', text: label.title)
+        expect(page).to have_selector('.badge', text: label.title)
       end
     end
 
@@ -45,7 +45,7 @@ feature 'Labels Hierarchy', :js, :nested_groups do
 
       wait_for_requests
 
-      expect(page).not_to have_selector('span.badge', text: child_group_label.title)
+      expect(page).not_to have_selector('.badge', text: child_group_label.title)
     end
   end
 
-- 
cgit v1.2.1


From bce890820f6ed0e75537b546d5ef1a0090c53b52 Mon Sep 17 00:00:00 2001
From: gfyoung 
Date: Fri, 15 Jun 2018 15:58:27 +0000
Subject: Enable no-restricted-globals in JS files

---
 spec/javascripts/blob/viewer/index_spec.js                            | 4 ++--
 spec/javascripts/bootstrap_linked_tabs_spec.js                        | 2 +-
 spec/javascripts/commits_spec.js                                      | 2 +-
 spec/javascripts/environments/environments_app_spec.js                | 2 +-
 spec/javascripts/environments/folder/environments_folder_view_spec.js | 2 +-
 spec/javascripts/ide/stores/actions/file_spec.js                      | 4 ++--
 spec/javascripts/issue_show/components/app_spec.js                    | 4 ++--
 spec/javascripts/lib/utils/common_utils_spec.js                       | 4 ++--
 spec/javascripts/pipelines/pipelines_spec.js                          | 2 +-
 spec/javascripts/settings_panels_spec.js                              | 4 ++--
 10 files changed, 15 insertions(+), 15 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/blob/viewer/index_spec.js b/spec/javascripts/blob/viewer/index_spec.js
index f920c4ca945..8b79624d9f4 100644
--- a/spec/javascripts/blob/viewer/index_spec.js
+++ b/spec/javascripts/blob/viewer/index_spec.js
@@ -32,7 +32,7 @@ describe('Blob viewer', () => {
 
   afterEach(() => {
     mock.restore();
-    location.hash = '';
+    window.location.hash = '';
   });
 
   it('loads source file after switching views', (done) => {
@@ -49,7 +49,7 @@ describe('Blob viewer', () => {
   });
 
   it('loads source file when line number is in hash', (done) => {
-    location.hash = '#L1';
+    window.location.hash = '#L1';
 
     new BlobViewer();
 
diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js b/spec/javascripts/bootstrap_linked_tabs_spec.js
index 93dc60d59fe..6f679369289 100644
--- a/spec/javascripts/bootstrap_linked_tabs_spec.js
+++ b/spec/javascripts/bootstrap_linked_tabs_spec.js
@@ -36,7 +36,7 @@ import LinkedTabs from '~/lib/utils/bootstrap_linked_tabs';
 
     describe('on click', () => {
       it('should change the url according to the clicked tab', () => {
-        const historySpy = spyOn(history, 'replaceState').and.callFake(() => {});
+        const historySpy = spyOn(window.history, 'replaceState').and.callFake(() => {});
 
         const linkedTabs = new LinkedTabs({
           action: 'show',
diff --git a/spec/javascripts/commits_spec.js b/spec/javascripts/commits_spec.js
index 60d100e8544..28b89157bd3 100644
--- a/spec/javascripts/commits_spec.js
+++ b/spec/javascripts/commits_spec.js
@@ -56,7 +56,7 @@ describe('Commits List', () => {
     beforeEach(() => {
       commitsList.searchField.val('');
 
-      spyOn(history, 'replaceState').and.stub();
+      spyOn(window.history, 'replaceState').and.stub();
       mock = new MockAdapter(axios);
 
       mock.onGet('/h5bp/html5-boilerplate/commits/master').reply(200, {
diff --git a/spec/javascripts/environments/environments_app_spec.js b/spec/javascripts/environments/environments_app_spec.js
index 615168645b4..6968fbc7ce7 100644
--- a/spec/javascripts/environments/environments_app_spec.js
+++ b/spec/javascripts/environments/environments_app_spec.js
@@ -220,7 +220,7 @@ describe('Environment', () => {
       );
 
       component = mountComponent(EnvironmentsComponent, mockData);
-      spyOn(history, 'pushState').and.stub();
+      spyOn(window.history, 'pushState').and.stub();
     });
 
     describe('updateContent', () => {
diff --git a/spec/javascripts/environments/folder/environments_folder_view_spec.js b/spec/javascripts/environments/folder/environments_folder_view_spec.js
index f5ce4df0bfe..51d4213c38f 100644
--- a/spec/javascripts/environments/folder/environments_folder_view_spec.js
+++ b/spec/javascripts/environments/folder/environments_folder_view_spec.js
@@ -177,7 +177,7 @@ describe('Environments Folder View', () => {
       });
 
       component = mountComponent(Component, mockData);
-      spyOn(history, 'pushState').and.stub();
+      spyOn(window.history, 'pushState').and.stub();
     });
 
     describe('updateContent', () => {
diff --git a/spec/javascripts/ide/stores/actions/file_spec.js b/spec/javascripts/ide/stores/actions/file_spec.js
index 7bebc2288e3..5746683917e 100644
--- a/spec/javascripts/ide/stores/actions/file_spec.js
+++ b/spec/javascripts/ide/stores/actions/file_spec.js
@@ -166,12 +166,12 @@ describe('IDE store file actions', () => {
     });
 
     it('resets location.hash for line highlighting', done => {
-      location.hash = 'test';
+      window.location.hash = 'test';
 
       store
         .dispatch('setFileActive', localFile.path)
         .then(() => {
-          expect(location.hash).not.toBe('test');
+          expect(window.location.hash).not.toBe('test');
 
           done();
         })
diff --git a/spec/javascripts/issue_show/components/app_spec.js b/spec/javascripts/issue_show/components/app_spec.js
index bf1f0c822fe..eb5e0bddb74 100644
--- a/spec/javascripts/issue_show/components/app_spec.js
+++ b/spec/javascripts/issue_show/components/app_spec.js
@@ -145,7 +145,7 @@ describe('Issuable output', () => {
         resolve({
           data: {
             confidential: false,
-            web_url: location.pathname,
+            web_url: window.location.pathname,
           },
         });
       }));
@@ -177,7 +177,7 @@ describe('Issuable output', () => {
       spyOn(vm.service, 'updateIssuable').and.callFake(() => new Promise((resolve) => {
         resolve({
           data: {
-            web_url: location.pathname,
+            web_url: window.location.pathname,
             confidential: vm.isConfidential,
           },
         });
diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js
index 2d7cc3443cf..a9ec7f42a9d 100644
--- a/spec/javascripts/lib/utils/common_utils_spec.js
+++ b/spec/javascripts/lib/utils/common_utils_spec.js
@@ -40,13 +40,13 @@ describe('common_utils', () => {
     });
 
     it('should decode params', () => {
-      history.pushState('', '', '?label_name%5B%5D=test');
+      window.history.pushState('', '', '?label_name%5B%5D=test');
 
       expect(
         commonUtils.getUrlParamsArray()[0],
       ).toBe('label_name[]=test');
 
-      history.pushState('', '', '?');
+      window.history.pushState('', '', '?');
     });
   });
 
diff --git a/spec/javascripts/pipelines/pipelines_spec.js b/spec/javascripts/pipelines/pipelines_spec.js
index ff17602da2b..50141bd99b4 100644
--- a/spec/javascripts/pipelines/pipelines_spec.js
+++ b/spec/javascripts/pipelines/pipelines_spec.js
@@ -427,7 +427,7 @@ describe('Pipelines', () => {
 
   describe('methods', () => {
     beforeEach(() => {
-      spyOn(history, 'pushState').and.stub();
+      spyOn(window.history, 'pushState').and.stub();
     });
 
     describe('updateContent', () => {
diff --git a/spec/javascripts/settings_panels_spec.js b/spec/javascripts/settings_panels_spec.js
index 4fba36bd4de..c1a69bd7018 100644
--- a/spec/javascripts/settings_panels_spec.js
+++ b/spec/javascripts/settings_panels_spec.js
@@ -9,11 +9,11 @@ describe('Settings Panels', () => {
 
   describe('initSettingsPane', () => {
     afterEach(() => {
-      location.hash = '';
+      window.location.hash = '';
     });
 
     it('should expand linked hash fragment panel', () => {
-      location.hash = '#autodevops-settings';
+      window.location.hash = '#autodevops-settings';
 
       const pipelineSettingsPanel = document.querySelector('#autodevops-settings');
       // Our test environment automatically expands everything so we need to clear that out first
-- 
cgit v1.2.1


From 5104098fab7f72fff15d5e1a69f1597391b59b31 Mon Sep 17 00:00:00 2001
From: Isaac Smith 
Date: Fri, 15 Jun 2018 13:22:56 -0500
Subject: Fix #47796 "Web IDE autocomplete should be disabled in markdown
 files"

---
 spec/javascripts/ide/lib/editor_spec.js | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

(limited to 'spec')

diff --git a/spec/javascripts/ide/lib/editor_spec.js b/spec/javascripts/ide/lib/editor_spec.js
index c1932284d53..c2cb964ea87 100644
--- a/spec/javascripts/ide/lib/editor_spec.js
+++ b/spec/javascripts/ide/lib/editor_spec.js
@@ -263,4 +263,23 @@ describe('Multi-file editor library', () => {
       expect(instance.isDiffEditorType).toBe(false);
     });
   });
+
+  it('sets quickSuggestions to false when language is markdown', () => {
+    instance.createInstance(holder);
+
+    spyOn(instance.instance, 'updateOptions').and.callThrough();
+
+    const model = instance.createModel({
+      ...file(),
+      key: 'index.md',
+      path: 'index.md',
+    });
+
+    instance.attachModel(model);
+
+    expect(instance.instance.updateOptions).toHaveBeenCalledWith({
+      readOnly: false,
+      quickSuggestions: false,
+    });
+  });
 });
-- 
cgit v1.2.1


From dbc74800e22c9ea417d30fd4c357d6154cc71870 Mon Sep 17 00:00:00 2001
From: gfyoung 
Date: Wed, 13 Jun 2018 23:18:05 -0700
Subject: Enable no-multi-assignment in JS files

Partially addresses #47006.
---
 spec/javascripts/gl_field_errors_spec.js                            | 4 +++-
 spec/javascripts/helpers/user_mock_data_helper.js                   | 2 +-
 spec/javascripts/profile/account/components/update_username_spec.js | 3 ++-
 spec/javascripts/test_bundle.js                                     | 3 ++-
 4 files changed, 8 insertions(+), 4 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/gl_field_errors_spec.js b/spec/javascripts/gl_field_errors_spec.js
index 4e93fd91751..108e0064c47 100644
--- a/spec/javascripts/gl_field_errors_spec.js
+++ b/spec/javascripts/gl_field_errors_spec.js
@@ -8,7 +8,9 @@ describe('GL Style Field Errors', function() {
 
   beforeEach(function() {
     loadFixtures('static/gl_field_errors.html.raw');
-    const $form = this.$form = $('form.gl-show-field-errors');
+    const $form = $('form.gl-show-field-errors');
+
+    this.$form = $form;
     this.fieldErrors = new GlFieldErrors($form);
   });
 
diff --git a/spec/javascripts/helpers/user_mock_data_helper.js b/spec/javascripts/helpers/user_mock_data_helper.js
index 323fee3767e..f6c3ce5aecc 100644
--- a/spec/javascripts/helpers/user_mock_data_helper.js
+++ b/spec/javascripts/helpers/user_mock_data_helper.js
@@ -1,7 +1,7 @@
 export default {
   createNumberRandomUsers(numberUsers) {
     const users = [];
-    for (let i = 0; i < numberUsers; i = i += 1) {
+    for (let i = 0; i < numberUsers; i += 1) {
       users.push(
         {
           avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
diff --git a/spec/javascripts/profile/account/components/update_username_spec.js b/spec/javascripts/profile/account/components/update_username_spec.js
index bac306edf5a..5311499fb73 100644
--- a/spec/javascripts/profile/account/components/update_username_spec.js
+++ b/spec/javascripts/profile/account/components/update_username_spec.js
@@ -90,7 +90,8 @@ describe('UpdateUsername component', () => {
   it('confirmation modal should escape usernames properly', done => {
     const { modalBody } = findElements();
 
-    vm.username = vm.newUsername = 'Italic';
+    vm.username = 'Italic';
+    vm.newUsername = vm.username;
 
     Vue.nextTick()
       .then(() => {
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index 2411d33a496..994011b262a 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -39,7 +39,8 @@ jasmine.getJSONFixtures().fixturesPath = FIXTURES_PATH;
 beforeAll(() => jasmine.addMatchers(customMatchers));
 
 // globalize common libraries
-window.$ = window.jQuery = $;
+window.$ = $;
+window.jQuery = window.$;
 
 // stub expected globals
 window.gl = window.gl || {};
-- 
cgit v1.2.1


From c6420ce2ab18681d6a5b06621d89775e3cf81065 Mon Sep 17 00:00:00 2001
From: Mario de la Ossa 
Date: Thu, 14 Jun 2018 13:39:17 -0600
Subject: Fix milestones disappearing when changed on MR

---
 .../projects/merge_requests_controller_spec.rb           |  2 +-
 .../api/schemas/entities/merge_request_basic.json        | 16 +++++++++++++++-
 2 files changed, 16 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb
index 22858de0475..a412e74581d 100644
--- a/spec/controllers/projects/merge_requests_controller_spec.rb
+++ b/spec/controllers/projects/merge_requests_controller_spec.rb
@@ -234,7 +234,7 @@ describe Projects::MergeRequestsController do
         body = JSON.parse(response.body)
 
         expect(body['assignee'].keys)
-          .to match_array(%w(name username avatar_url))
+          .to match_array(%w(name username avatar_url id state web_url))
       end
     end
 
diff --git a/spec/fixtures/api/schemas/entities/merge_request_basic.json b/spec/fixtures/api/schemas/entities/merge_request_basic.json
index f7bc137c90c..cf257ac00de 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_basic.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_basic.json
@@ -14,7 +14,21 @@
     "subscribed": { "type": ["boolean", "null"] },
     "participants": { "type": "array" },
     "allow_collaboration": { "type": "boolean"},
-    "allow_maintainer_to_push": { "type": "boolean"}
+    "allow_maintainer_to_push": { "type": "boolean"},
+    "assignee": {
+      "oneOf": [
+        { "type": "null" },
+        { "$ref": "user.json" }
+      ]
+    },
+    "milestone": {
+      "type": [ "object", "null" ]
+    },
+    "labels": {
+      "type": [ "array", "null" ]
+    },
+    "task_status": { "type": "string" },
+    "task_status_short": { "type": "string" }
   },
   "additionalProperties": false
 }
-- 
cgit v1.2.1


From 2b1153f71a680b0c5a4fb787897c20068a405fbf Mon Sep 17 00:00:00 2001
From: blackst0ne 
Date: Sat, 16 Jun 2018 15:26:15 +1100
Subject: [Rails5] Fix pipeline_schedules_controller_spec

In Rails 5.0 there's a bug [1] in controller tests that doesn't parse
nested parameters correctly.

This commit brings a workaround to make specs work again both in rails4
and rails5.

[1]: https://github.com/rails/rails/issues/23997
---
 .../projects/pipeline_schedules_controller_spec.rb       | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

(limited to 'spec')

diff --git a/spec/controllers/projects/pipeline_schedules_controller_spec.rb b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
index 3506305f755..4cdaa54e0bc 100644
--- a/spec/controllers/projects/pipeline_schedules_controller_spec.rb
+++ b/spec/controllers/projects/pipeline_schedules_controller_spec.rb
@@ -310,9 +310,19 @@ describe Projects::PipelineSchedulesController do
     end
 
     def go
-      put :update, namespace_id: project.namespace.to_param,
-                   project_id: project, id: pipeline_schedule,
-                   schedule: schedule
+      if Gitlab.rails5?
+        put :update, params: { namespace_id: project.namespace.to_param,
+                               project_id: project,
+                               id: pipeline_schedule,
+                               schedule: schedule },
+                     as: :html
+
+      else
+        put :update, namespace_id: project.namespace.to_param,
+                     project_id: project,
+                     id: pipeline_schedule,
+                     schedule: schedule
+      end
     end
   end
 
-- 
cgit v1.2.1


From 79c3ec014c7db667457268a75f9c47bee8653650 Mon Sep 17 00:00:00 2001
From: blackst0ne 
Date: Sat, 16 Jun 2018 19:12:46 +1100
Subject: [Rails5] Fix sessions_controller_spec

Refactor sessions_controller_spec to work both in rails4 and rails5.
Remove the stubbed `request.referer` method, set real header instead.
---
 spec/controllers/sessions_controller_spec.rb | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

(limited to 'spec')

diff --git a/spec/controllers/sessions_controller_spec.rb b/spec/controllers/sessions_controller_spec.rb
index 555b186fe31..2b61e0d4a85 100644
--- a/spec/controllers/sessions_controller_spec.rb
+++ b/spec/controllers/sessions_controller_spec.rb
@@ -257,15 +257,15 @@ describe SessionsController do
     end
   end
 
-  describe '#new' do
+  describe "#new" do
     before do
       set_devise_mapping(context: @request)
     end
 
-    it 'redirects correctly for referer on same host with params' do
-      search_path = '/search?search=seed_project'
-      allow(controller.request).to receive(:referer)
-        .and_return('http://%{host}%{path}' % { host: 'test.host', path: search_path })
+    it "redirects correctly for referer on same host with params" do
+      host = "test.host"
+      search_path = "/search?search=seed_project"
+      request.headers[:HTTP_REFERER] = "http://#{host}#{search_path}"
 
       get(:new, redirect_to_referer: :yes)
 
-- 
cgit v1.2.1


From 20adfb53693879a4b5c29b752fc06a130df18d42 Mon Sep 17 00:00:00 2001
From: Jan Provaznik 
Date: Sat, 16 Jun 2018 21:20:58 +0200
Subject: Fix nil formats test

One of the spec files sets `nil` value for env varialbe
`action_dispatch.request.formats`. Rather than setting `nil` value,
we can delete the `action_dispatch.request.formats` key from `env`
(which should be closer to real use case anyway). The reason is that
in Rails 5, `formats` method does not set default array of formats
if the env key is already set (even if set to `nil`).
---
 spec/lib/gitlab/auth/user_auth_finders_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/auth/user_auth_finders_spec.rb b/spec/lib/gitlab/auth/user_auth_finders_spec.rb
index 136646bd4ee..454ad1589b9 100644
--- a/spec/lib/gitlab/auth/user_auth_finders_spec.rb
+++ b/spec/lib/gitlab/auth/user_auth_finders_spec.rb
@@ -99,7 +99,7 @@ describe Gitlab::Auth::UserAuthFinders do
 
     context 'when the request format is empty' do
       it 'the method call does not modify the original value' do
-        env['action_dispatch.request.formats'] = nil
+        env.delete('action_dispatch.request.formats')
 
         find_user_from_feed_token
 
-- 
cgit v1.2.1


From cc48d67ca57ac99e5c61b422a56d96a1643a7de8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Kamil=20Trzci=C5=84ski?= 
Date: Sun, 17 Jun 2018 16:47:25 +0200
Subject: Optimised paused runners to not re-query every 3s

We have long polling mechanism which is not being used by paused runners.
This makes the paused runner to generate a request every 3s,
where it could be fired only every 1h.
---
 spec/requests/api/runner_spec.rb | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/requests/api/runner_spec.rb b/spec/requests/api/runner_spec.rb
index 16e6f19773f..e7639599874 100644
--- a/spec/requests/api/runner_spec.rb
+++ b/spec/requests/api/runner_spec.rb
@@ -351,11 +351,13 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
       context 'when valid token is provided' do
         context 'when Runner is not active' do
           let(:runner) { create(:ci_runner, :inactive) }
+          let(:update_value) { runner.ensure_runner_queue_value }
 
           it 'returns 204 error' do
             request_job
 
-            expect(response).to have_gitlab_http_status 204
+            expect(response).to have_gitlab_http_status(204)
+            expect(response.header['X-GitLab-Last-Update']).to eq(update_value)
           end
         end
 
-- 
cgit v1.2.1


From 14000a561b8ed59905b6700541703fa7bcdb68d0 Mon Sep 17 00:00:00 2001
From: "Jacob Vosmaer (GitLab)" 
Date: Mon, 18 Jun 2018 08:19:11 +0000
Subject: Make Gitaly wiki RPC's mandatory

---
 spec/lib/gitlab/git/committer_with_hooks_spec.rb | 216 ++++++++++++-----------
 spec/lib/gitlab/git/wiki_spec.rb                 |   6 +-
 2 files changed, 111 insertions(+), 111 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/git/committer_with_hooks_spec.rb b/spec/lib/gitlab/git/committer_with_hooks_spec.rb
index 267056b96e6..2100690f873 100644
--- a/spec/lib/gitlab/git/committer_with_hooks_spec.rb
+++ b/spec/lib/gitlab/git/committer_with_hooks_spec.rb
@@ -1,154 +1,156 @@
 require 'spec_helper'
 
 describe Gitlab::Git::CommitterWithHooks, seed_helper: true do
-  shared_examples 'calling wiki hooks' do
-    let(:project) { create(:project) }
-    let(:user) { project.owner }
-    let(:project_wiki) { ProjectWiki.new(project, user) }
-    let(:wiki) { project_wiki.wiki }
-    let(:options) do
-      {
-        id: user.id,
-        username: user.username,
-        name: user.name,
-        email: user.email,
-        message: 'commit message'
-      }
-    end
-
-    subject { described_class.new(wiki, options) }
+  # TODO https://gitlab.com/gitlab-org/gitaly/issues/1234
+  skip 'needs to be moved to gitaly-ruby test suite' do
+    shared_examples 'calling wiki hooks' do
+      let(:project) { create(:project) }
+      let(:user) { project.owner }
+      let(:project_wiki) { ProjectWiki.new(project, user) }
+      let(:wiki) { project_wiki.wiki }
+      let(:options) do
+        {
+          id: user.id,
+          username: user.username,
+          name: user.name,
+          email: user.email,
+          message: 'commit message'
+        }
+      end
 
-    before do
-      project_wiki.create_page('home', 'test content')
-    end
+      subject { described_class.new(wiki, options) }
 
-    shared_examples 'failing pre-receive hook' do
       before do
-        expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([false, ''])
-        expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('update')
-        expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('post-receive')
+        project_wiki.create_page('home', 'test content')
       end
 
-      it 'raises exception' do
-        expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
-      end
+      shared_examples 'failing pre-receive hook' do
+        before do
+          expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([false, ''])
+          expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('update')
+          expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('post-receive')
+        end
 
-      it 'does not create a new commit inside the repository' do
-        current_rev = find_current_rev
+        it 'raises exception' do
+          expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+        end
 
-        expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+        it 'does not create a new commit inside the repository' do
+          current_rev = find_current_rev
 
-        expect(current_rev).to eq find_current_rev
-      end
-    end
+          expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
 
-    shared_examples 'failing update hook' do
-      before do
-        expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([true, ''])
-        expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('update').and_return([false, ''])
-        expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('post-receive')
+          expect(current_rev).to eq find_current_rev
+        end
       end
 
-      it 'raises exception' do
-        expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
-      end
+      shared_examples 'failing update hook' do
+        before do
+          expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([true, ''])
+          expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('update').and_return([false, ''])
+          expect_any_instance_of(Gitlab::Git::HooksService).not_to receive(:run_hook).with('post-receive')
+        end
 
-      it 'does not create a new commit inside the repository' do
-        current_rev = find_current_rev
+        it 'raises exception' do
+          expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+        end
 
-        expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
+        it 'does not create a new commit inside the repository' do
+          current_rev = find_current_rev
 
-        expect(current_rev).to eq find_current_rev
-      end
-    end
+          expect { subject.commit }.to raise_error(Gitlab::Git::Wiki::OperationError)
 
-    shared_examples 'failing post-receive hook' do
-      before do
-        expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([true, ''])
-        expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('update').and_return([true, ''])
-        expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('post-receive').and_return([false, ''])
+          expect(current_rev).to eq find_current_rev
+        end
       end
 
-      it 'does not raise exception' do
-        expect { subject.commit }.not_to raise_error
-      end
+      shared_examples 'failing post-receive hook' do
+        before do
+          expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('pre-receive').and_return([true, ''])
+          expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('update').and_return([true, ''])
+          expect_any_instance_of(Gitlab::Git::HooksService).to receive(:run_hook).with('post-receive').and_return([false, ''])
+        end
+
+        it 'does not raise exception' do
+          expect { subject.commit }.not_to raise_error
+        end
 
-      it 'creates the commit' do
-        current_rev = find_current_rev
+        it 'creates the commit' do
+          current_rev = find_current_rev
 
-        subject.commit
+          subject.commit
 
-        expect(current_rev).not_to eq find_current_rev
+          expect(current_rev).not_to eq find_current_rev
+        end
       end
-    end
 
-    shared_examples 'when hooks call succceeds' do
-      let(:hook) { double(:hook) }
+      shared_examples 'when hooks call succceeds' do
+        let(:hook) { double(:hook) }
 
-      it 'calls the three hooks' do
-        expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
-        expect(hook).to receive(:trigger).exactly(3).times.and_return([true, nil])
+        it 'calls the three hooks' do
+          expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
+          expect(hook).to receive(:trigger).exactly(3).times.and_return([true, nil])
 
-        subject.commit
-      end
+          subject.commit
+        end
 
-      it 'creates the commit' do
-        current_rev = find_current_rev
+        it 'creates the commit' do
+          current_rev = find_current_rev
 
-        subject.commit
+          subject.commit
 
-        expect(current_rev).not_to eq find_current_rev
+          expect(current_rev).not_to eq find_current_rev
+        end
       end
-    end
 
-    context 'when creating a page' do
-      before do
-        project_wiki.create_page('index', 'test content')
+      context 'when creating a page' do
+        before do
+          project_wiki.create_page('index', 'test content')
+        end
+
+        it_behaves_like 'failing pre-receive hook'
+        it_behaves_like 'failing update hook'
+        it_behaves_like 'failing post-receive hook'
+        it_behaves_like 'when hooks call succceeds'
       end
 
-      it_behaves_like 'failing pre-receive hook'
-      it_behaves_like 'failing update hook'
-      it_behaves_like 'failing post-receive hook'
-      it_behaves_like 'when hooks call succceeds'
-    end
+      context 'when updating a page' do
+        before do
+          project_wiki.update_page(find_page('home'), content: 'some other content', format: :markdown)
+        end
 
-    context 'when updating a page' do
-      before do
-        project_wiki.update_page(find_page('home'), content: 'some other content', format: :markdown)
+        it_behaves_like 'failing pre-receive hook'
+        it_behaves_like 'failing update hook'
+        it_behaves_like 'failing post-receive hook'
+        it_behaves_like 'when hooks call succceeds'
       end
 
-      it_behaves_like 'failing pre-receive hook'
-      it_behaves_like 'failing update hook'
-      it_behaves_like 'failing post-receive hook'
-      it_behaves_like 'when hooks call succceeds'
-    end
+      context 'when deleting a page' do
+        before do
+          project_wiki.delete_page(find_page('home'))
+        end
 
-    context 'when deleting a page' do
-      before do
-        project_wiki.delete_page(find_page('home'))
+        it_behaves_like 'failing pre-receive hook'
+        it_behaves_like 'failing update hook'
+        it_behaves_like 'failing post-receive hook'
+        it_behaves_like 'when hooks call succceeds'
       end
 
-      it_behaves_like 'failing pre-receive hook'
-      it_behaves_like 'failing update hook'
-      it_behaves_like 'failing post-receive hook'
-      it_behaves_like 'when hooks call succceeds'
-    end
+      def find_current_rev
+        wiki.gollum_wiki.repo.commits.first&.sha
+      end
 
-    def find_current_rev
-      wiki.gollum_wiki.repo.commits.first&.sha
+      def find_page(name)
+        wiki.page(title: name)
+      end
     end
 
-    def find_page(name)
-      wiki.page(title: name)
+    context 'when Gitaly is enabled' do
+      it_behaves_like 'calling wiki hooks'
     end
-  end
-
-  # TODO: Uncomment once Gitaly updates the ruby vendor code
-  # context 'when Gitaly is enabled' do
-  #   it_behaves_like 'calling wiki hooks'
-  # end
 
-  context 'when Gitaly is disabled', :skip_gitaly_mock do
-    it_behaves_like 'calling wiki hooks'
+    context 'when Gitaly is disabled', :disable_gitaly do
+      it_behaves_like 'calling wiki hooks'
+    end
   end
 end
diff --git a/spec/lib/gitlab/git/wiki_spec.rb b/spec/lib/gitlab/git/wiki_spec.rb
index 35b06b14620..b63658e1b3b 100644
--- a/spec/lib/gitlab/git/wiki_spec.rb
+++ b/spec/lib/gitlab/git/wiki_spec.rb
@@ -6,9 +6,7 @@ describe Gitlab::Git::Wiki do
   let(:project_wiki) { ProjectWiki.new(project, user) }
   subject { project_wiki.wiki }
 
-  # Remove skip_gitaly_mock flag when gitaly_find_page when
-  # https://gitlab.com/gitlab-org/gitlab-ce/issues/42039 is solved
-  describe '#page', :skip_gitaly_mock do
+  describe '#page' do
     before do
       create_page('page1', 'content')
       create_page('foo/page1', 'content foo/page1')
@@ -25,7 +23,7 @@ describe Gitlab::Git::Wiki do
     end
   end
 
-  describe '#delete_page', :skip_gitaly_mock do
+  describe '#delete_page' do
     after do
       destroy_page('page1')
     end
-- 
cgit v1.2.1


From 6954ebbe55688633c6e4b43c28088e195191e8fc Mon Sep 17 00:00:00 2001
From: Imre Farkas 
Date: Tue, 12 Jun 2018 11:35:34 +0200
Subject: Render calendar feed inline when accessed from GitLab

With text/calendar as Content-Type, the browser always downloads the
content as a file (even ignoring the Content-Disposition header). We
want to display the content inline when accessed from GitLab, similarly
to the RSS feed.
---
 spec/features/ics/dashboard_issues_spec.rb | 26 ++++++++++++++++++--------
 spec/features/ics/group_issues_spec.rb     | 26 ++++++++++++++++++--------
 spec/features/ics/project_issues_spec.rb   | 26 ++++++++++++++++++--------
 3 files changed, 54 insertions(+), 24 deletions(-)

(limited to 'spec')

diff --git a/spec/features/ics/dashboard_issues_spec.rb b/spec/features/ics/dashboard_issues_spec.rb
index 5d6cd44ad1c..90d02f7e40f 100644
--- a/spec/features/ics/dashboard_issues_spec.rb
+++ b/spec/features/ics/dashboard_issues_spec.rb
@@ -11,13 +11,25 @@ describe 'Dashboard Issues Calendar Feed'  do
     end
 
     context 'when authenticated' do
-      it 'renders calendar feed' do
-        sign_in user
-        visit issues_dashboard_path(:ics)
+      context 'with no referer' do
+        it 'renders calendar feed' do
+          sign_in user
+          visit issues_dashboard_path(:ics)
 
-        expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
-        expect(body).to have_text('BEGIN:VCALENDAR')
+          expect(response_headers['Content-Type']).to have_content('text/calendar')
+          expect(body).to have_text('BEGIN:VCALENDAR')
+        end
+      end
+
+      context 'with GitLab as the referer' do
+        it 'renders calendar feed as text/plain' do
+          sign_in user
+          page.driver.header('Referer', issues_dashboard_url(host: Settings.gitlab.base_url))
+          visit issues_dashboard_path(:ics)
+
+          expect(response_headers['Content-Type']).to have_content('text/plain')
+          expect(body).to have_text('BEGIN:VCALENDAR')
+        end
       end
     end
 
@@ -28,7 +40,6 @@ describe 'Dashboard Issues Calendar Feed'  do
         visit issues_dashboard_path(:ics, private_token: personal_access_token.token)
 
         expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
         expect(body).to have_text('BEGIN:VCALENDAR')
       end
     end
@@ -38,7 +49,6 @@ describe 'Dashboard Issues Calendar Feed'  do
         visit issues_dashboard_path(:ics, feed_token: user.feed_token)
 
         expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
         expect(body).to have_text('BEGIN:VCALENDAR')
       end
     end
diff --git a/spec/features/ics/group_issues_spec.rb b/spec/features/ics/group_issues_spec.rb
index 0a049be2ffe..24de5b4b7c6 100644
--- a/spec/features/ics/group_issues_spec.rb
+++ b/spec/features/ics/group_issues_spec.rb
@@ -13,13 +13,25 @@ describe 'Group Issues Calendar Feed'  do
     end
 
     context 'when authenticated' do
-      it 'renders calendar feed' do
-        sign_in user
-        visit issues_group_path(group, :ics)
+      context 'with no referer' do
+        it 'renders calendar feed' do
+          sign_in user
+          visit issues_group_path(group, :ics)
 
-        expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
-        expect(body).to have_text('BEGIN:VCALENDAR')
+          expect(response_headers['Content-Type']).to have_content('text/calendar')
+          expect(body).to have_text('BEGIN:VCALENDAR')
+        end
+      end
+
+      context 'with GitLab as the referer' do
+        it 'renders calendar feed as text/plain' do
+          sign_in user
+          page.driver.header('Referer', issues_group_url(group, host: Settings.gitlab.base_url))
+          visit issues_group_path(group, :ics)
+
+          expect(response_headers['Content-Type']).to have_content('text/plain')
+          expect(body).to have_text('BEGIN:VCALENDAR')
+        end
       end
     end
 
@@ -30,7 +42,6 @@ describe 'Group Issues Calendar Feed'  do
         visit issues_group_path(group, :ics, private_token: personal_access_token.token)
 
         expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
         expect(body).to have_text('BEGIN:VCALENDAR')
       end
     end
@@ -40,7 +51,6 @@ describe 'Group Issues Calendar Feed'  do
         visit issues_group_path(group, :ics, feed_token: user.feed_token)
 
         expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
         expect(body).to have_text('BEGIN:VCALENDAR')
       end
     end
diff --git a/spec/features/ics/project_issues_spec.rb b/spec/features/ics/project_issues_spec.rb
index b99e9607f1d..2ca3d52a5be 100644
--- a/spec/features/ics/project_issues_spec.rb
+++ b/spec/features/ics/project_issues_spec.rb
@@ -12,13 +12,25 @@ describe 'Project Issues Calendar Feed'  do
     end
 
     context 'when authenticated' do
-      it 'renders calendar feed' do
-        sign_in user
-        visit project_issues_path(project, :ics)
+      context 'with no referer' do
+        it 'renders calendar feed' do
+          sign_in user
+          visit project_issues_path(project, :ics)
 
-        expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
-        expect(body).to have_text('BEGIN:VCALENDAR')
+          expect(response_headers['Content-Type']).to have_content('text/calendar')
+          expect(body).to have_text('BEGIN:VCALENDAR')
+        end
+      end
+
+      context 'with GitLab as the referer' do
+        it 'renders calendar feed as text/plain' do
+          sign_in user
+          page.driver.header('Referer', project_issues_url(project, host: Settings.gitlab.base_url))
+          visit project_issues_path(project, :ics)
+
+          expect(response_headers['Content-Type']).to have_content('text/plain')
+          expect(body).to have_text('BEGIN:VCALENDAR')
+        end
       end
     end
 
@@ -29,7 +41,6 @@ describe 'Project Issues Calendar Feed'  do
         visit project_issues_path(project, :ics, private_token: personal_access_token.token)
 
         expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
         expect(body).to have_text('BEGIN:VCALENDAR')
       end
     end
@@ -39,7 +50,6 @@ describe 'Project Issues Calendar Feed'  do
         visit project_issues_path(project, :ics, feed_token: user.feed_token)
 
         expect(response_headers['Content-Type']).to have_content('text/calendar')
-        expect(response_headers['Content-Disposition']).to have_content('inline')
         expect(body).to have_text('BEGIN:VCALENDAR')
       end
     end
-- 
cgit v1.2.1


From 1533dbf9018fc4ed91725b369a779b7d4c40f99f Mon Sep 17 00:00:00 2001
From: Filipa Lacerda 
Date: Mon, 18 Jun 2018 10:18:40 +0100
Subject: Uses long sha version of the  merged commit in MR widget copy to
 clipboard button

---
 .../vue_mr_widget/components/states/mr_widget_merged_spec.js         | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
index 3e2fd71b5b8..efa5c878678 100644
--- a/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/states/mr_widget_merged_spec.js
@@ -39,7 +39,8 @@ describe('MRWidgetMerged', () => {
         readableClosedAt: '',
       },
       updatedAt: 'mergedUpdatedAt',
-      shortMergeCommitSha: 'asdf1234',
+      shortMergeCommitSha: '958c0475',
+      mergeCommitSha: '958c047516e182dfc52317f721f696e8a1ee85ed',
       mergeCommitPath: 'http://localhost:3000/root/nautilus/commit/f7ce827c314c9340b075657fd61c789fb01cf74d',
       sourceBranch: 'bar',
       targetBranch,
@@ -153,7 +154,7 @@ describe('MRWidgetMerged', () => {
 
   it('shows button to copy commit SHA to clipboard', () => {
     expect(selectors.copyMergeShaButton).toExist();
-    expect(selectors.copyMergeShaButton.getAttribute('data-clipboard-text')).toBe(vm.mr.shortMergeCommitSha);
+    expect(selectors.copyMergeShaButton.getAttribute('data-clipboard-text')).toBe(vm.mr.mergeCommitSha);
   });
 
   it('shows merge commit SHA link', () => {
-- 
cgit v1.2.1


From b762fc4b460bed9f0510f19e20130fc331fa1efe Mon Sep 17 00:00:00 2001
From: Douwe Maan 
Date: Mon, 18 Jun 2018 13:28:21 +0200
Subject: Allow trailing whitespace on blockquote fence lines

---
 spec/lib/banzai/filter/blockquote_fence_filter_spec.rb | 4 ++++
 1 file changed, 4 insertions(+)

(limited to 'spec')

diff --git a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
index 8224dc5a6b9..b645e49bd43 100644
--- a/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
+++ b/spec/lib/banzai/filter/blockquote_fence_filter_spec.rb
@@ -11,4 +11,8 @@ describe Banzai::Filter::BlockquoteFenceFilter do
 
     expect(output).to eq(expected)
   end
+
+  it 'allows trailing whitespace on blockquote fence lines' do
+    expect(filter(">>> \ntest\n>>> ")).to eq("> test")
+  end
 end
-- 
cgit v1.2.1


From 404b49a74d790d7fd58a9540cd4b98a5d3b31854 Mon Sep 17 00:00:00 2001
From: Robert Speicher 
Date: Mon, 18 Jun 2018 12:15:58 -0500
Subject: Bring CE-EE parity to migrations/remove_soft_removed_objects_spec.rb

---
 .../migrations/remove_soft_removed_objects_spec.rb | 36 +++++++++++++++++-----
 1 file changed, 29 insertions(+), 7 deletions(-)

(limited to 'spec')

diff --git a/spec/migrations/remove_soft_removed_objects_spec.rb b/spec/migrations/remove_soft_removed_objects_spec.rb
index fb70c284f5e..d0bde98b80e 100644
--- a/spec/migrations/remove_soft_removed_objects_spec.rb
+++ b/spec/migrations/remove_soft_removed_objects_spec.rb
@@ -3,6 +3,18 @@ require Rails.root.join('db', 'post_migrate', '20171207150343_remove_soft_remove
 
 describe RemoveSoftRemovedObjects, :migration do
   describe '#up' do
+    let!(:groups) do
+      table(:namespaces).tap do |t|
+        t.inheritance_column = nil
+      end
+    end
+
+    let!(:routes) do
+      table(:routes).tap do |t|
+        t.inheritance_column = nil
+      end
+    end
+
     it 'removes various soft removed objects' do
       5.times do
         create_with_deleted_at(:issue)
@@ -28,19 +40,20 @@ describe RemoveSoftRemovedObjects, :migration do
 
     it 'removes routes of soft removed personal namespaces' do
       namespace = create_with_deleted_at(:namespace)
-      group = create(:group) # rubocop:disable RSpec/FactoriesInMigrationSpecs
+      group = groups.create!(name: 'group', path: 'group_path', type: 'Group')
+      routes.create!(source_id: group.id, source_type: 'Group', name: 'group', path: 'group_path')
 
-      expect(Route.where(source: namespace).exists?).to eq(true)
-      expect(Route.where(source: group).exists?).to eq(true)
+      expect(routes.where(source_id: namespace.id).exists?).to eq(true)
+      expect(routes.where(source_id: group.id).exists?).to eq(true)
 
       run_migration
 
-      expect(Route.where(source: namespace).exists?).to eq(false)
-      expect(Route.where(source: group).exists?).to eq(true)
+      expect(routes.where(source_id: namespace.id).exists?).to eq(false)
+      expect(routes.where(source_id: group.id).exists?).to eq(true)
     end
 
     it 'schedules the removal of soft removed groups' do
-      group = create_with_deleted_at(:group)
+      group = create_deleted_group
       admin = create(:user, admin: true) # rubocop:disable RSpec/FactoriesInMigrationSpecs
 
       expect_any_instance_of(GroupDestroyWorker)
@@ -51,7 +64,7 @@ describe RemoveSoftRemovedObjects, :migration do
     end
 
     it 'does not remove soft removed groups when no admin user could be found' do
-      create_with_deleted_at(:group)
+      create_deleted_group
 
       expect_any_instance_of(GroupDestroyWorker)
         .not_to receive(:perform)
@@ -74,4 +87,13 @@ describe RemoveSoftRemovedObjects, :migration do
 
     row
   end
+
+  def create_deleted_group
+    group = groups.create!(name: 'group', path: 'group_path', type: 'Group')
+    routes.create!(source_id: group.id, source_type: 'Group', name: 'group', path: 'group_path')
+
+    groups.where(id: group.id).update_all(deleted_at: 1.year.ago)
+
+    group
+  end
 end
-- 
cgit v1.2.1


From 24865a4e17917fcf79d83508d18f683c5623ded8 Mon Sep 17 00:00:00 2001
From: "Marko, Peter" 
Date: Fri, 15 Jun 2018 12:16:21 +0200
Subject: Add id as second sort parameter for group sort by name

Adding primary key to database query order rule
generates deterministic sort result and thus pagination.
This is needed because subgroups can have identical names.

Signed-off-by: Marko, Peter 
---
 spec/requests/api/groups_spec.rb | 32 +++++++++++++++++++++++++++++++-
 1 file changed, 31 insertions(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index f5218ebfac2..da23fdd7dca 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -138,12 +138,15 @@ describe API::Groups do
 
     context "when using sorting" do
       let(:group3) { create(:group, name: "a#{group1.name}", path: "z#{group1.path}") }
-      let(:group4) { create(:group, name: "z#{group1.name}", path: "y#{group1.path}") }
+      let(:group4) { create(:group, name: "same-name", path: "y#{group1.path}") }
+      let(:group5) { create(:group, name: "same-name") }
       let(:response_groups) { json_response.map { |group| group['name'] } }
+      let(:response_groups_ids) { json_response.map { |group| group['id'] } }
 
       before do
         group3.add_owner(user1)
         group4.add_owner(user1)
+        group5.add_owner(user1)
       end
 
       it "sorts by name ascending by default" do
@@ -181,6 +184,33 @@ describe API::Groups do
         expect(json_response).to be_an Array
         expect(response_groups).to eq(Group.visible_to_user(user1).order(:id).pluck(:name))
       end
+
+      it "sorts also by descending id with pagination fix" do
+        get api("/groups", user1), order_by: "id", sort: "desc"
+
+        expect(response).to have_gitlab_http_status(200)
+        expect(response).to include_pagination_headers
+        expect(json_response).to be_an Array
+        expect(response_groups).to eq(Group.visible_to_user(user1).order(id: :desc).pluck(:name))
+      end
+
+      it "sorts identical keys by id for good pagination" do
+        get api("/groups", user1), search: "same-name", order_by: "name"
+
+        expect(response).to have_gitlab_http_status(200)
+        expect(response).to include_pagination_headers
+        expect(json_response).to be_an Array
+        expect(response_groups_ids).to eq(Group.select { |group| group['name'] == 'same-name' }.map { |group| group['id'] }.sort)
+      end
+
+      it "sorts descending identical keys by id for good pagination" do
+        get api("/groups", user1), search: "same-name", order_by: "name", sort: "desc"
+
+        expect(response).to have_gitlab_http_status(200)
+        expect(response).to include_pagination_headers
+        expect(json_response).to be_an Array
+        expect(response_groups_ids).to eq(Group.select { |group| group['name'] == 'same-name' }.map { |group| group['id'] }.sort)
+      end
     end
 
     context 'when using owned in the request' do
-- 
cgit v1.2.1


From 5679beb2285e4eade892324b24ded1754d277db6 Mon Sep 17 00:00:00 2001
From: Robert Speicher 
Date: Mon, 18 Jun 2018 14:21:37 -0500
Subject: CE-EE parity for spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb

---
 spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index c5a4d9b4778..17419b05278 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -174,7 +174,7 @@ describe Gitlab::Ci::Pipeline::Chain::Populate do
       end
 
       let(:pipeline) do
-        build(:ci_pipeline, ref: 'master', config: config)
+        build(:ci_pipeline, ref: 'master', project: project, config: config)
       end
 
       it_behaves_like 'a correct pipeline'
-- 
cgit v1.2.1


From 9c48089190b8fafe0227f354a307e4ad01938437 Mon Sep 17 00:00:00 2001
From: Robert Speicher 
Date: Mon, 18 Jun 2018 14:22:38 -0500
Subject: CE-EE parity to spec/lib/gitlab/ci/yaml_processor_spec.rb

---
 spec/lib/gitlab/ci/yaml_processor_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index ecb16daec96..fa5327c26f0 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
 
 module Gitlab
   module Ci
-    describe YamlProcessor, :lib do
+    describe YamlProcessor do
       subject { described_class.new(config) }
 
       describe 'our current .gitlab-ci.yml' do
-- 
cgit v1.2.1


From 557f4e6a437344d86409ea6b15f3454bc2c5b341 Mon Sep 17 00:00:00 2001
From: Robert Speicher 
Date: Mon, 18 Jun 2018 14:25:28 -0500
Subject: CE-EE parity to spec/lib/gitlab/ci/config_spec.rb

---
 spec/lib/gitlab/ci/config_spec.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index bc5a5e43103..2e204da307d 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -49,7 +49,7 @@ describe Gitlab::Ci::Config do
       describe '.new' do
         it 'raises error' do
           expect { config }.to raise_error(
-            Gitlab::Ci::Config::Loader::FormatError,
+            ::Gitlab::Ci::Config::Loader::FormatError,
             /Invalid configuration format/
           )
         end
-- 
cgit v1.2.1


From 6a684432eebcc8bbf622e9e740381997f02d2a7e Mon Sep 17 00:00:00 2001
From: Robert Speicher 
Date: Mon, 18 Jun 2018 15:22:04 -0500
Subject: Correct CE-EE parity in two CI-related specs

---
 spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb        | 2 +-
 spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
index 17419b05278..284aed91e29 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/populate_spec.rb
@@ -1,7 +1,7 @@
 require 'spec_helper'
 
 describe Gitlab::Ci::Pipeline::Chain::Populate do
-  set(:project) { create(:project) }
+  set(:project) { create(:project, :repository) }
   set(:user) { create(:user) }
 
   let(:pipeline) do
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb
index c53294d091c..a8dc5356413 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/config_spec.rb
@@ -1,7 +1,7 @@
 require 'spec_helper'
 
 describe Gitlab::Ci::Pipeline::Chain::Validate::Config do
-  set(:project) { create(:project) }
+  set(:project) { create(:project, :repository) }
   set(:user) { create(:user) }
 
   let(:command) do
-- 
cgit v1.2.1


From 4f9068dfc06269ca7e2247fb0be2796452546de1 Mon Sep 17 00:00:00 2001
From: Stan Hu 
Date: Mon, 18 Jun 2018 16:38:34 -0700
Subject: Eliminate N+1 queries in LFS file locks checks during a push

This significantly improves performance when a user pushes many references.

project.path_locks.any? doesn't cache the output and runs `SELECT 1 AS one
FROM "path_locks" WHERE project_id = N` each time. When there are thousands
of refs being pushed, this can time out the unicorn worker.

CE port for https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/6159.
---
 spec/lib/gitlab/git_access_spec.rb | 16 ++++++++++++++++
 spec/models/project_spec.rb        | 16 ++++++++++++++++
 2 files changed, 32 insertions(+)

(limited to 'spec')

diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 0d5f6a0b576..ff32025253a 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -934,6 +934,22 @@ describe Gitlab::GitAccess do
         expect(project.repository).to receive(:clean_stale_repository_files).and_call_original
         expect { push_access_check }.not_to raise_error
       end
+
+      it 'avoids N+1 queries', :request_store do
+        # Run this once to establish a baseline. Cached queries should get
+        # cached, so that when we introduce another change we shouldn't see
+        # additional queries.
+        access.check('git-receive-pack', changes)
+
+        control_count = ActiveRecord::QueryRecorder.new do
+          access.check('git-receive-pack', changes)
+        end
+
+        changes = ['6f6d7e7ed 570e7b2ab refs/heads/master', '6f6d7e7ed 570e7b2ab refs/heads/feature']
+
+        # There is still an N+1 query with protected branches
+        expect { access.check('git-receive-pack', changes) }.not_to exceed_query_limit(control_count).with_threshold(1)
+      end
     end
   end
 
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index bc9cce6b0c3..a2f8fac2f38 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -2339,6 +2339,22 @@ describe Project do
     end
   end
 
+  describe '#any_lfs_file_locks?', :request_store do
+    set(:project) { create(:project) }
+
+    it 'returns false when there are no LFS file locks' do
+      expect(project.any_lfs_file_locks?).to be_falsey
+    end
+
+    it 'returns a cached true when there are LFS file locks' do
+      create(:lfs_file_lock, project: project)
+
+      expect(project.lfs_file_locks).to receive(:any?).once.and_call_original
+
+      2.times { expect(project.any_lfs_file_locks?).to be_truthy }
+    end
+  end
+
   describe '#protected_for?' do
     let(:project) { create(:project) }
 
-- 
cgit v1.2.1


From c46ff7de67d31bfc8875abf58d0fd096b6d725ae Mon Sep 17 00:00:00 2001
From: Eric Eastwood 
Date: Mon, 18 Jun 2018 19:00:25 -0500
Subject: Fix flakey time-sensitive specs that rely on notes background Sidekiq
 jobs

Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/48093

We use `perform_enqueued_jobs` because it is "adapter-agnostic so it's better to use it over Sidekiq::Testing.inline!." -- https://gitlab.com/gitlab-org/gitlab-ce/issues/22991
---
 spec/support/helpers/features/notes_helpers.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'spec')

diff --git a/spec/support/helpers/features/notes_helpers.rb b/spec/support/helpers/features/notes_helpers.rb
index 1a1d5853a7a..2b9f8b30c60 100644
--- a/spec/support/helpers/features/notes_helpers.rb
+++ b/spec/support/helpers/features/notes_helpers.rb
@@ -13,7 +13,7 @@ module Spec
       module Features
         module NotesHelpers
           def add_note(text)
-            Sidekiq::Testing.fake! do
+            perform_enqueued_jobs do
               page.within(".js-main-target-form") do
                 fill_in("note[note]", with: text)
                 find(".js-comment-submit-button").click
-- 
cgit v1.2.1


From 9ae8b57467ac8b38f1fa9020a466d94a93cbb9dd Mon Sep 17 00:00:00 2001
From: Zeger-Jan van de Weg 
Date: Thu, 14 Jun 2018 13:21:59 +0200
Subject: Move language detection to mandatory

Closes https://gitlab.com/gitlab-org/gitaly/issues/732
Closes https://gitlab.com/gitlab-org/gitaly/issues/360
---
 spec/lib/gitlab/git/repository_spec.rb | 46 ++++++++++++++--------------------
 1 file changed, 19 insertions(+), 27 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 5bae99101e6..10a264a5030 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1688,41 +1688,33 @@ describe Gitlab::Git::Repository, seed_helper: true do
   end
 
   describe '#languages' do
-    shared_examples 'languages' do
-      it 'returns exactly the expected results' do
-        languages = repository.languages('4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6')
-        expected_languages = [
-          { value: 66.63, label: "Ruby", color: "#701516", highlight: "#701516" },
-          { value: 22.96, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
-          { value: 7.9, label: "HTML", color: "#e34c26", highlight: "#e34c26" },
-          { value: 2.51, label: "CoffeeScript", color: "#244776", highlight: "#244776" }
-        ]
+    it 'returns exactly the expected results' do
+      languages = repository.languages('4b4918a572fa86f9771e5ba40fbd48e1eb03e2c6')
+      expected_languages = [
+        { value: 66.63, label: "Ruby", color: "#701516", highlight: "#701516" },
+        { value: 22.96, label: "JavaScript", color: "#f1e05a", highlight: "#f1e05a" },
+        { value: 7.9, label: "HTML", color: "#e34c26", highlight: "#e34c26" },
+        { value: 2.51, label: "CoffeeScript", color: "#244776", highlight: "#244776" }
+      ]
 
-        expect(languages.size).to eq(expected_languages.size)
+      expect(languages.size).to eq(expected_languages.size)
 
-        expected_languages.size.times do |i|
-          a = expected_languages[i]
-          b = languages[i]
+      expected_languages.size.times do |i|
+        a = expected_languages[i]
+        b = languages[i]
 
-          expect(a.keys.sort).to eq(b.keys.sort)
-          expect(a[:value]).to be_within(0.1).of(b[:value])
+        expect(a.keys.sort).to eq(b.keys.sort)
+        expect(a[:value]).to be_within(0.1).of(b[:value])
 
-          non_float_keys = a.keys - [:value]
-          expect(a.values_at(*non_float_keys)).to eq(b.values_at(*non_float_keys))
-        end
-      end
-
-      it "uses the repository's HEAD when no ref is passed" do
-        lang = repository.languages.first
-
-        expect(lang[:label]).to eq('Ruby')
+        non_float_keys = a.keys - [:value]
+        expect(a.values_at(*non_float_keys)).to eq(b.values_at(*non_float_keys))
       end
     end
 
-    it_behaves_like 'languages'
+    it "uses the repository's HEAD when no ref is passed" do
+      lang = repository.languages.first
 
-    context 'with rugged', :skip_gitaly_mock do
-      it_behaves_like 'languages'
+      expect(lang[:label]).to eq('Ruby')
     end
   end
 
-- 
cgit v1.2.1


From da8419a1ba1cbcc6c5c6365c99419cf17ab2d497 Mon Sep 17 00:00:00 2001
From: Zeger-Jan van de Weg 
Date: Thu, 14 Jun 2018 13:24:17 +0200
Subject: License detection happens soley through Gitaly now

Migration: https://gitlab.com/gitlab-org/gitaly/issues/1026

Conflicts:
	lib/gitlab/git/repository.rb
---
 spec/lib/gitlab/git/repository_spec.rb | 28 +++++++++-------------------
 1 file changed, 9 insertions(+), 19 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 5bae99101e6..f0e7e390f8b 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1727,31 +1727,21 @@ describe Gitlab::Git::Repository, seed_helper: true do
   end
 
   describe '#license_short_name' do
-    shared_examples 'acquiring the Licensee license key' do
-      subject { repository.license_short_name }
+    subject { repository.license_short_name }
 
-      context 'when no license file can be found' do
-        let(:project) { create(:project, :repository) }
-        let(:repository) { project.repository.raw_repository }
-
-        before do
-          project.repository.delete_file(project.owner, 'LICENSE', message: 'remove license', branch_name: 'master')
-        end
-
-        it { is_expected.to be_nil }
-      end
+    context 'when no license file can be found' do
+      let(:project) { create(:project, :repository) }
+      let(:repository) { project.repository.raw_repository }
 
-      context 'when an mit license is found' do
-        it { is_expected.to eq('mit') }
+      before do
+        project.repository.delete_file(project.owner, 'LICENSE', message: 'remove license', branch_name: 'master')
       end
-    end
 
-    context 'when gitaly is enabled' do
-      it_behaves_like 'acquiring the Licensee license key'
+      it { is_expected.to be_nil }
     end
 
-    context 'when gitaly is disabled', :disable_gitaly do
-      it_behaves_like 'acquiring the Licensee license key'
+    context 'when an mit license is found' do
+      it { is_expected.to eq('mit') }
     end
   end
 
-- 
cgit v1.2.1


From c24e39ab88af8fa3087efa0c7c6335e2941d8641 Mon Sep 17 00:00:00 2001
From: Zeger-Jan van de Weg 
Date: Thu, 14 Jun 2018 13:01:55 +0200
Subject: Counting commits is done by Gitaly

Closes https://gitlab.com/gitlab-org/gitaly/issues/382
---
 spec/lib/gitlab/git/repository_spec.rb | 10 +---------
 1 file changed, 1 insertion(+), 9 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 5bae99101e6..b9eb002df3b 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -1114,7 +1114,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
   end
 
   describe '#count_commits' do
-    shared_examples 'extended commit counting' do
+    describe 'extended commit counting' do
       context 'with after timestamp' do
         it 'returns the number of commits after timestamp' do
           options = { ref: 'master', after: Time.iso8601('2013-03-03T20:15:01+00:00') }
@@ -1199,14 +1199,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
         end
       end
     end
-
-    context 'when Gitaly count_commits feature is enabled' do
-      it_behaves_like 'extended commit counting'
-    end
-
-    context 'when Gitaly count_commits feature is disabled', :disable_gitaly do
-      it_behaves_like 'extended commit counting'
-    end
   end
 
   describe '#autocrlf' do
-- 
cgit v1.2.1


From 1dc0332726ffbcb488439e84373958753ee4ac5e Mon Sep 17 00:00:00 2001
From: Zeger-Jan van de Weg 
Date: Tue, 19 Jun 2018 12:17:54 +0200
Subject: Move forking to Gitaly

Closes https://gitlab.com/gitlab-org/gitaly/issues/817

Closes https://gitlab.com/gitlab-org/gitaly/issues/1236
---
 spec/lib/gitlab/shell_spec.rb               | 34 ++++++++---------------------
 spec/workers/repository_fork_worker_spec.rb | 10 ---------
 2 files changed, 9 insertions(+), 35 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 155e1663298..c435f988cdd 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -498,34 +498,18 @@ describe Gitlab::Shell do
         )
       end
 
-      context 'with gitaly' do
-        it 'returns true when the command succeeds' do
-          expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
-            .with(repository.raw_repository) { :gitaly_response_object }
-
-          is_expected.to be_truthy
-        end
-
-        it 'return false when the command fails' do
-          expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
-            .with(repository.raw_repository) { raise GRPC::BadStatus, 'bla' }
+      it 'returns true when the command succeeds' do
+        expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
+          .with(repository.raw_repository) { :gitaly_response_object }
 
-          is_expected.to be_falsy
-        end
+        is_expected.to be_truthy
       end
 
-      context 'without gitaly', :disable_gitaly do
-        it 'returns true when the command succeeds' do
-          expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { true }
-
-          is_expected.to be_truthy
-        end
-
-        it 'return false when the command fails' do
-          expect(gitlab_projects).to receive(:fork_repository).with('nfs-file05', 'fork/path.git') { false }
+      it 'return false when the command fails' do
+        expect_any_instance_of(Gitlab::GitalyClient::RepositoryService).to receive(:fork_repository)
+          .with(repository.raw_repository) { raise GRPC::BadStatus, 'bla' }
 
-          is_expected.to be_falsy
-        end
+        is_expected.to be_falsy
       end
     end
 
@@ -665,7 +649,7 @@ describe Gitlab::Shell do
 
         subject do
           gitlab_shell.fetch_remote(repository.raw_repository, remote_name,
-            forced: true, no_tags: true, ssh_auth: ssh_auth)
+                                    forced: true, no_tags: true, ssh_auth: ssh_auth)
         end
 
         it 'passes the correct params to the gitaly service' do
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 5d83397e8df..ac8716ecfb1 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -92,16 +92,6 @@ describe RepositoryForkWorker do
       end
 
       it_behaves_like 'RepositoryForkWorker performing'
-
-      it 'logs a message about forking with old-style arguments' do
-        allow(subject).to receive(:gitlab_shell).and_return(shell)
-        expect(shell).to receive(:fork_repository) { true }
-
-        allow(Rails.logger).to receive(:info).with(anything) # To compensate for other logs
-        expect(Rails.logger).to receive(:info).with("Project #{fork_project.id} is being forked using old-style arguments.")
-
-        perform!
-      end
     end
   end
 end
-- 
cgit v1.2.1


From c2cdefd4413e2b9946d2a50461b338fc60cef1af Mon Sep 17 00:00:00 2001
From: Zeger-Jan van de Weg 
Date: Tue, 19 Jun 2018 15:01:36 +0200
Subject: Force push is handled by Gitaly now

Closes gitlab-org/gitaly#348
---
 spec/lib/gitlab/checks/force_push_spec.rb | 18 +++++++-----------
 spec/lib/gitlab/git/rev_list_spec.rb      | 10 ----------
 2 files changed, 7 insertions(+), 21 deletions(-)

(limited to 'spec')

diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb
index a65012d2314..0e0788ce974 100644
--- a/spec/lib/gitlab/checks/force_push_spec.rb
+++ b/spec/lib/gitlab/checks/force_push_spec.rb
@@ -1,21 +1,17 @@
 require 'spec_helper'
 
 describe Gitlab::Checks::ForcePush do
-  let(:project) { create(:project, :repository) }
-  let(:repository) { project.repository.raw }
+  set(:project) { create(:project, :repository) }
 
-  context "exit code checking", :skip_gitaly_mock do
-    it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
-      allow(repository).to receive(:popen).and_return(['normal output', 0])
+  describe '.force_push?' do
+    it 'returns false if the repo is empty' do
+      allow(project).to receive(:empty_repo?).and_return(true)
 
-      expect { described_class.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
+      expect(described_class.force_push?(project, 'HEAD', 'HEAD~')).to be(false)
     end
 
-    it "raises a GitError error if the `popen` call to git returns a non-zero exit code" do
-      allow(repository).to receive(:popen).and_return(['error', 1])
-
-      expect { described_class.force_push?(project, 'oldrev', 'newrev') }
-        .to raise_error(Gitlab::Git::Repository::GitError)
+    it 'checks if old rev is an anchestor' do
+      expect(described_class.force_push?(project, 'HEAD', 'HEAD~')).to be(true)
     end
   end
 end
diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb
index 95dc47e2a00..b752c3e8341 100644
--- a/spec/lib/gitlab/git/rev_list_spec.rb
+++ b/spec/lib/gitlab/git/rev_list_spec.rb
@@ -93,14 +93,4 @@ describe Gitlab::Git::RevList do
       expect { |b| rev_list.all_objects(&b) }.to yield_with_args(%w[sha1 sha2])
     end
   end
-
-  context "#missed_ref" do
-    let(:rev_list) { described_class.new(repository, oldrev: 'oldrev', newrev: 'newrev') }
-
-    it 'calls out to `popen`' do
-      stub_popen_rev_list('--max-count=1', 'oldrev', '^newrev', with_lazy_block: false, output: "sha1\nsha2")
-
-      expect(rev_list.missed_ref).to eq(%w[sha1 sha2])
-    end
-  end
 end
-- 
cgit v1.2.1