diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-26 21:08:03 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-26 21:08:03 +0300 |
commit | dc003cd08b4cb72fecbb03aa978ea0c53c03aeb4 (patch) | |
tree | 5e77ce228c33619201ac6706b9789d4a2eed2a3b /spec/lib | |
parent | e80e0dd64fbb04f60394cb1bb08e17dbcb22b8ce (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/lib')
-rw-r--r-- | spec/lib/banzai/filter/label_reference_filter_spec.rb | 7 | ||||
-rw-r--r-- | spec/lib/banzai/filter/reference_redactor_filter_spec.rb | 64 | ||||
-rw-r--r-- | spec/lib/gitlab/auth_spec.rb | 41 | ||||
-rw-r--r-- | spec/lib/gitlab/gfm/uploads_rewriter_spec.rb | 10 | ||||
-rw-r--r-- | spec/lib/gitlab/hotlinking_detector_spec.rb | 75 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/attribute_cleaner_spec.rb | 3 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/json/legacy_reader/file_spec.rb | 32 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/json/legacy_reader/hash_spec.rb | 35 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/json/legacy_reader/shared_example.rb | 110 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/json/legacy_reader_spec.rb | 149 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/json/legacy_writer_spec.rb | 92 | ||||
-rw-r--r-- | spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb | 36 | ||||
-rw-r--r-- | spec/lib/gitlab/regex_spec.rb | 32 |
13 files changed, 473 insertions, 213 deletions
diff --git a/spec/lib/banzai/filter/label_reference_filter_spec.rb b/spec/lib/banzai/filter/label_reference_filter_spec.rb index 5a672de13d7..de7a70db1ac 100644 --- a/spec/lib/banzai/filter/label_reference_filter_spec.rb +++ b/spec/lib/banzai/filter/label_reference_filter_spec.rb @@ -523,7 +523,12 @@ describe Banzai::Filter::LabelReferenceFilter do end context 'when group name has HTML entities' do - let(:another_group) { create(:group, name: '<img src=x onerror=alert(1)>', path: 'another_group') } + let(:another_group) { create(:group, name: 'random', path: 'another_group') } + + before do + another_group.name = "<img src=x onerror=alert(1)>" + another_group.save!(validate: false) + end it 'escapes the HTML entities' do expect(result.text) diff --git a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb index 9739afd3d57..a68581b3000 100644 --- a/spec/lib/banzai/filter/reference_redactor_filter_spec.rb +++ b/spec/lib/banzai/filter/reference_redactor_filter_spec.rb @@ -20,8 +20,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do it 'skips when the skip_redaction flag is set' do user = create(:user) project = create(:project) - link = reference_link(project: project.id, reference_type: 'test') + doc = filter(link, current_user: user, skip_redaction: true) expect(doc.css('a').length).to eq 1 @@ -51,8 +51,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do user = create(:user) project = create(:project) project.add_maintainer(user) - link = reference_link(project: project.id, reference_type: 'test') + doc = filter(link, current_user: user) expect(doc.css('a').length).to eq 1 @@ -69,8 +69,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do it 'removes unpermitted references' do user = create(:user) project = create(:project) - link = reference_link(project: project.id, reference_type: 'test') + doc = filter(link, current_user: user) expect(doc.css('a').length).to eq 0 @@ -90,8 +90,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do non_member = create(:user) project = create(:project, :public) issue = create(:issue, :confidential, project: project) - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: non_member) expect(doc.css('a').length).to eq 0 @@ -124,8 +124,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do assignee = create(:user) project = create(:project, :public) issue = create(:issue, :confidential, project: project, assignees: [assignee]) - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: assignee) expect(doc.css('a').length).to eq 1 @@ -136,8 +136,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do project = create(:project, :public) project.add_developer(member) issue = create(:issue, :confidential, project: project) - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: member) expect(doc.css('a').length).to eq 1 @@ -147,20 +147,62 @@ describe Banzai::Filter::ReferenceRedactorFilter do admin = create(:admin) project = create(:project, :public) issue = create(:issue, :confidential, project: project) - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: admin) expect(doc.css('a').length).to eq 1 end + + context "when a confidential issue is moved from a public project to a private one" do + let(:public_project) { create(:project, :public) } + let(:private_project) { create(:project, :private) } + + it 'removes references for author' do + author = create(:user) + issue = create(:issue, :confidential, project: public_project, author: author) + issue.update!(project: private_project) # move issue to private project + link = reference_link(project: private_project.id, issue: issue.id, reference_type: 'issue') + + doc = filter(link, current_user: author) + + expect(doc.css('a').length).to eq 0 + end + + it 'removes references for assignee' do + assignee = create(:user) + issue = create(:issue, :confidential, project: public_project, assignees: [assignee]) + issue.update!(project: private_project) # move issue to private project + link = reference_link(project: private_project.id, issue: issue.id, reference_type: 'issue') + + doc = filter(link, current_user: assignee) + + expect(doc.css('a').length).to eq 0 + end + + it 'allows references for project members' do + member = create(:user) + project = create(:project, :public) + project_2 = create(:project, :private) + project.add_developer(member) + project_2.add_developer(member) + issue = create(:issue, :confidential, project: project) + issue.update!(project: project_2) # move issue to private project + link = reference_link(project: project_2.id, issue: issue.id, reference_type: 'issue') + + doc = filter(link, current_user: member) + + expect(doc.css('a').length).to eq 1 + end + end end it 'allows references for non confidential issues' do user = create(:user) project = create(:project, :public) issue = create(:issue, project: project) - link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue') + doc = filter(link, current_user: user) expect(doc.css('a').length).to eq 1 @@ -172,8 +214,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do it 'removes unpermitted Group references' do user = create(:user) group = create(:group, :private) - link = reference_link(group: group.id, reference_type: 'user') + doc = filter(link, current_user: user) expect(doc.css('a').length).to eq 0 @@ -183,8 +225,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do user = create(:user) group = create(:group, :private) group.add_developer(user) - link = reference_link(group: group.id, reference_type: 'user') + doc = filter(link, current_user: user) expect(doc.css('a').length).to eq 1 @@ -200,8 +242,8 @@ describe Banzai::Filter::ReferenceRedactorFilter do context 'with data-user' do it 'allows any User reference' do user = create(:user) - link = reference_link(user: user.id, reference_type: 'user') + doc = filter(link) expect(doc.css('a').length).to eq 1 diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index e0c1f830165..528019bb9ff 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -164,6 +164,12 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do expect(subject).to eq(Gitlab::Auth::Result.new(build.user, build.project, :build, described_class.build_authentication_abilities)) end + + it 'fails with blocked user token' do + build.update(user: create(:user, :blocked)) + + expect(subject).to eq(Gitlab::Auth::Result.new(nil, nil, nil, nil)) + end end (HasStatus::AVAILABLE_STATUSES - ['running']).each do |build_status| @@ -259,6 +265,15 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip') end + + context 'blocked user' do + let(:user) { create(:user, :blocked) } + + it 'fails' do + expect(gl_auth.find_for_git_client("oauth2", token_w_api_scope.token, project: nil, ip: 'ip')) + .to eq(Gitlab::Auth::Result.new(nil, nil, nil, nil)) + end + end end context 'while using personal access tokens as passwords' do @@ -307,9 +322,35 @@ describe Gitlab::Auth, :use_clean_rails_memory_store_caching do it 'fails if password is nil' do expect_results_with_abilities(nil, nil, false) end + + context 'when user is blocked' do + let(:user) { create(:user, :blocked) } + let(:personal_access_token) { create(:personal_access_token, scopes: ['read_registry'], user: user) } + + before do + stub_container_registry_config(enabled: true) + end + + it 'fails if user is blocked' do + expect(gl_auth.find_for_git_client('', personal_access_token.token, project: nil, ip: 'ip')) + .to eq(Gitlab::Auth::Result.new(nil, nil, nil, nil)) + end + end end context 'while using regular user and password' do + it 'fails for a blocked user' do + user = create( + :user, + :blocked, + username: 'normal_user', + password: 'my-secret' + ) + + expect(gl_auth.find_for_git_client(user.username, user.password, project: nil, ip: 'ip')) + .to eq(Gitlab::Auth::Result.new(nil, nil, nil, nil)) + end + it 'goes through lfs authentication' do user = create( :user, diff --git a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb index 5a930d44dcb..ebd7c7af265 100644 --- a/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/uploads_rewriter_spec.rb @@ -68,6 +68,16 @@ describe Gitlab::Gfm::UploadsRewriter do expect(moved_text.scan(/\A\[.*?\]/).count).to eq(1) end + context 'path traversal in file name' do + let(:text) do + "![a](/uploads/11111111111111111111111111111111/../../../../../../../../../../../../../../etc/passwd)" + end + + it 'throw an error' do + expect { rewriter.rewrite(new_project) }.to raise_error(an_instance_of(StandardError).and having_attributes(message: "Invalid path")) + end + end + context "file are stored locally" do include_examples "files are accessible" end diff --git a/spec/lib/gitlab/hotlinking_detector_spec.rb b/spec/lib/gitlab/hotlinking_detector_spec.rb new file mode 100644 index 00000000000..536d744c197 --- /dev/null +++ b/spec/lib/gitlab/hotlinking_detector_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe Gitlab::HotlinkingDetector do + describe ".intercept_hotlinking?" do + using RSpec::Parameterized::TableSyntax + + subject { described_class.intercept_hotlinking?(request) } + + let(:request) { double("request", headers: headers) } + let(:headers) { {} } + + context "hotlinked as media" do + where(:return_value, :accept_header) do + # These are default formats in modern browsers, and IE + false | "*/*" + false | "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + false | "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8" + false | "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + false | "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" + false | "image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/msword, */*" + false | "text/html, application/xhtml+xml, image/jxr, */*" + false | "text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/webp, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1" + + # These are image request formats + true | "image/webp,*/*" + true | "image/png,image/*;q=0.8,*/*;q=0.5" + true | "image/webp,image/apng,image/*,*/*;q=0.8" + true | "image/png,image/svg+xml,image/*;q=0.8, */*;q=0.5" + + # Video request formats + true | "video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5" + + # Audio request formats + true | "audio/webm,audio/ogg,audio/wav,audio/*;q=0.9,application/ogg;q=0.7,video/*;q=0.6,*/*;q=0.5" + + # CSS request formats + true | "text/css,*/*;q=0.1" + true | "text/css" + true | "text/css,*/*;q=0.1" + end + + with_them do + let(:headers) do + { "Accept" => accept_header } + end + + it { is_expected.to be(return_value) } + end + end + + context "hotlinked as a script" do + where(:return_value, :fetch_mode) do + # Standard navigation fetch modes + false | "navigate" + false | "nested-navigate" + false | "same-origin" + + # Fetch modes when linking as JS + true | "cors" + true | "no-cors" + true | "websocket" + end + + with_them do + let(:headers) do + { "Sec-Fetch-Mode" => fetch_mode } + end + + it { is_expected.to be(return_value) } + end + end + end +end diff --git a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb index 12857f97f7c..65e99c0c3b8 100644 --- a/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb +++ b/spec/lib/gitlab/import_export/attribute_cleaner_spec.rb @@ -32,6 +32,9 @@ describe Gitlab::ImportExport::AttributeCleaner do 'issue_ids' => [1, 2, 3], 'merge_request_ids' => [1, 2, 3], 'note_ids' => [1, 2, 3], + 'remote_attachment_url' => 'http://something.dodgy', + 'remote_attachment_request_header' => 'bad value', + 'remote_attachment_urls' => %w(http://something.dodgy http://something.okay), 'attributes' => { 'issue_ids' => [1, 2, 3], 'merge_request_ids' => [1, 2, 3], diff --git a/spec/lib/gitlab/import_export/json/legacy_reader/file_spec.rb b/spec/lib/gitlab/import_export/json/legacy_reader/file_spec.rb new file mode 100644 index 00000000000..1021ce3cd50 --- /dev/null +++ b/spec/lib/gitlab/import_export/json/legacy_reader/file_spec.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative 'shared_example.rb' + +describe Gitlab::ImportExport::JSON::LegacyReader::File do + it_behaves_like 'import/export json legacy reader' do + let(:valid_path) { 'spec/fixtures/lib/gitlab/import_export/light/project.json' } + let(:data) { valid_path } + let(:json_data) { JSON.parse(File.read(valid_path)) } + end + + describe '#exist?' do + let(:legacy_reader) do + described_class.new(path, relation_names: []) + end + + subject { legacy_reader.exist? } + + context 'given valid path' do + let(:path) { 'spec/fixtures/lib/gitlab/import_export/light/project.json' } + + it { is_expected.to be true } + end + + context 'given invalid path' do + let(:path) { 'spec/non-existing-folder/do-not-create-this-file.json' } + + it { is_expected.to be false } + end + end +end diff --git a/spec/lib/gitlab/import_export/json/legacy_reader/hash_spec.rb b/spec/lib/gitlab/import_export/json/legacy_reader/hash_spec.rb new file mode 100644 index 00000000000..8c4dfd2f356 --- /dev/null +++ b/spec/lib/gitlab/import_export/json/legacy_reader/hash_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_relative 'shared_example.rb' + +describe Gitlab::ImportExport::JSON::LegacyReader::Hash do + it_behaves_like 'import/export json legacy reader' do + let(:path) { 'spec/fixtures/lib/gitlab/import_export/light/project.json' } + + # the hash is modified by the `LegacyReader` + # we need to deep-dup it + let(:json_data) { JSON.parse(File.read(path)) } + let(:data) { JSON.parse(File.read(path)) } + end + + describe '#exist?' do + let(:legacy_reader) do + described_class.new(tree_hash, relation_names: []) + end + + subject { legacy_reader.exist? } + + context 'tree_hash is nil' do + let(:tree_hash) { nil } + + it { is_expected.to be_falsey } + end + + context 'tree_hash presents' do + let(:tree_hash) { { "issues": [] } } + + it { is_expected.to be_truthy } + end + end +end diff --git a/spec/lib/gitlab/import_export/json/legacy_reader/shared_example.rb b/spec/lib/gitlab/import_export/json/legacy_reader/shared_example.rb new file mode 100644 index 00000000000..297a5946703 --- /dev/null +++ b/spec/lib/gitlab/import_export/json/legacy_reader/shared_example.rb @@ -0,0 +1,110 @@ +# frozen_string_literal: true + +RSpec.shared_examples 'import/export json legacy reader' do + let(:relation_names) { [] } + + let(:legacy_reader) do + described_class.new( + data, + relation_names: relation_names, + allowed_path: "project") + end + + describe '#consume_attributes' do + context 'when valid path is passed' do + subject { legacy_reader.consume_attributes("project") } + + context 'no excluded attributes' do + let(:excluded_attributes) { [] } + let(:relation_names) { [] } + + it 'returns the whole tree from parsed JSON' do + expect(subject).to eq(json_data) + end + end + + context 'some attributes are excluded' do + let(:relation_names) { %w[milestones labels] } + + it 'returns hash without excluded attributes and relations' do + expect(subject).not_to include('milestones', 'labels') + end + end + end + + context 'when invalid path is passed' do + it 'raises an exception' do + expect { legacy_reader.consume_attributes("invalid-path") } + .to raise_error(ArgumentError) + end + end + end + + describe '#consume_relation' do + context 'when valid path is passed' do + let(:key) { 'description' } + + context 'block not given' do + it 'returns value of the key' do + expect(legacy_reader).to receive(:relations).and_return({ key => 'test value' }) + expect(legacy_reader.consume_relation("project", key)).to eq('test value') + end + end + + context 'key has been consumed' do + before do + legacy_reader.consume_relation("project", key) + end + + it 'does not yield' do + expect do |blk| + legacy_reader.consume_relation("project", key, &blk) + end.not_to yield_control + end + end + + context 'value is nil' do + before do + expect(legacy_reader).to receive(:relations).and_return({ key => nil }) + end + + it 'does not yield' do + expect do |blk| + legacy_reader.consume_relation("project", key, &blk) + end.not_to yield_control + end + end + + context 'value is not array' do + before do + expect(legacy_reader).to receive(:relations).and_return({ key => 'value' }) + end + + it 'yield the value with index 0' do + expect do |blk| + legacy_reader.consume_relation("project", key, &blk) + end.to yield_with_args('value', 0) + end + end + + context 'value is an array' do + before do + expect(legacy_reader).to receive(:relations).and_return({ key => %w[item1 item2 item3] }) + end + + it 'yield each array element with index' do + expect do |blk| + legacy_reader.consume_relation("project", key, &blk) + end.to yield_successive_args(['item1', 0], ['item2', 1], ['item3', 2]) + end + end + end + + context 'when invalid path is passed' do + it 'raises an exception' do + expect { legacy_reader.consume_relation("invalid") } + .to raise_error(ArgumentError) + end + end + end +end diff --git a/spec/lib/gitlab/import_export/json/legacy_reader_spec.rb b/spec/lib/gitlab/import_export/json/legacy_reader_spec.rb deleted file mode 100644 index 0009a5f81de..00000000000 --- a/spec/lib/gitlab/import_export/json/legacy_reader_spec.rb +++ /dev/null @@ -1,149 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe Gitlab::ImportExport::JSON::LegacyReader::User do - let(:relation_names) { [] } - let(:legacy_reader) { described_class.new(tree_hash, relation_names) } - - describe '#valid?' do - subject { legacy_reader.valid? } - - context 'tree_hash not present' do - let(:tree_hash) { nil } - - it { is_expected.to be false } - end - - context 'tree_hash presents' do - let(:tree_hash) { { "issues": [] } } - - it { is_expected.to be true } - end - end -end - -describe Gitlab::ImportExport::JSON::LegacyReader::File do - let(:fixture) { 'spec/fixtures/lib/gitlab/import_export/light/project.json' } - let(:project_tree) { JSON.parse(File.read(fixture)) } - let(:relation_names) { [] } - let(:legacy_reader) { described_class.new(path, relation_names) } - - describe '#valid?' do - subject { legacy_reader.valid? } - - context 'given valid path' do - let(:path) { fixture } - - it { is_expected.to be true } - end - - context 'given invalid path' do - let(:path) { 'spec/non-existing-folder/do-not-create-this-file.json' } - - it { is_expected.to be false } - end - end - - describe '#root_attributes' do - let(:path) { fixture } - - subject { legacy_reader.root_attributes(excluded_attributes) } - - context 'No excluded attributes' do - let(:excluded_attributes) { [] } - let(:relation_names) { [] } - - it 'returns the whole tree from parsed JSON' do - expect(subject).to eq(project_tree) - end - end - - context 'Some attributes are excluded' do - let(:excluded_attributes) { %w[milestones labels issues services snippets] } - let(:relation_names) { %w[import_type archived] } - - it 'returns hash without excluded attributes and relations' do - expect(subject).not_to include('milestones', 'labels', 'issues', 'services', 'snippets', 'import_type', 'archived') - end - end - end - - describe '#consume_relation' do - let(:path) { fixture } - let(:key) { 'description' } - - context 'block not given' do - it 'returns value of the key' do - expect(legacy_reader).to receive(:relations).and_return({ key => 'test value' }) - expect(legacy_reader.consume_relation(key)).to eq('test value') - end - end - - context 'key has been consumed' do - before do - legacy_reader.consume_relation(key) - end - - it 'does not yield' do - expect do |blk| - legacy_reader.consume_relation(key, &blk) - end.not_to yield_control - end - end - - context 'value is nil' do - before do - expect(legacy_reader).to receive(:relations).and_return({ key => nil }) - end - - it 'does not yield' do - expect do |blk| - legacy_reader.consume_relation(key, &blk) - end.not_to yield_control - end - end - - context 'value is not array' do - before do - expect(legacy_reader).to receive(:relations).and_return({ key => 'value' }) - end - - it 'yield the value with index 0' do - expect do |blk| - legacy_reader.consume_relation(key, &blk) - end.to yield_with_args('value', 0) - end - end - - context 'value is an array' do - before do - expect(legacy_reader).to receive(:relations).and_return({ key => %w[item1 item2 item3] }) - end - - it 'yield each array element with index' do - expect do |blk| - legacy_reader.consume_relation(key, &blk) - end.to yield_successive_args(['item1', 0], ['item2', 1], ['item3', 2]) - end - end - end - - describe '#tree_hash' do - let(:path) { fixture } - - subject { legacy_reader.send(:tree_hash) } - - it 'parses the JSON into the expected tree' do - expect(subject).to eq(project_tree) - end - - context 'invalid JSON' do - let(:path) { 'spec/fixtures/lib/gitlab/import_export/invalid_json/project.json' } - - it 'raise Exception' do - expect { subject }.to raise_exception(Gitlab::ImportExport::Error, 'Incorrect JSON format') - end - end - end -end diff --git a/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb b/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb index b4cdfee3b22..1f39b26e46a 100644 --- a/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb +++ b/spec/lib/gitlab/import_export/json/legacy_writer_spec.rb @@ -5,20 +5,37 @@ require 'spec_helper' describe Gitlab::ImportExport::JSON::LegacyWriter do let(:path) { "#{Dir.tmpdir}/legacy_writer_spec/test.json" } - subject { described_class.new(path) } + subject do + described_class.new(path, allowed_path: "project") + end after do FileUtils.rm_rf(path) end - describe "#write" do + describe "#write_attributes" do + it "writes correct json" do + expected_hash = { "key" => "value_1", "key_1" => "value_2" } + subject.write_attributes("project", expected_hash) + + expect(subject_json).to eq(expected_hash) + end + + context 'when invalid path is used' do + it 'raises an exception' do + expect { subject.write_attributes("invalid", { "key" => "value" }) } + .to raise_error(ArgumentError) + end + end + end + + describe "#write_relation" do context "when key is already written" do it "raises exception" do - key = "key" - value = "value" - subject.write(key, value) + subject.write_relation("project", "key", "old value") - expect { subject.write(key, "new value") }.to raise_exception("key '#{key}' already written") + expect { subject.write_relation("project", "key", "new value") } + .to raise_exception("key 'key' already written") end end @@ -27,53 +44,58 @@ describe Gitlab::ImportExport::JSON::LegacyWriter do it "writes correct json" do expected_hash = { "key" => "value_1", "key_1" => "value_2" } expected_hash.each do |key, value| - subject.write(key, value) + subject.write_relation("project", key, value) end - subject.close - expect(saved_json(path)).to eq(expected_hash) + expect(subject_json).to eq(expected_hash) end end end + + context 'when invalid path is used' do + it 'raises an exception' do + expect { subject.write_relation("invalid", "key", "value") } + .to raise_error(ArgumentError) + end + end end - describe "#append" do - context "when key is already written" do - it "appends values under a given key" do - key = "key" - values = %w(value_1 value_2) - expected_hash = { key => values } - values.each do |value| - subject.append(key, value) - end - subject.close + describe "#write_relation_array" do + context 'when array is used' do + it 'writes correct json' do + subject.write_relation_array("project", "key", ["value"]) - expect(saved_json(path)).to eq(expected_hash) + expect(subject_json).to eq({ "key" => ["value"] }) end end - context "when key is not already written" do - it "writes correct json" do - expected_hash = { "key" => ["value"] } - subject.append("key", "value") - subject.close + context 'when enumerable is used' do + it 'writes correct json' do + values = %w(value1 value2) + + enumerator = Enumerator.new do |items| + values.each { |value| items << value } + end + + subject.write_relation_array("project", "key", enumerator) - expect(saved_json(path)).to eq(expected_hash) + expect(subject_json).to eq({ "key" => values }) end end - end - describe "#set" do - it "writes correct json" do - expected_hash = { "key" => "value_1", "key_1" => "value_2" } - subject.set(expected_hash) - subject.close + context "when key is already written" do + it "raises an exception" do + subject.write_relation_array("project", "key", %w(old_value)) - expect(saved_json(path)).to eq(expected_hash) + expect { subject.write_relation_array("project", "key", %w(new_value)) } + .to raise_error(ArgumentError) + end end end - def saved_json(filename) - ::JSON.parse(IO.read(filename)) + def subject_json + subject.close + + ::JSON.parse(IO.read(subject.path)) end end diff --git a/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb index e36144b1a30..52e1efa70e0 100644 --- a/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/relation_tree_restorer_spec.rb @@ -14,23 +14,24 @@ describe Gitlab::ImportExport::RelationTreeRestorer do let(:user) { create(:user) } let(:shared) { Gitlab::ImportExport::Shared.new(importable) } - let(:members_mapper) { Gitlab::ImportExport::MembersMapper.new(exported_members: {}, user: user, importable: importable) } + let(:attributes) { {} } - let(:importable_hash) do - json = IO.read(path) - ActiveSupport::JSON.decode(json) + let(:members_mapper) do + Gitlab::ImportExport::MembersMapper.new(exported_members: {}, user: user, importable: importable) end let(:relation_tree_restorer) do described_class.new( - user: user, - shared: shared, - relation_reader: relation_reader, - importable: importable, - object_builder: object_builder, - members_mapper: members_mapper, - relation_factory: relation_factory, - reader: reader + user: user, + shared: shared, + relation_reader: relation_reader, + object_builder: object_builder, + members_mapper: members_mapper, + relation_factory: relation_factory, + reader: reader, + importable: importable, + importable_path: nil, + importable_attributes: attributes ) end @@ -100,7 +101,14 @@ describe Gitlab::ImportExport::RelationTreeRestorer do let(:reader) { Gitlab::ImportExport::Reader.new(shared: shared) } context 'using legacy reader' do - let(:relation_reader) { Gitlab::ImportExport::JSON::LegacyReader::File.new(path, reader.project_relation_names) } + let(:relation_reader) do + Gitlab::ImportExport::JSON::LegacyReader::File.new( + path, + relation_names: reader.project_relation_names + ) + end + + let(:attributes) { relation_reader.consume_attributes(nil) } it_behaves_like 'import project successfully' @@ -119,7 +127,7 @@ describe Gitlab::ImportExport::RelationTreeRestorer do let(:importable) { create(:group, parent: group) } let(:object_builder) { Gitlab::ImportExport::Group::ObjectBuilder } let(:relation_factory) { Gitlab::ImportExport::Group::RelationFactory } - let(:relation_reader) { Gitlab::ImportExport::JSON::LegacyReader::File.new(path, reader.group_relation_names) } + let(:relation_reader) { Gitlab::ImportExport::JSON::LegacyReader::File.new(path, relation_names: reader.group_relation_names) } let(:reader) do Gitlab::ImportExport::Reader.new( shared: shared, diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb index c580b46cf8d..f1b5393a2d8 100644 --- a/spec/lib/gitlab/regex_spec.rb +++ b/spec/lib/gitlab/regex_spec.rb @@ -3,9 +3,7 @@ require 'spec_helper' describe Gitlab::Regex do - describe '.project_name_regex' do - subject { described_class.project_name_regex } - + shared_examples_for 'project/group name regex' do it { is_expected.to match('gitlab-ce') } it { is_expected.to match('GitLab CE') } it { is_expected.to match('100 lines') } @@ -15,6 +13,34 @@ describe Gitlab::Regex do it { is_expected.not_to match('?gitlab') } end + shared_examples_for 'project/group name error message' do + it { is_expected.to eq("can contain only letters, digits, emojis, '_', '.', dash, space. It must start with letter, digit, emoji or '_'.") } + end + + describe '.project_name_regex' do + subject { described_class.project_name_regex } + + it_behaves_like 'project/group name regex' + end + + describe '.group_name_regex' do + subject { described_class.group_name_regex } + + it_behaves_like 'project/group name regex' + end + + describe '.project_name_regex_message' do + subject { described_class.project_name_regex_message } + + it_behaves_like 'project/group name error message' + end + + describe '.group_name_regex_message' do + subject { described_class.group_name_regex_message } + + it_behaves_like 'project/group name error message' + end + describe '.environment_name_regex' do subject { described_class.environment_name_regex } |