summaryrefslogtreecommitdiff
path: root/spec/models
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models')
-rw-r--r--spec/models/blob_spec.rb543
-rw-r--r--spec/models/commit_spec.rb229
-rw-r--r--spec/models/concerns/redis_cacheable_spec.rb4
-rw-r--r--spec/models/personal_snippet_spec.rb9
-rw-r--r--spec/models/project_snippet_spec.rb9
-rw-r--r--spec/models/project_spec.rb19
-rw-r--r--spec/models/repository_spec.rb2
-rw-r--r--spec/models/snippet_repository_spec.rb23
-rw-r--r--spec/models/snippet_spec.rb106
-rw-r--r--spec/models/user_spec.rb2
10 files changed, 800 insertions, 146 deletions
diff --git a/spec/models/blob_spec.rb b/spec/models/blob_spec.rb
index 7099d000d4c..a0193b29bb3 100644
--- a/spec/models/blob_spec.rb
+++ b/spec/models/blob_spec.rb
@@ -6,6 +6,8 @@ describe Blob do
include FakeBlobHelpers
let(:project) { build(:project, lfs_enabled: true) }
+ let(:personal_snippet) { build(:personal_snippet) }
+ let(:project_snippet) { build(:project_snippet, project: project) }
before do
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
@@ -18,77 +20,146 @@ describe Blob do
end
describe '.lazy' do
- let(:project) { create(:project, :repository) }
- let(:same_project) { Project.find(project.id) }
- let(:other_project) { create(:project, :repository) }
let(:commit_id) { 'e63f41fe459e62e1228fcef60d7189127aeba95a' }
let(:blob_size_limit) { 10 * 1024 * 1024 }
- it 'does not fetch blobs when none are accessed' do
- expect(project.repository).not_to receive(:blobs_at)
+ shared_examples '.lazy checks' do
+ it 'does not fetch blobs when none are accessed' do
+ expect(container.repository).not_to receive(:blobs_at)
- described_class.lazy(project, commit_id, 'CHANGELOG')
- end
+ described_class.lazy(container, commit_id, 'CHANGELOG')
+ end
+
+ it 'fetches all blobs for the same repository when one is accessed' do
+ expect(container.repository).to receive(:blobs_at)
+ .with([[commit_id, 'CHANGELOG'], [commit_id, 'CONTRIBUTING.md']], blob_size_limit: blob_size_limit)
+ .once.and_call_original
+ expect(other_container.repository).not_to receive(:blobs_at)
+
+ changelog = described_class.lazy(container, commit_id, 'CHANGELOG')
+ contributing = described_class.lazy(same_container, commit_id, 'CONTRIBUTING.md')
+
+ described_class.lazy(other_container, commit_id, 'CHANGELOG')
+
+ # Access property so the values are loaded
+ changelog.id
+ contributing.id
+ end
+
+ it 'does not include blobs from previous requests in later requests' do
+ changelog = described_class.lazy(container, commit_id, 'CHANGELOG')
+ contributing = described_class.lazy(same_container, commit_id, 'CONTRIBUTING.md')
- it 'fetches all blobs for the same repository when one is accessed' do
- expect(project.repository).to receive(:blobs_at)
- .with([[commit_id, 'CHANGELOG'], [commit_id, 'CONTRIBUTING.md']], blob_size_limit: blob_size_limit)
- .once.and_call_original
- expect(other_project.repository).not_to receive(:blobs_at)
+ # Access property so the values are loaded
+ changelog.id
+ contributing.id
- changelog = described_class.lazy(project, commit_id, 'CHANGELOG')
- contributing = described_class.lazy(same_project, commit_id, 'CONTRIBUTING.md')
+ readme = described_class.lazy(container, commit_id, 'README.md')
- described_class.lazy(other_project, commit_id, 'CHANGELOG')
+ expect(container.repository).to receive(:blobs_at)
+ .with([[commit_id, 'README.md']], blob_size_limit: blob_size_limit).once.and_call_original
- # Access property so the values are loaded
- changelog.id
- contributing.id
+ readme.id
+ end
end
- it 'does not include blobs from previous requests in later requests' do
- changelog = described_class.lazy(project, commit_id, 'CHANGELOG')
- contributing = described_class.lazy(same_project, commit_id, 'CONTRIBUTING.md')
+ context 'with project' do
+ let(:container) { create(:project, :repository) }
+ let(:same_container) { Project.find(container.id) }
+ let(:other_container) { create(:project, :repository) }
- # Access property so the values are loaded
- changelog.id
- contributing.id
+ it_behaves_like '.lazy checks'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { create(:personal_snippet, :repository) }
+ let(:same_container) { PersonalSnippet.find(container.id) }
+ let(:other_container) { create(:personal_snippet, :repository) }
- readme = described_class.lazy(project, commit_id, 'README.md')
+ it_behaves_like '.lazy checks'
+ end
- expect(project.repository).to receive(:blobs_at)
- .with([[commit_id, 'README.md']], blob_size_limit: blob_size_limit).once.and_call_original
+ context 'with project snippet' do
+ let(:container) { create(:project_snippet, :repository) }
+ let(:same_container) { ProjectSnippet.find(container.id) }
+ let(:other_container) { create(:project_snippet, :repository) }
- readme.id
+ it_behaves_like '.lazy checks'
end
end
describe '#data' do
- context 'using a binary blob' do
- it 'returns the data as-is' do
- data = "\n\xFF\xB9\xC3"
- blob = fake_blob(binary: true, data: data)
+ shared_examples '#data checks' do
+ context 'using a binary blob' do
+ it 'returns the data as-is' do
+ data = "\n\xFF\xB9\xC3"
+ blob = fake_blob(binary: true, data: data, container: container)
- expect(blob.data).to eq(data)
+ expect(blob.data).to eq(data)
+ end
end
- end
- context 'using a text blob' do
- it 'converts the data to UTF-8' do
- blob = fake_blob(binary: false, data: "\n\xFF\xB9\xC3")
+ context 'using a text blob' do
+ it 'converts the data to UTF-8' do
+ blob = fake_blob(binary: false, data: "\n\xFF\xB9\xC3", container: container)
- expect(blob.data).to eq("\n���")
+ expect(blob.data).to eq("\n���")
+ end
end
end
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like '#data checks'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like '#data checks'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like '#data checks'
+ end
end
describe '#external_storage_error?' do
+ shared_examples 'no error' do
+ it do
+ expect(blob.external_storage_error?).to be_falsey
+ end
+ end
+
+ shared_examples 'returns error' do
+ it do
+ expect(blob.external_storage_error?).to be_truthy
+ end
+ end
+
context 'if the blob is stored in LFS' do
- let(:blob) { fake_blob(path: 'file.pdf', lfs: true) }
+ let(:blob) { fake_blob(path: 'file.pdf', lfs: true, container: container) }
context 'when the project has LFS enabled' do
- it 'returns false' do
- expect(blob.external_storage_error?).to be_falsey
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'no error'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns error'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'no error'
end
end
@@ -97,17 +168,39 @@ describe Blob do
project.lfs_enabled = false
end
- it 'returns true' do
- expect(blob.external_storage_error?).to be_truthy
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns error'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns error'
end
end
end
context 'if the blob is not stored in LFS' do
- let(:blob) { fake_blob(path: 'file.md') }
+ let(:blob) { fake_blob(path: 'file.md', container: container) }
- it 'returns false' do
- expect(blob.external_storage_error?).to be_falsey
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'no error'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'no error'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'no error'
end
end
end
@@ -116,19 +209,59 @@ describe Blob do
context 'if the blob is stored in LFS' do
let(:blob) { fake_blob(path: 'file.pdf', lfs: true) }
- context 'when the project has LFS enabled' do
- it 'returns true' do
+ shared_examples 'returns true' do
+ it do
expect(blob.stored_externally?).to be_truthy
end
end
+ shared_examples 'returns false' do
+ it do
+ expect(blob.stored_externally?).to be_falsey
+ end
+ end
+
+ context 'when the project has LFS enabled' do
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns true'
+ end
+ end
+
context 'when the project does not have LFS enabled' do
before do
project.lfs_enabled = false
end
- it 'returns false' do
- expect(blob.stored_externally?).to be_falsey
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns false'
end
end
end
@@ -143,21 +276,63 @@ describe Blob do
end
describe '#binary?' do
+ shared_examples 'returns true' do
+ it do
+ expect(blob.binary?).to be_truthy
+ end
+ end
+
+ shared_examples 'returns false' do
+ it do
+ expect(blob.binary?).to be_falsey
+ end
+ end
+
context 'if the blob is stored externally' do
+ let(:blob) { fake_blob(path: file, lfs: true) }
+
context 'if the extension has a rich viewer' do
context 'if the viewer is binary' do
- it 'returns true' do
- blob = fake_blob(path: 'file.pdf', lfs: true)
+ let(:file) { 'file.pdf' }
- expect(blob.binary?).to be_truthy
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns true'
end
end
context 'if the viewer is text-based' do
- it 'return false' do
- blob = fake_blob(path: 'file.md', lfs: true)
+ let(:file) { 'file.md' }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
- expect(blob.binary?).to be_falsey
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns false'
end
end
end
@@ -165,54 +340,138 @@ describe Blob do
context "if the extension doesn't have a rich viewer" do
context 'if the extension has a text mime type' do
context 'if the extension is for a programming language' do
- it 'returns false' do
- blob = fake_blob(path: 'file.txt', lfs: true)
+ let(:file) { 'file.txt' }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
- expect(blob.binary?).to be_falsey
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns false'
end
end
context 'if the extension is not for a programming language' do
- it 'returns false' do
- blob = fake_blob(path: 'file.ics', lfs: true)
+ let(:file) { 'file.ics' }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
- expect(blob.binary?).to be_falsey
+ it_behaves_like 'returns false'
end
end
end
context 'if the extension has a binary mime type' do
context 'if the extension is for a programming language' do
- it 'returns false' do
- blob = fake_blob(path: 'file.rb', lfs: true)
+ let(:file) { 'file.rb' }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
- expect(blob.binary?).to be_falsey
+ it_behaves_like 'returns false'
end
end
context 'if the extension is not for a programming language' do
- it 'returns true' do
- blob = fake_blob(path: 'file.exe', lfs: true)
+ let(:file) { 'file.exe' }
- expect(blob.binary?).to be_truthy
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns true'
end
end
end
context 'if the extension has an unknown mime type' do
context 'if the extension is for a programming language' do
- it 'returns false' do
- blob = fake_blob(path: 'file.ini', lfs: true)
+ let(:file) { 'file.ini' }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
- expect(blob.binary?).to be_falsey
+ it_behaves_like 'returns false'
end
end
context 'if the extension is not for a programming language' do
- it 'returns true' do
- blob = fake_blob(path: 'file.wtf', lfs: true)
+ let(:file) { 'file.wtf' }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
- expect(blob.binary?).to be_truthy
+ it_behaves_like 'returns true'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns true'
end
end
end
@@ -221,18 +480,46 @@ describe Blob do
context 'if the blob is not stored externally' do
context 'if the blob is binary' do
- it 'returns true' do
- blob = fake_blob(path: 'file.pdf', binary: true)
+ let(:blob) { fake_blob(path: 'file.pdf', binary: true, container: container) }
- expect(blob.binary?).to be_truthy
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns true'
end
end
context 'if the blob is text-based' do
- it 'return false' do
- blob = fake_blob(path: 'file.md')
+ let(:blob) { fake_blob(path: 'file.md', container: container) }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
- expect(blob.binary?).to be_falsey
+ it_behaves_like 'returns false'
end
end
end
@@ -389,38 +676,110 @@ describe Blob do
end
describe '#rendered_as_text?' do
+ shared_examples 'returns true' do
+ it do
+ expect(blob.rendered_as_text?(ignore_errors: ignore_errors)).to be_truthy
+ end
+ end
+
+ shared_examples 'returns false' do
+ it do
+ expect(blob.rendered_as_text?(ignore_errors: ignore_errors)).to be_falsey
+ end
+ end
+
context 'when ignoring errors' do
+ let(:ignore_errors) { true }
+
context 'when the simple viewer is text-based' do
- it 'returns true' do
- blob = fake_blob(path: 'file.md', size: 100.megabytes)
+ let(:blob) { fake_blob(path: 'file.md', size: 100.megabytes, container: container) }
- expect(blob.rendered_as_text?).to be_truthy
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns true'
end
end
context 'when the simple viewer is binary' do
- it 'returns false' do
- blob = fake_blob(path: 'file.pdf', binary: true, size: 100.megabytes)
+ let(:blob) { fake_blob(path: 'file.pdf', binary: true, size: 100.megabytes, container: container) }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
- expect(blob.rendered_as_text?).to be_falsey
+ it_behaves_like 'returns false'
end
end
end
context 'when not ignoring errors' do
+ let(:ignore_errors) { false }
+
context 'when the viewer has render errors' do
- it 'returns false' do
- blob = fake_blob(path: 'file.md', size: 100.megabytes)
+ let(:blob) { fake_blob(path: 'file.md', size: 100.megabytes, container: container) }
- expect(blob.rendered_as_text?(ignore_errors: false)).to be_falsey
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns false'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns false'
end
end
context "when the viewer doesn't have render errors" do
- it 'returns true' do
- blob = fake_blob(path: 'file.md')
+ let(:blob) { fake_blob(path: 'file.md', container: container) }
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns true'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
- expect(blob.rendered_as_text?(ignore_errors: false)).to be_truthy
+ it_behaves_like 'returns true'
end
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index ada25005064..26cc68eb58c 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -3,8 +3,10 @@
require 'spec_helper'
describe Commit do
- let(:project) { create(:project, :public, :repository) }
- let(:commit) { project.commit }
+ let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be(:personal_snippet) { create(:personal_snippet, :repository) }
+ let_it_be(:project_snippet) { create(:project_snippet, :repository) }
+ let(:commit) { project.commit }
describe 'modules' do
subject { described_class }
@@ -17,49 +19,67 @@ describe Commit do
end
describe '.lazy' do
- let_it_be(:project) { create(:project, :repository) }
+ shared_examples '.lazy checks' do
+ context 'when the commits are found' do
+ let(:oids) do
+ %w(
+ 498214de67004b1da3d820901307bed2a68a8ef6
+ c642fe9b8b9f28f9225d7ea953fe14e74748d53b
+ 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
+ 048721d90c449b244b7b4c53a9186b04330174ec
+ 281d3a76f31c812dbf48abce82ccf6860adedd81
+ )
+ end
- context 'when the commits are found' do
- let(:oids) do
- %w(
- 498214de67004b1da3d820901307bed2a68a8ef6
- c642fe9b8b9f28f9225d7ea953fe14e74748d53b
- 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
- 048721d90c449b244b7b4c53a9186b04330174ec
- 281d3a76f31c812dbf48abce82ccf6860adedd81
- )
- end
+ subject { oids.map { |oid| described_class.lazy(container, oid) } }
- subject { oids.map { |oid| described_class.lazy(project, oid) } }
+ it 'batches requests for commits' do
+ expect(container.repository).to receive(:commits_by).once.and_call_original
- it 'batches requests for commits' do
- expect(project.repository).to receive(:commits_by).once.and_call_original
+ subject.first.title
+ subject.last.title
+ end
- subject.first.title
- subject.last.title
- end
+ it 'maintains ordering' do
+ subject.each_with_index do |commit, i|
+ expect(commit.id).to eq(oids[i])
+ end
+ end
- it 'maintains ordering' do
- subject.each_with_index do |commit, i|
- expect(commit.id).to eq(oids[i])
+ it 'does not attempt to replace methods via BatchLoader' do
+ subject.each do |commit|
+ expect(commit).to receive(:method_missing).and_call_original
+
+ commit.id
+ end
end
end
- it 'does not attempt to replace methods via BatchLoader' do
- subject.each do |commit|
- expect(commit).to receive(:method_missing).and_call_original
+ context 'when not found' do
+ it 'returns nil as commit' do
+ commit = described_class.lazy(container, 'deadbeef').__sync
- commit.id
+ expect(commit).to be_nil
end
end
end
- context 'when not found' do
- it 'returns nil as commit' do
- commit = described_class.lazy(project, 'deadbeef').__sync
+ context 'with project' do
+ let(:container) { project }
- expect(commit).to be_nil
- end
+ it_behaves_like '.lazy checks'
+ end
+
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like '.lazy checks'
+ end
+
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like '.lazy checks'
end
end
@@ -231,15 +251,43 @@ describe Commit do
end
describe '#to_reference' do
- let(:project) { create(:project, :repository, path: 'sample-project') }
+ context 'with project' do
+ let(:project) { create(:project, :repository, path: 'sample-project') }
+
+ it 'returns a String reference to the object' do
+ expect(commit.to_reference).to eq commit.id
+ end
- it 'returns a String reference to the object' do
- expect(commit.to_reference).to eq commit.id
+ it 'supports a cross-project reference' do
+ another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
+ expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}"
+ end
end
- it 'supports a cross-project reference' do
- another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
- expect(commit.to_reference(another_project)).to eq "sample-project@#{commit.id}"
+ context 'with personal snippet' do
+ let(:commit) { personal_snippet.commit }
+
+ it 'returns a String reference to the object' do
+ expect(commit.to_reference).to eq "$#{personal_snippet.id}@#{commit.id}"
+ end
+
+ it 'supports a cross-snippet reference' do
+ another_snippet = build(:personal_snippet)
+ expect(commit.to_reference(another_snippet)).to eq "$#{personal_snippet.id}@#{commit.id}"
+ end
+ end
+
+ context 'with project snippet' do
+ let(:commit) { project_snippet.commit }
+
+ it 'returns a String reference to the object' do
+ expect(commit.to_reference).to eq "$#{project_snippet.id}@#{commit.id}"
+ end
+
+ it 'supports a cross-snippet project reference' do
+ another_snippet = build(:personal_snippet)
+ expect(commit.to_reference(another_snippet)).to eq "#{project_snippet.project.path}$#{project_snippet.id}@#{commit.id}"
+ end
end
end
@@ -264,13 +312,41 @@ describe Commit do
describe '#reference_link_text' do
let(:project) { create(:project, :repository, path: 'sample-project') }
- it 'returns a String reference to the object' do
- expect(commit.reference_link_text).to eq commit.short_id
+ context 'with project' do
+ it 'returns a String reference to the object' do
+ expect(commit.reference_link_text).to eq commit.short_id
+ end
+
+ it 'supports a cross-project reference' do
+ another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
+ expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}"
+ end
+ end
+
+ context 'with personal snippet' do
+ let(:commit) { personal_snippet.commit }
+
+ it 'returns a String reference to the object' do
+ expect(commit.reference_link_text).to eq "$#{personal_snippet.id}@#{commit.short_id}"
+ end
+
+ it 'supports a cross-snippet reference' do
+ another_snippet = build(:personal_snippet, :repository)
+ expect(commit.reference_link_text(another_snippet)).to eq "$#{personal_snippet.id}@#{commit.short_id}"
+ end
end
- it 'supports a cross-project reference' do
- another_project = build(:project, :repository, name: 'another-project', namespace: project.namespace)
- expect(commit.reference_link_text(another_project)).to eq "sample-project@#{commit.short_id}"
+ context 'with project snippet' do
+ let(:commit) { project_snippet.commit }
+
+ it 'returns a String reference to the object' do
+ expect(commit.reference_link_text).to eq "$#{project_snippet.id}@#{commit.short_id}"
+ end
+
+ it 'supports a cross-snippet project reference' do
+ another_snippet = build(:project_snippet, :repository)
+ expect(commit.reference_link_text(another_snippet)).to eq "#{project_snippet.project.path}$#{project_snippet.id}@#{commit.short_id}"
+ end
end
end
@@ -401,6 +477,26 @@ eos
expect(commit.closes_issues).to be_empty
end
+
+ context 'with personal snippet' do
+ let(:commit) { personal_snippet.commit }
+
+ it 'does not call Gitlab::ClosingIssueExtractor' do
+ expect(Gitlab::ClosingIssueExtractor).not_to receive(:new)
+
+ commit.closes_issues
+ end
+ end
+
+ context 'with project snippet' do
+ let(:commit) { project_snippet.commit }
+
+ it 'does not call Gitlab::ClosingIssueExtractor' do
+ expect(Gitlab::ClosingIssueExtractor).not_to receive(:new)
+
+ commit.closes_issues
+ end
+ end
end
it_behaves_like 'a mentionable' do
@@ -597,19 +693,39 @@ eos
end
describe '.from_hash' do
- let(:new_commit) { described_class.from_hash(commit.to_hash, project) }
+ subject { described_class.from_hash(commit.to_hash, container) }
- it 'returns a Commit' do
- expect(new_commit).to be_an_instance_of(described_class)
+ shared_examples 'returns Commit' do
+ it 'returns a Commit' do
+ expect(subject).to be_an_instance_of(described_class)
+ end
+
+ it 'wraps a Gitlab::Git::Commit' do
+ expect(subject.raw).to be_an_instance_of(Gitlab::Git::Commit)
+ end
+
+ it 'stores the correct commit fields' do
+ expect(subject.id).to eq(commit.id)
+ expect(subject.message).to eq(commit.message)
+ end
+ end
+
+ context 'with project' do
+ let(:container) { project }
+
+ it_behaves_like 'returns Commit'
end
- it 'wraps a Gitlab::Git::Commit' do
- expect(new_commit.raw).to be_an_instance_of(Gitlab::Git::Commit)
+ context 'with personal snippet' do
+ let(:container) { personal_snippet }
+
+ it_behaves_like 'returns Commit'
end
- it 'stores the correct commit fields' do
- expect(new_commit.id).to eq(commit.id)
- expect(new_commit.message).to eq(commit.message)
+ context 'with project snippet' do
+ let(:container) { project_snippet }
+
+ it_behaves_like 'returns Commit'
end
end
@@ -670,6 +786,19 @@ eos
expect(commit1.merge_requests).to contain_exactly(merge_request1, merge_request2)
expect(commit2.merge_requests).to contain_exactly(merge_request1)
end
+
+ context 'with personal snippet' do
+ it 'returns empty relation' do
+ expect(personal_snippet.repository.commit.merge_requests).to eq MergeRequest.none
+ end
+ end
+
+ context 'with project snippet' do
+ it 'returns empty relation' do
+ expect(project_snippet.project).not_to receive(:merge_requests)
+ expect(project_snippet.repository.commit.merge_requests).to eq MergeRequest.none
+ end
+ end
end
describe 'signed commits' do
diff --git a/spec/models/concerns/redis_cacheable_spec.rb b/spec/models/concerns/redis_cacheable_spec.rb
index a9dca27f258..f88d64e2013 100644
--- a/spec/models/concerns/redis_cacheable_spec.rb
+++ b/spec/models/concerns/redis_cacheable_spec.rb
@@ -28,7 +28,7 @@ describe RedisCacheable do
end
describe '#cached_attribute' do
- subject { instance.cached_attribute(payload.keys.first) }
+ subject { instance.cached_attribute(payload.each_key.first) }
it 'gets the cache attribute' do
Gitlab::Redis::SharedState.with do |redis|
@@ -36,7 +36,7 @@ describe RedisCacheable do
.and_return(payload.to_json)
end
- expect(subject).to eq(payload.values.first)
+ expect(subject).to eq(payload.each_value.first)
end
end
diff --git a/spec/models/personal_snippet_spec.rb b/spec/models/personal_snippet_spec.rb
index 276c8e22731..4a949a75cbd 100644
--- a/spec/models/personal_snippet_spec.rb
+++ b/spec/models/personal_snippet_spec.rb
@@ -16,4 +16,13 @@ describe PersonalSnippet do
end
end
end
+
+ it_behaves_like 'model with repository' do
+ let_it_be(:container) { create(:personal_snippet, :repository) }
+ let(:stubbed_container) { build_stubbed(:personal_snippet) }
+ let(:expected_full_path) { "@snippets/#{container.id}" }
+ let(:expected_repository_klass) { Repository }
+ let(:expected_storage_klass) { Storage::Hashed }
+ let(:expected_web_url_path) { "snippets/#{container.id}" }
+ end
end
diff --git a/spec/models/project_snippet_spec.rb b/spec/models/project_snippet_spec.rb
index 903671afb13..09b4ec3677c 100644
--- a/spec/models/project_snippet_spec.rb
+++ b/spec/models/project_snippet_spec.rb
@@ -32,4 +32,13 @@ describe ProjectSnippet do
end
end
end
+
+ it_behaves_like 'model with repository' do
+ let_it_be(:container) { create(:project_snippet, :repository) }
+ let(:stubbed_container) { build_stubbed(:project_snippet) }
+ let(:expected_full_path) { "#{container.project.full_path}/@snippets/#{container.id}" }
+ let(:expected_repository_klass) { Repository }
+ let(:expected_storage_klass) { Storage::Hashed }
+ let(:expected_web_url_path) { "#{container.project.full_path}/snippets/#{container.id}" }
+ end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 9dc362594dd..5c56d1aa757 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -113,6 +113,7 @@ describe Project do
let(:expected_full_path) { "#{container.namespace.full_path}/somewhere" }
let(:expected_repository_klass) { Repository }
let(:expected_storage_klass) { Storage::Hashed }
+ let(:expected_web_url_path) { "#{container.namespace.full_path}/somewhere" }
end
it 'has an inverse relationship with merge requests' do
@@ -5592,6 +5593,24 @@ describe Project do
it { is_expected.to be_falsey }
end
+ describe '#self_monitoring?' do
+ let_it_be(:project) { create(:project) }
+
+ subject { project.self_monitoring? }
+
+ context 'when the project is instance self monitoring' do
+ before do
+ stub_application_setting(self_monitoring_project_id: project.id)
+ end
+
+ it { is_expected.to be true }
+ end
+
+ context 'when the project is not self monitoring' do
+ it { is_expected.to be false }
+ end
+ end
+
def rugged_config
rugged_repo(project.repository).config
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 77114696fd2..0adf3fc8e85 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -372,7 +372,7 @@ describe Repository do
context 'when some commits are not found ' do
let(:oids) do
- ['deadbeef'] + TestEnv::BRANCH_SHA.values.first(10)
+ ['deadbeef'] + TestEnv::BRANCH_SHA.each_value.first(10)
end
it 'returns only found commits' do
diff --git a/spec/models/snippet_repository_spec.rb b/spec/models/snippet_repository_spec.rb
new file mode 100644
index 00000000000..9befbb02b17
--- /dev/null
+++ b/spec/models/snippet_repository_spec.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe SnippetRepository do
+ describe 'associations' do
+ it { is_expected.to belong_to(:shard) }
+ it { is_expected.to belong_to(:snippet) }
+ end
+
+ describe '.find_snippet' do
+ it 'finds snippet by disk path' do
+ snippet = create(:snippet)
+ snippet.track_snippet_repository
+
+ expect(described_class.find_snippet(snippet.disk_path)).to eq(snippet)
+ end
+
+ it 'returns nil when it does not find the snippet' do
+ expect(described_class.find_snippet('@@unexisting/path/to/snippet')).to be_nil
+ end
+ end
+end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index ae43c0d585a..93bc42c144d 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -19,6 +19,7 @@ describe Snippet do
it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:award_emoji).dependent(:destroy) }
it { is_expected.to have_many(:user_mentions).class_name("SnippetUserMention") }
+ it { is_expected.to have_one(:snippet_repository) }
end
describe 'validation' do
@@ -525,4 +526,109 @@ describe Snippet do
snippet.to_json(params)
end
end
+
+ describe '#storage' do
+ let(:snippet) { create(:snippet) }
+
+ it "stores snippet in #{Storage::Hashed::SNIPPET_REPOSITORY_PATH_PREFIX} dir" do
+ expect(snippet.storage.disk_path).to start_with Storage::Hashed::SNIPPET_REPOSITORY_PATH_PREFIX
+ end
+ end
+
+ describe '#track_snippet_repository' do
+ let(:snippet) { create(:snippet, :repository) }
+
+ context 'when a snippet repository entry does not exist' do
+ it 'creates a new entry' do
+ expect { snippet.track_snippet_repository }.to change(snippet, :snippet_repository)
+ end
+
+ it 'tracks the snippet storage location' do
+ snippet.track_snippet_repository
+
+ expect(snippet.snippet_repository).to have_attributes(
+ disk_path: snippet.disk_path,
+ shard_name: snippet.repository_storage
+ )
+ end
+ end
+
+ context 'when a tracking entry exists' do
+ let!(:snippet_repository) { create(:snippet_repository, snippet: snippet) }
+ let!(:shard) { create(:shard, name: 'foo') }
+
+ it 'does not create a new entry in the database' do
+ expect { snippet.track_snippet_repository }.not_to change(snippet, :snippet_repository)
+ end
+
+ it 'updates the snippet storage location' do
+ allow(snippet).to receive(:disk_path).and_return('fancy/new/path')
+ allow(snippet).to receive(:repository_storage).and_return('foo')
+
+ snippet.track_snippet_repository
+
+ expect(snippet.snippet_repository).to have_attributes(
+ disk_path: 'fancy/new/path',
+ shard_name: 'foo'
+ )
+ end
+ end
+ end
+
+ describe '#create_repository' do
+ let(:snippet) { create(:snippet) }
+
+ it 'creates the repository' do
+ expect(snippet.repository).to receive(:after_create).and_call_original
+
+ expect(snippet.create_repository).to be_truthy
+ expect(snippet.repository.exists?).to be_truthy
+ end
+
+ it 'tracks snippet repository' do
+ expect do
+ snippet.create_repository
+ end.to change(SnippetRepository, :count).by(1)
+ end
+
+ context 'when repository exists' do
+ let(:snippet) { create(:snippet, :repository) }
+
+ it 'does not try to create repository' do
+ expect(snippet.repository).not_to receive(:after_create)
+
+ expect(snippet.create_repository).to be_nil
+ end
+
+ it 'does not track snippet repository' do
+ expect do
+ snippet.create_repository
+ end.not_to change(SnippetRepository, :count)
+ end
+ end
+ end
+
+ describe '#repository_storage' do
+ let(:snippet) { create(:snippet) }
+
+ it 'returns default repository storage' do
+ expect(Gitlab::CurrentSettings).to receive(:pick_repository_storage)
+
+ snippet.repository_storage
+ end
+
+ context 'when snippet_project is already created' do
+ let!(:snippet_repository) { create(:snippet_repository, snippet: snippet) }
+
+ before do
+ allow(snippet_repository).to receive(:shard_name).and_return('foo')
+ end
+
+ it 'returns repository_storage from snippet_project' do
+ expect(Gitlab::CurrentSettings).not_to receive(:pick_repository_storage)
+
+ expect(snippet.repository_storage).to eq 'foo'
+ end
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index ac001ec3118..90795e0a8e4 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -4160,7 +4160,7 @@ describe User, :do_not_mock_admin_mode do
describe '#dismissed_callout?' do
subject(:user) { create(:user) }
- let(:feature_name) { UserCallout.feature_names.keys.first }
+ let(:feature_name) { UserCallout.feature_names.each_key.first }
context 'when no callout dismissal record exists' do
it 'returns false when no ignore_dismissal_earlier_than provided' do