2019-03-30 03:23:56 -04:00
|
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
2019-08-29 03:56:52 -04:00
|
|
|
|
require 'spec_helper'
|
2016-02-18 18:19:43 -05:00
|
|
|
|
|
|
|
|
|
describe Blob do
|
2017-04-25 16:22:56 -04:00
|
|
|
|
include FakeBlobHelpers
|
|
|
|
|
|
2017-08-02 15:55:11 -04:00
|
|
|
|
let(:project) { build(:project, lfs_enabled: true) }
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:personal_snippet) { build(:personal_snippet) }
|
|
|
|
|
let(:project_snippet) { build(:project_snippet, project: project) }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
|
|
|
|
before do
|
|
|
|
|
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
|
|
|
|
|
end
|
|
|
|
|
|
2016-02-18 18:19:43 -05:00
|
|
|
|
describe '.decorate' do
|
|
|
|
|
it 'returns NilClass when given nil' do
|
|
|
|
|
expect(described_class.decorate(nil)).to be_nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-11-03 09:16:43 -04:00
|
|
|
|
describe '.lazy' do
|
2018-11-23 06:26:17 -05:00
|
|
|
|
let(:commit_id) { 'e63f41fe459e62e1228fcef60d7189127aeba95a' }
|
2020-02-02 01:08:56 -05:00
|
|
|
|
let(:blob_size_limit) { 10 * 1024 * 1024 }
|
2017-11-03 09:16:43 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
shared_examples '.lazy checks' do
|
|
|
|
|
it 'does not fetch blobs when none are accessed' do
|
|
|
|
|
expect(container.repository).not_to receive(:blobs_at)
|
2017-11-03 09:16:43 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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')
|
2018-11-23 06:26:17 -05:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
# Access property so the values are loaded
|
|
|
|
|
changelog.id
|
|
|
|
|
contributing.id
|
2018-11-23 06:26:17 -05:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
readme = described_class.lazy(container, commit_id, 'README.md')
|
2018-11-23 06:26:17 -05:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
expect(container.repository).to receive(:blobs_at)
|
|
|
|
|
.with([[commit_id, 'README.md']], blob_size_limit: blob_size_limit).once.and_call_original
|
2017-11-03 09:16:43 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
readme.id
|
|
|
|
|
end
|
2017-11-03 09:16:43 -04:00
|
|
|
|
end
|
Ensure that we only request blobs in one batch
Blob.lazy adds a blob to a batch to load at a later point, using the
BatchLoader library. Whenever any lazy blob's attributes are accessed,
all lazy blobs requested to that point will be loaded.
BatchLoader, the library we use for this, should only request items in a
batch once. That is, if we have these batches:
1. a, b, c
2. d, e, f
Then a, b, and c should only be requested in the first batch. But if you
modify the list of items in the batch, then the second batch will
request a, b, c, d, e, f, which is almost certainly not what we want!
https://github.com/exAspArk/batch-loader/issues/44 is the upstream issue
for this, but we can also solve this in our application by not modifying
the arguments we're using inside a BatchLoader batch.
2019-04-24 09:13:32 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
context 'with project' do
|
|
|
|
|
let(:container) { create(:project, :repository) }
|
|
|
|
|
let(:same_container) { Project.find(container.id) }
|
|
|
|
|
let(:other_container) { create(:project, :repository) }
|
Ensure that we only request blobs in one batch
Blob.lazy adds a blob to a batch to load at a later point, using the
BatchLoader library. Whenever any lazy blob's attributes are accessed,
all lazy blobs requested to that point will be loaded.
BatchLoader, the library we use for this, should only request items in a
batch once. That is, if we have these batches:
1. a, b, c
2. d, e, f
Then a, b, and c should only be requested in the first batch. But if you
modify the list of items in the batch, then the second batch will
request a, b, c, d, e, f, which is almost certainly not what we want!
https://github.com/exAspArk/batch-loader/issues/44 is the upstream issue
for this, but we can also solve this in our application by not modifying
the arguments we're using inside a BatchLoader batch.
2019-04-24 09:13:32 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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) }
|
Ensure that we only request blobs in one batch
Blob.lazy adds a blob to a batch to load at a later point, using the
BatchLoader library. Whenever any lazy blob's attributes are accessed,
all lazy blobs requested to that point will be loaded.
BatchLoader, the library we use for this, should only request items in a
batch once. That is, if we have these batches:
1. a, b, c
2. d, e, f
Then a, b, and c should only be requested in the first batch. But if you
modify the list of items in the batch, then the second batch will
request a, b, c, d, e, f, which is almost certainly not what we want!
https://github.com/exAspArk/batch-loader/issues/44 is the upstream issue
for this, but we can also solve this in our application by not modifying
the arguments we're using inside a BatchLoader batch.
2019-04-24 09:13:32 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like '.lazy checks'
|
|
|
|
|
end
|
Ensure that we only request blobs in one batch
Blob.lazy adds a blob to a batch to load at a later point, using the
BatchLoader library. Whenever any lazy blob's attributes are accessed,
all lazy blobs requested to that point will be loaded.
BatchLoader, the library we use for this, should only request items in a
batch once. That is, if we have these batches:
1. a, b, c
2. d, e, f
Then a, b, and c should only be requested in the first batch. But if you
modify the list of items in the batch, then the second batch will
request a, b, c, d, e, f, which is almost certainly not what we want!
https://github.com/exAspArk/batch-loader/issues/44 is the upstream issue
for this, but we can also solve this in our application by not modifying
the arguments we're using inside a BatchLoader batch.
2019-04-24 09:13:32 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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) }
|
Ensure that we only request blobs in one batch
Blob.lazy adds a blob to a batch to load at a later point, using the
BatchLoader library. Whenever any lazy blob's attributes are accessed,
all lazy blobs requested to that point will be loaded.
BatchLoader, the library we use for this, should only request items in a
batch once. That is, if we have these batches:
1. a, b, c
2. d, e, f
Then a, b, and c should only be requested in the first batch. But if you
modify the list of items in the batch, then the second batch will
request a, b, c, d, e, f, which is almost certainly not what we want!
https://github.com/exAspArk/batch-loader/issues/44 is the upstream issue
for this, but we can also solve this in our application by not modifying
the arguments we're using inside a BatchLoader batch.
2019-04-24 09:13:32 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like '.lazy checks'
|
Ensure that we only request blobs in one batch
Blob.lazy adds a blob to a batch to load at a later point, using the
BatchLoader library. Whenever any lazy blob's attributes are accessed,
all lazy blobs requested to that point will be loaded.
BatchLoader, the library we use for this, should only request items in a
batch once. That is, if we have these batches:
1. a, b, c
2. d, e, f
Then a, b, and c should only be requested in the first batch. But if you
modify the list of items in the batch, then the second batch will
request a, b, c, d, e, f, which is almost certainly not what we want!
https://github.com/exAspArk/batch-loader/issues/44 is the upstream issue
for this, but we can also solve this in our application by not modifying
the arguments we're using inside a BatchLoader batch.
2019-04-24 09:13:32 -04:00
|
|
|
|
end
|
2017-11-03 09:16:43 -04:00
|
|
|
|
end
|
|
|
|
|
|
2016-09-12 11:25:35 -04:00
|
|
|
|
describe '#data' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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)
|
2016-09-12 11:25:35 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
expect(blob.data).to eq(data)
|
|
|
|
|
end
|
2016-09-12 11:25:35 -04:00
|
|
|
|
end
|
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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)
|
2016-09-12 11:25:35 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
expect(blob.data).to eq("\n<EFBFBD><EFBFBD><EFBFBD>")
|
|
|
|
|
end
|
2016-09-12 11:25:35 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
2020-02-13 10:08:52 -05:00
|
|
|
|
|
|
|
|
|
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
|
2016-09-12 11:25:35 -04:00
|
|
|
|
end
|
|
|
|
|
|
2017-05-02 18:45:50 -04:00
|
|
|
|
describe '#external_storage_error?' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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
|
|
|
|
|
|
2017-05-02 18:45:50 -04:00
|
|
|
|
context 'if the blob is stored in LFS' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:blob) { fake_blob(path: 'file.pdf', lfs: true, container: container) }
|
2017-05-02 18:45:50 -04:00
|
|
|
|
|
|
|
|
|
context 'when the project has LFS enabled' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the project does not have LFS enabled' do
|
|
|
|
|
before do
|
|
|
|
|
project.lfs_enabled = false
|
|
|
|
|
end
|
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the blob is not stored in LFS' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:blob) { fake_blob(path: 'file.md', container: container) }
|
2017-05-02 18:45:50 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe '#stored_externally?' do
|
|
|
|
|
context 'if the blob is stored in LFS' do
|
|
|
|
|
let(:blob) { fake_blob(path: 'file.pdf', lfs: true) }
|
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
shared_examples 'returns true' do
|
|
|
|
|
it do
|
2017-05-02 18:45:50 -04:00
|
|
|
|
expect(blob.stored_externally?).to be_truthy
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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
|
|
|
|
|
|
2017-05-02 18:45:50 -04:00
|
|
|
|
context 'when the project does not have LFS enabled' do
|
|
|
|
|
before do
|
|
|
|
|
project.lfs_enabled = false
|
|
|
|
|
end
|
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the blob is not stored in LFS' do
|
|
|
|
|
let(:blob) { fake_blob(path: 'file.md') }
|
|
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
|
expect(blob.stored_externally?).to be_falsey
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2018-12-13 12:49:05 -05:00
|
|
|
|
describe '#binary?' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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
|
|
|
|
|
|
2017-05-02 18:45:50 -04:00
|
|
|
|
context 'if the blob is stored externally' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:blob) { fake_blob(path: file, lfs: true) }
|
|
|
|
|
|
2017-04-25 16:22:56 -04:00
|
|
|
|
context 'if the extension has a rich viewer' do
|
|
|
|
|
context 'if the viewer is binary' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:file) { 'file.pdf' }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the viewer is text-based' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns false'
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with project snippet' do
|
|
|
|
|
let(:container) { project_snippet }
|
|
|
|
|
|
|
|
|
|
it_behaves_like 'returns false'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "if the extension doesn't have a rich viewer" do
|
2017-05-02 18:45:50 -04:00
|
|
|
|
context 'if the extension has a text mime type' do
|
|
|
|
|
context 'if the extension is for a programming language' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:file) { 'file.txt' }
|
|
|
|
|
|
|
|
|
|
context 'with project' do
|
|
|
|
|
let(:container) { project }
|
|
|
|
|
|
|
|
|
|
it_behaves_like 'returns false'
|
|
|
|
|
end
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the extension is not for a programming language' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-05-02 18:45:50 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns false'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the extension has a binary mime type' do
|
|
|
|
|
context 'if the extension is for a programming language' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-05-02 18:45:50 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns false'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the extension is not for a programming language' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:file) { 'file.exe' }
|
2017-05-02 18:45:50 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the extension has an unknown mime type' do
|
|
|
|
|
context 'if the extension is for a programming language' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-05-02 18:45:50 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns false'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the extension is not for a programming language' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-05-02 18:45:50 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns true'
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'with project snippet' do
|
|
|
|
|
let(:container) { project_snippet }
|
|
|
|
|
|
|
|
|
|
it_behaves_like 'returns true'
|
2017-05-02 18:45:50 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-05-02 18:45:50 -04:00
|
|
|
|
context 'if the blob is not stored externally' do
|
2017-04-25 16:22:56 -04:00
|
|
|
|
context 'if the blob is binary' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:blob) { fake_blob(path: 'file.pdf', binary: true, container: container) }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'if the blob is text-based' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns false'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe '#extension' do
|
|
|
|
|
it 'returns the extension' do
|
|
|
|
|
blob = fake_blob(path: 'file.md')
|
|
|
|
|
|
|
|
|
|
expect(blob.extension).to eq('md')
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-06-06 17:26:31 -04:00
|
|
|
|
describe '#file_type' do
|
|
|
|
|
it 'returns the file type' do
|
|
|
|
|
blob = fake_blob(path: 'README.md')
|
|
|
|
|
|
|
|
|
|
expect(blob.file_type).to eq(:readme)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-04-25 16:22:56 -04:00
|
|
|
|
describe '#simple_viewer' do
|
|
|
|
|
context 'when the blob is empty' do
|
|
|
|
|
it 'returns an empty viewer' do
|
2017-05-02 18:45:50 -04:00
|
|
|
|
blob = fake_blob(data: '', size: 0)
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
|
|
|
|
expect(blob.simple_viewer).to be_a(BlobViewer::Empty)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the file represented by the blob is binary' do
|
|
|
|
|
it 'returns a download viewer' do
|
|
|
|
|
blob = fake_blob(binary: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.simple_viewer).to be_a(BlobViewer::Download)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the file represented by the blob is text-based' do
|
|
|
|
|
it 'returns a text viewer' do
|
|
|
|
|
blob = fake_blob
|
|
|
|
|
|
|
|
|
|
expect(blob.simple_viewer).to be_a(BlobViewer::Text)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
describe '#rich_viewer' do
|
2017-05-02 18:45:50 -04:00
|
|
|
|
context 'when the blob has an external storage error' do
|
2017-04-25 16:22:56 -04:00
|
|
|
|
before do
|
|
|
|
|
project.lfs_enabled = false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'returns nil' do
|
|
|
|
|
blob = fake_blob(path: 'file.pdf', lfs: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.rich_viewer).to be_nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is empty' do
|
|
|
|
|
it 'returns nil' do
|
|
|
|
|
blob = fake_blob(data: '')
|
|
|
|
|
|
|
|
|
|
expect(blob.rich_viewer).to be_nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-05-02 18:45:50 -04:00
|
|
|
|
context 'when the blob is stored externally' do
|
2017-04-25 16:22:56 -04:00
|
|
|
|
it 'returns a matching viewer' do
|
|
|
|
|
blob = fake_blob(path: 'file.pdf', lfs: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.rich_viewer).to be_a(BlobViewer::PDF)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is binary' do
|
|
|
|
|
it 'returns a matching binary viewer' do
|
|
|
|
|
blob = fake_blob(path: 'file.pdf', binary: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.rich_viewer).to be_a(BlobViewer::PDF)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is text-based' do
|
|
|
|
|
it 'returns a matching text-based viewer' do
|
|
|
|
|
blob = fake_blob(path: 'file.md')
|
|
|
|
|
|
|
|
|
|
expect(blob.rich_viewer).to be_a(BlobViewer::Markup)
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-10-16 11:06:17 -04:00
|
|
|
|
|
|
|
|
|
context 'when the blob is video' do
|
|
|
|
|
it 'returns a video viewer' do
|
|
|
|
|
blob = fake_blob(path: 'file.mp4', binary: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.rich_viewer).to be_a(BlobViewer::Video)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is audio' do
|
|
|
|
|
it 'returns an audio viewer' do
|
|
|
|
|
blob = fake_blob(path: 'file.wav', binary: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.rich_viewer).to be_a(BlobViewer::Audio)
|
|
|
|
|
end
|
|
|
|
|
end
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
|
2017-05-08 19:50:23 -04:00
|
|
|
|
describe '#auxiliary_viewer' do
|
|
|
|
|
context 'when the blob has an external storage error' do
|
|
|
|
|
before do
|
|
|
|
|
project.lfs_enabled = false
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
it 'returns nil' do
|
|
|
|
|
blob = fake_blob(path: 'LICENSE', lfs: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.auxiliary_viewer).to be_nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is empty' do
|
|
|
|
|
it 'returns nil' do
|
|
|
|
|
blob = fake_blob(data: '')
|
|
|
|
|
|
|
|
|
|
expect(blob.auxiliary_viewer).to be_nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is stored externally' do
|
|
|
|
|
it 'returns a matching viewer' do
|
|
|
|
|
blob = fake_blob(path: 'LICENSE', lfs: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.auxiliary_viewer).to be_a(BlobViewer::License)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is binary' do
|
|
|
|
|
it 'returns nil' do
|
|
|
|
|
blob = fake_blob(path: 'LICENSE', binary: true)
|
|
|
|
|
|
|
|
|
|
expect(blob.auxiliary_viewer).to be_nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the blob is text-based' do
|
|
|
|
|
it 'returns a matching text-based viewer' do
|
|
|
|
|
blob = fake_blob(path: 'LICENSE')
|
|
|
|
|
|
|
|
|
|
expect(blob.auxiliary_viewer).to be_a(BlobViewer::License)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
2017-04-25 16:22:56 -04:00
|
|
|
|
describe '#rendered_as_text?' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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
|
|
|
|
|
|
2017-04-25 16:22:56 -04:00
|
|
|
|
context 'when ignoring errors' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:ignore_errors) { true }
|
|
|
|
|
|
2017-04-25 16:22:56 -04:00
|
|
|
|
context 'when the simple viewer is text-based' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:blob) { fake_blob(path: 'file.md', size: 100.megabytes, container: container) }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when the simple viewer is binary' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns false'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when not ignoring errors' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:ignore_errors) { false }
|
|
|
|
|
|
2017-04-25 16:22:56 -04:00
|
|
|
|
context 'when the viewer has render errors' do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
let(:blob) { fake_blob(path: 'file.md', size: 100.megabytes, container: container) }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context "when the viewer doesn't have render errors" do
|
2020-02-13 10:08:52 -05:00
|
|
|
|
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 }
|
2017-04-25 16:22:56 -04:00
|
|
|
|
|
2020-02-13 10:08:52 -05:00
|
|
|
|
it_behaves_like 'returns true'
|
2017-04-25 16:22:56 -04:00
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2019-12-17 10:08:15 -05:00
|
|
|
|
|
|
|
|
|
describe 'policy' do
|
|
|
|
|
let(:project) { build(:project) }
|
2019-12-18 19:08:01 -05:00
|
|
|
|
|
2019-12-17 10:08:15 -05:00
|
|
|
|
subject { described_class.new(fake_blob(path: 'foo'), project) }
|
|
|
|
|
|
|
|
|
|
it 'works with policy' do
|
|
|
|
|
expect(Ability.allowed?(project.creator, :read_blob, subject)).to be_truthy
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
context 'when project is nil' do
|
|
|
|
|
subject { described_class.new(fake_blob(path: 'foo')) }
|
|
|
|
|
|
|
|
|
|
it 'does not err' do
|
|
|
|
|
expect(Ability.allowed?(project.creator, :read_blob, subject)).to be_falsey
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
2016-02-18 18:19:43 -05:00
|
|
|
|
end
|