diff options
Diffstat (limited to 'spec/models')
-rw-r--r-- | spec/models/application_setting_spec.rb | 36 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 6 | ||||
-rw-r--r-- | spec/models/ci/build_trace_chunk_spec.rb | 12 | ||||
-rw-r--r-- | spec/models/clusters/applications/ingress_spec.rb | 1 | ||||
-rw-r--r-- | spec/models/clusters/applications/jupyter_spec.rb | 1 | ||||
-rw-r--r-- | spec/models/clusters/applications/prometheus_spec.rb | 1 | ||||
-rw-r--r-- | spec/models/clusters/applications/runner_spec.rb | 1 | ||||
-rw-r--r-- | spec/models/commit_spec.rb | 31 | ||||
-rw-r--r-- | spec/models/concerns/reactive_caching_spec.rb | 11 | ||||
-rw-r--r-- | spec/models/concerns/resolvable_discussion_spec.rb | 13 | ||||
-rw-r--r-- | spec/models/concerns/sortable_spec.rb | 18 | ||||
-rw-r--r-- | spec/models/hooks/web_hook_log_spec.rb | 18 | ||||
-rw-r--r-- | spec/models/merge_request_diff_spec.rb | 46 | ||||
-rw-r--r-- | spec/models/merge_request_spec.rb | 105 | ||||
-rw-r--r-- | spec/models/namespace_spec.rb | 13 | ||||
-rw-r--r-- | spec/models/note_spec.rb | 10 | ||||
-rw-r--r-- | spec/models/project_services/bamboo_service_spec.rb | 22 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 20 | ||||
-rw-r--r-- | spec/models/repository_spec.rb | 288 |
19 files changed, 381 insertions, 272 deletions
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb index 3e6656e0f12..02f74e2ea54 100644 --- a/spec/models/application_setting_spec.rb +++ b/spec/models/application_setting_spec.rb @@ -25,15 +25,6 @@ describe ApplicationSetting do it { is_expected.to allow_value(https).for(:after_sign_out_path) } it { is_expected.not_to allow_value(ftp).for(:after_sign_out_path) } - describe 'disabled_oauth_sign_in_sources validations' do - before do - allow(Devise).to receive(:omniauth_providers).and_return([:github]) - end - - it { is_expected.to allow_value(['github']).for(:disabled_oauth_sign_in_sources) } - it { is_expected.not_to allow_value(['test']).for(:disabled_oauth_sign_in_sources) } - end - describe 'default_artifacts_expire_in' do it 'sets an error if it cannot parse' do setting.update(default_artifacts_expire_in: 'a') @@ -314,6 +305,33 @@ describe ApplicationSetting do end end + describe '#disabled_oauth_sign_in_sources=' do + before do + allow(Devise).to receive(:omniauth_providers).and_return([:github]) + end + + it 'removes unknown sources (as strings) from the array' do + subject.disabled_oauth_sign_in_sources = %w[github test] + + expect(subject).to be_valid + expect(subject.disabled_oauth_sign_in_sources).to eq ['github'] + end + + it 'removes unknown sources (as symbols) from the array' do + subject.disabled_oauth_sign_in_sources = %i[github test] + + expect(subject).to be_valid + expect(subject.disabled_oauth_sign_in_sources).to eq ['github'] + end + + it 'ignores nil' do + subject.disabled_oauth_sign_in_sources = nil + + expect(subject).to be_valid + expect(subject.disabled_oauth_sign_in_sources).to be_empty + end + end + context 'restricted signup domains' do it 'sets single domain' do setting.domain_whitelist_raw = 'example.com' diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 51b9b518117..6758adc59eb 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1871,7 +1871,11 @@ describe Ci::Build do end context 'when yaml_variables are undefined' do - let(:pipeline) { create(:ci_pipeline, project: project) } + let(:pipeline) do + create(:ci_pipeline, project: project, + sha: project.commit.id, + ref: project.default_branch) + end before do build.yaml_variables = nil diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb index b5a6d959ccb..464897de306 100644 --- a/spec/models/ci/build_trace_chunk_spec.rb +++ b/spec/models/ci/build_trace_chunk_spec.rb @@ -1,6 +1,8 @@ require 'spec_helper' describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do + include ExclusiveLeaseHelpers + set(:build) { create(:ci_build, :running) } let(:chunk_index) { 0 } let(:data_store) { :redis } @@ -125,14 +127,6 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do end end end - - context 'when data_store is others' do - before do - build_trace_chunk.send(:write_attribute, :data_store, -1) - end - - it { expect { subject }.to raise_error('Unsupported data store') } - end end describe '#truncate' do @@ -330,7 +324,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do describe 'ExclusiveLock' do before do - allow_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain) { nil } + stub_exclusive_lease_taken stub_const('Ci::BuildTraceChunk::WRITE_LOCK_RETRY', 1) end diff --git a/spec/models/clusters/applications/ingress_spec.rb b/spec/models/clusters/applications/ingress_spec.rb index a47a07d908d..bb5b2ef3a47 100644 --- a/spec/models/clusters/applications/ingress_spec.rb +++ b/spec/models/clusters/applications/ingress_spec.rb @@ -73,6 +73,7 @@ describe Clusters::Applications::Ingress do it 'should be initialized with ingress arguments' do expect(subject.name).to eq('ingress') expect(subject.chart).to eq('stable/nginx-ingress') + expect(subject.version).to be_nil expect(subject.values).to eq(ingress.values) end end diff --git a/spec/models/clusters/applications/jupyter_spec.rb b/spec/models/clusters/applications/jupyter_spec.rb index ca48a1d8072..65750141e65 100644 --- a/spec/models/clusters/applications/jupyter_spec.rb +++ b/spec/models/clusters/applications/jupyter_spec.rb @@ -36,6 +36,7 @@ describe Clusters::Applications::Jupyter do it 'should be initialized with 4 arguments' do expect(subject.name).to eq('jupyter') expect(subject.chart).to eq('jupyter/jupyterhub') + expect(subject.version).to be_nil expect(subject.repository).to eq('https://jupyterhub.github.io/helm-chart/') expect(subject.values).to eq(jupyter.values) end diff --git a/spec/models/clusters/applications/prometheus_spec.rb b/spec/models/clusters/applications/prometheus_spec.rb index d2302583ac8..efd57040005 100644 --- a/spec/models/clusters/applications/prometheus_spec.rb +++ b/spec/models/clusters/applications/prometheus_spec.rb @@ -109,6 +109,7 @@ describe Clusters::Applications::Prometheus do it 'should be initialized with 3 arguments' do expect(subject.name).to eq('prometheus') expect(subject.chart).to eq('stable/prometheus') + expect(subject.version).to eq('6.7.3') expect(subject.values).to eq(prometheus.values) end end diff --git a/spec/models/clusters/applications/runner_spec.rb b/spec/models/clusters/applications/runner_spec.rb index 3ef59457c5f..b12500d0acd 100644 --- a/spec/models/clusters/applications/runner_spec.rb +++ b/spec/models/clusters/applications/runner_spec.rb @@ -31,6 +31,7 @@ describe Clusters::Applications::Runner do it 'should be initialized with 4 arguments' do expect(subject.name).to eq('runner') expect(subject.chart).to eq('runner/gitlab-runner') + expect(subject.version).to be_nil expect(subject.repository).to eq('https://charts.gitlab.io') expect(subject.values).to eq(gitlab_runner.values) end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index 090f91168ad..5157d8fc645 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -514,30 +514,21 @@ eos end describe '#uri_type' do - shared_examples 'URI type' do - it 'returns the URI type at the given path' do - expect(commit.uri_type('files/html')).to be(:tree) - expect(commit.uri_type('files/images/logo-black.png')).to be(:raw) - expect(project.commit('video').uri_type('files/videos/intro.mp4')).to be(:raw) - expect(commit.uri_type('files/js/application.js')).to be(:blob) - end - - it "returns nil if the path doesn't exists" do - expect(commit.uri_type('this/path/doesnt/exist')).to be_nil - end - - it 'is nil if the path is nil or empty' do - expect(commit.uri_type(nil)).to be_nil - expect(commit.uri_type("")).to be_nil - end + it 'returns the URI type at the given path' do + expect(commit.uri_type('files/html')).to be(:tree) + expect(commit.uri_type('files/images/logo-black.png')).to be(:raw) + expect(project.commit('video').uri_type('files/videos/intro.mp4')).to be(:raw) + expect(commit.uri_type('files/js/application.js')).to be(:blob) end - context 'when Gitaly commit_tree_entry feature is enabled' do - it_behaves_like 'URI type' + it "returns nil if the path doesn't exists" do + expect(commit.uri_type('this/path/doesnt/exist')).to be_nil + expect(commit.uri_type('../path/doesnt/exist')).to be_nil end - context 'when Gitaly commit_tree_entry feature is disabled', :disable_gitaly do - it_behaves_like 'URI type' + it 'is nil if the path is nil or empty' do + expect(commit.uri_type(nil)).to be_nil + expect(commit.uri_type("")).to be_nil end end diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb index f2a3df50c1a..0f156619e9e 100644 --- a/spec/models/concerns/reactive_caching_spec.rb +++ b/spec/models/concerns/reactive_caching_spec.rb @@ -1,6 +1,7 @@ require 'spec_helper' describe ReactiveCaching, :use_clean_rails_memory_store_caching do + include ExclusiveLeaseHelpers include ReactiveCachingHelpers class CacheTest @@ -106,8 +107,8 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do end it 'takes and releases the lease' do - expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return("000000") - expect(Gitlab::ExclusiveLease).to receive(:cancel).with(cache_key, "000000") + expect_to_obtain_exclusive_lease(cache_key, 'uuid') + expect_to_cancel_exclusive_lease(cache_key, 'uuid') go! end @@ -153,11 +154,9 @@ describe ReactiveCaching, :use_clean_rails_memory_store_caching do end context 'when the lease is already taken' do - before do - expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(nil) - end - it 'skips the calculation' do + stub_exclusive_lease_taken(cache_key) + expect(instance).to receive(:calculate_reactive_cache).never go! diff --git a/spec/models/concerns/resolvable_discussion_spec.rb b/spec/models/concerns/resolvable_discussion_spec.rb index 2a2ef5a304d..2f9f63ce7e0 100644 --- a/spec/models/concerns/resolvable_discussion_spec.rb +++ b/spec/models/concerns/resolvable_discussion_spec.rb @@ -534,11 +534,18 @@ describe Discussion, ResolvableDiscussion do describe "#last_resolved_note" do let(:current_user) { create(:user) } + let(:time) { Time.now.utc } before do - first_note.resolve!(current_user) - third_note.resolve!(current_user) - second_note.resolve!(current_user) + Timecop.freeze(time - 1.second) do + first_note.resolve!(current_user) + end + Timecop.freeze(time) do + third_note.resolve!(current_user) + end + Timecop.freeze(time + 1.second) do + second_note.resolve!(current_user) + end end it "returns the last note that was resolved" do diff --git a/spec/models/concerns/sortable_spec.rb b/spec/models/concerns/sortable_spec.rb index b821a84d5e0..39c16ae60af 100644 --- a/spec/models/concerns/sortable_spec.rb +++ b/spec/models/concerns/sortable_spec.rb @@ -40,15 +40,25 @@ describe Sortable do describe 'ordering by name' do it 'ascending' do - expect(relation).to receive(:reorder).with("lower(name) asc") + expect(relation).to receive(:reorder).once.and_call_original - relation.order_by('name_asc') + table = Regexp.escape(ActiveRecord::Base.connection.quote_table_name(:namespaces)) + column = Regexp.escape(ActiveRecord::Base.connection.quote_column_name(:name)) + + sql = relation.order_by('name_asc').to_sql + + expect(sql).to match /.+ORDER BY LOWER\(#{table}.#{column}\) ASC\z/ end it 'descending' do - expect(relation).to receive(:reorder).with("lower(name) desc") + expect(relation).to receive(:reorder).once.and_call_original + + table = Regexp.escape(ActiveRecord::Base.connection.quote_table_name(:namespaces)) + column = Regexp.escape(ActiveRecord::Base.connection.quote_column_name(:name)) + + sql = relation.order_by('name_desc').to_sql - relation.order_by('name_desc') + expect(sql).to match /.+ORDER BY LOWER\(#{table}.#{column}\) DESC\z/ end end diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb index 19bc88b1333..744a6ccae8b 100644 --- a/spec/models/hooks/web_hook_log_spec.rb +++ b/spec/models/hooks/web_hook_log_spec.rb @@ -9,6 +9,24 @@ describe WebHookLog do it { is_expected.to validate_presence_of(:web_hook) } + describe '.recent' do + let(:hook) { create(:project_hook) } + + it 'does not return web hook logs that are too old' do + create(:web_hook_log, web_hook: hook, created_at: 91.days.ago) + + expect(described_class.recent.size).to be_zero + end + + it 'returns the web hook logs in descending order' do + hook1 = create(:web_hook_log, web_hook: hook, created_at: 2.hours.ago) + hook2 = create(:web_hook_log, web_hook: hook, created_at: 1.hour.ago) + hooks = described_class.recent.to_a + + expect(hooks).to eq([hook2, hook1]) + end + end + describe '#success?' do let(:web_hook_log) { build(:web_hook_log, response_status: status) } diff --git a/spec/models/merge_request_diff_spec.rb b/spec/models/merge_request_diff_spec.rb index b4249d72fc8..ccc3ff861c5 100644 --- a/spec/models/merge_request_diff_spec.rb +++ b/spec/models/merge_request_diff_spec.rb @@ -47,6 +47,45 @@ describe MergeRequestDiff do end describe '#diffs' do + let(:merge_request) { create(:merge_request, :with_diffs) } + let!(:diff) { merge_request.merge_request_diff.reload } + + context 'when it was not cleaned by the system' do + it 'returns persisted diffs' do + expect(diff).to receive(:load_diffs) + + diff.diffs + end + end + + context 'when diff was cleaned by the system' do + before do + diff.clean! + end + + it 'returns diffs from repository if can compare with current diff refs' do + expect(diff).not_to receive(:load_diffs) + + expect(Compare) + .to receive(:new) + .with(instance_of(Gitlab::Git::Compare), merge_request.target_project, + base_sha: diff.base_commit_sha, straight: false) + .and_call_original + + diff.diffs + end + + it 'returns persisted diffs if cannot compare with diff refs' do + expect(diff).to receive(:load_diffs) + + diff.update!(head_commit_sha: 'invalid-sha') + + diff.diffs + end + end + end + + describe '#raw_diffs' do context 'when the :ignore_whitespace_change option is set' do it 'creates a new compare object instead of loading from the DB' do expect(diff_with_commits).not_to receive(:load_diffs) @@ -114,6 +153,13 @@ describe MergeRequestDiff do expect(mr_diff.empty?).to be_truthy end + it 'expands collapsed diffs before saving' do + mr_diff = create(:merge_request, source_branch: 'expand-collapse-lines', target_branch: 'master').merge_request_diff + diff_file = mr_diff.merge_request_diff_files.find_by(new_path: 'expand-collapse/file-5.txt') + + expect(diff_file.diff).not_to be_empty + end + it 'saves binary diffs correctly' do path = 'files/images/icn-time-tracking.pdf' mr_diff = create(:merge_request, source_branch: 'add-pdf-text-binary', target_branch: 'master').merge_request_diff diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 3f028b3bd5c..8c6b411ec9a 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1324,6 +1324,7 @@ describe MergeRequest do context 'when broken' do before do allow(subject).to receive(:broken?) { true } + allow(project.repository).to receive(:can_be_merged?).and_return(false) end it 'becomes unmergeable' do @@ -1629,28 +1630,17 @@ describe MergeRequest do end describe "#reload_diff" do - let(:discussion) { create(:diff_note_on_merge_request, project: subject.project, noteable: subject).to_discussion } - let(:commit) { subject.project.commit(sample_commit.id) } - - it "does not change existing merge request diff" do - expect(subject.merge_request_diff).not_to receive(:save_git_content) - subject.reload_diff - end - - it "creates new merge request diff" do - expect { subject.reload_diff }.to change { subject.merge_request_diffs.count }.by(1) - end - - it "executes diff cache service" do - expect_any_instance_of(MergeRequests::MergeRequestDiffCacheService).to receive(:execute).with(subject, an_instance_of(MergeRequestDiff)) + it 'calls MergeRequests::ReloadDiffsService#execute with correct params' do + user = create(:user) + service = instance_double(MergeRequests::ReloadDiffsService, execute: nil) - subject.reload_diff - end + expect(MergeRequests::ReloadDiffsService) + .to receive(:new).with(subject, user) + .and_return(service) - it "calls update_diff_discussion_positions" do - expect(subject).to receive(:update_diff_discussion_positions) + subject.reload_diff(user) - subject.reload_diff + expect(service).to have_received(:execute) end context 'when using the after_update hook to update' do @@ -2144,32 +2134,77 @@ describe MergeRequest do describe 'transition to cannot_be_merged' do let(:notification_service) { double(:notification_service) } let(:todo_service) { double(:todo_service) } - - subject { create(:merge_request, merge_status: :unchecked) } + subject { create(:merge_request, state, merge_status: :unchecked) } before do allow(NotificationService).to receive(:new).and_return(notification_service) allow(TodoService).to receive(:new).and_return(todo_service) + + allow(subject.project.repository).to receive(:can_be_merged?).and_return(false) + end + + [:opened, :locked].each do |state| + context state do + let(:state) { state } + + it 'notifies conflict, but does not notify again if rechecking still results in cannot_be_merged' do + expect(notification_service).to receive(:merge_request_unmergeable).with(subject).once + expect(todo_service).to receive(:merge_request_became_unmergeable).with(subject).once + + subject.mark_as_unmergeable + subject.mark_as_unchecked + subject.mark_as_unmergeable + end + + it 'notifies conflict, whenever newly unmergeable' do + expect(notification_service).to receive(:merge_request_unmergeable).with(subject).twice + expect(todo_service).to receive(:merge_request_became_unmergeable).with(subject).twice + + subject.mark_as_unmergeable + subject.mark_as_unchecked + subject.mark_as_mergeable + subject.mark_as_unchecked + subject.mark_as_unmergeable + end + + it 'does not notify whenever merge request is newly unmergeable due to other reasons' do + allow(subject.project.repository).to receive(:can_be_merged?).and_return(true) + + expect(notification_service).not_to receive(:merge_request_unmergeable) + expect(todo_service).not_to receive(:merge_request_became_unmergeable) + + subject.mark_as_unmergeable + end + end end - it 'notifies, but does not notify again if rechecking still results in cannot_be_merged' do - expect(notification_service).to receive(:merge_request_unmergeable).with(subject).once - expect(todo_service).to receive(:merge_request_became_unmergeable).with(subject).once + [:closed, :merged].each do |state| + let(:state) { state } - subject.mark_as_unmergeable - subject.mark_as_unchecked - subject.mark_as_unmergeable + context state do + it 'does not notify' do + expect(notification_service).not_to receive(:merge_request_unmergeable) + expect(todo_service).not_to receive(:merge_request_became_unmergeable) + + subject.mark_as_unmergeable + end + end end - it 'notifies whenever merge request is newly unmergeable' do - expect(notification_service).to receive(:merge_request_unmergeable).with(subject).twice - expect(todo_service).to receive(:merge_request_became_unmergeable).with(subject).twice + context 'source branch is missing' do + subject { create(:merge_request, :invalid, :opened, merge_status: :unchecked, target_branch: 'master') } + + before do + allow(subject.project.repository).to receive(:can_be_merged?).and_call_original + end - subject.mark_as_unmergeable - subject.mark_as_unchecked - subject.mark_as_mergeable - subject.mark_as_unchecked - subject.mark_as_unmergeable + it 'does not raise error' do + expect(notification_service).not_to receive(:merge_request_unmergeable) + expect(todo_service).not_to receive(:merge_request_became_unmergeable) + + expect { subject.mark_as_unmergeable }.not_to raise_error + expect(subject.cannot_be_merged?).to eq(true) + end end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 18b01c3e6b7..70f1a1c8b38 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -655,6 +655,19 @@ describe Namespace do end end + describe '#root_ancestor' do + it 'returns the top most ancestor', :nested_groups do + root_group = create(:group) + nested_group = create(:group, parent: root_group) + deep_nested_group = create(:group, parent: nested_group) + very_deep_nested_group = create(:group, parent: deep_nested_group) + + expect(nested_group.root_ancestor).to eq(root_group) + expect(deep_nested_group.root_ancestor).to eq(root_group) + expect(very_deep_nested_group.root_ancestor).to eq(root_group) + end + end + describe '#remove_exports' do let(:legacy_project) { create(:project, :with_export, :legacy_storage, namespace: namespace) } let(:hashed_project) { create(:project, :with_export, namespace: namespace) } diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 6a6c71e6c82..a2cb716cb93 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -828,5 +828,15 @@ describe Note do note.destroy! end + + context 'when issuable etag caching is disabled' do + it 'does not store cache key' do + allow(note.noteable).to receive(:etag_caching_enabled?).and_return(false) + + expect_any_instance_of(Gitlab::EtagCaching::Store).not_to receive(:touch) + + note.save! + end + end end end diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb index 85baaccf035..f4f7afb1b92 100644 --- a/spec/models/project_services/bamboo_service_spec.rb +++ b/spec/models/project_services/bamboo_service_spec.rb @@ -120,6 +120,14 @@ describe BambooService, :use_clean_rails_memory_store_caching do end end + describe '#execute' do + it 'runs update and build action' do + stub_update_and_build_request + + subject.execute(Gitlab::DataBuilder::Push::SAMPLE_DATA) + end + end + describe '#build_page' do it 'returns the contents of the reactive cache' do stub_reactive_cache(service, { build_page: 'foo' }, 'sha', 'ref') @@ -216,10 +224,20 @@ describe BambooService, :use_clean_rails_memory_store_caching do end end + def stub_update_and_build_request(status: 200, body: nil) + bamboo_full_url = 'http://gitlab.com/bamboo/updateAndBuild.action?buildKey=foo&os_authType=basic' + + stub_bamboo_request(bamboo_full_url, status, body) + end + def stub_request(status: 200, body: nil) - bamboo_full_url = 'http://gitlab.com/bamboo/rest/api/latest/result?label=123&os_authType=basic' + bamboo_full_url = 'http://gitlab.com/bamboo/rest/api/latest/result/byChangeset/123?os_authType=basic' + + stub_bamboo_request(bamboo_full_url, status, body) + end - WebMock.stub_request(:get, bamboo_full_url).to_return( + def stub_bamboo_request(url, status, body) + WebMock.stub_request(:get, url).to_return( status: status, headers: { 'Content-Type' => 'application/json' }, body: body diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index bc9cce6b0c3..abdc65336ca 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -571,13 +571,13 @@ describe Project do last_activity_at: timestamp, last_repository_updated_at: timestamp - 1.hour) - expect(project.last_activity_date).to eq(timestamp) + expect(project.last_activity_date).to be_like_time(timestamp) project.update_attributes(updated_at: timestamp, last_activity_at: timestamp - 1.hour, last_repository_updated_at: nil) - expect(project.last_activity_date).to eq(timestamp) + expect(project.last_activity_date).to be_like_time(timestamp) end end end @@ -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) } diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index b6df048d4ca..d060ab923d1 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -46,7 +46,7 @@ describe Repository do it { is_expected.not_to include('feature') } it { is_expected.not_to include('fix') } - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.branch_names_contains(sample_commit.id) @@ -192,7 +192,7 @@ describe Repository do it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') } - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.last_commit_id_for_path(sample_commit.id, '.gitignore') @@ -226,7 +226,7 @@ describe Repository do is_expected.to eq('c1acaa5') end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.last_commit_for_path(sample_commit.id, '.gitignore').id @@ -391,7 +391,7 @@ describe Repository do it_behaves_like 'finding commits by message' end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error { broken_repository.find_commits_by_message('s') } end @@ -434,44 +434,34 @@ describe Repository do end describe '#can_be_merged?' do - shared_examples 'can be merged' do - context 'mergeable branches' do - subject { repository.can_be_merged?('0b4bc9a49b562e85de7cc9e834518ea6828729b9', 'master') } + context 'mergeable branches' do + subject { repository.can_be_merged?('0b4bc9a49b562e85de7cc9e834518ea6828729b9', 'master') } - it { is_expected.to be_truthy } - end - - context 'non-mergeable branches without conflict sides missing' do - subject { repository.can_be_merged?('bb5206fee213d983da88c47f9cf4cc6caf9c66dc', 'feature') } - - it { is_expected.to be_falsey } - end + it { is_expected.to be_truthy } + end - context 'non-mergeable branches with conflict sides missing' do - subject { repository.can_be_merged?('conflict-missing-side', 'conflict-start') } + context 'non-mergeable branches without conflict sides missing' do + subject { repository.can_be_merged?('bb5206fee213d983da88c47f9cf4cc6caf9c66dc', 'feature') } - it { is_expected.to be_falsey } - end + it { is_expected.to be_falsey } + end - context 'non merged branch' do - subject { repository.merged_to_root_ref?('fix') } + context 'non-mergeable branches with conflict sides missing' do + subject { repository.can_be_merged?('conflict-missing-side', 'conflict-start') } - it { is_expected.to be_falsey } - end + it { is_expected.to be_falsey } + end - context 'non existent branch' do - subject { repository.merged_to_root_ref?('non_existent_branch') } + context 'non merged branch' do + subject { repository.merged_to_root_ref?('fix') } - it { is_expected.to be_nil } - end + it { is_expected.to be_falsey } end - context 'when Gitaly can_be_merged feature is enabled' do - it_behaves_like 'can be merged' - end + context 'non existent branch' do + subject { repository.merged_to_root_ref?('non_existent_branch') } - context 'when Gitaly can_be_merged feature is disabled', :disable_gitaly do - it_behaves_like 'can be merged' + it { is_expected.to be_nil } end end @@ -489,6 +479,14 @@ describe Repository do end end + context 'when ref is not specified' do + it 'is using a root ref' do + expect(repository).to receive(:find_commit).with('master') + + repository.commit + end + end + context 'when ref is not valid' do context 'when preceding tree element exists' do it 'returns nil' do @@ -674,7 +672,7 @@ describe Repository do end end - shared_examples "search_files_by_content" do + describe "search_files_by_content" do let(:results) { repository.search_files_by_content('feature', 'master') } subject { results } @@ -705,7 +703,7 @@ describe Repository do expect(results).to match_array([]) end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.search_files_by_content('feature', 'master') @@ -721,7 +719,7 @@ describe Repository do end end - shared_examples "search_files_by_name" do + describe "search_files_by_name" do let(:results) { repository.search_files_by_name('files', 'master') } it 'returns result' do @@ -754,23 +752,13 @@ describe Repository do expect(results).to match_array([]) end - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error { broken_repository.search_files_by_name('files', 'master') } end end end - describe 'with gitaly enabled' do - it_behaves_like 'search_files_by_content' - it_behaves_like 'search_files_by_name' - end - - describe 'with gitaly disabled', :disable_gitaly do - it_behaves_like 'search_files_by_content' - it_behaves_like 'search_files_by_name' - end - describe '#async_remove_remote' do before do masterrev = repository.find_branch('master').dereferenced_target @@ -806,7 +794,7 @@ describe Repository do describe '#fetch_ref' do let(:broken_repository) { create(:project, :broken_storage).repository } - describe 'when storage is broken', :broken_storage do + describe 'when storage is broken', :broken_storage do it 'should raise a storage error' do expect_to_raise_storage_error do broken_repository.fetch_ref(broken_repository, source_ref: '1', target_ref: '2') @@ -1709,19 +1697,29 @@ describe Repository do end describe '#after_change_head' do - it 'flushes the readme cache' do + it 'flushes the method caches' do expect(repository).to receive(:expire_method_caches).with([ - :readme, + :size, + :commit_count, + :rendered_readme, + :contribution_guide, :changelog, - :license, - :contributing, + :license_blob, + :license_key, :gitignore, - :koding, - :gitlab_ci, + :koding_yml, + :gitlab_ci_yml, + :branch_names, + :tag_names, + :branch_count, + :tag_count, :avatar, - :issue_template, - :merge_request_template, - :xcode_config + :exists?, + :root_ref, + :has_visible_content?, + :issue_template_names, + :merge_request_template_names, + :xcode_project? ]) repository.after_change_head @@ -1863,155 +1861,61 @@ describe Repository do describe '#add_tag' do let(:user) { build_stubbed(:user) } - shared_examples 'adding tag' do - context 'with a valid target' do - it 'creates the tag' do - repository.add_tag(user, '8.5', 'master', 'foo') - - tag = repository.find_tag('8.5') - expect(tag).to be_present - expect(tag.message).to eq('foo') - expect(tag.dereferenced_target.id).to eq(repository.commit('master').id) - end - - it 'returns a Gitlab::Git::Tag object' do - tag = repository.add_tag(user, '8.5', 'master', 'foo') + context 'with a valid target' do + it 'creates the tag' do + repository.add_tag(user, '8.5', 'master', 'foo') - expect(tag).to be_a(Gitlab::Git::Tag) - end + tag = repository.find_tag('8.5') + expect(tag).to be_present + expect(tag.message).to eq('foo') + expect(tag.dereferenced_target.id).to eq(repository.commit('master').id) end - context 'with an invalid target' do - it 'returns false' do - expect(repository.add_tag(user, '8.5', 'bar', 'foo')).to be false - end - end - end - - context 'when Gitaly operation_user_add_tag feature is enabled' do - it_behaves_like 'adding tag' - end - - context 'when Gitaly operation_user_add_tag feature is disabled', :disable_gitaly do - it_behaves_like 'adding tag' - - it 'passes commit SHA to pre-receive and update hooks and tag SHA to post-receive hook' do - pre_receive_hook = Gitlab::Git::Hook.new('pre-receive', project) - update_hook = Gitlab::Git::Hook.new('update', project) - post_receive_hook = Gitlab::Git::Hook.new('post-receive', project) - - allow(Gitlab::Git::Hook).to receive(:new) - .and_return(pre_receive_hook, update_hook, post_receive_hook) - - allow(pre_receive_hook).to receive(:trigger).and_call_original - allow(update_hook).to receive(:trigger).and_call_original - allow(post_receive_hook).to receive(:trigger).and_call_original - + it 'returns a Gitlab::Git::Tag object' do tag = repository.add_tag(user, '8.5', 'master', 'foo') - commit_sha = repository.commit('master').id - tag_sha = tag.target - - expect(pre_receive_hook).to have_received(:trigger) - .with(anything, anything, anything, commit_sha, anything) - expect(update_hook).to have_received(:trigger) - .with(anything, anything, anything, commit_sha, anything) - expect(post_receive_hook).to have_received(:trigger) - .with(anything, anything, anything, tag_sha, anything) + expect(tag).to be_a(Gitlab::Git::Tag) end end - end - - describe '#rm_branch' do - shared_examples "user deleting a branch" do - it 'removes a branch' do - expect(repository).to receive(:before_remove_branch) - expect(repository).to receive(:after_remove_branch) - repository.rm_branch(user, 'feature') + context 'with an invalid target' do + it 'returns false' do + expect(repository.add_tag(user, '8.5', 'bar', 'foo')).to be false end end + end - context 'with gitaly enabled' do - it_behaves_like "user deleting a branch" - - context 'when pre hooks failed' do - before do - allow_any_instance_of(Gitlab::GitalyClient::OperationService) - .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::PreReceiveError) + describe '#rm_branch' do + it 'removes a branch' do + expect(repository).to receive(:before_remove_branch) + expect(repository).to receive(:after_remove_branch) - expect(repository.find_branch('feature')).not_to be_nil - end - end + repository.rm_branch(user, 'feature') end - context 'with gitaly disabled', :disable_gitaly do - it_behaves_like "user deleting a branch" - - let(:old_rev) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' } # git rev-parse feature - let(:blank_sha) { '0000000000000000000000000000000000000000' } - - context 'when pre hooks were successful' do - it 'runs without errors' do - expect_any_instance_of(Gitlab::Git::HooksService).to receive(:execute) - .with(git_user, repository.raw_repository, old_rev, blank_sha, 'refs/heads/feature') - - expect { repository.rm_branch(user, 'feature') }.not_to raise_error - end - - it 'deletes the branch' do - allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([true, nil]) - - expect { repository.rm_branch(user, 'feature') }.not_to raise_error - - expect(repository.find_branch('feature')).to be_nil - end + context 'when pre hooks failed' do + before do + allow_any_instance_of(Gitlab::GitalyClient::OperationService) + .to receive(:user_delete_branch).and_raise(Gitlab::Git::PreReceiveError) end - context 'when pre hooks failed' do - it 'gets an error' do - allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, '']) - - expect do - repository.rm_branch(user, 'feature') - end.to raise_error(Gitlab::Git::PreReceiveError) - end - - it 'does not delete the branch' do - allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, '']) + it 'gets an error and does not delete the branch' do + expect do + repository.rm_branch(user, 'feature') + end.to raise_error(Gitlab::Git::PreReceiveError) - expect do - repository.rm_branch(user, 'feature') - end.to raise_error(Gitlab::Git::PreReceiveError) - expect(repository.find_branch('feature')).not_to be_nil - end + expect(repository.find_branch('feature')).not_to be_nil end end end describe '#rm_tag' do - shared_examples 'removing tag' do - it 'removes a tag' do - expect(repository).to receive(:before_remove_tag) + it 'removes a tag' do + expect(repository).to receive(:before_remove_tag) - repository.rm_tag(build_stubbed(:user), 'v1.1.0') + repository.rm_tag(build_stubbed(:user), 'v1.1.0') - expect(repository.find_tag('v1.1.0')).to be_nil - end - end - - context 'when Gitaly operation_user_delete_tag feature is enabled' do - it_behaves_like 'removing tag' - end - - context 'when Gitaly operation_user_delete_tag feature is disabled', :skip_gitaly_mock do - it_behaves_like 'removing tag' + expect(repository.find_tag('v1.1.0')).to be_nil end end @@ -2304,6 +2208,28 @@ describe Repository do end end + describe '#local_branches' do + it 'returns the local branches' do + masterrev = repository.find_branch('master').dereferenced_target + create_remote_branch('joe', 'remote_branch', masterrev) + repository.add_branch(user, 'local_branch', masterrev.id) + + expect(repository.local_branches.any? { |branch| branch.name == 'remote_branch' }).to eq(false) + expect(repository.local_branches.any? { |branch| branch.name == 'local_branch' }).to eq(true) + end + end + + describe '#remote_branches' do + it 'returns the remote branches' do + masterrev = repository.find_branch('master').dereferenced_target + create_remote_branch('joe', 'remote_branch', masterrev) + repository.add_branch(user, 'local_branch', masterrev.id) + + expect(repository.remote_branches('joe').any? { |branch| branch.name == 'local_branch' }).to eq(false) + expect(repository.remote_branches('joe').any? { |branch| branch.name == 'remote_branch' }).to eq(true) + end + end + describe '#commit_count' do context 'with a non-existing repository' do it 'returns 0' do |