2019-03-30 03:23:56 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2019-08-29 03:56:52 -04:00
|
|
|
require 'spec_helper'
|
2017-06-09 07:48:25 -04:00
|
|
|
|
2020-06-24 14:09:03 -04:00
|
|
|
RSpec.describe MergeRequestDiffFile do
|
2020-03-03 07:08:08 -05:00
|
|
|
it_behaves_like 'a BulkInsertSafe model', MergeRequestDiffFile do
|
2020-09-09 05:08:40 -04:00
|
|
|
let(:valid_items_for_bulk_insertion) do
|
|
|
|
build_list(:merge_request_diff_file, 10) do |mr_diff_file|
|
|
|
|
mr_diff_file.merge_request_diff = create(:merge_request_diff)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-03-03 07:08:08 -05:00
|
|
|
let(:invalid_items_for_bulk_insertion) { [] } # class does not have any validations defined
|
|
|
|
end
|
2020-02-12 16:08:48 -05:00
|
|
|
|
2022-07-05 14:08:43 -04:00
|
|
|
let(:unpacked) { 'unpacked' }
|
|
|
|
let(:packed) { [unpacked].pack('m0') }
|
|
|
|
let(:file) { create(:merge_request).merge_request_diff.merge_request_diff_files.first }
|
|
|
|
|
2017-07-25 12:57:02 -04:00
|
|
|
describe '#diff' do
|
2022-07-05 14:08:43 -04:00
|
|
|
let(:file) { build(:merge_request_diff_file) }
|
|
|
|
|
2019-09-10 03:33:03 -04:00
|
|
|
context 'when diff is not stored' do
|
|
|
|
let(:unpacked) { 'unpacked' }
|
|
|
|
let(:packed) { [unpacked].pack('m0') }
|
2017-07-25 12:57:02 -04:00
|
|
|
|
|
|
|
before do
|
2022-07-05 14:08:43 -04:00
|
|
|
file.diff = packed
|
2019-09-10 03:33:03 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the diff is marked as binary' do
|
|
|
|
before do
|
2022-07-05 14:08:43 -04:00
|
|
|
file.binary = true
|
2019-09-10 03:33:03 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'unpacks from base 64' do
|
2022-07-05 14:08:43 -04:00
|
|
|
expect(file.diff).to eq(unpacked)
|
2019-09-10 03:33:03 -04:00
|
|
|
end
|
2020-08-28 11:10:21 -04:00
|
|
|
|
|
|
|
context 'invalid base64' do
|
|
|
|
let(:packed) { '---/dev/null' }
|
|
|
|
|
|
|
|
it 'returns the raw diff' do
|
2022-07-05 14:08:43 -04:00
|
|
|
expect(file.diff).to eq(packed)
|
2020-08-28 11:10:21 -04:00
|
|
|
end
|
|
|
|
end
|
2019-09-10 03:33:03 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the diff is not marked as binary' do
|
|
|
|
it 'returns the raw diff' do
|
2022-07-05 14:08:43 -04:00
|
|
|
expect(file.diff).to eq(packed)
|
2019-09-10 03:33:03 -04:00
|
|
|
end
|
2017-07-25 12:57:02 -04:00
|
|
|
end
|
2019-09-10 03:33:03 -04:00
|
|
|
end
|
2017-07-25 12:57:02 -04:00
|
|
|
|
2019-09-10 03:33:03 -04:00
|
|
|
context 'when diff is stored in DB' do
|
|
|
|
it 'returns UTF-8 string' do
|
|
|
|
expect(file.diff.encoding).to eq Encoding::UTF_8
|
2017-07-25 12:57:02 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-09-10 03:33:03 -04:00
|
|
|
context 'when diff is stored in external storage' do
|
|
|
|
let(:test_dir) { 'tmp/tests/external-diffs' }
|
|
|
|
|
|
|
|
around do |example|
|
|
|
|
FileUtils.mkdir_p(test_dir)
|
|
|
|
|
|
|
|
begin
|
|
|
|
example.run
|
|
|
|
ensure
|
|
|
|
FileUtils.rm_rf(test_dir)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
stub_external_diffs_setting(enabled: true, storage_path: test_dir)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns UTF-8 string' do
|
|
|
|
expect(file.diff.encoding).to eq Encoding::UTF_8
|
2017-07-25 12:57:02 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-06-09 07:48:25 -04:00
|
|
|
describe '#utf8_diff' do
|
2017-07-25 12:57:02 -04:00
|
|
|
it 'does not raise error when the diff is binary' do
|
2022-07-05 14:08:43 -04:00
|
|
|
file = build(:merge_request_diff_file)
|
|
|
|
file.diff = "\x05\x00\x68\x65\x6c\x6c\x6f"
|
2017-06-09 07:48:25 -04:00
|
|
|
|
2022-07-05 14:08:43 -04:00
|
|
|
expect { file.utf8_diff }.not_to raise_error
|
2017-06-09 07:48:25 -04:00
|
|
|
end
|
2022-06-16 20:09:23 -04:00
|
|
|
|
|
|
|
it 'calls #diff once' do
|
2022-07-05 14:08:43 -04:00
|
|
|
allow(file).to receive(:diff).and_return('test')
|
|
|
|
|
|
|
|
expect(file).to receive(:diff).once
|
|
|
|
|
|
|
|
file.utf8_diff
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#diff_export' do
|
|
|
|
context 'when diff is externally stored' do
|
|
|
|
let(:test_dir) { 'tmp/tests/external-diffs' }
|
|
|
|
|
|
|
|
around do |example|
|
|
|
|
FileUtils.mkdir_p(test_dir)
|
|
|
|
|
|
|
|
begin
|
|
|
|
example.run
|
|
|
|
ensure
|
|
|
|
FileUtils.rm_rf(test_dir)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
before do
|
|
|
|
stub_external_diffs_setting(enabled: true, storage_path: test_dir)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when external diff is not cached' do
|
|
|
|
it 'caches external diffs' do
|
|
|
|
expect(file.merge_request_diff).to receive(:cache_external_diff).and_call_original
|
|
|
|
|
|
|
|
expect(file.diff_export).to eq(file.utf8_diff)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when external diff is already cached' do
|
|
|
|
it 'reads diff from cached external diff' do
|
|
|
|
file_stub = double
|
|
|
|
|
|
|
|
allow(file.merge_request_diff).to receive(:cached_external_diff).and_yield(file_stub)
|
|
|
|
expect(file_stub).to receive(:seek).with(file.external_diff_offset)
|
|
|
|
expect(file_stub).to receive(:read).with(file.external_diff_size)
|
|
|
|
|
|
|
|
file.diff_export
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the diff is marked as binary' do
|
|
|
|
let(:file) { build(:merge_request_diff_file) }
|
2022-06-16 20:09:23 -04:00
|
|
|
|
2022-07-05 14:08:43 -04:00
|
|
|
before do
|
|
|
|
allow(file.merge_request_diff).to receive(:stored_externally?).and_return(true)
|
|
|
|
allow(file.merge_request_diff).to receive(:cached_external_diff).and_return(packed)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the diff is marked as binary' do
|
|
|
|
before do
|
|
|
|
file.binary = true
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'unpacks from base 64' do
|
|
|
|
expect(file.diff_export).to eq(unpacked)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'invalid base64' do
|
|
|
|
let(:packed) { '---/dev/null' }
|
|
|
|
|
|
|
|
it 'returns the raw diff' do
|
|
|
|
expect(file.diff_export).to eq(packed)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when the diff is not marked as binary' do
|
|
|
|
it 'returns the raw diff' do
|
|
|
|
expect(file.diff_export).to eq(packed)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when content responds to #encoding' do
|
|
|
|
it 'encodes content to utf8 encoding' do
|
|
|
|
expect(file.diff_export.encoding).to eq(Encoding::UTF_8)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when content is blank' do
|
|
|
|
it 'returns an empty string' do
|
|
|
|
allow(file.merge_request_diff).to receive(:cached_external_diff).and_return(nil)
|
|
|
|
|
|
|
|
expect(file.diff_export).to eq('')
|
|
|
|
end
|
|
|
|
end
|
2022-06-16 20:09:23 -04:00
|
|
|
|
2022-07-05 14:08:43 -04:00
|
|
|
context 'when exception is raised' do
|
|
|
|
it 'falls back to #utf8_diff' do
|
|
|
|
allow(file).to receive(:binary?).and_raise(StandardError)
|
|
|
|
expect(file).to receive(:utf8_diff)
|
|
|
|
|
|
|
|
file.diff_export
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when externally_stored_diffs_caching_export feature flag is disabled' do
|
|
|
|
it 'calls #utf8_diff' do
|
|
|
|
stub_feature_flags(externally_stored_diffs_caching_export: false)
|
|
|
|
|
|
|
|
expect(file).to receive(:utf8_diff)
|
|
|
|
|
|
|
|
file.diff_export
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when diff is not stored externally' do
|
|
|
|
it 'calls #utf8_diff' do
|
|
|
|
expect(file).to receive(:utf8_diff)
|
|
|
|
|
|
|
|
file.diff_export
|
|
|
|
end
|
2022-06-16 20:09:23 -04:00
|
|
|
end
|
2017-06-09 07:48:25 -04:00
|
|
|
end
|
|
|
|
end
|