summaryrefslogtreecommitdiff
path: root/spec/lib
diff options
context:
space:
mode:
authorClement Ho <ClemMakesApps@gmail.com>2018-01-08 13:03:48 -0600
committerClement Ho <ClemMakesApps@gmail.com>2018-01-08 13:03:48 -0600
commitcecea7529fb37893af6bf514a53e239a3be1eea6 (patch)
tree2781b7d777b9cf6fb76ba238b2fdce0e01a08618 /spec/lib
parent691cf4409145d80c09e43a10fd252d88075dc3e6 (diff)
parent1d7b46062feb1d93dd3efaf6ba4d5d934068342c (diff)
downloadgitlab-ce-cecea7529fb37893af6bf514a53e239a3be1eea6.tar.gz
Merge branch 'master' into fix-no-template
Diffstat (limited to 'spec/lib')
-rw-r--r--spec/lib/banzai/filter/mermaid_filter_spec.rb4
-rw-r--r--spec/lib/banzai/filter/redactor_filter_spec.rb6
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb86
-rw-r--r--spec/lib/banzai/filter/upload_link_filter_spec.rb133
-rw-r--r--spec/lib/banzai/filter/user_reference_filter_spec.rb6
-rw-r--r--spec/lib/banzai/reference_parser/user_parser_spec.rb6
-rw-r--r--spec/lib/gitlab/action_rate_limiter_spec.rb29
-rw-r--r--spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb27
-rw-r--r--spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb13
-rw-r--r--spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb19
-rw-r--r--spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb19
-rw-r--r--spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb124
-rw-r--r--spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb17
-rw-r--r--spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb13
-rw-r--r--spec/lib/gitlab/bare_repository_import/importer_spec.rb23
-rw-r--r--spec/lib/gitlab/bare_repository_import/repository_spec.rb130
-rw-r--r--spec/lib/gitlab/checks/project_moved_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/ansi2html_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/build/common_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/external/common_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/external/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/common_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/stage/common_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/status/stage/factory_spec.rb2
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb6
-rw-r--r--spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb2
-rw-r--r--spec/lib/gitlab/cycle_analytics/events_spec.rb14
-rw-r--r--spec/lib/gitlab/cycle_analytics/permissions_spec.rb8
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb101
-rw-r--r--spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb14
-rw-r--r--spec/lib/gitlab/diff/file_spec.rb25
-rw-r--r--spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb12
-rw-r--r--spec/lib/gitlab/email/handler/create_note_handler_spec.rb4
-rw-r--r--spec/lib/gitlab/encoding_helper_spec.rb32
-rw-r--r--spec/lib/gitlab/exclusive_lease_spec.rb15
-rw-r--r--spec/lib/gitlab/gfm/reference_rewriter_spec.rb2
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb19
-rw-r--r--spec/lib/gitlab/git/commit_spec.rb6
-rw-r--r--spec/lib/gitlab/git/gitlab_projects_spec.rb337
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb352
-rw-r--r--spec/lib/gitlab/git_access_spec.rb10
-rw-r--r--spec/lib/gitlab/git_access_wiki_spec.rb4
-rw-r--r--spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb90
-rw-r--r--spec/lib/gitlab/gitaly_client/remote_service_spec.rb47
-rw-r--r--spec/lib/gitlab/gitaly_client_spec.rb14
-rw-r--r--spec/lib/gitlab/github_import/importer/repository_importer_spec.rb8
-rw-r--r--spec/lib/gitlab/google_code_import/importer_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project.json770
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb26
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb14
-rw-r--r--spec/lib/gitlab/import_export/repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml1
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb2
-rw-r--r--spec/lib/gitlab/kubernetes/helm/api_spec.rb (renamed from spec/lib/gitlab/kubernetes/helm_spec.rb)49
-rw-r--r--spec/lib/gitlab/kubernetes/helm/install_command_spec.rb111
-rw-r--r--spec/lib/gitlab/kubernetes/helm/pod_spec.rb86
-rw-r--r--spec/lib/gitlab/ldap/adapter_spec.rb10
-rw-r--r--spec/lib/gitlab/ldap/person_spec.rb73
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb15
-rw-r--r--spec/lib/gitlab/metrics/method_call_spec.rb43
-rw-r--r--spec/lib/gitlab/metrics/system_spec.rb8
-rw-r--r--spec/lib/gitlab/o_auth/user_spec.rb70
-rw-r--r--spec/lib/gitlab/project_authorizations_spec.rb2
-rw-r--r--spec/lib/gitlab/project_search_results_spec.rb8
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb14
-rw-r--r--spec/lib/gitlab/search_results_spec.rb42
-rw-r--r--spec/lib/gitlab/shell_spec.rb175
-rw-r--r--spec/lib/gitlab/sidekiq_config_spec.rb23
-rw-r--r--spec/lib/gitlab/sidekiq_versioning/manager_spec.rb22
-rw-r--r--spec/lib/gitlab/sidekiq_versioning_spec.rb44
-rw-r--r--spec/lib/gitlab/slash_commands/issue_new_spec.rb2
-rw-r--r--spec/lib/gitlab/slash_commands/issue_search_spec.rb2
-rw-r--r--spec/lib/gitlab/slash_commands/issue_show_spec.rb2
-rw-r--r--spec/lib/gitlab/tcp_checker_spec.rb32
-rw-r--r--spec/lib/gitlab/user_access_spec.rb36
-rw-r--r--spec/lib/gitlab/utils/strong_memoize_spec.rb12
-rw-r--r--spec/lib/gitlab/view/presenter/factory_spec.rb8
-rw-r--r--spec/lib/gitlab/visibility_level_spec.rb27
-rw-r--r--spec/lib/google_api/cloud_platform/client_spec.rb24
80 files changed, 2649 insertions, 909 deletions
diff --git a/spec/lib/banzai/filter/mermaid_filter_spec.rb b/spec/lib/banzai/filter/mermaid_filter_spec.rb
index 532d25e121d..f6474c8936d 100644
--- a/spec/lib/banzai/filter/mermaid_filter_spec.rb
+++ b/spec/lib/banzai/filter/mermaid_filter_spec.rb
@@ -3,9 +3,9 @@ require 'spec_helper'
describe Banzai::Filter::MermaidFilter do
include FilterSpecHelper
- it 'adds `js-render-mermaid` class to the `pre` tag' do
+ it 'adds `js-render-mermaid` class to the `code` tag' do
doc = filter("<pre class='code highlight js-syntax-highlight mermaid' lang='mermaid' v-pre='true'><code>graph TD;\n A--&gt;B;\n</code></pre>")
- result = doc.xpath('descendant-or-self::pre').first
+ result = doc.css('code').first
expect(result[:class]).to include('js-render-mermaid')
end
diff --git a/spec/lib/banzai/filter/redactor_filter_spec.rb b/spec/lib/banzai/filter/redactor_filter_spec.rb
index 68643effb66..5a7858e77f3 100644
--- a/spec/lib/banzai/filter/redactor_filter_spec.rb
+++ b/spec/lib/banzai/filter/redactor_filter_spec.rb
@@ -46,7 +46,7 @@ describe Banzai::Filter::RedactorFilter do
it 'allows permitted Project references' do
user = create(:user)
project = create(:project)
- project.team << [user, :master]
+ project.add_master(user)
link = reference_link(project: project.id, reference_type: 'test')
doc = filter(link, current_user: user)
@@ -94,7 +94,7 @@ describe Banzai::Filter::RedactorFilter do
it 'removes references for project members with guest role' do
member = create(:user)
project = create(:project, :public)
- project.team << [member, :guest]
+ project.add_guest(member)
issue = create(:issue, :confidential, project: project)
link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
@@ -128,7 +128,7 @@ describe Banzai::Filter::RedactorFilter do
it 'allows references for project members' do
member = create(:user)
project = create(:project, :public)
- project.team << [member, :developer]
+ project.add_developer(member)
issue = create(:issue, :confidential, project: project)
link = reference_link(project: project.id, issue: issue.id, reference_type: 'issue')
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index 08beede62db..f38f0776303 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -5,6 +5,7 @@ describe Banzai::Filter::RelativeLinkFilter do
contexts.reverse_merge!({
commit: commit,
project: project,
+ group: group,
project_wiki: project_wiki,
ref: ref,
requested_path: requested_path
@@ -25,7 +26,12 @@ describe Banzai::Filter::RelativeLinkFilter do
%(<a href="#{path}">#{path}</a>)
end
+ def nested(element)
+ %(<div>#{element}</div>)
+ end
+
let(:project) { create(:project, :repository) }
+ let(:group) { nil }
let(:project_path) { project.full_path }
let(:ref) { 'markdown' }
let(:commit) { project.commit(ref) }
@@ -70,6 +76,11 @@ describe Banzai::Filter::RelativeLinkFilter do
expect { filter(act) }.not_to raise_error
end
+ it 'does not raise an exception with a garbled path' do
+ act = link("open(/var/tmp/):%20/location%0Afrom:%20/test")
+ expect { filter(act) }.not_to raise_error
+ end
+
it 'ignores ref if commit is passed' do
doc = filter(link('non/existent.file'), commit: project.commit('empty-branch') )
expect(doc.at_css('a')['href'])
@@ -223,4 +234,79 @@ describe Banzai::Filter::RelativeLinkFilter do
let(:commit) { nil } # force filter to use ref instead of commit
include_examples :valid_repository
end
+
+ context 'with a /upload/ URL' do
+ # not needed
+ let(:commit) { nil }
+ let(:ref) { nil }
+ let(:requested_path) { nil }
+
+ context 'to a project upload' do
+ it 'rebuilds relative URL for a link' do
+ doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+ expect(doc.at_css('a')['href'])
+ .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+
+ doc = filter(nested(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')))
+ expect(doc.at_css('a')['href'])
+ .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ end
+
+ it 'rebuilds relative URL for an image' do
+ doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+ expect(doc.at_css('img')['src'])
+ .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+
+ doc = filter(nested(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg')))
+ expect(doc.at_css('img')['src'])
+ .to eq "/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ end
+
+ it 'does not modify absolute URL' do
+ doc = filter(link('http://example.com'))
+ expect(doc.at_css('a')['href']).to eq 'http://example.com'
+ end
+
+ it 'supports Unicode filenames' do
+ path = '/uploads/한글.png'
+ escaped = Addressable::URI.escape(path)
+
+ # Stub these methods so the file doesn't actually need to be in the repo
+ allow_any_instance_of(described_class)
+ .to receive(:file_exists?).and_return(true)
+ allow_any_instance_of(described_class)
+ .to receive(:image?).with(path).and_return(true)
+
+ doc = filter(image(escaped))
+ expect(doc.at_css('img')['src']).to match "/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png"
+ end
+ end
+
+ context 'to a group upload' do
+ let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') }
+ let(:group) { create(:group) }
+ let(:project) { nil }
+ let(:relative_path) { "/groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" }
+
+ it 'rewrites the link correctly' do
+ doc = filter(upload_link)
+
+ expect(doc.at_css('a')['href']).to eq(relative_path)
+ end
+
+ it 'rewrites the link correctly for subgroup' do
+ group.update!(parent: create(:group))
+
+ doc = filter(upload_link)
+
+ expect(doc.at_css('a')['href']).to eq(relative_path)
+ end
+
+ it 'does not modify absolute URL' do
+ doc = filter(link('http://example.com'))
+
+ expect(doc.at_css('a')['href']).to eq 'http://example.com'
+ end
+ end
+ end
end
diff --git a/spec/lib/banzai/filter/upload_link_filter_spec.rb b/spec/lib/banzai/filter/upload_link_filter_spec.rb
deleted file mode 100644
index 76bc0c36ab7..00000000000
--- a/spec/lib/banzai/filter/upload_link_filter_spec.rb
+++ /dev/null
@@ -1,133 +0,0 @@
-require 'spec_helper'
-
-describe Banzai::Filter::UploadLinkFilter do
- def filter(doc, contexts = {})
- contexts.reverse_merge!({
- project: project
- })
-
- raw_filter(doc, contexts)
- end
-
- def raw_filter(doc, contexts = {})
- described_class.call(doc, contexts)
- end
-
- def image(path)
- %(<img src="#{path}" />)
- end
-
- def link(path)
- %(<a href="#{path}">#{path}</a>)
- end
-
- def nested_image(path)
- %(<div><img src="#{path}" /></div>)
- end
-
- def nested_link(path)
- %(<div><a href="#{path}">#{path}</a></div>)
- end
-
- let(:project) { create(:project) }
-
- shared_examples :preserve_unchanged do
- it 'does not modify any relative URL in anchor' do
- doc = filter(link('README.md'))
- expect(doc.at_css('a')['href']).to eq 'README.md'
- end
-
- it 'does not modify any relative URL in image' do
- doc = filter(image('files/images/logo-black.png'))
- expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
- end
- end
-
- it 'does not raise an exception on invalid URIs' do
- act = link("://foo")
- expect { filter(act) }.not_to raise_error
- end
-
- context 'with a valid repository' do
- it 'rebuilds relative URL for a link' do
- doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
-
- doc = filter(nested_link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('a')['href'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
- end
-
- it 'rebuilds relative URL for an image' do
- doc = filter(image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('img')['src'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
-
- doc = filter(nested_image('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
- expect(doc.at_css('img')['src'])
- .to eq "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
- end
-
- it 'does not modify absolute URL' do
- doc = filter(link('http://example.com'))
- expect(doc.at_css('a')['href']).to eq 'http://example.com'
- end
-
- it 'supports Unicode filenames' do
- path = '/uploads/한글.png'
- escaped = Addressable::URI.escape(path)
-
- # Stub these methods so the file doesn't actually need to be in the repo
- allow_any_instance_of(described_class)
- .to receive(:file_exists?).and_return(true)
- allow_any_instance_of(described_class)
- .to receive(:image?).with(path).and_return(true)
-
- doc = filter(image(escaped))
- expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.full_path}/uploads/%ED%95%9C%EA%B8%80.png"
- end
- end
-
- context 'in group context' do
- let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') }
- let(:group) { create(:group) }
- let(:filter_context) { { project: nil, group: group } }
- let(:relative_path) { "groups/#{group.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg" }
-
- it 'rewrites the link correctly' do
- doc = raw_filter(upload_link, filter_context)
-
- expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}")
- end
-
- it 'rewrites the link correctly for subgroup' do
- subgroup = create(:group, parent: group)
- relative_path = "groups/#{subgroup.full_path}/-/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
-
- doc = raw_filter(upload_link, { project: nil, group: subgroup })
-
- expect(doc.at_css('a')['href']).to eq("#{Gitlab.config.gitlab.url}/#{relative_path}")
- end
-
- it 'does not modify absolute URL' do
- doc = filter(link('http://example.com'), filter_context)
-
- expect(doc.at_css('a')['href']).to eq 'http://example.com'
- end
- end
-
- context 'when project or group context does not exist' do
- let(:upload_link) { link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg') }
-
- it 'does not raise error' do
- expect { raw_filter(upload_link, project: nil) }.not_to raise_error
- end
-
- it 'does not rewrite link' do
- doc = raw_filter(upload_link, project: nil)
-
- expect(doc.to_html).to eq upload_link
- end
- end
-end
diff --git a/spec/lib/banzai/filter/user_reference_filter_spec.rb b/spec/lib/banzai/filter/user_reference_filter_spec.rb
index fc03741976e..c76adc262fc 100644
--- a/spec/lib/banzai/filter/user_reference_filter_spec.rb
+++ b/spec/lib/banzai/filter/user_reference_filter_spec.rb
@@ -34,11 +34,11 @@ describe Banzai::Filter::UserReferenceFilter do
let(:reference) { User.reference_prefix + 'all' }
before do
- project.team << [project.creator, :developer]
+ project.add_developer(project.creator)
end
it 'supports a special @all mention' do
- project.team << [user, :developer]
+ project.add_developer(user)
doc = reference_filter("Hey #{reference}", author: user)
expect(doc.css('a').length).to eq 1
@@ -47,7 +47,7 @@ describe Banzai::Filter::UserReferenceFilter do
end
it 'includes a data-author attribute when there is an author' do
- project.team << [user, :developer]
+ project.add_developer(user)
doc = reference_filter(reference, author: user)
expect(doc.css('a').first.attr('data-author')).to eq(user.id.to_s)
diff --git a/spec/lib/banzai/reference_parser/user_parser_spec.rb b/spec/lib/banzai/reference_parser/user_parser_spec.rb
index e49726aca6c..b079a3be029 100644
--- a/spec/lib/banzai/reference_parser/user_parser_spec.rb
+++ b/spec/lib/banzai/reference_parser/user_parser_spec.rb
@@ -63,8 +63,8 @@ describe Banzai::ReferenceParser::UserParser do
let(:contributor) { create(:user) }
before do
- project.team << [user, :developer]
- project.team << [contributor, :developer]
+ project.add_developer(user)
+ project.add_developer(contributor)
end
it 'returns the members of a project' do
@@ -162,7 +162,7 @@ describe Banzai::ReferenceParser::UserParser do
context 'when the link has a data-author attribute' do
it 'returns the nodes when the user is a member of the project' do
other_project = create(:project)
- other_project.team << [user, :developer]
+ other_project.add_developer(user)
link['data-project'] = other_project.id.to_s
link['data-author'] = user.id.to_s
diff --git a/spec/lib/gitlab/action_rate_limiter_spec.rb b/spec/lib/gitlab/action_rate_limiter_spec.rb
new file mode 100644
index 00000000000..542fc03e555
--- /dev/null
+++ b/spec/lib/gitlab/action_rate_limiter_spec.rb
@@ -0,0 +1,29 @@
+require 'spec_helper'
+
+describe Gitlab::ActionRateLimiter do
+ let(:redis) { double('redis') }
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:key) { [user, project] }
+ let(:cache_key) { "action_rate_limiter:test_action:user:#{user.id}:project:#{project.id}" }
+
+ subject { described_class.new(action: :test_action, expiry_time: 100) }
+
+ before do
+ allow(Gitlab::Redis::Cache).to receive(:with).and_yield(redis)
+ end
+
+ it 'increases the throttle count and sets the expire time' do
+ expect(redis).to receive(:incr).with(cache_key).and_return(1)
+ expect(redis).to receive(:expire).with(cache_key, 100)
+
+ expect(subject.throttled?(key, 1)).to be false
+ end
+
+ it 'returns true if the key is throttled' do
+ expect(redis).to receive(:incr).with(cache_key).and_return(2)
+ expect(redis).not_to receive(:expire)
+
+ expect(subject.throttled?(key, 1)).to be true
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb b/spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb
index 79d2c071446..e1c4f9cfea7 100644
--- a/spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb
+++ b/spec/lib/gitlab/background_migration/create_fork_network_memberships_range_spec.rb
@@ -2,19 +2,20 @@ require 'spec_helper'
describe Gitlab::BackgroundMigration::CreateForkNetworkMembershipsRange, :migration, schema: 20170929131201 do
let(:migration) { described_class.new }
+ let(:projects) { table(:projects) }
- let(:base1) { create(:project) }
- let(:base1_fork1) { create(:project) }
- let(:base1_fork2) { create(:project) }
+ let(:base1) { projects.create }
+ let(:base1_fork1) { projects.create }
+ let(:base1_fork2) { projects.create }
- let(:base2) { create(:project) }
- let(:base2_fork1) { create(:project) }
- let(:base2_fork2) { create(:project) }
+ let(:base2) { projects.create }
+ let(:base2_fork1) { projects.create }
+ let(:base2_fork2) { projects.create }
- let(:fork_of_fork) { create(:project) }
- let(:fork_of_fork2) { create(:project) }
- let(:second_level_fork) { create(:project) }
- let(:third_level_fork) { create(:project) }
+ let(:fork_of_fork) { projects.create }
+ let(:fork_of_fork2) { projects.create }
+ let(:second_level_fork) { projects.create }
+ let(:third_level_fork) { projects.create }
let(:fork_network1) { fork_networks.find_by(root_project_id: base1.id) }
let(:fork_network2) { fork_networks.find_by(root_project_id: base2.id) }
@@ -97,7 +98,7 @@ describe Gitlab::BackgroundMigration::CreateForkNetworkMembershipsRange, :migrat
end
it 'does not miss members for forks of forks for which the root was deleted' do
- forked_project_links.create(id: 9, forked_from_project_id: base1_fork1.id, forked_to_project_id: create(:project).id)
+ forked_project_links.create(id: 9, forked_from_project_id: base1_fork1.id, forked_to_project_id: projects.create.id)
base1.destroy
expect(migration.missing_members?(7, 10)).to be_falsy
@@ -105,8 +106,8 @@ describe Gitlab::BackgroundMigration::CreateForkNetworkMembershipsRange, :migrat
context 'with more forks' do
before do
- forked_project_links.create(id: 9, forked_from_project_id: fork_of_fork.id, forked_to_project_id: create(:project).id)
- forked_project_links.create(id: 10, forked_from_project_id: fork_of_fork.id, forked_to_project_id: create(:project).id)
+ forked_project_links.create(id: 9, forked_from_project_id: fork_of_fork.id, forked_to_project_id: projects.create.id)
+ forked_project_links.create(id: 10, forked_from_project_id: fork_of_fork.id, forked_to_project_id: projects.create.id)
end
it 'only processes a single batch of links at a time' do
diff --git a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
index 5c471cbdeda..9bae7e53b71 100644
--- a/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
+++ b/spec/lib/gitlab/background_migration/delete_conflicting_redirect_routes_range_spec.rb
@@ -24,17 +24,12 @@ describe Gitlab::BackgroundMigration::DeleteConflictingRedirectRoutesRange, :mig
redirect_routes.create!(source_id: 1, source_type: 'Namespace', path: 'foo5')
end
- it 'deletes the conflicting redirect_routes in the range' do
+ # No-op. See https://gitlab.com/gitlab-com/infrastructure/issues/3460#note_53223252
+ it 'NO-OP: does not delete any redirect_routes' do
expect(redirect_routes.count).to eq(8)
- expect do
- described_class.new.perform(1, 3)
- end.to change { redirect_routes.where("path like 'foo%'").count }.from(5).to(2)
+ described_class.new.perform(1, 5)
- expect do
- described_class.new.perform(4, 5)
- end.to change { redirect_routes.where("path like 'foo%'").count }.from(2).to(0)
-
- expect(redirect_routes.count).to eq(3)
+ expect(redirect_routes.count).to eq(8)
end
end
diff --git a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
index cb52d971047..5432d270555 100644
--- a/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
+++ b/spec/lib/gitlab/background_migration/migrate_events_to_push_event_payloads_spec.rb
@@ -225,9 +225,10 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati
let(:user_class) { table(:users) }
let(:author) { build(:user).becomes(user_class).tap(&:save!).becomes(User) }
let(:namespace) { create(:namespace, owner: author) }
- let(:project) { create(:project_empty_repo, namespace: namespace, creator: author) }
+ let(:projects) { table(:projects) }
+ let(:project) { projects.create(namespace_id: namespace.id, creator_id: author.id) }
- # We can not rely on FactoryGirl as the state of Event may change in ways that
+ # We can not rely on FactoryBot as the state of Event may change in ways that
# the background migration does not expect, hence we use the Event class of
# the migration itself.
def create_push_event(project, author, data = nil)
@@ -280,6 +281,17 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati
migration.process_event(event)
end
+
+ it 'handles an error gracefully' do
+ event1 = create_push_event(project, author, { commits: [] })
+
+ expect(migration).to receive(:replicate_event).and_call_original
+ expect(migration).to receive(:create_push_event_payload).and_raise(ActiveRecord::InvalidForeignKey, 'invalid foreign key')
+
+ migration.process_event(event1)
+
+ expect(described_class::EventForMigration.all.count).to eq(0)
+ end
end
describe '#replicate_event' do
@@ -334,9 +346,8 @@ describe Gitlab::BackgroundMigration::MigrateEventsToPushEventPayloads, :migrati
it 'does not create push event payloads for removed events' do
allow(event).to receive(:id).and_return(-1)
- payload = migration.create_push_event_payload(event)
+ expect { migration.create_push_event_payload(event) }.to raise_error(ActiveRecord::InvalidForeignKey)
- expect(payload).to be_nil
expect(PushEventPayload.count).to eq(0)
end
diff --git a/spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb b/spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb
index e52baf8dde7..8582af96199 100644
--- a/spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_fork_networks_range_spec.rb
@@ -2,10 +2,11 @@ require 'spec_helper'
describe Gitlab::BackgroundMigration::PopulateForkNetworksRange, :migration, schema: 20170929131201 do
let(:migration) { described_class.new }
- let(:base1) { create(:project) }
+ let(:projects) { table(:projects) }
+ let(:base1) { projects.create }
- let(:base2) { create(:project) }
- let(:base2_fork1) { create(:project) }
+ let(:base2) { projects.create }
+ let(:base2_fork1) { projects.create }
let!(:forked_project_links) { table(:forked_project_links) }
let!(:fork_networks) { table(:fork_networks) }
@@ -18,10 +19,10 @@ describe Gitlab::BackgroundMigration::PopulateForkNetworksRange, :migration, sch
# A normal fork link
forked_project_links.create(id: 1,
forked_from_project_id: base1.id,
- forked_to_project_id: create(:project).id)
+ forked_to_project_id: projects.create.id)
forked_project_links.create(id: 2,
forked_from_project_id: base1.id,
- forked_to_project_id: create(:project).id)
+ forked_to_project_id: projects.create.id)
forked_project_links.create(id: 3,
forked_from_project_id: base2.id,
forked_to_project_id: base2_fork1.id)
@@ -29,10 +30,10 @@ describe Gitlab::BackgroundMigration::PopulateForkNetworksRange, :migration, sch
# create a fork of a fork
forked_project_links.create(id: 4,
forked_from_project_id: base2_fork1.id,
- forked_to_project_id: create(:project).id)
+ forked_to_project_id: projects.create.id)
forked_project_links.create(id: 5,
- forked_from_project_id: create(:project).id,
- forked_to_project_id: create(:project).id)
+ forked_from_project_id: projects.create.id,
+ forked_to_project_id: projects.create.id)
# Stub out the calls to the other migrations
allow(BackgroundMigrationWorker).to receive(:perform_in)
@@ -63,7 +64,7 @@ describe Gitlab::BackgroundMigration::PopulateForkNetworksRange, :migration, sch
end
it 'creates a fork network for the fork of which the source was deleted' do
- fork = create(:project)
+ fork = projects.create
forked_project_links.create(id: 6, forked_from_project_id: 99999, forked_to_project_id: fork.id)
migration.perform(5, 8)
diff --git a/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb b/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb
new file mode 100644
index 00000000000..dfe3b31f1c0
--- /dev/null
+++ b/spec/lib/gitlab/background_migration/populate_merge_request_metrics_with_events_data_spec.rb
@@ -0,0 +1,124 @@
+require 'rails_helper'
+
+describe Gitlab::BackgroundMigration::PopulateMergeRequestMetricsWithEventsData, :migration, schema: 20171128214150 do
+ describe '#perform' do
+ let(:mr_with_event) { create(:merge_request) }
+ let!(:merged_event) { create(:event, :merged, target: mr_with_event) }
+ let!(:closed_event) { create(:event, :closed, target: mr_with_event) }
+
+ before do
+ # Make sure no metrics are created and kept through after_* callbacks.
+ mr_with_event.metrics.destroy!
+ end
+
+ it 'inserts metrics and updates closed and merged events' do
+ subject.perform(mr_with_event.id, mr_with_event.id)
+
+ mr_with_event.reload
+
+ expect(mr_with_event.metrics).to have_attributes(latest_closed_by_id: closed_event.author_id,
+ merged_by_id: merged_event.author_id)
+ expect(mr_with_event.metrics.latest_closed_at.to_s).to eq(closed_event.updated_at.to_s)
+ end
+ end
+
+ describe '#insert_metrics_for_range' do
+ let!(:mrs_without_metrics) { create_list(:merge_request, 3) }
+ let!(:mrs_with_metrics) { create_list(:merge_request, 2) }
+
+ before do
+ # Make sure no metrics are created and kept through after_* callbacks.
+ mrs_without_metrics.each { |m| m.metrics.destroy! }
+ end
+
+ it 'inserts merge_request_metrics for merge_requests without one' do
+ expect { subject.insert_metrics_for_range(MergeRequest.first.id, MergeRequest.last.id) }
+ .to change(MergeRequest::Metrics, :count).from(2).to(5)
+
+ mrs_without_metrics.each do |mr_without_metrics|
+ expect(mr_without_metrics.reload.metrics).to be_present
+ end
+ end
+
+ it 'does not inserts merge_request_metrics for MRs out of given range' do
+ expect { subject.insert_metrics_for_range(mrs_with_metrics.first.id, mrs_with_metrics.last.id) }
+ .not_to change(MergeRequest::Metrics, :count).from(2)
+ end
+ end
+
+ describe '#update_metrics_with_events_data' do
+ context 'closed events data update' do
+ let(:users) { create_list(:user, 3) }
+ let(:mrs_with_event) { create_list(:merge_request, 3) }
+
+ before do
+ create_list(:event, 2, :closed, author: users.first, target: mrs_with_event.first)
+ create_list(:event, 3, :closed, author: users.second, target: mrs_with_event.second)
+ create(:event, :closed, author: users.third, target: mrs_with_event.third)
+ end
+
+ it 'migrates multiple MR metrics with closed event data' do
+ mr_without_event = create(:merge_request)
+ create(:event, :merged)
+
+ subject.update_metrics_with_events_data(mrs_with_event.first.id, mrs_with_event.last.id)
+
+ mrs_with_event.each do |mr_with_event|
+ latest_event = Event.where(action: 3, target: mr_with_event).last
+
+ mr_with_event.metrics.reload
+
+ expect(mr_with_event.metrics.latest_closed_by).to eq(latest_event.author)
+ expect(mr_with_event.metrics.latest_closed_at.to_s).to eq(latest_event.updated_at.to_s)
+ end
+
+ expect(mr_without_event.metrics.reload).to have_attributes(latest_closed_by_id: nil,
+ latest_closed_at: nil)
+ end
+
+ it 'does not updates metrics out of given range' do
+ out_of_range_mr = create(:merge_request)
+ create(:event, :closed, author: users.last, target: out_of_range_mr)
+
+ expect { subject.perform(mrs_with_event.first.id, mrs_with_event.second.id) }
+ .not_to change { out_of_range_mr.metrics.reload.merged_by }
+ .from(nil)
+ end
+ end
+
+ context 'merged events data update' do
+ let(:users) { create_list(:user, 3) }
+ let(:mrs_with_event) { create_list(:merge_request, 3) }
+
+ before do
+ create_list(:event, 2, :merged, author: users.first, target: mrs_with_event.first)
+ create_list(:event, 3, :merged, author: users.second, target: mrs_with_event.second)
+ create(:event, :merged, author: users.third, target: mrs_with_event.third)
+ end
+
+ it 'migrates multiple MR metrics with merged event data' do
+ mr_without_event = create(:merge_request)
+ create(:event, :merged)
+
+ subject.update_metrics_with_events_data(mrs_with_event.first.id, mrs_with_event.last.id)
+
+ mrs_with_event.each do |mr_with_event|
+ latest_event = Event.where(action: Event::MERGED, target: mr_with_event).last
+
+ expect(mr_with_event.metrics.reload.merged_by).to eq(latest_event.author)
+ end
+
+ expect(mr_without_event.metrics.reload).to have_attributes(merged_by_id: nil)
+ end
+
+ it 'does not updates metrics out of given range' do
+ out_of_range_mr = create(:merge_request)
+ create(:event, :merged, author: users.last, target: out_of_range_mr)
+
+ expect { subject.perform(mrs_with_event.first.id, mrs_with_event.second.id) }
+ .not_to change { out_of_range_mr.metrics.reload.merged_by }
+ .from(nil)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
index b80df6956b0..be45c00dfe6 100644
--- a/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
+++ b/spec/lib/gitlab/background_migration/populate_untracked_uploads_spec.rb
@@ -182,13 +182,22 @@ describe Gitlab::BackgroundMigration::PopulateUntrackedUploads, :sidekiq do
end
context 'for a pre-Markdown Note attachment file path' do
- class Note < ActiveRecord::Base
- has_many :uploads, as: :model, dependent: :destroy
+ let(:model) { create(:note, :with_attachment) }
+ let!(:expected_upload_attrs) { Upload.where(model_type: 'Note', model_id: model.id).first.attributes.slice('path', 'uploader', 'size', 'checksum') }
+ let!(:untracked_file) { untracked_files_for_uploads.create!(path: expected_upload_attrs['path']) }
+
+ before do
+ Upload.where(model_type: 'Note', model_id: model.id).delete_all
end
- let(:model) { create(:note, :with_attachment) }
+ # Can't use the shared example because Note doesn't have an `uploads` association
+ it 'creates an Upload record' do
+ expect do
+ subject.perform(1, untracked_files_for_uploads.last.id)
+ end.to change { Upload.where(model_type: 'Note', model_id: model.id).count }.from(0).to(1)
- it_behaves_like 'non_markdown_file'
+ expect(Upload.where(model_type: 'Note', model_id: model.id).first.attributes).to include(expected_upload_attrs)
+ end
end
context 'for a user avatar file path' do
diff --git a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
index cd3f1a45270..8bb9ebe0419 100644
--- a/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
+++ b/spec/lib/gitlab/background_migration/prepare_untracked_uploads_spec.rb
@@ -2,21 +2,10 @@ require 'spec_helper'
describe Gitlab::BackgroundMigration::PrepareUntrackedUploads, :sidekiq do
include TrackUntrackedUploadsHelpers
+ include MigrationsHelpers
let!(:untracked_files_for_uploads) { described_class::UntrackedFile }
- matcher :be_scheduled_migration do |*expected|
- match do |migration|
- BackgroundMigrationWorker.jobs.any? do |job|
- job['args'] == [migration, expected]
- end
- end
-
- failure_message do |migration|
- "Migration `#{migration}` with args `#{expected.inspect}` not scheduled!"
- end
- end
-
before do
DatabaseCleaner.clean
diff --git a/spec/lib/gitlab/bare_repository_import/importer_spec.rb b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
index 8a83e446935..b5d86df09d2 100644
--- a/spec/lib/gitlab/bare_repository_import/importer_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/importer_spec.rb
@@ -68,8 +68,14 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
expect(Project.find_by_full_path(project_path)).not_to be_nil
end
+ it 'does not schedule an import' do
+ expect_any_instance_of(Project).not_to receive(:import_schedule)
+
+ importer.create_project_if_needed
+ end
+
it 'creates the Git repo in disk' do
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git"))
+ create_bare_repository("#{project_path}.git")
importer.create_project_if_needed
@@ -124,13 +130,14 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
end
it 'creates the Git repo in disk' do
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git"))
+ create_bare_repository("#{project_path}.git")
importer.create_project_if_needed
project = Project.find_by_full_path("#{admin.full_path}/#{project_path}")
expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.git'))
+ expect(File).to exist(File.join(project.repository_storage_path, project.disk_path + '.wiki.git'))
end
it 'moves an existing project to the correct path' do
@@ -158,8 +165,11 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
it_behaves_like 'importing a repository'
it 'creates the Wiki git repo in disk' do
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.git"))
- FileUtils.mkdir_p(File.join(base_dir, "#{project_path}.wiki.git"))
+ create_bare_repository("#{project_path}.git")
+ create_bare_repository("#{project_path}.wiki.git")
+
+ expect(Projects::CreateService).to receive(:new).with(admin, hash_including(skip_wiki: true,
+ import_type: 'bare_repository')).and_call_original
importer.create_project_if_needed
@@ -182,4 +192,9 @@ describe Gitlab::BareRepositoryImport::Importer, repository: true do
end
end
end
+
+ def create_bare_repository(project_path)
+ repo_path = File.join(base_dir, project_path)
+ Gitlab::Git::Repository.create(repo_path, bare: true)
+ end
end
diff --git a/spec/lib/gitlab/bare_repository_import/repository_spec.rb b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
index 61b73abcba4..9f42cf1dfca 100644
--- a/spec/lib/gitlab/bare_repository_import/repository_spec.rb
+++ b/spec/lib/gitlab/bare_repository_import/repository_spec.rb
@@ -1,58 +1,122 @@
require 'spec_helper'
describe ::Gitlab::BareRepositoryImport::Repository do
- let(:project_repo_path) { described_class.new('/full/path/', '/full/path/to/repo.git') }
+ context 'legacy storage' do
+ subject { described_class.new('/full/path/', '/full/path/to/repo.git') }
- it 'stores the repo path' do
- expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git')
- end
+ it 'stores the repo path' do
+ expect(subject.repo_path).to eq('/full/path/to/repo.git')
+ end
- it 'stores the group path' do
- expect(project_repo_path.group_path).to eq('to')
- end
+ it 'stores the group path' do
+ expect(subject.group_path).to eq('to')
+ end
- it 'stores the project name' do
- expect(project_repo_path.project_name).to eq('repo')
- end
+ it 'stores the project name' do
+ expect(subject.project_name).to eq('repo')
+ end
- it 'stores the wiki path' do
- expect(project_repo_path.wiki_path).to eq('/full/path/to/repo.wiki.git')
- end
+ it 'stores the wiki path' do
+ expect(subject.wiki_path).to eq('/full/path/to/repo.wiki.git')
+ end
+
+ describe '#processable?' do
+ it 'returns false if it is a wiki' do
+ subject = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git')
+
+ expect(subject).not_to be_processable
+ end
+
+ it 'returns true if group path is missing' do
+ subject = described_class.new('/full/path/', '/full/path/repo.git')
- describe '#wiki?' do
- it 'returns true if it is a wiki' do
- wiki_path = described_class.new('/full/path/', '/full/path/to/a/b/my.wiki.git')
+ expect(subject).to be_processable
+ end
- expect(wiki_path.wiki?).to eq(true)
+ it 'returns true when group path and project name are present' do
+ expect(subject).to be_processable
+ end
end
- it 'returns false if it is not a wiki' do
- expect(project_repo_path.wiki?).to eq(false)
+ describe '#project_full_path' do
+ it 'returns the project full path with trailing slash in the root path' do
+ expect(subject.project_full_path).to eq('to/repo')
+ end
+
+ it 'returns the project full path with no trailing slash in the root path' do
+ subject = described_class.new('/full/path', '/full/path/to/repo.git')
+
+ expect(subject.project_full_path).to eq('to/repo')
+ end
end
end
- describe '#hashed?' do
- it 'returns true if it is a hashed folder' do
- path = described_class.new('/full/path/', '/full/path/@hashed/my.repo.git')
+ context 'hashed storage' do
+ let(:gitlab_shell) { Gitlab::Shell.new }
+ let(:repository_storage) { 'default' }
+ let(:root_path) { Gitlab.config.repositories.storages[repository_storage]['path'] }
+ let(:hash) { '6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b' }
+ let(:hashed_path) { "@hashed/6b/86/6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" }
+ let(:repo_path) { File.join(root_path, "#{hashed_path}.git") }
+ let(:wiki_path) { File.join(root_path, "#{hashed_path}.wiki.git") }
- expect(path.hashed?).to eq(true)
+ before do
+ gitlab_shell.add_repository(repository_storage, hashed_path)
+ repository = Rugged::Repository.new(repo_path)
+ repository.config['gitlab.fullpath'] = 'to/repo'
end
- it 'returns false if it is not a hashed folder' do
- expect(project_repo_path.hashed?).to eq(false)
+ after do
+ gitlab_shell.remove_repository(root_path, hashed_path)
end
- end
- describe '#project_full_path' do
- it 'returns the project full path' do
- expect(project_repo_path.repo_path).to eq('/full/path/to/repo.git')
- expect(project_repo_path.project_full_path).to eq('to/repo')
+ subject { described_class.new(root_path, repo_path) }
+
+ it 'stores the repo path' do
+ expect(subject.repo_path).to eq(repo_path)
+ end
+
+ it 'stores the wiki path' do
+ expect(subject.wiki_path).to eq(wiki_path)
+ end
+
+ it 'reads the group path from .git/config' do
+ expect(subject.group_path).to eq('to')
+ end
+
+ it 'reads the project name from .git/config' do
+ expect(subject.project_name).to eq('repo')
end
- it 'with no trailing slash in the root path' do
- repo_path = described_class.new('/full/path', '/full/path/to/repo.git')
+ describe '#processable?' do
+ it 'returns false if it is a wiki' do
+ subject = described_class.new(root_path, wiki_path)
+
+ expect(subject).not_to be_processable
+ end
+
+ it 'returns false when group and project name are missing' do
+ repository = Rugged::Repository.new(repo_path)
+ repository.config.delete('gitlab.fullpath')
+
+ expect(subject).not_to be_processable
+ end
+
+ it 'returns true when group path and project name are present' do
+ expect(subject).to be_processable
+ end
+ end
+
+ describe '#project_full_path' do
+ it 'returns the project full path with trailing slash in the root path' do
+ expect(subject.project_full_path).to eq('to/repo')
+ end
+
+ it 'returns the project full path with no trailing slash in the root path' do
+ subject = described_class.new(root_path[0...-1], repo_path)
- expect(repo_path.project_full_path).to eq('to/repo')
+ expect(subject.project_full_path).to eq('to/repo')
+ end
end
end
end
diff --git a/spec/lib/gitlab/checks/project_moved_spec.rb b/spec/lib/gitlab/checks/project_moved_spec.rb
index fa1575e2177..f90c2d6aded 100644
--- a/spec/lib/gitlab/checks/project_moved_spec.rb
+++ b/spec/lib/gitlab/checks/project_moved_spec.rb
@@ -35,6 +35,12 @@ describe Gitlab::Checks::ProjectMoved, :clean_gitlab_redis_shared_state do
project_moved = described_class.new(project, user, 'foo/bar', 'http')
expect(project_moved.add_redirect_message).to eq("OK")
end
+
+ it 'should handle anonymous clones' do
+ project_moved = described_class.new(project, nil, 'foo/bar', 'http')
+
+ expect(project_moved.add_redirect_message).to eq(nil)
+ end
end
describe '#redirect_message' do
diff --git a/spec/lib/gitlab/ci/ansi2html_spec.rb b/spec/lib/gitlab/ci/ansi2html_spec.rb
index 33540eab5d6..05e2d94cbd6 100644
--- a/spec/lib/gitlab/ci/ansi2html_spec.rb
+++ b/spec/lib/gitlab/ci/ansi2html_spec.rb
@@ -120,6 +120,10 @@ describe Gitlab::Ci::Ansi2html do
expect(convert_html("\e[48;5;240mHello")).to eq('<span class="xterm-bg-240">Hello</span>')
end
+ it "can print 256 xterm fg bold colors" do
+ expect(convert_html("\e[38;5;16;1mHello")).to eq('<span class="xterm-fg-16 term-bold">Hello</span>')
+ end
+
it "can print 256 xterm bg colors on normal magenta foreground" do
expect(convert_html("\e[48;5;16;35mHello")).to eq('<span class="term-fg-magenta xterm-bg-16">Hello</span>')
end
diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb
index 03d1f46b517..2cce7a23ea7 100644
--- a/spec/lib/gitlab/ci/status/build/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/build/common_spec.rb
@@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Build::Common do
describe '#has_details?' do
context 'when user has access to read build' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
it { is_expected.to have_details }
diff --git a/spec/lib/gitlab/ci/status/external/common_spec.rb b/spec/lib/gitlab/ci/status/external/common_spec.rb
index b38fbee2486..40871f86568 100644
--- a/spec/lib/gitlab/ci/status/external/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/external/common_spec.rb
@@ -29,7 +29,7 @@ describe Gitlab::Ci::Status::External::Common do
describe '#has_details?' do
context 'when user has access to read commit status' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
it { is_expected.to have_details }
diff --git a/spec/lib/gitlab/ci/status/external/factory_spec.rb b/spec/lib/gitlab/ci/status/external/factory_spec.rb
index c96fd53e730..529d02a3e39 100644
--- a/spec/lib/gitlab/ci/status/external/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/external/factory_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::Ci::Status::External::Factory do
let(:external_url) { 'http://gitlab.com/status' }
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
context 'when external status has a simple core status' do
diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
index 4a5b45e7cae..57df8325635 100644
--- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
@@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Pipeline::Common do
describe '#has_details?' do
context 'when user has access to read pipeline' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
it { is_expected.to have_details }
diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
index dd754b849b2..defb3fdc0df 100644
--- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
@@ -7,7 +7,7 @@ describe Gitlab::Ci::Status::Pipeline::Factory do
let(:factory) { described_class.new(pipeline, user) }
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
context 'when pipeline has a core status' do
diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb
index f5f03ac0395..6ec35f8da7e 100644
--- a/spec/lib/gitlab/ci/status/stage/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb
@@ -27,7 +27,7 @@ describe Gitlab::Ci::Status::Stage::Common do
context 'when user has permission to read pipeline' do
before do
- project.team << [user, :master]
+ project.add_master(user)
end
it 'has details' do
diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
index 432b07e4902..dee4f4efd1b 100644
--- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
@@ -18,7 +18,7 @@ describe Gitlab::Ci::Status::Stage::Factory do
end
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
context 'when stage has a core status' do
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index ef7d766a13d..8c79ef54c6c 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -13,8 +13,8 @@ describe Gitlab::ClosingIssueExtractor do
subject { described_class.new(project, project.creator) }
before do
- project.team << [project.creator, :developer]
- project2.team << [project.creator, :master]
+ project.add_developer(project.creator)
+ project2.add_master(project.creator)
end
describe "#closed_by_message" do
@@ -297,7 +297,7 @@ describe Gitlab::ClosingIssueExtractor do
context 'with an external issue tracker reference' do
it 'extracts the referenced issue' do
jira_project = create(:jira_project, name: 'JIRA_EXT1')
- jira_project.team << [jira_project.creator, :master]
+ jira_project.add_master(jira_project.creator)
jira_issue = ExternalIssue.new("#{jira_project.name}-1", project: jira_project)
closing_issue_extractor = described_class.new(jira_project, jira_project.creator)
message = "Resolve #{jira_issue.to_reference}"
diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
index 0560c47f03f..3fe0493ed9b 100644
--- a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
@@ -23,6 +23,8 @@ describe Gitlab::CycleAnalytics::BaseEventFetcher do
allow_any_instance_of(described_class).to receive(:serialize) do |event|
event
end
+ allow_any_instance_of(described_class)
+ .to receive(:allowed_ids).and_return(nil)
stub_const('Gitlab::CycleAnalytics::BaseEventFetcher::MAX_EVENTS', max_events)
diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb
index 28ea7d4c303..38a47a159e1 100644
--- a/spec/lib/gitlab/cycle_analytics/events_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb
@@ -122,17 +122,18 @@ describe 'cycle analytics events' do
let(:stage) { :test }
let(:merge_request) { MergeRequest.first }
+
let!(:pipeline) do
create(:ci_pipeline,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha,
- project: context.project,
+ project: project,
head_pipeline_of: merge_request)
end
before do
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
pipeline.run!
pipeline.succeed!
@@ -219,17 +220,18 @@ describe 'cycle analytics events' do
describe '#staging_events' do
let(:stage) { :staging }
let(:merge_request) { MergeRequest.first }
+
let!(:pipeline) do
create(:ci_pipeline,
ref: merge_request.source_branch,
sha: merge_request.diff_head_sha,
- project: context.project,
+ project: project,
head_pipeline_of: merge_request)
end
before do
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
- create(:ci_build, pipeline: pipeline, status: :success, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
+ create(:ci_build, :success, pipeline: pipeline, author: user)
pipeline.run!
pipeline.succeed!
diff --git a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb
index 2a0dd7be439..6de4bd3dc7c 100644
--- a/spec/lib/gitlab/cycle_analytics/permissions_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/permissions_spec.rb
@@ -38,7 +38,7 @@ describe Gitlab::CycleAnalytics::Permissions do
context 'user is master' do
before do
- project.team << [user, :master]
+ project.add_master(user)
end
it 'has permissions to issue stage' do
@@ -72,7 +72,7 @@ describe Gitlab::CycleAnalytics::Permissions do
context 'user has no build permissions' do
before do
- project.team << [user, :guest]
+ project.add_guest(user)
end
it 'has permissions to issue stage' do
@@ -90,7 +90,7 @@ describe Gitlab::CycleAnalytics::Permissions do
context 'user has no merge request permissions' do
before do
- project.team << [user, :guest]
+ project.add_guest(user)
end
it 'has permissions to issue stage' do
@@ -108,7 +108,7 @@ describe Gitlab::CycleAnalytics::Permissions do
context 'user has no issue permissions' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 664ba0f7234..43761c2fe0c 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -902,7 +902,7 @@ describe Gitlab::Database::MigrationHelpers do
describe '#check_trigger_permissions!' do
it 'does nothing when the user has the correct permissions' do
expect { model.check_trigger_permissions!('users') }
- .not_to raise_error(RuntimeError)
+ .not_to raise_error
end
it 'raises RuntimeError when the user does not have the correct permissions' do
@@ -1006,12 +1006,12 @@ describe Gitlab::Database::MigrationHelpers do
context 'with batch_size option' do
it 'queues jobs correctly' do
Sidekiq::Testing.fake! do
- model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.seconds, batch_size: 2)
+ model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.minutes, batch_size: 2)
expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['FooJob', [id1, id2]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.minutes.from_now.to_f)
expect(BackgroundMigrationWorker.jobs[1]['args']).to eq(['FooJob', [id3, id3]])
- expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(20.minutes.from_now.to_f)
end
end
end
@@ -1019,10 +1019,10 @@ describe Gitlab::Database::MigrationHelpers do
context 'without batch_size option' do
it 'queues jobs correctly' do
Sidekiq::Testing.fake! do
- model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.seconds)
+ model.queue_background_migration_jobs_by_range_at_intervals(User, 'FooJob', 10.minutes)
expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['FooJob', [id1, id3]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.seconds.from_now.to_f)
+ expect(BackgroundMigrationWorker.jobs[0]['at']).to eq(10.minutes.from_now.to_f)
end
end
end
@@ -1036,4 +1036,93 @@ describe Gitlab::Database::MigrationHelpers do
end
end
end
+
+ describe '#change_column_type_using_background_migration' do
+ let!(:issue) { create(:issue) }
+
+ let(:issue_model) do
+ Class.new(ActiveRecord::Base) do
+ self.table_name = 'issues'
+ include EachBatch
+ end
+ end
+
+ it 'changes the type of a column using a background migration' do
+ expect(model)
+ .to receive(:add_column)
+ .with('issues', 'closed_at_for_type_change', :datetime_with_timezone)
+
+ expect(model)
+ .to receive(:install_rename_triggers)
+ .with('issues', :closed_at, 'closed_at_for_type_change')
+
+ expect(BackgroundMigrationWorker)
+ .to receive(:perform_in)
+ .ordered
+ .with(
+ 10.minutes,
+ 'CopyColumn',
+ ['issues', :closed_at, 'closed_at_for_type_change', issue.id, issue.id]
+ )
+
+ expect(BackgroundMigrationWorker)
+ .to receive(:perform_in)
+ .ordered
+ .with(
+ 1.hour + 10.minutes,
+ 'CleanupConcurrentTypeChange',
+ ['issues', :closed_at, 'closed_at_for_type_change']
+ )
+
+ expect(Gitlab::BackgroundMigration)
+ .to receive(:steal)
+ .ordered
+ .with('CopyColumn')
+
+ expect(Gitlab::BackgroundMigration)
+ .to receive(:steal)
+ .ordered
+ .with('CleanupConcurrentTypeChange')
+
+ model.change_column_type_using_background_migration(
+ issue_model.all,
+ :closed_at,
+ :datetime_with_timezone
+ )
+ end
+ end
+
+ describe '#perform_background_migration_inline?' do
+ it 'returns true in a test environment' do
+ allow(Rails.env)
+ .to receive(:test?)
+ .and_return(true)
+
+ expect(model.perform_background_migration_inline?).to eq(true)
+ end
+
+ it 'returns true in a development environment' do
+ allow(Rails.env)
+ .to receive(:test?)
+ .and_return(false)
+
+ allow(Rails.env)
+ .to receive(:development?)
+ .and_return(true)
+
+ expect(model.perform_background_migration_inline?).to eq(true)
+ end
+
+ it 'returns false in a production environment' do
+ allow(Rails.env)
+ .to receive(:test?)
+ .and_return(false)
+
+ allow(Rails.env)
+ .to receive(:development?)
+ .and_return(false)
+
+ expect(model.perform_background_migration_inline?).to eq(false)
+ end
+ end
end
diff --git a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
index d81774c8b8f..a067c42b75b 100644
--- a/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
+++ b/spec/lib/gitlab/diff/file_collection/merge_request_diff_spec.rb
@@ -19,4 +19,18 @@ describe Gitlab::Diff::FileCollection::MergeRequestDiff do
diff_files
end
+
+ shared_examples 'initializes a DiffCollection' do
+ it 'returns a valid instance of a DiffCollection' do
+ expect(diff_files).to be_a(Gitlab::Git::DiffCollection)
+ end
+ end
+
+ context 'with Gitaly disabled', :disable_gitaly do
+ it_behaves_like 'initializes a DiffCollection'
+ end
+
+ context 'with Gitaly enabled' do
+ it_behaves_like 'initializes a DiffCollection'
+ end
end
diff --git a/spec/lib/gitlab/diff/file_spec.rb b/spec/lib/gitlab/diff/file_spec.rb
index ff9acfd08b9..9204ea37963 100644
--- a/spec/lib/gitlab/diff/file_spec.rb
+++ b/spec/lib/gitlab/diff/file_spec.rb
@@ -431,4 +431,29 @@ describe Gitlab::Diff::File do
end
end
end
+
+ context 'when neither blob exists' do
+ let(:blank_diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: Gitlab::Git::BLANK_SHA, head_sha: Gitlab::Git::BLANK_SHA) }
+ let(:diff_file) { described_class.new(diff, diff_refs: blank_diff_refs, repository: project.repository) }
+
+ describe '#blob' do
+ it 'returns a concrete nil so it can be used in boolean expressions' do
+ actual = diff_file.blob && true
+
+ expect(actual).to be_nil
+ end
+ end
+
+ describe '#binary?' do
+ it 'returns false' do
+ expect(diff_file).not_to be_binary
+ end
+ end
+
+ describe '#size' do
+ it 'returns zero' do
+ expect(diff_file.size).to be_zero
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb b/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb
index 51ce3116880..dc1a93367a4 100644
--- a/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_merge_request_handler_spec.rb
@@ -49,6 +49,7 @@ describe Gitlab::Email::Handler::CreateMergeRequestHandler do
expect(merge_request.author).to eq(user)
expect(merge_request.source_branch).to eq('feature')
expect(merge_request.title).to eq('Feature added')
+ expect(merge_request.description).to eq('Merge request description')
expect(merge_request.target_branch).to eq(project.default_branch)
end
end
@@ -79,6 +80,17 @@ describe Gitlab::Email::Handler::CreateMergeRequestHandler do
expect { receiver.execute }.to raise_error(Gitlab::Email::InvalidMergeRequestError)
end
end
+
+ context "when the message body is blank" do
+ let(:email_raw) { fixture_file("emails/valid_new_merge_request_no_description.eml") }
+
+ it "creates a new merge request with description set from the last commit" do
+ expect { receiver.execute }.to change { project.merge_requests.count }.by(1)
+ merge_request = project.merge_requests.last
+
+ expect(merge_request.description).to eq('Signed-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>')
+ end
+ end
end
end
end
diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
index d0fa16ce4d1..031efcf1291 100644
--- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
+++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb
@@ -66,7 +66,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler do
context 'and current user can update noteable' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
it 'does not raise an error' do
@@ -99,7 +99,7 @@ describe Gitlab::Email::Handler::CreateNoteHandler do
context 'and current user can update noteable' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
it 'post a note and updates the noteable' do
diff --git a/spec/lib/gitlab/encoding_helper_spec.rb b/spec/lib/gitlab/encoding_helper_spec.rb
index f6e5c55240f..4e9367323cb 100644
--- a/spec/lib/gitlab/encoding_helper_spec.rb
+++ b/spec/lib/gitlab/encoding_helper_spec.rb
@@ -120,6 +120,24 @@ describe Gitlab::EncodingHelper do
it 'returns empty string on conversion errors' do
expect { ext_class.encode_utf8('') }.not_to raise_error(ArgumentError)
end
+
+ context 'with strings that can be forcefully encoded into utf8' do
+ let(:test_string) do
+ "refs/heads/FixSymbolsTitleDropdown".encode("ASCII-8BIT")
+ end
+ let(:expected_string) do
+ "refs/heads/FixSymbolsTitleDropdown".encode("UTF-8")
+ end
+
+ subject { ext_class.encode_utf8(test_string) }
+
+ it "doesn't use CharlockHolmes if the encoding can be forced into utf_8" do
+ expect(CharlockHolmes::EncodingDetector).not_to receive(:detect)
+
+ expect(subject).to eq(expected_string)
+ expect(subject.encoding.name).to eq('UTF-8')
+ end
+ end
end
describe '#clean' do
@@ -145,4 +163,18 @@ describe Gitlab::EncodingHelper do
end
end
end
+
+ describe 'encode_binary' do
+ [
+ [nil, ""],
+ ["", ""],
+ [" ", " "],
+ %w(a1 a1),
+ ["编码", "\xE7\xBC\x96\xE7\xA0\x81".b]
+ ].each do |input, result|
+ it "encodes #{input.inspect} to #{result.inspect}" do
+ expect(ext_class.encode_binary(input)).to eq(result)
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/exclusive_lease_spec.rb b/spec/lib/gitlab/exclusive_lease_spec.rb
index 7322a326b01..6193e177668 100644
--- a/spec/lib/gitlab/exclusive_lease_spec.rb
+++ b/spec/lib/gitlab/exclusive_lease_spec.rb
@@ -73,4 +73,19 @@ describe Gitlab::ExclusiveLease, :clean_gitlab_redis_shared_state do
described_class.new(key, timeout: 3600).try_obtain
end
end
+
+ describe '#ttl' do
+ it 'returns the TTL of the Redis key' do
+ lease = described_class.new('kittens', timeout: 100)
+ lease.try_obtain
+
+ expect(lease.ttl <= 100).to eq(true)
+ end
+
+ it 'returns nil when the lease does not exist' do
+ lease = described_class.new('kittens', timeout: 10)
+
+ expect(lease.ttl).to be_nil
+ end
+ end
end
diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
index 7dc06c90078..4d2f08f95fc 100644
--- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
+++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::Gfm::ReferenceRewriter do
let(:text) { 'some text' }
before do
- old_project.team << [user, :reporter]
+ old_project.add_reporter(user)
end
describe '#rewrite' do
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index c04a9688503..07eb5b82d5f 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -146,7 +146,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
context 'when sha references a tree' do
it 'returns nil' do
- tree = Gitlab::Git::Commit.find(repository, 'master').tree
+ tree = repository.rugged.rev_parse('master^{tree}')
blob = Gitlab::Git::Blob.raw(repository, tree.oid)
@@ -202,16 +202,6 @@ describe Gitlab::Git::Blob, seed_helper: true do
context 'limiting' do
subject { described_class.batch(repository, blob_references, blob_size_limit: blob_size_limit) }
- context 'default' do
- let(:blob_size_limit) { nil }
-
- it 'limits to MAX_DATA_DISPLAY_SIZE' do
- stub_const('Gitlab::Git::Blob::MAX_DATA_DISPLAY_SIZE', 100)
-
- expect(subject.first.data.size).to eq(100)
- end
- end
-
context 'positive' do
let(:blob_size_limit) { 10 }
@@ -221,7 +211,10 @@ describe Gitlab::Git::Blob, seed_helper: true do
context 'zero' do
let(:blob_size_limit) { 0 }
- it { expect(subject.first.data).to eq('') }
+ it 'only loads the metadata' do
+ expect(subject.first.size).not_to be(0)
+ expect(subject.first.data).to eq('')
+ end
end
context 'negative' do
@@ -237,7 +230,7 @@ describe Gitlab::Git::Blob, seed_helper: true do
end
describe '.batch_lfs_pointers' do
- let(:tree_object) { Gitlab::Git::Commit.find(repository, 'master').tree }
+ let(:tree_object) { repository.rugged.rev_parse('master^{tree}') }
let(:non_lfs_blob) do
Gitlab::Git::Blob.find(
diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb
index 5ed639543e0..6a07a3ca8b8 100644
--- a/spec/lib/gitlab/git/commit_spec.rb
+++ b/spec/lib/gitlab/git/commit_spec.rb
@@ -55,7 +55,6 @@ describe Gitlab::Git::Commit, seed_helper: true do
it { expect(@commit.parents).to eq(@gitlab_parents) }
it { expect(@commit.parent_id).to eq(@parents.first.oid) }
it { expect(@commit.no_commit_message).to eq("--no commit message") }
- it { expect(@commit.tree).to eq(@tree) }
after do
# Erase the new commit so other tests get the original repo
@@ -428,6 +427,11 @@ describe Gitlab::Git::Commit, seed_helper: true do
subject { super().deletions }
it { is_expected.to eq(6) }
end
+
+ describe '#total' do
+ subject { super().total }
+ it { is_expected.to eq(17) }
+ end
end
describe '#stats with gitaly on' do
diff --git a/spec/lib/gitlab/git/gitlab_projects_spec.rb b/spec/lib/gitlab/git/gitlab_projects_spec.rb
new file mode 100644
index 00000000000..a798b188a0d
--- /dev/null
+++ b/spec/lib/gitlab/git/gitlab_projects_spec.rb
@@ -0,0 +1,337 @@
+require 'spec_helper'
+
+describe Gitlab::Git::GitlabProjects do
+ after do
+ TestEnv.clean_test_path
+ end
+
+ let(:project) { create(:project, :repository) }
+
+ if $VERBOSE
+ let(:logger) { Logger.new(STDOUT) }
+ else
+ let(:logger) { double('logger').as_null_object }
+ end
+
+ let(:tmp_repos_path) { TestEnv.repos_path }
+ let(:repo_name) { project.disk_path + '.git' }
+ let(:tmp_repo_path) { File.join(tmp_repos_path, repo_name) }
+ let(:gl_projects) { build_gitlab_projects(tmp_repos_path, repo_name) }
+
+ describe '#initialize' do
+ it { expect(gl_projects.shard_path).to eq(tmp_repos_path) }
+ it { expect(gl_projects.repository_relative_path).to eq(repo_name) }
+ it { expect(gl_projects.repository_absolute_path).to eq(File.join(tmp_repos_path, repo_name)) }
+ it { expect(gl_projects.logger).to eq(logger) }
+ end
+
+ describe '#mv_project' do
+ let(:new_repo_path) { File.join(tmp_repos_path, 'repo.git') }
+
+ it 'moves a repo directory' do
+ expect(File.exist?(tmp_repo_path)).to be_truthy
+
+ message = "Moving repository from <#{tmp_repo_path}> to <#{new_repo_path}>."
+ expect(logger).to receive(:info).with(message)
+
+ expect(gl_projects.mv_project('repo.git')).to be_truthy
+
+ expect(File.exist?(tmp_repo_path)).to be_falsy
+ expect(File.exist?(new_repo_path)).to be_truthy
+ end
+
+ it "fails if the source path doesn't exist" do
+ expected_source_path = File.join(tmp_repos_path, 'bad-src.git')
+ expect(logger).to receive(:error).with("mv-project failed: source path <#{expected_source_path}> does not exist.")
+
+ result = build_gitlab_projects(tmp_repos_path, 'bad-src.git').mv_project('repo.git')
+ expect(result).to be_falsy
+ end
+
+ it 'fails if the destination path already exists' do
+ FileUtils.mkdir_p(File.join(tmp_repos_path, 'already-exists.git'))
+
+ expected_distination_path = File.join(tmp_repos_path, 'already-exists.git')
+ message = "mv-project failed: destination path <#{expected_distination_path}> already exists."
+ expect(logger).to receive(:error).with(message)
+
+ expect(gl_projects.mv_project('already-exists.git')).to be_falsy
+ end
+ end
+
+ describe '#rm_project' do
+ it 'removes a repo directory' do
+ expect(File.exist?(tmp_repo_path)).to be_truthy
+ expect(logger).to receive(:info).with("Removing repository <#{tmp_repo_path}>.")
+
+ expect(gl_projects.rm_project).to be_truthy
+
+ expect(File.exist?(tmp_repo_path)).to be_falsy
+ end
+ end
+
+ describe '#push_branches' do
+ let(:remote_name) { 'remote-name' }
+ let(:branch_name) { 'master' }
+ let(:cmd) { %W(git push -- #{remote_name} #{branch_name}) }
+ let(:force) { false }
+
+ subject { gl_projects.push_branches(remote_name, 600, force, [branch_name]) }
+
+ it 'executes the command' do
+ stub_spawn(cmd, 600, tmp_repo_path, success: true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'fails' do
+ stub_spawn(cmd, 600, tmp_repo_path, success: false)
+
+ is_expected.to be_falsy
+ end
+
+ context 'with --force' do
+ let(:cmd) { %W(git push --force -- #{remote_name} #{branch_name}) }
+ let(:force) { true }
+
+ it 'executes the command' do
+ stub_spawn(cmd, 600, tmp_repo_path, success: true)
+
+ is_expected.to be_truthy
+ end
+ end
+ end
+
+ describe '#fetch_remote' do
+ let(:remote_name) { 'remote-name' }
+ let(:branch_name) { 'master' }
+ let(:force) { false }
+ let(:tags) { true }
+ let(:args) { { force: force, tags: tags }.merge(extra_args) }
+ let(:extra_args) { {} }
+ let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --tags) }
+
+ subject { gl_projects.fetch_remote(remote_name, 600, args) }
+
+ def stub_tempfile(name, filename, opts = {})
+ chmod = opts.delete(:chmod)
+ file = StringIO.new
+
+ allow(file).to receive(:close!)
+ allow(file).to receive(:path).and_return(name)
+
+ expect(Tempfile).to receive(:new).with(filename).and_return(file)
+ expect(file).to receive(:chmod).with(chmod) if chmod
+
+ file
+ end
+
+ context 'with default args' do
+ it 'executes the command' do
+ stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'fails' do
+ stub_spawn(cmd, 600, tmp_repo_path, {}, success: false)
+
+ is_expected.to be_falsy
+ end
+ end
+
+ context 'with --force' do
+ let(:force) { true }
+ let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --force --tags) }
+
+ it 'executes the command with forced option' do
+ stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
+
+ is_expected.to be_truthy
+ end
+ end
+
+ context 'with --no-tags' do
+ let(:tags) { false }
+ let(:cmd) { %W(git fetch #{remote_name} --prune --quiet --no-tags) }
+
+ it 'executes the command' do
+ stub_spawn(cmd, 600, tmp_repo_path, {}, success: true)
+
+ is_expected.to be_truthy
+ end
+ end
+
+ describe 'with an SSH key' do
+ let(:extra_args) { { ssh_key: 'SSH KEY' } }
+
+ it 'sets GIT_SSH to a custom script' do
+ script = stub_tempfile('scriptFile', 'gitlab-shell-ssh-wrapper', chmod: 0o755)
+ key = stub_tempfile('/tmp files/keyFile', 'gitlab-shell-key-file', chmod: 0o400)
+
+ stub_spawn(cmd, 600, tmp_repo_path, { 'GIT_SSH' => 'scriptFile' }, success: true)
+
+ is_expected.to be_truthy
+
+ expect(script.string).to eq("#!/bin/sh\nexec ssh '-oIdentityFile=\"/tmp files/keyFile\"' '-oIdentitiesOnly=\"yes\"' \"$@\"")
+ expect(key.string).to eq('SSH KEY')
+ end
+ end
+
+ describe 'with known_hosts data' do
+ let(:extra_args) { { known_hosts: 'KNOWN HOSTS' } }
+
+ it 'sets GIT_SSH to a custom script' do
+ script = stub_tempfile('scriptFile', 'gitlab-shell-ssh-wrapper', chmod: 0o755)
+ key = stub_tempfile('/tmp files/knownHosts', 'gitlab-shell-known-hosts', chmod: 0o400)
+
+ stub_spawn(cmd, 600, tmp_repo_path, { 'GIT_SSH' => 'scriptFile' }, success: true)
+
+ is_expected.to be_truthy
+
+ expect(script.string).to eq("#!/bin/sh\nexec ssh '-oStrictHostKeyChecking=\"yes\"' '-oUserKnownHostsFile=\"/tmp files/knownHosts\"' \"$@\"")
+ expect(key.string).to eq('KNOWN HOSTS')
+ end
+ end
+ end
+
+ describe '#import_project' do
+ let(:project) { create(:project) }
+ let(:import_url) { TestEnv.factory_repo_path_bare }
+ let(:cmd) { %W(git clone --bare -- #{import_url} #{tmp_repo_path}) }
+ let(:timeout) { 600 }
+
+ subject { gl_projects.import_project(import_url, timeout) }
+
+ context 'success import' do
+ it 'imports a repo' do
+ expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy
+
+ message = "Importing project from <#{import_url}> to <#{tmp_repo_path}>."
+ expect(logger).to receive(:info).with(message)
+
+ is_expected.to be_truthy
+
+ expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_truthy
+ end
+ end
+
+ context 'already exists' do
+ it "doesn't import" do
+ FileUtils.mkdir_p(tmp_repo_path)
+
+ is_expected.to be_falsy
+ end
+ end
+
+ context 'timeout' do
+ it 'does not import a repo' do
+ stub_spawn_timeout(cmd, timeout, nil)
+
+ message = "Importing project from <#{import_url}> to <#{tmp_repo_path}> failed."
+ expect(logger).to receive(:error).with(message)
+
+ is_expected.to be_falsy
+
+ expect(gl_projects.output).to eq("Timed out\n")
+ expect(File.exist?(File.join(tmp_repo_path, 'HEAD'))).to be_falsy
+ end
+ end
+ end
+
+ describe '#fork_repository' do
+ let(:dest_repos_path) { tmp_repos_path }
+ let(:dest_repo_name) { File.join('@hashed', 'aa', 'bb', 'xyz.git') }
+ let(:dest_repo) { File.join(dest_repos_path, dest_repo_name) }
+
+ subject { gl_projects.fork_repository(dest_repos_path, dest_repo_name) }
+
+ before do
+ FileUtils.mkdir_p(dest_repos_path)
+ end
+
+ after do
+ FileUtils.rm_rf(dest_repos_path)
+ end
+
+ shared_examples 'forking a repository' do
+ it 'forks the repository' do
+ is_expected.to be_truthy
+
+ expect(File.exist?(dest_repo)).to be_truthy
+ expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy
+ expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy
+ end
+
+ it 'does not fork if a project of the same name already exists' do
+ # create a fake project at the intended destination
+ FileUtils.mkdir_p(dest_repo)
+
+ is_expected.to be_falsy
+ end
+ end
+
+ context 'when Gitaly fork_repository feature is enabled' do
+ it_behaves_like 'forking a repository'
+ end
+
+ context 'when Gitaly fork_repository feature is disabled', :disable_gitaly do
+ it_behaves_like 'forking a repository'
+
+ # We seem to be stuck to having only one working Gitaly storage in tests, changing
+ # that is not very straight-forward so I'm leaving this test here for now till
+ # https://gitlab.com/gitlab-org/gitlab-ce/issues/41393 is fixed.
+ context 'different storages' do
+ let(:dest_repos_path) { File.join(File.dirname(tmp_repos_path), 'alternative') }
+
+ it 'forks the repo' do
+ is_expected.to be_truthy
+
+ expect(File.exist?(dest_repo)).to be_truthy
+ expect(File.exist?(File.join(dest_repo, 'hooks', 'pre-receive'))).to be_truthy
+ expect(File.exist?(File.join(dest_repo, 'hooks', 'post-receive'))).to be_truthy
+ end
+ end
+
+ describe 'log messages' do
+ describe 'successful fork' do
+ it do
+ message = "Forking repository from <#{tmp_repo_path}> to <#{dest_repo}>."
+ expect(logger).to receive(:info).with(message)
+
+ subject
+ end
+ end
+
+ describe 'failed fork due existing destination' do
+ it do
+ FileUtils.mkdir_p(dest_repo)
+ message = "fork-repository failed: destination repository <#{dest_repo}> already exists."
+ expect(logger).to receive(:error).with(message)
+
+ subject
+ end
+ end
+ end
+ end
+ end
+
+ def build_gitlab_projects(*args)
+ described_class.new(
+ *args,
+ global_hooks_path: Gitlab.config.gitlab_shell.hooks_path,
+ logger: logger
+ )
+ end
+
+ def stub_spawn(*args, success: true)
+ exitstatus = success ? 0 : nil
+ expect(gl_projects).to receive(:popen_with_timeout).with(*args)
+ .and_return(["output", exitstatus])
+ end
+
+ def stub_spawn_timeout(*args)
+ expect(gl_projects).to receive(:popen_with_timeout).with(*args)
+ .and_raise(Timeout::Error)
+ end
+end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index f19b65a5f71..f346a345f00 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -18,6 +18,52 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
+ let(:storage_path) { TestEnv.repos_path }
+
+ describe '.create_hooks' do
+ let(:repo_path) { File.join(storage_path, 'hook-test.git') }
+ let(:hooks_dir) { File.join(repo_path, 'hooks') }
+ let(:target_hooks_dir) { Gitlab.config.gitlab_shell.hooks_path }
+ let(:existing_target) { File.join(repo_path, 'foobar') }
+
+ before do
+ FileUtils.rm_rf(repo_path)
+ FileUtils.mkdir_p(repo_path)
+ end
+
+ context 'hooks is a directory' do
+ let(:existing_file) { File.join(hooks_dir, 'my-file') }
+
+ before do
+ FileUtils.mkdir_p(hooks_dir)
+ FileUtils.touch(existing_file)
+ described_class.create_hooks(repo_path, target_hooks_dir)
+ end
+
+ it { expect(File.readlink(hooks_dir)).to eq(target_hooks_dir) }
+ it { expect(Dir[File.join(repo_path, "hooks.old.*/my-file")].count).to eq(1) }
+ end
+
+ context 'hooks is a valid symlink' do
+ before do
+ FileUtils.mkdir_p existing_target
+ File.symlink(existing_target, hooks_dir)
+ described_class.create_hooks(repo_path, target_hooks_dir)
+ end
+
+ it { expect(File.readlink(hooks_dir)).to eq(target_hooks_dir) }
+ end
+
+ context 'hooks is a broken symlink' do
+ before do
+ FileUtils.rm_f(existing_target)
+ File.symlink(existing_target, hooks_dir)
+ described_class.create_hooks(repo_path, target_hooks_dir)
+ end
+
+ it { expect(File.readlink(hooks_dir)).to eq(target_hooks_dir) }
+ end
+ end
describe "Respond to" do
subject { repository }
@@ -588,44 +634,54 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#fetch_as_mirror_without_shell' do
+ describe '#fetch_repository_as_mirror' do
let(:new_repository) do
Gitlab::Git::Repository.new('default', 'my_project.git', '')
end
- subject { new_repository.fetch_as_mirror_without_shell(repository.path) }
+ subject { new_repository.fetch_repository_as_mirror(repository) }
before do
Gitlab::Shell.new.add_repository('default', 'my_project')
end
after do
- Gitlab::Shell.new.remove_repository(TestEnv.repos_path, 'my_project')
+ Gitlab::Shell.new.remove_repository(storage_path, 'my_project')
end
- it 'fetches a url as a mirror remote' do
- subject
+ shared_examples 'repository mirror fecthing' do
+ it 'fetches a repository as a mirror remote' do
+ subject
- expect(refs(new_repository.path)).to eq(refs(repository.path))
- end
+ expect(refs(new_repository.path)).to eq(refs(repository.path))
+ end
- context 'with keep-around refs' do
- let(:sha) { SeedRepo::Commit::ID }
- let(:keep_around_ref) { "refs/keep-around/#{sha}" }
- let(:tmp_ref) { "refs/tmp/#{SecureRandom.hex}" }
+ context 'with keep-around refs' do
+ let(:sha) { SeedRepo::Commit::ID }
+ let(:keep_around_ref) { "refs/keep-around/#{sha}" }
+ let(:tmp_ref) { "refs/tmp/#{SecureRandom.hex}" }
- before do
- repository.rugged.references.create(keep_around_ref, sha, force: true)
- repository.rugged.references.create(tmp_ref, sha, force: true)
- end
+ before do
+ repository.rugged.references.create(keep_around_ref, sha, force: true)
+ repository.rugged.references.create(tmp_ref, sha, force: true)
+ end
- it 'includes the temporary and keep-around refs' do
- subject
+ it 'includes the temporary and keep-around refs' do
+ subject
- expect(refs(new_repository.path)).to include(keep_around_ref)
- expect(refs(new_repository.path)).to include(tmp_ref)
+ expect(refs(new_repository.path)).to include(keep_around_ref)
+ expect(refs(new_repository.path)).to include(tmp_ref)
+ end
end
end
+
+ context 'with gitaly enabled' do
+ it_behaves_like 'repository mirror fecthing'
+ end
+
+ context 'with gitaly enabled', :skip_gitaly_mock do
+ it_behaves_like 'repository mirror fecthing'
+ end
end
describe '#remote_tags' do
@@ -656,21 +712,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#remote_exists?' do
- before(:all) do
- @repo = Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
- @repo.add_remote("new_remote", SeedHelper::GITLAB_GIT_TEST_REPO_URL)
- end
-
- it 'returns true for an existing remote' do
- expect(@repo.remote_exists?('new_remote')).to eq(true)
- end
-
- it 'returns false for a non-existing remote' do
- expect(@repo.remote_exists?('foo')).to eq(false)
- end
- end
-
describe "#log" do
let(:commit_with_old_name) do
Gitlab::Git::Commit.decorate(repository, @commit_with_old_name_id)
@@ -985,7 +1026,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
shared_examples 'extended commit counting' do
context 'with after timestamp' do
it 'returns the number of commits after timestamp' do
- options = { ref: 'master', limit: nil, after: Time.iso8601('2013-03-03T20:15:01+00:00') }
+ options = { ref: 'master', after: Time.iso8601('2013-03-03T20:15:01+00:00') }
expect(repository.count_commits(options)).to eq(25)
end
@@ -993,19 +1034,65 @@ describe Gitlab::Git::Repository, seed_helper: true do
context 'with before timestamp' do
it 'returns the number of commits before timestamp' do
- options = { ref: 'feature', limit: nil, before: Time.iso8601('2015-03-03T20:15:01+00:00') }
+ options = { ref: 'feature', before: Time.iso8601('2015-03-03T20:15:01+00:00') }
expect(repository.count_commits(options)).to eq(9)
end
end
+ context 'with max_count' do
+ it 'returns the number of commits with path ' do
+ options = { ref: 'master', max_count: 5 }
+
+ expect(repository.count_commits(options)).to eq(5)
+ end
+ end
+
context 'with path' do
it 'returns the number of commits with path ' do
- options = { ref: 'master', limit: nil, path: "encoding" }
+ options = { ref: 'master', path: 'encoding' }
expect(repository.count_commits(options)).to eq(2)
end
end
+
+ context 'with option :from and option :to' do
+ it 'returns the number of commits ahead for fix-mode..fix-blob-path' do
+ options = { from: 'fix-mode', to: 'fix-blob-path' }
+
+ expect(repository.count_commits(options)).to eq(2)
+ end
+
+ it 'returns the number of commits ahead for fix-blob-path..fix-mode' do
+ options = { from: 'fix-blob-path', to: 'fix-mode' }
+
+ expect(repository.count_commits(options)).to eq(1)
+ end
+
+ context 'with option :left_right' do
+ it 'returns the number of commits for fix-mode...fix-blob-path' do
+ options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true }
+
+ expect(repository.count_commits(options)).to eq([1, 2])
+ end
+
+ context 'with max_count' do
+ it 'returns the number of commits with path ' do
+ options = { from: 'fix-mode', to: 'fix-blob-path', left_right: true, max_count: 1 }
+
+ expect(repository.count_commits(options)).to eq([1, 1])
+ end
+ end
+ end
+ end
+
+ context 'with max_count' do
+ it 'returns the number of commits up to the passed limit' do
+ options = { ref: 'master', max_count: 10, after: Time.iso8601('2013-03-03T20:15:01+00:00') }
+
+ expect(repository.count_commits(options)).to eq(10)
+ end
+ end
end
context 'when Gitaly count_commits feature is enabled' do
@@ -1625,7 +1712,7 @@ describe Gitlab::Git::Repository, seed_helper: true do
let(:branch_name) { "to-be-deleted-soon" }
before do
- project.team << [user, :developer]
+ project.add_developer(user)
repository.create_branch(branch_name)
end
@@ -1662,21 +1749,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- describe '#fetch_remote_without_shell' do
- let(:git_path) { Gitlab.config.git.bin_path }
- let(:remote_name) { 'my_remote' }
-
- subject { repository.fetch_remote_without_shell(remote_name) }
-
- it 'fetches the remote and returns true if the command was successful' do
- expect(repository).to receive(:popen)
- .with(%W(#{git_path} fetch #{remote_name}), repository.path, {})
- .and_return(['', 0])
-
- expect(subject).to be(true)
- end
- end
-
describe '#merge' do
let(:repository) do
Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
@@ -1704,6 +1776,20 @@ describe Gitlab::Git::Repository, seed_helper: true do
expect(result.repo_created).to eq(false)
expect(result.branch_created).to eq(false)
end
+
+ it 'returns nil if there was a concurrent branch update' do
+ concurrent_update_id = '33f3729a45c02fc67d00adb1b8bca394b0e761d9'
+ result = repository.merge(user, source_sha, target_branch, 'Test merge') do
+ # This ref update should make the merge fail
+ repository.write_ref(Gitlab::Git::BRANCH_REF_PREFIX + target_branch, concurrent_update_id)
+ end
+
+ # This 'nil' signals that the merge was not applied
+ expect(result).to be_nil
+
+ # Our concurrent ref update should not have been undone
+ expect(repository.find_branch(target_branch).target).to eq(concurrent_update_id)
+ end
end
context 'with gitaly' do
@@ -1813,6 +1899,166 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
+ describe 'remotes' do
+ let(:repository) do
+ Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '')
+ end
+ let(:remote_name) { 'my-remote' }
+
+ after do
+ ensure_seeds
+ end
+
+ describe '#add_remote' do
+ let(:url) { 'http://my-repo.git' }
+ let(:mirror_refmap) { '+refs/*:refs/*' }
+
+ it 'creates a new remote via Gitaly' do
+ expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
+ .to receive(:add_remote).with(remote_name, url, mirror_refmap)
+
+ repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap)
+ end
+
+ context 'with Gitaly disabled', :skip_gitaly_mock do
+ it 'creates a new remote via Rugged' do
+ expect_any_instance_of(Rugged::RemoteCollection).to receive(:create)
+ .with(remote_name, url)
+ expect_any_instance_of(Rugged::Config).to receive(:[]=)
+ .with("remote.#{remote_name}.mirror", true)
+ expect_any_instance_of(Rugged::Config).to receive(:[]=)
+ .with("remote.#{remote_name}.prune", true)
+ expect_any_instance_of(Rugged::Config).to receive(:[]=)
+ .with("remote.#{remote_name}.fetch", mirror_refmap)
+
+ repository.add_remote(remote_name, url, mirror_refmap: mirror_refmap)
+ end
+ end
+ end
+
+ describe '#remove_remote' do
+ it 'removes the remote via Gitaly' do
+ expect_any_instance_of(Gitlab::GitalyClient::RemoteService)
+ .to receive(:remove_remote).with(remote_name)
+
+ repository.remove_remote(remote_name)
+ end
+
+ context 'with Gitaly disabled', :skip_gitaly_mock do
+ it 'removes the remote via Rugged' do
+ expect_any_instance_of(Rugged::RemoteCollection).to receive(:delete)
+ .with(remote_name)
+
+ repository.remove_remote(remote_name)
+ end
+ end
+ end
+ end
+
+ describe '#gitlab_projects' do
+ subject { repository.gitlab_projects }
+
+ it { expect(subject.shard_path).to eq(storage_path) }
+ it { expect(subject.repository_relative_path).to eq(repository.relative_path) }
+ end
+
+ context 'gitlab_projects commands' do
+ let(:gitlab_projects) { repository.gitlab_projects }
+ let(:timeout) { Gitlab.config.gitlab_shell.git_timeout }
+
+ describe '#push_remote_branches' do
+ subject do
+ repository.push_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:push_branches)
+ .with('downstream-remote', timeout, true, ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:push_branches)
+ .with('downstream-remote', timeout, true, ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
+
+ describe '#delete_remote_branches' do
+ subject do
+ repository.delete_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
+
+ describe '#delete_remote_branches' do
+ subject do
+ repository.delete_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
+
+ describe '#delete_remote_branches' do
+ subject do
+ repository.delete_remote_branches('downstream-remote', ['master'])
+ end
+
+ it 'executes the command' do
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(true)
+
+ is_expected.to be_truthy
+ end
+
+ it 'raises an error if the command fails' do
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:delete_remote_branches)
+ .with('downstream-remote', ['master'])
+ .and_return(false)
+
+ expect { subject }.to raise_error(Gitlab::Git::CommandError, 'error')
+ end
+ end
+ end
+
def create_remote_branch(repository, remote_name, branch_name, source_branch_name)
source_branch = repository.branches.find { |branch| branch.name == source_branch_name }
rugged = repository.rugged
diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb
index 2db560c2cec..4290fbb0087 100644
--- a/spec/lib/gitlab/git_access_spec.rb
+++ b/spec/lib/gitlab/git_access_spec.rb
@@ -275,7 +275,7 @@ describe Gitlab::GitAccess do
describe '#check_command_disabled!' do
before do
- project.team << [user, :master]
+ project.add_master(user)
end
context 'over http' do
@@ -404,7 +404,7 @@ describe Gitlab::GitAccess do
describe 'reporter user' do
before do
- project.team << [user, :reporter]
+ project.add_reporter(user)
end
context 'pull code' do
@@ -417,7 +417,7 @@ describe Gitlab::GitAccess do
context 'when member of the project' do
before do
- project.team << [user, :reporter]
+ project.add_reporter(user)
end
context 'pull code' do
@@ -497,7 +497,7 @@ describe Gitlab::GitAccess do
if role == :admin
user.update_attribute(:admin, true)
else
- project.team << [user, role]
+ project.add_role(user, role)
end
aggregate_failures do
@@ -658,7 +658,7 @@ describe Gitlab::GitAccess do
context 'when project is authorized' do
before do
- project.team << [user, :reporter]
+ project.add_reporter(user)
end
it { expect { push_access_check }.to raise_unauthorized(described_class::ERROR_MESSAGES[:upload]) }
diff --git a/spec/lib/gitlab/git_access_wiki_spec.rb b/spec/lib/gitlab/git_access_wiki_spec.rb
index 1056074264a..186b2d9279d 100644
--- a/spec/lib/gitlab/git_access_wiki_spec.rb
+++ b/spec/lib/gitlab/git_access_wiki_spec.rb
@@ -18,7 +18,7 @@ describe Gitlab::GitAccessWiki do
context 'when user can :create_wiki' do
before do
create(:protected_branch, name: 'master', project: project)
- project.team << [user, :developer]
+ project.add_developer(user)
end
subject { access.check('git-receive-pack', changes) }
@@ -41,7 +41,7 @@ describe Gitlab::GitAccessWiki do
subject { access.check('git-upload-pack', '_any') }
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
context 'when wiki feature is enabled' do
diff --git a/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb b/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb
new file mode 100644
index 00000000000..b9641de7eda
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/conflicts_service_spec.rb
@@ -0,0 +1,90 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::ConflictsService do
+ let(:project) { create(:project, :repository) }
+ let(:target_project) { create(:project, :repository) }
+ let(:source_repository) { project.repository.raw }
+ let(:target_repository) { target_project.repository.raw }
+ let(:target_gitaly_repository) { target_repository.gitaly_repository }
+ let(:our_commit_oid) { 'f00' }
+ let(:their_commit_oid) { 'f44' }
+ let(:client) do
+ described_class.new(target_repository, our_commit_oid, their_commit_oid)
+ end
+
+ describe '#list_conflict_files' do
+ let(:request) do
+ Gitaly::ListConflictFilesRequest.new(
+ repository: target_gitaly_repository, our_commit_oid: our_commit_oid,
+ their_commit_oid: their_commit_oid
+ )
+ end
+ let(:our_path) { 'our/path' }
+ let(:their_path) { 'their/path' }
+ let(:our_mode) { 0744 }
+ let(:header) do
+ double(repository: target_gitaly_repository, commit_oid: our_commit_oid,
+ our_path: our_path, our_mode: 0744, their_path: their_path)
+ end
+ let(:response) do
+ [
+ double(files: [double(header: header), double(content: 'foo', header: nil)]),
+ double(files: [double(content: 'bar', header: nil)])
+ ]
+ end
+ let(:file) { subject[0] }
+
+ subject { client.list_conflict_files }
+
+ it 'sends an RPC request' do
+ expect_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:list_conflict_files)
+ .with(request, kind_of(Hash)).and_return([])
+
+ subject
+ end
+
+ it 'forms a Gitlab::Git::ConflictFile collection from the response' do
+ allow_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:list_conflict_files)
+ .with(request, kind_of(Hash)).and_return(response)
+
+ expect(subject.size).to be(1)
+ expect(file.content).to eq('foobar')
+ expect(file.their_path).to eq(their_path)
+ expect(file.our_path).to eq(our_path)
+ expect(file.our_mode).to be(our_mode)
+ expect(file.repository).to eq(target_repository)
+ expect(file.commit_oid).to eq(our_commit_oid)
+ end
+ end
+
+ describe '#resolve_conflicts' do
+ let(:user) { create(:user) }
+ let(:files) do
+ [{ old_path: 'some/path', new_path: 'some/path', content: '' }]
+ end
+ let(:source_branch) { 'master' }
+ let(:target_branch) { 'feature' }
+ let(:commit_message) { 'Solving conflicts' }
+ let(:resolution) do
+ Gitlab::Git::Conflict::Resolution.new(user, files, commit_message)
+ end
+
+ subject do
+ client.resolve_conflicts(source_repository, resolution, source_branch, target_branch)
+ end
+
+ it 'sends an RPC request' do
+ expect_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:resolve_conflicts)
+ .with(kind_of(Enumerator), kind_of(Hash)).and_return(double(resolution_error: ""))
+
+ subject
+ end
+
+ it 'raises a relevant exception if resolution_error is present' do
+ expect_any_instance_of(Gitaly::ConflictsService::Stub).to receive(:resolve_conflicts)
+ .with(kind_of(Enumerator), kind_of(Hash)).and_return(double(resolution_error: "something happened"))
+
+ expect { subject }.to raise_error(Gitlab::Git::Conflict::Resolver::ResolutionError)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client/remote_service_spec.rb b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb
new file mode 100644
index 00000000000..9d540446532
--- /dev/null
+++ b/spec/lib/gitlab/gitaly_client/remote_service_spec.rb
@@ -0,0 +1,47 @@
+require 'spec_helper'
+
+describe Gitlab::GitalyClient::RemoteService do
+ let(:project) { create(:project) }
+ let(:storage_name) { project.repository_storage }
+ let(:relative_path) { project.disk_path + '.git' }
+ let(:remote_name) { 'my-remote' }
+ let(:client) { described_class.new(project.repository) }
+
+ describe '#add_remote' do
+ let(:url) { 'http://my-repo.git' }
+ let(:mirror_refmap) { :all_refs }
+
+ it 'sends an add_remote message' do
+ expect_any_instance_of(Gitaly::RemoteService::Stub)
+ .to receive(:add_remote)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return(double(:add_remote_response))
+
+ client.add_remote(remote_name, url, mirror_refmap)
+ end
+ end
+
+ describe '#remove_remote' do
+ it 'sends an remove_remote message and returns the result value' do
+ expect_any_instance_of(Gitaly::RemoteService::Stub)
+ .to receive(:remove_remote)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return(double(result: true))
+
+ expect(client.remove_remote(remote_name)).to be(true)
+ end
+ end
+
+ describe '#fetch_internal_remote' do
+ let(:remote_repository) { Gitlab::Git::Repository.new('default', TEST_MUTABLE_REPO_PATH, '') }
+
+ it 'sends an fetch_internal_remote message and returns the result value' do
+ expect_any_instance_of(Gitaly::RemoteService::Stub)
+ .to receive(:fetch_internal_remote)
+ .with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
+ .and_return(double(result: true))
+
+ expect(client.fetch_internal_remote(remote_repository)).to be(true)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/gitaly_client_spec.rb b/spec/lib/gitlab/gitaly_client_spec.rb
index a871ed0df0e..309b7338ef0 100644
--- a/spec/lib/gitlab/gitaly_client_spec.rb
+++ b/spec/lib/gitlab/gitaly_client_spec.rb
@@ -38,20 +38,6 @@ describe Gitlab::GitalyClient, skip_gitaly_mock: true do
end
end
- describe 'encode' do
- [
- [nil, ""],
- ["", ""],
- [" ", " "],
- %w(a1 a1),
- ["编码", "\xE7\xBC\x96\xE7\xA0\x81".b]
- ].each do |input, result|
- it "encodes #{input.inspect} to #{result.inspect}" do
- expect(described_class.encode(input)).to eq result
- end
- end
- end
-
describe 'allow_n_plus_1_calls' do
context 'when RequestStore is enabled', :request_store do
it 'returns the result of the allow_n_plus_1_calls block' do
diff --git a/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb b/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb
index 168e5d07504..46a57e08963 100644
--- a/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb
+++ b/spec/lib/gitlab/github_import/importer/repository_importer_spec.rb
@@ -70,7 +70,7 @@ describe Gitlab::GithubImport::Importer::RepositoryImporter do
describe '#execute' do
it 'imports the repository and wiki' do
- expect(repository)
+ expect(project)
.to receive(:empty_repo?)
.and_return(true)
@@ -93,7 +93,7 @@ describe Gitlab::GithubImport::Importer::RepositoryImporter do
end
it 'does not import the repository if it already exists' do
- expect(repository)
+ expect(project)
.to receive(:empty_repo?)
.and_return(false)
@@ -115,7 +115,7 @@ describe Gitlab::GithubImport::Importer::RepositoryImporter do
end
it 'does not import the wiki if it is disabled' do
- expect(repository)
+ expect(project)
.to receive(:empty_repo?)
.and_return(true)
@@ -137,7 +137,7 @@ describe Gitlab::GithubImport::Importer::RepositoryImporter do
end
it 'does not import the wiki if the repository could not be imported' do
- expect(repository)
+ expect(project)
.to receive(:empty_repo?)
.and_return(true)
diff --git a/spec/lib/gitlab/google_code_import/importer_spec.rb b/spec/lib/gitlab/google_code_import/importer_spec.rb
index 798ea0bac58..017facd0f5e 100644
--- a/spec/lib/gitlab/google_code_import/importer_spec.rb
+++ b/spec/lib/gitlab/google_code_import/importer_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::GoogleCodeImport::Importer do
subject { described_class.new(project) }
before do
- project.team << [project.creator, :master]
+ project.add_master(project.creator)
project.create_import_data(data: import_data)
end
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index f0752649121..7580b62cfc0 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -6465,78 +6465,100 @@
}
}
],
- "statuses": [
- {
- "id": 71,
- "project_id": 5,
- "status": "failed",
- "finished_at": "2016-03-29T06:28:12.630Z",
- "trace": null,
- "created_at": "2016-03-22T15:20:35.772Z",
- "updated_at": "2016-03-29T06:28:12.634Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 36,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
- "erased_by_id": null,
- "erased_at": null,
- "type": "Ci::Build",
- "token": "abcd"
- },
- {
- "id": 72,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.",
- "created_at": "2016-03-22T15:20:35.777Z",
- "updated_at": "2016-03-22T15:20:35.777Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 36,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 11,
+ "project_id": 5,
+ "pipeline_id": 36,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 71,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": "2016-03-29T06:28:12.630Z",
+ "trace": null,
+ "created_at": "2016-03-22T15:20:35.772Z",
+ "updated_at": "2016-03-29T06:28:12.634Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 36,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "stage_id": 11,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": null
+ },
+ "artifacts_metadata": {
+ "url": null
+ },
+ "erased_by_id": null,
+ "erased_at": null,
+ "type": "Ci::Build",
+ "token": "abcd"
+ },
+ {
+ "id": 72,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Porro ea qui ut dolores. Labore ab nemo explicabo aspernatur quis voluptates corporis. Et quasi delectus est sit aperiam perspiciatis asperiores. Repudiandae cum aut consectetur accusantium officia sunt.\n\nQuidem dolore iusto quaerat ut aut inventore et molestiae. Libero voluptates atque nemo qui. Nulla temporibus ipsa similique facere.\n\nAliquam ipsam perferendis qui fugit accusantium omnis id voluptatum. Dignissimos aliquid dicta eos voluptatem assumenda quia. Sed autem natus unde dolor et non nisi et. Consequuntur nihil consequatur rerum est.\n\nSimilique neque est iste ducimus qui fuga cupiditate. Libero autem est aut fuga. Consectetur natus quis non ducimus ut dolore. Magni voluptatibus eius et maxime aut.\n\nAd officiis tempore voluptate vitae corrupti explicabo labore est. Consequatur expedita et sunt nihil aut. Deleniti porro iusto molestiae et beatae.\n\nDeleniti modi nulla qui et labore sequi corrupti. Qui voluptatem assumenda eum cupiditate et. Nesciunt ipsam ut ea possimus eum. Consectetur quidem suscipit atque dolore itaque voluptatibus et cupiditate.",
+ "created_at": "2016-03-22T15:20:35.777Z",
+ "updated_at": "2016-03-22T15:20:35.777Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 36,
+ "commands": "$ deploy command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "deploy",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "stage_id": 12,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/72/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
+ },
+ {
+ "id": 12,
+ "project_id": 5,
+ "pipeline_id": 36,
+ "name": "deploy",
+ "status": 2,
+ "created_at": "2016-03-22T15:45:45.772Z",
+ "updated_at": "2016-03-29T06:45:45.634Z"
}
]
},
@@ -6556,76 +6578,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 74,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.",
- "created_at": "2016-03-22T15:20:35.846Z",
- "updated_at": "2016-03-22T15:20:35.846Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 37,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 73,
- "project_id": 5,
- "status": "canceled",
- "finished_at": null,
- "trace": null,
- "created_at": "2016-03-22T15:20:35.842Z",
- "updated_at": "2016-03-22T15:20:35.842Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 37,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 21,
+ "project_id": 5,
+ "pipeline_id": 37,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 74,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Ad ut quod repudiandae iste dolor doloribus. Adipisci consequuntur deserunt omnis quasi eveniet et sed fugit. Aut nemo omnis molestiae impedit ex consequatur ducimus. Voluptatum exercitationem quia aut est et hic dolorem.\n\nQuasi repellendus et eaque magni eum facilis. Dolorem aperiam nam nihil pariatur praesentium ad aliquam. Commodi enim et eos tenetur. Odio voluptatibus laboriosam mollitia rerum exercitationem magnam consequuntur. Tenetur ea vel eum corporis.\n\nVoluptatibus optio in aliquid est voluptates. Ad a ut ab placeat vero blanditiis. Earum aspernatur quia beatae expedita voluptatem dignissimos provident. Quis minima id nemo ut aut est veritatis provident.\n\nRerum voluptatem quidem eius maiores magnam veniam. Voluptatem aperiam aut voluptate et nulla deserunt voluptas. Quaerat aut accusantium laborum est dolorem architecto reiciendis. Aliquam asperiores doloribus omnis maxime enim nesciunt. Eum aut rerum repellendus debitis et ut eius.\n\nQuaerat assumenda ea sit consequatur autem in. Cum eligendi voluptatem quo sed. Ut fuga iusto cupiditate autem sint.\n\nOfficia totam officiis architecto corporis molestiae amet ut. Tempora sed dolorum rerum omnis voluptatem accusantium sit eum. Quia debitis ipsum quidem aliquam inventore sunt consequatur qui.",
+ "created_at": "2016-03-22T15:20:35.846Z",
+ "updated_at": "2016-03-22T15:20:35.846Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 37,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/74/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 73,
+ "project_id": 5,
+ "status": "canceled",
+ "finished_at": null,
+ "trace": null,
+ "created_at": "2016-03-22T15:20:35.842Z",
+ "updated_at": "2016-03-22T15:20:35.842Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 37,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": null
+ },
+ "artifacts_metadata": {
+ "url": null
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
},
@@ -6645,76 +6678,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 76,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.",
- "created_at": "2016-03-22T15:20:35.882Z",
- "updated_at": "2016-03-22T15:20:35.882Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 38,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 75,
- "project_id": 5,
- "status": "failed",
- "finished_at": null,
- "trace": "Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.",
- "created_at": "2016-03-22T15:20:35.864Z",
- "updated_at": "2016-03-22T15:20:35.864Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 38,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 22,
+ "project_id": 5,
+ "pipeline_id": 38,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 76,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Et rerum quia ea cumque ut modi non. Libero eaque ipsam architecto maiores expedita deleniti. Ratione quia qui est id.\n\nQuod sit officiis sed unde inventore veniam quisquam velit. Ea harum cum quibusdam quisquam minima quo possimus non. Temporibus itaque aliquam aut rerum veritatis at.\n\nMagnam ipsum eius recusandae qui quis sit maiores eum. Et animi iusto aut itaque. Doloribus harum deleniti nobis accusantium et libero.\n\nRerum fuga perferendis magni commodi officiis id repudiandae. Consequatur ratione consequatur suscipit facilis sunt iure est dicta. Qui unde quasi facilis et quae nesciunt. Magnam iste et nobis officiis tenetur. Aspernatur quo et temporibus non in.\n\nNisi rerum velit est ad enim sint molestiae consequuntur. Quaerat nisi nesciunt quasi officiis. Possimus non blanditiis laborum quos.\n\nRerum laudantium facere animi qui. Ipsa est iusto magnam nihil. Enim omnis occaecati non dignissimos ut recusandae eum quasi. Qui maxime dolor et nemo voluptates incidunt quia.",
+ "created_at": "2016-03-22T15:20:35.882Z",
+ "updated_at": "2016-03-22T15:20:35.882Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 38,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/76/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 75,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": null,
+ "trace": "Sed et iste recusandae dicta corporis. Sunt alias porro fugit sunt. Fugiat omnis nihil dignissimos aperiam explicabo doloremque sit aut. Harum fugit expedita quia rerum ut consequatur laboriosam aliquam.\n\nNatus libero ut ut tenetur earum. Tempora omnis autem omnis et libero dolores illum autem. Deleniti eos sunt mollitia ipsam. Cum dolor repellendus dolorum sequi officia. Ullam sunt in aut pariatur excepturi.\n\nDolor nihil debitis et est eos. Cumque eos eum saepe ducimus autem. Alias architecto consequatur aut pariatur possimus. Aut quos aut incidunt quam velit et. Quas voluptatum ad dolorum dignissimos.\n\nUt voluptates consectetur illo et. Est commodi accusantium vel quo. Eos qui fugiat soluta porro.\n\nRatione possimus alias vel maxime sint totam est repellat. Ipsum corporis eos sint voluptatem eos odit. Temporibus libero nulla harum eligendi labore similique ratione magnam. Suscipit sequi in omnis neque.\n\nLaudantium dolor amet omnis placeat mollitia aut molestiae. Aut rerum similique ipsum quod illo quas unde. Sunt aut veritatis eos omnis porro. Rem veritatis mollitia praesentium dolorem. Consequatur sequi ad cumque earum omnis quia necessitatibus.",
+ "created_at": "2016-03-22T15:20:35.864Z",
+ "updated_at": "2016-03-22T15:20:35.864Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 38,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/75/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
},
@@ -6734,76 +6778,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 78,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.",
- "created_at": "2016-03-22T15:20:35.927Z",
- "updated_at": "2016-03-22T15:20:35.927Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 39,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 77,
- "project_id": 5,
- "status": "failed",
- "finished_at": null,
- "trace": "Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.",
- "created_at": "2016-03-22T15:20:35.905Z",
- "updated_at": "2016-03-22T15:20:35.905Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 39,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 23,
+ "project_id": 5,
+ "pipeline_id": 39,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 78,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Dolorem deserunt quas quia error hic quo cum vel. Natus voluptatem cumque expedita numquam odit. Eos expedita nostrum corporis consequatur est recusandae.\n\nCulpa blanditiis rerum repudiandae alias voluptatem. Velit iusto est ullam consequatur doloribus porro. Corporis voluptas consectetur est veniam et quia quae.\n\nEt aut magni fuga nesciunt officiis molestias. Quaerat et nam necessitatibus qui rerum. Architecto quia officiis voluptatem laborum est recusandae. Quasi ducimus soluta odit necessitatibus labore numquam dignissimos. Quia facere sint temporibus inventore sunt nihil saepe dolorum.\n\nFacere dolores quis dolores a. Est minus nostrum nihil harum. Earum laborum et ipsum unde neque sit nemo. Corrupti est consequatur minima fugit. Illum voluptatem illo error ducimus officia qui debitis.\n\nDignissimos porro a autem harum aut. Aut id reprehenderit et exercitationem. Est et quisquam ipsa temporibus molestiae. Architecto natus dolore qui fugiat incidunt. Autem odit veniam excepturi et voluptatibus culpa ipsum eos.\n\nAmet quo quisquam dignissimos soluta modi dolores. Sint omnis eius optio corporis dolor. Eligendi animi porro quia placeat ut.",
+ "created_at": "2016-03-22T15:20:35.927Z",
+ "updated_at": "2016-03-22T15:20:35.927Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 39,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/78/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 77,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": null,
+ "trace": "Rerum ut et suscipit est perspiciatis. Inventore debitis cum eius vitae. Ex incidunt id velit aut quo nisi. Laboriosam repellat deserunt eius reiciendis architecto et. Est harum quos nesciunt nisi consectetur.\n\nAlias esse omnis sint officia est consequatur in nobis. Dignissimos dolorum vel eligendi nesciunt dolores sit. Veniam mollitia ducimus et exercitationem molestiae libero sed. Atque omnis debitis laudantium voluptatibus qui. Repellendus tempore est commodi pariatur.\n\nExpedita voluptate illum est alias non. Modi nesciunt ab assumenda laborum nulla consequatur molestias doloremque. Magnam quod officia vel explicabo accusamus ut voluptatem incidunt. Rerum ut aliquid ullam saepe. Est eligendi debitis beatae blanditiis reiciendis.\n\nQui fuga sit dolores libero maiores et suscipit. Consectetur asperiores omnis minima impedit eos fugiat. Similique omnis nisi sed vero inventore ipsum aliquam exercitationem.\n\nBlanditiis magni iure dolorum omnis ratione delectus molestiae. Atque officia dolor voluptatem culpa quod. Incidunt suscipit quidem possimus veritatis non vel. Iusto aliquid et id quia quasi.\n\nVel facere velit blanditiis incidunt cupiditate sed maiores consequuntur. Quasi quia dicta consequuntur et quia voluptatem iste id. Incidunt et rerum fuga esse sint.",
+ "created_at": "2016-03-22T15:20:35.905Z",
+ "updated_at": "2016-03-22T15:20:35.905Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 39,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/77/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
},
@@ -6823,76 +6878,87 @@
"started_at": null,
"finished_at": null,
"duration": null,
- "statuses": [
- {
- "id": 79,
- "project_id": 5,
- "status": "failed",
- "finished_at": "2016-03-29T06:28:12.695Z",
- "trace": "Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.",
- "created_at": "2016-03-22T15:20:35.950Z",
- "updated_at": "2016-03-29T06:28:12.696Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 40,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 1",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": null
- },
- "artifacts_metadata": {
- "url": null
- },
- "erased_by_id": null,
- "erased_at": null
- },
- {
- "id": 80,
- "project_id": 5,
- "status": "success",
- "finished_at": null,
- "trace": "Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.",
- "created_at": "2016-03-22T15:20:35.966Z",
- "updated_at": "2016-03-22T15:20:35.966Z",
- "started_at": null,
- "runner_id": null,
- "coverage": null,
- "commit_id": 40,
- "commands": "$ build command",
- "job_id": null,
- "name": "test build 2",
- "deploy": false,
- "options": null,
- "allow_failure": false,
- "stage": "test",
- "trigger_request_id": null,
- "stage_idx": 1,
- "tag": null,
- "ref": "master",
- "user_id": null,
- "target_url": null,
- "description": null,
- "artifacts_file": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip"
- },
- "artifacts_metadata": {
- "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz"
- },
- "erased_by_id": null,
- "erased_at": null
+ "stages": [
+ {
+ "id": 24,
+ "project_id": 5,
+ "pipeline_id": 40,
+ "name": "test",
+ "status": 1,
+ "created_at": "2016-03-22T15:44:44.772Z",
+ "updated_at": "2016-03-29T06:44:44.634Z",
+ "statuses": [
+ {
+ "id": 79,
+ "project_id": 5,
+ "status": "failed",
+ "finished_at": "2016-03-29T06:28:12.695Z",
+ "trace": "Sed culpa est et facere saepe vel id ab. Quas temporibus aut similique dolorem consequatur corporis aut praesentium. Cum officia molestiae sit earum excepturi.\n\nSint possimus aut ratione quia. Quis nesciunt ratione itaque illo. Tenetur est dolor assumenda possimus voluptatem quia minima. Accusamus reprehenderit ut et itaque non reiciendis incidunt.\n\nRerum suscipit quibusdam dolore nam omnis. Consequatur ipsa nihil ut enim blanditiis delectus. Nulla quis hic occaecati mollitia qui placeat. Quo rerum sed perferendis a accusantium consequatur commodi ut. Sit quae et cumque vel eius tempora nostrum.\n\nUllam dolorem et itaque sint est. Ea molestias quia provident dolorem vitae error et et. Ea expedita officiis iste non. Qui vitae odit saepe illum. Dolores enim ratione deserunt tempore expedita amet non neque.\n\nEligendi asperiores voluptatibus omnis repudiandae expedita distinctio qui aliquid. Autem aut doloremque distinctio ab. Nostrum sapiente repudiandae aspernatur ea et quae voluptas. Officiis perspiciatis nisi laudantium asperiores error eligendi ab. Eius quia amet magni omnis exercitationem voluptatum et.\n\nVoluptatem ullam labore quas dicta est ex voluptas. Pariatur ea modi voluptas consequatur dolores perspiciatis similique. Numquam in distinctio perspiciatis ut qui earum. Quidem omnis mollitia facere aut beatae. Ea est iure et voluptatem.",
+ "created_at": "2016-03-22T15:20:35.950Z",
+ "updated_at": "2016-03-29T06:28:12.696Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 40,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 1",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": null
+ },
+ "artifacts_metadata": {
+ "url": null
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ },
+ {
+ "id": 80,
+ "project_id": 5,
+ "status": "success",
+ "finished_at": null,
+ "trace": "Impedit et optio nemo ipsa. Non ad non quis ut sequi laudantium omnis velit. Corporis a enim illo eos. Quia totam tempore inventore ad est.\n\nNihil recusandae cupiditate eaque voluptatem molestias sint. Consequatur id voluptatem cupiditate harum. Consequuntur iusto quaerat reiciendis aut autem libero est. Quisquam dolores veritatis rerum et sint maxime ullam libero. Id quas porro ut perspiciatis rem amet vitae.\n\nNemo inventore minus blanditiis magnam. Modi consequuntur nostrum aut voluptatem ex. Sunt rerum rem optio mollitia qui aliquam officiis officia. Aliquid eos et id aut minus beatae reiciendis.\n\nDolores non in temporibus dicta. Fugiat voluptatem est aspernatur expedita voluptatum nam qui. Quia et eligendi sit quae sint tempore exercitationem eos. Est sapiente corrupti quidem at. Qui magni odio repudiandae saepe tenetur optio dolore.\n\nEos placeat soluta at dolorem adipisci provident. Quo commodi id reprehenderit possimus quo tenetur. Ipsum et quae eligendi laborum. Et qui nesciunt at quasi quidem voluptatem cum rerum. Excepturi non facilis aut sunt vero sed.\n\nQui explicabo ratione ut eligendi recusandae. Quis quasi quas molestiae consequatur voluptatem et voluptatem. Ex repellat saepe occaecati aperiam ea eveniet dignissimos facilis.",
+ "created_at": "2016-03-22T15:20:35.966Z",
+ "updated_at": "2016-03-22T15:20:35.966Z",
+ "started_at": null,
+ "runner_id": null,
+ "coverage": null,
+ "commit_id": 40,
+ "commands": "$ build command",
+ "job_id": null,
+ "name": "test build 2",
+ "deploy": false,
+ "options": null,
+ "allow_failure": false,
+ "stage": "test",
+ "trigger_request_id": null,
+ "stage_idx": 1,
+ "tag": null,
+ "ref": "master",
+ "user_id": null,
+ "target_url": null,
+ "description": null,
+ "artifacts_file": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts.zip"
+ },
+ "artifacts_metadata": {
+ "url": "/Users/Test/Test/gitlab-development-kit/gitlab/shared/artifacts/2016_03/5/80/p5_build_artifacts_metadata.gz"
+ },
+ "erased_by_id": null,
+ "erased_at": null
+ }
+ ]
}
]
}
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 0ab3afd0074..9dfd879a1bc 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -179,6 +179,32 @@ describe Gitlab::ImportExport::ProjectTreeRestorer do
end
end
end
+
+ context 'when restoring hierarchy of pipeline, stages and jobs' do
+ it 'restores pipelines' do
+ expect(Ci::Pipeline.all.count).to be 5
+ end
+
+ it 'restores pipeline stages' do
+ expect(Ci::Stage.all.count).to be 6
+ end
+
+ it 'correctly restores association between stage and a pipeline' do
+ expect(Ci::Stage.all).to all(have_attributes(pipeline_id: a_value > 0))
+ end
+
+ it 'restores statuses' do
+ expect(CommitStatus.all.count).to be 10
+ end
+
+ it 'correctly restores association between a stage and a job' do
+ expect(CommitStatus.all).to all(have_attributes(stage_id: a_value > 0))
+ end
+
+ it 'correctly restores association between a pipeline and a job' do
+ expect(CommitStatus.all).to all(have_attributes(pipeline_id: a_value > 0))
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index 6243b6ac9f0..08e5bbbd400 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -9,7 +9,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
let!(:project) { setup_project }
before do
- project.team << [user, :master]
+ project.add_master(user)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
allow_any_instance_of(MergeRequest).to receive(:source_branch_sha).and_return('ABCD')
allow_any_instance_of(MergeRequest).to receive(:target_branch_sha).and_return('DCBA')
@@ -109,12 +109,20 @@ describe Gitlab::ImportExport::ProjectTreeSaver do
expect(saved_project_json['merge_requests'].first['notes'].first['author']).not_to be_empty
end
+ it 'has pipeline stages' do
+ expect(saved_project_json.dig('pipelines', 0, 'stages')).not_to be_empty
+ end
+
it 'has pipeline statuses' do
- expect(saved_project_json['pipelines'].first['statuses']).not_to be_empty
+ expect(saved_project_json.dig('pipelines', 0, 'stages', 0, 'statuses')).not_to be_empty
end
it 'has pipeline builds' do
- expect(saved_project_json['pipelines'].first['statuses'].count { |hash| hash['type'] == 'Ci::Build' }).to eq(1)
+ builds_count = saved_project_json
+ .dig('pipelines', 0, 'stages', 0, 'statuses')
+ .count { |hash| hash['type'] == 'Ci::Build' }
+
+ expect(builds_count).to eq(1)
end
it 'has no when YML attributes but only the DB column' do
diff --git a/spec/lib/gitlab/import_export/repo_saver_spec.rb b/spec/lib/gitlab/import_export/repo_saver_spec.rb
index e6ad516deef..44f972fe530 100644
--- a/spec/lib/gitlab/import_export/repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/repo_saver_spec.rb
@@ -9,7 +9,7 @@ describe Gitlab::ImportExport::RepoSaver do
let(:bundler) { described_class.new(project: project, shared: shared) }
before do
- project.team << [user, :master]
+ project.add_master(user)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
end
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index ec8fa99e0da..ec577903eb5 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -459,6 +459,7 @@ Project:
- delete_error
- merge_requests_ff_only_enabled
- merge_requests_rebase_enabled
+- jobs_cache_index
Author:
- name
ProjectFeature:
diff --git a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
index 0e55993c8ef..1d1e7e7f89a 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::ImportExport::WikiRepoSaver do
let!(:project_wiki) { ProjectWiki.new(project, user) }
before do
- project.team << [user, :master]
+ project.add_master(user)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
project_wiki.wiki
project_wiki.create_page("index", "test content")
diff --git a/spec/lib/gitlab/kubernetes/helm_spec.rb b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
index 15f99b0401f..69112fe90b1 100644
--- a/spec/lib/gitlab/kubernetes/helm_spec.rb
+++ b/spec/lib/gitlab/kubernetes/helm/api_spec.rb
@@ -1,22 +1,23 @@
require 'spec_helper'
-describe Gitlab::Kubernetes::Helm do
+describe Gitlab::Kubernetes::Helm::Api do
let(:client) { double('kubernetes client') }
let(:helm) { described_class.new(client) }
- let(:namespace) { Gitlab::Kubernetes::Namespace.new(described_class::NAMESPACE, client) }
+ let(:gitlab_namespace) { Gitlab::Kubernetes::Helm::NAMESPACE }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(gitlab_namespace, client) }
let(:install_helm) { true }
let(:chart) { 'stable/a_chart' }
let(:application_name) { 'app_name' }
- let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm, chart) }
+ let(:command) { Gitlab::Kubernetes::Helm::InstallCommand.new(application_name, install_helm: install_helm, chart: chart) }
subject { helm }
before do
- allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client).and_return(namespace)
+ allow(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client).and_return(namespace)
end
describe '#initialize' do
it 'creates a namespace object' do
- expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(described_class::NAMESPACE, client)
+ expect(Gitlab::Kubernetes::Namespace).to receive(:new).with(gitlab_namespace, client)
subject
end
@@ -41,7 +42,7 @@ describe Gitlab::Kubernetes::Helm do
let(:pod) { Kubeclient::Resource.new(status: { phase: phase }) } # partial representation
it 'fetches POD phase from kubernetes cluster' do
- expect(client).to receive(:get_pod).with(command.pod_name, described_class::NAMESPACE).once.and_return(pod)
+ expect(client).to receive(:get_pod).with(command.pod_name, gitlab_namespace).once.and_return(pod)
expect(subject.installation_status(command.pod_name)).to eq(phase)
end
@@ -52,7 +53,7 @@ describe Gitlab::Kubernetes::Helm do
let(:response) { RestClient::Response.new(log) }
it 'fetches POD phase from kubernetes cluster' do
- expect(client).to receive(:get_pod_log).with(command.pod_name, described_class::NAMESPACE).once.and_return(response)
+ expect(client).to receive(:get_pod_log).with(command.pod_name, gitlab_namespace).once.and_return(response)
expect(subject.installation_log(command.pod_name)).to eq(log)
end
@@ -60,41 +61,9 @@ describe Gitlab::Kubernetes::Helm do
describe '#delete_installation_pod!' do
it 'deletes the POD from kubernetes cluster' do
- expect(client).to receive(:delete_pod).with(command.pod_name, described_class::NAMESPACE).once
+ expect(client).to receive(:delete_pod).with(command.pod_name, gitlab_namespace).once
subject.delete_installation_pod!(command.pod_name)
end
end
-
- describe '#helm_init_command' do
- subject { helm.send(:helm_init_command, command) }
-
- context 'when command.install_helm is true' do
- let(:install_helm) { true }
-
- it { is_expected.to eq('helm init >/dev/null') }
- end
-
- context 'when command.install_helm is false' do
- let(:install_helm) { false }
-
- it { is_expected.to eq('helm init --client-only >/dev/null') }
- end
- end
-
- describe '#helm_install_command' do
- subject { helm.send(:helm_install_command, command) }
-
- context 'when command.chart is nil' do
- let(:chart) { nil }
-
- it { is_expected.to be_nil }
- end
-
- context 'when command.chart is set' do
- let(:chart) { 'stable/a_chart' }
-
- it { is_expected.to eq("helm install #{chart} --name #{application_name} --namespace #{namespace.name} >/dev/null")}
- end
- end
end
diff --git a/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
new file mode 100644
index 00000000000..4afe48e72ad
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/install_command_spec.rb
@@ -0,0 +1,111 @@
+require 'rails_helper'
+
+describe Gitlab::Kubernetes::Helm::InstallCommand do
+ let(:prometheus) { create(:clusters_applications_prometheus) }
+
+ describe "#initialize" do
+ context "With all the params" do
+ subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: prometheus.chart_values_file) }
+
+ it 'should assign all parameters' do
+ expect(subject.name).to eq(prometheus.name)
+ expect(subject.install_helm).to be_truthy
+ expect(subject.chart).to eq(prometheus.chart)
+ expect(subject.chart_values_file).to eq("#{Rails.root}/vendor/prometheus/values.yaml")
+ end
+ end
+
+ context 'when install_helm is not set' do
+ subject { described_class.new(prometheus.name, chart: prometheus.chart, chart_values_file: true) }
+
+ it 'should set install_helm as false' do
+ expect(subject.install_helm).to be_falsy
+ end
+ end
+
+ context 'when chart is not set' do
+ subject { described_class.new(prometheus.name, install_helm: true) }
+
+ it 'should set chart as nil' do
+ expect(subject.chart).to be_falsy
+ end
+ end
+
+ context 'when chart_values_file is not set' do
+ subject { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart) }
+
+ it 'should set chart_values_file as nil' do
+ expect(subject.chart_values_file).to be_falsy
+ end
+ end
+ end
+
+ describe "#generate_script" do
+ let(:install_command) { described_class.new(prometheus.name, install_helm: install_helm) }
+ let(:client) { double('kubernetes client') }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) }
+ subject { install_command.send(:generate_script, namespace.name) }
+
+ context 'when install helm is true' do
+ let(:install_helm) { true }
+ let(:command) do
+ <<~MSG
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+
+ context 'when install helm is false' do
+ let(:install_helm) { false }
+ let(:command) do
+ <<~MSG
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init --client-only >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+
+ context 'when chart is present' do
+ let(:install_command) { described_class.new(prometheus.name, chart: prometheus.chart) }
+ let(:command) do
+ <<~MSG.chomp
+ set -eo pipefail
+ apk add -U ca-certificates openssl >/dev/null
+ wget -q -O - https://kubernetes-helm.storage.googleapis.com/helm-v2.7.0-linux-amd64.tar.gz | tar zxC /tmp >/dev/null
+ mv /tmp/linux-amd64/helm /usr/bin/
+
+ helm init --client-only >/dev/null
+ helm install #{prometheus.chart} --name #{prometheus.name} --namespace #{namespace.name} >/dev/null
+ MSG
+ end
+
+ it 'should return appropriate command' do
+ is_expected.to eq(command)
+ end
+ end
+ end
+
+ describe "#pod_name" do
+ let(:install_command) { described_class.new(prometheus.name, install_helm: true, chart: prometheus.chart, chart_values_file: true) }
+ subject { install_command.send(:pod_name) }
+
+ it { is_expected.to eq('install-prometheus') }
+ end
+end
diff --git a/spec/lib/gitlab/kubernetes/helm/pod_spec.rb b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
new file mode 100644
index 00000000000..906b10b96d4
--- /dev/null
+++ b/spec/lib/gitlab/kubernetes/helm/pod_spec.rb
@@ -0,0 +1,86 @@
+require 'rails_helper'
+
+describe Gitlab::Kubernetes::Helm::Pod do
+ describe '#generate' do
+ let(:cluster) { create(:cluster) }
+ let(:app) { create(:clusters_applications_prometheus, cluster: cluster) }
+ let(:command) { app.install_command }
+ let(:client) { double('kubernetes client') }
+ let(:namespace) { Gitlab::Kubernetes::Namespace.new(Gitlab::Kubernetes::Helm::NAMESPACE, client) }
+ subject { described_class.new(command, namespace.name, client) }
+
+ before do
+ allow(client).to receive(:create_config_map).and_return(nil)
+ end
+
+ shared_examples 'helm pod' do
+ it 'should generate a Kubeclient::Resource' do
+ expect(subject.generate).to be_a_kind_of(Kubeclient::Resource)
+ end
+
+ it 'should generate the appropriate metadata' do
+ metadata = subject.generate.metadata
+ expect(metadata.name).to eq("install-#{app.name}")
+ expect(metadata.namespace).to eq('gitlab-managed-apps')
+ expect(metadata.labels['gitlab.org/action']).to eq('install')
+ expect(metadata.labels['gitlab.org/application']).to eq(app.name)
+ end
+
+ it 'should generate a container spec' do
+ spec = subject.generate.spec
+ expect(spec.containers.count).to eq(1)
+ end
+
+ it 'should generate the appropriate specifications for the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.name).to eq('helm')
+ expect(container.image).to eq('alpine:3.6')
+ expect(container.env.count).to eq(3)
+ expect(container.env.map(&:name)).to match_array([:HELM_VERSION, :TILLER_NAMESPACE, :COMMAND_SCRIPT])
+ expect(container.command).to match_array(["/bin/sh"])
+ expect(container.args).to match_array(["-c", "$(COMMAND_SCRIPT)"])
+ end
+
+ it 'should include a never restart policy' do
+ spec = subject.generate.spec
+ expect(spec.restartPolicy).to eq('Never')
+ end
+ end
+
+ context 'with a configuration file' do
+ it_behaves_like 'helm pod'
+
+ it 'should include volumes for the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.volumeMounts.first['name']).to eq('config-volume')
+ expect(container.volumeMounts.first['mountPath']).to eq('/etc/config')
+ end
+
+ it 'should include a volume inside the specification' do
+ spec = subject.generate.spec
+ expect(spec.volumes.first['name']).to eq('config-volume')
+ end
+
+ it 'should mount configMap specification in the volume' do
+ spec = subject.generate.spec
+ expect(spec.volumes.first.configMap['name']).to eq('values-config')
+ end
+ end
+
+ context 'without a configuration file' do
+ let(:app) { create(:clusters_applications_ingress, cluster: cluster) }
+
+ it_behaves_like 'helm pod'
+
+ it 'should not include volumeMounts inside the container' do
+ container = subject.generate.spec.containers.first
+ expect(container.volumeMounts).to be_nil
+ end
+
+ it 'should not a volume inside the specification' do
+ spec = subject.generate.spec
+ expect(spec.volumes).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ldap/adapter_spec.rb b/spec/lib/gitlab/ldap/adapter_spec.rb
index d9ddb4326be..6132abd9b35 100644
--- a/spec/lib/gitlab/ldap/adapter_spec.rb
+++ b/spec/lib/gitlab/ldap/adapter_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search) do |arg|
expect(arg[:filter].to_s).to eq('(uid=johndoe)')
expect(arg[:base]).to eq('dc=example,dc=com')
- expect(arg[:attributes]).to match(%w{dn uid cn mail email userPrincipalName})
+ expect(arg[:attributes]).to match(ldap_attributes)
end.and_return({})
adapter.users('uid', 'johndoe')
@@ -26,7 +26,7 @@ describe Gitlab::LDAP::Adapter do
expect(adapter).to receive(:ldap_search).with(
base: 'uid=johndoe,ou=users,dc=example,dc=com',
scope: Net::LDAP::SearchScope_BaseObject,
- attributes: %w{dn uid cn mail email userPrincipalName},
+ attributes: ldap_attributes,
filter: nil
).and_return({})
@@ -63,7 +63,7 @@ describe Gitlab::LDAP::Adapter do
it 'uses the right uid attribute when non-default' do
stub_ldap_config(uid: 'sAMAccountName')
expect(adapter).to receive(:ldap_search).with(
- hash_including(attributes: %w{dn sAMAccountName cn mail email userPrincipalName})
+ hash_including(attributes: ldap_attributes)
).and_return({})
adapter.users('sAMAccountName', 'johndoe')
@@ -137,4 +137,8 @@ describe Gitlab::LDAP::Adapter do
end
end
end
+
+ def ldap_attributes
+ Gitlab::LDAP::Person.ldap_attributes(Gitlab::LDAP::Config.new('ldapmain'))
+ end
end
diff --git a/spec/lib/gitlab/ldap/person_spec.rb b/spec/lib/gitlab/ldap/person_spec.rb
index d204050ef66..ff29d9aa5be 100644
--- a/spec/lib/gitlab/ldap/person_spec.rb
+++ b/spec/lib/gitlab/ldap/person_spec.rb
@@ -8,13 +8,16 @@ describe Gitlab::LDAP::Person do
before do
stub_ldap_config(
options: {
+ 'uid' => 'uid',
'attributes' => {
- 'name' => 'cn',
- 'email' => %w(mail email userPrincipalName)
+ 'name' => 'cn',
+ 'email' => %w(mail email userPrincipalName),
+ 'username' => username_attribute
}
}
)
end
+ let(:username_attribute) { %w(uid sAMAccountName userid) }
describe '.normalize_dn' do
subject { described_class.normalize_dn(given) }
@@ -44,6 +47,34 @@ describe Gitlab::LDAP::Person do
end
end
+ describe '.ldap_attributes' do
+ it 'returns a compact and unique array' do
+ stub_ldap_config(
+ options: {
+ 'uid' => nil,
+ 'attributes' => {
+ 'name' => 'cn',
+ 'email' => 'mail',
+ 'username' => %w(uid mail memberof)
+ }
+ }
+ )
+ config = Gitlab::LDAP::Config.new('ldapmain')
+ ldap_attributes = described_class.ldap_attributes(config)
+
+ expect(ldap_attributes).to match_array(%w(dn uid cn mail memberof))
+ end
+ end
+
+ describe '.validate_entry' do
+ it 'raises InvalidEntryError' do
+ entry['foo'] = 'bar'
+
+ expect { described_class.new(entry, 'ldapmain') }
+ .to raise_error(Gitlab::LDAP::Person::InvalidEntryError)
+ end
+ end
+
describe '#name' do
it 'uses the configured name attribute and handles values as an array' do
name = 'John Doe'
@@ -72,6 +103,44 @@ describe Gitlab::LDAP::Person do
end
end
+ describe '#username' do
+ context 'with default uid username attribute' do
+ let(:username_attribute) { 'uid' }
+
+ it 'returns the proper username value' do
+ attr_value = 'johndoe'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+
+ context 'with a different username attribute' do
+ let(:username_attribute) { 'sAMAccountName' }
+
+ it 'returns the proper username value' do
+ attr_value = 'johndoe'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+
+ context 'with a non-standard username attribute' do
+ let(:username_attribute) { 'mail' }
+
+ it 'returns the proper username value' do
+ attr_value = 'john.doe@example.com'
+ entry[username_attribute] = attr_value
+ person = described_class.new(entry, 'ldapmain')
+
+ expect(person.username).to eq(attr_value)
+ end
+ end
+ end
+
def assert_generic_test(test_description, got, expected)
test_failure_message = "Failed test description: '#{test_description}'\n\n expected: #{expected}\n got: #{got}"
expect(got).to eq(expected), test_failure_message
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index 260df6e4dae..048caa38fcf 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -38,7 +38,6 @@ describe Gitlab::LDAP::User do
it "does not mark existing ldap user as changed" do
create(:omniauth_user, email: 'john@example.com', extern_uid: 'uid=john smith,ou=people,dc=example,dc=com', provider: 'ldapmain')
- ldap_user.gl_user.user_synced_attributes_metadata(provider: 'ldapmain', email: true)
expect(ldap_user.changed?).to be_falsey
end
end
@@ -144,11 +143,15 @@ describe Gitlab::LDAP::User do
expect(ldap_user.gl_user.email).to eq(info[:email])
end
- it "has user_synced_attributes_metadata email set to true" do
+ it "has email set as synced" do
expect(ldap_user.gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
end
- it "has synced_attribute_provider set to ldapmain" do
+ it "has email set as read-only" do
+ expect(ldap_user.gl_user.read_only_attribute?(:email)).to be_truthy
+ end
+
+ it "has synced attributes provider set to ldapmain" do
expect(ldap_user.gl_user.user_synced_attributes_metadata.provider).to eql 'ldapmain'
end
end
@@ -162,9 +165,13 @@ describe Gitlab::LDAP::User do
expect(ldap_user.gl_user.temp_oauth_email?).to be_truthy
end
- it "has synced attribute email set to false" do
+ it "has email set as not synced" do
expect(ldap_user.gl_user.user_synced_attributes_metadata.email_synced).to be_falsey
end
+
+ it "does not have email set as read-only" do
+ expect(ldap_user.gl_user.read_only_attribute?(:email)).to be_falsey
+ end
end
end
diff --git a/spec/lib/gitlab/metrics/method_call_spec.rb b/spec/lib/gitlab/metrics/method_call_spec.rb
index 5341addf911..41a9d1d9c90 100644
--- a/spec/lib/gitlab/metrics/method_call_spec.rb
+++ b/spec/lib/gitlab/metrics/method_call_spec.rb
@@ -20,9 +20,39 @@ describe Gitlab::Metrics::MethodCall do
context 'prometheus instrumentation is enabled' do
before do
+ allow(Feature.get(:prometheus_metrics_method_instrumentation)).to receive(:enabled?).and_call_original
+ described_class.measurement_enabled_cache_expires_at.value = Time.now.to_i - 1
Feature.get(:prometheus_metrics_method_instrumentation).enable
end
+ around do |example|
+ Timecop.freeze do
+ example.run
+ end
+ end
+
+ it 'caches subsequent invocations of feature check' do
+ 10.times do
+ method_call.measure { 'foo' }
+ end
+
+ expect(Feature.get(:prometheus_metrics_method_instrumentation)).to have_received(:enabled?).once
+ end
+
+ it 'expires feature check cache after 1 minute' do
+ method_call.measure { 'foo' }
+
+ Timecop.travel(1.minute.from_now) do
+ method_call.measure { 'foo' }
+ end
+
+ Timecop.travel(1.minute.from_now + 1.second) do
+ method_call.measure { 'foo' }
+ end
+
+ expect(Feature.get(:prometheus_metrics_method_instrumentation)).to have_received(:enabled?).twice
+ end
+
it 'observes the performance of the supplied block' do
expect(described_class.call_duration_histogram)
.to receive(:observe)
@@ -34,6 +64,8 @@ describe Gitlab::Metrics::MethodCall do
context 'prometheus instrumentation is disabled' do
before do
+ described_class.measurement_enabled_cache_expires_at.value = Time.now.to_i - 1
+
Feature.get(:prometheus_metrics_method_instrumentation).disable
end
@@ -64,14 +96,17 @@ describe Gitlab::Metrics::MethodCall do
describe '#to_metric' do
it 'returns a Metric instance' do
+ expect(method_call).to receive(:real_time).and_return(4.0001)
+ expect(method_call).to receive(:cpu_time).and_return(3.0001)
+
method_call.measure { 'foo' }
metric = method_call.to_metric
expect(metric).to be_an_instance_of(Gitlab::Metrics::Metric)
expect(metric.series).to eq('rails_method_calls')
- expect(metric.values[:duration]).to be_a_kind_of(Numeric)
- expect(metric.values[:cpu_duration]).to be_a_kind_of(Numeric)
+ expect(metric.values[:duration]).to eq(4000)
+ expect(metric.values[:cpu_duration]).to eq(3000)
expect(metric.values[:call_count]).to be_an(Integer)
expect(metric.tags).to eq({ method: 'Foo#bar' })
@@ -84,13 +119,13 @@ describe Gitlab::Metrics::MethodCall do
end
it 'returns false when the total call time is not above the threshold' do
- expect(method_call).to receive(:real_time).and_return(9)
+ expect(method_call).to receive(:real_time).and_return(0.009)
expect(method_call.above_threshold?).to eq(false)
end
it 'returns true when the total call time is above the threshold' do
- expect(method_call).to receive(:real_time).and_return(9000)
+ expect(method_call).to receive(:real_time).and_return(9)
expect(method_call.above_threshold?).to eq(true)
end
diff --git a/spec/lib/gitlab/metrics/system_spec.rb b/spec/lib/gitlab/metrics/system_spec.rb
index 4d94d8705fb..14afcdf5daa 100644
--- a/spec/lib/gitlab/metrics/system_spec.rb
+++ b/spec/lib/gitlab/metrics/system_spec.rb
@@ -29,19 +29,19 @@ describe Gitlab::Metrics::System do
describe '.cpu_time' do
it 'returns a Fixnum' do
- expect(described_class.cpu_time).to be_an(Integer)
+ expect(described_class.cpu_time).to be_an(Float)
end
end
describe '.real_time' do
it 'returns a Fixnum' do
- expect(described_class.real_time).to be_an(Integer)
+ expect(described_class.real_time).to be_an(Float)
end
end
describe '.monotonic_time' do
- it 'returns a Fixnum' do
- expect(described_class.monotonic_time).to be_an(Integer)
+ it 'returns a Float' do
+ expect(described_class.monotonic_time).to be_an(Float)
end
end
end
diff --git a/spec/lib/gitlab/o_auth/user_spec.rb b/spec/lib/gitlab/o_auth/user_spec.rb
index 2f19fb7312d..45fff4c5787 100644
--- a/spec/lib/gitlab/o_auth/user_spec.rb
+++ b/spec/lib/gitlab/o_auth/user_spec.rb
@@ -202,11 +202,13 @@ describe Gitlab::OAuth::User do
end
context "and no account for the LDAP user" do
- it "creates a user with dual LDAP and omniauth identities" do
+ before do
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
oauth_user.save
+ end
+ it "creates a user with dual LDAP and omniauth identities" do
expect(gl_user).to be_valid
expect(gl_user.username).to eql uid
expect(gl_user.email).to eql 'johndoe@example.com'
@@ -219,6 +221,18 @@ describe Gitlab::OAuth::User do
]
)
end
+
+ it "has email set as synced" do
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
+ end
+
+ it "has email set as read-only" do
+ expect(gl_user.read_only_attribute?(:email)).to be_truthy
+ end
+
+ it "has synced attributes provider set to ldapmain" do
+ expect(gl_user.user_synced_attributes_metadata.provider).to eql 'ldapmain'
+ end
end
context "and LDAP user has an account already" do
@@ -261,6 +275,26 @@ describe Gitlab::OAuth::User do
end
end
+ context 'and a corresponding LDAP person with a non-default username' do
+ before do
+ allow(ldap_user).to receive(:uid) { uid }
+ allow(ldap_user).to receive(:username) { 'johndoe@example.com' }
+ allow(ldap_user).to receive(:email) { %w(johndoe@example.com john2@example.com) }
+ allow(ldap_user).to receive(:dn) { dn }
+ end
+
+ context 'and no account for the LDAP user' do
+ it 'creates a user favoring the LDAP username and strips email domain' do
+ allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(ldap_user)
+
+ oauth_user.save
+
+ expect(gl_user).to be_valid
+ expect(gl_user.username).to eql 'johndoe'
+ end
+ end
+ end
+
context "and no corresponding LDAP person" do
before do
allow(Gitlab::LDAP::Person).to receive(:find_by_uid).and_return(nil)
@@ -440,11 +474,15 @@ describe Gitlab::OAuth::User do
expect(gl_user.email).to eq(info_hash[:email])
end
- it "has external_attributes set to true" do
- expect(gl_user.user_synced_attributes_metadata).not_to be_nil
+ it "has email set as synced" do
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be_truthy
end
- it "has attributes_provider set to my-provider" do
+ it "has email set as read-only" do
+ expect(gl_user.read_only_attribute?(:email)).to be_truthy
+ end
+
+ it "has synced attributes provider set to my-provider" do
expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
end
end
@@ -458,10 +496,13 @@ describe Gitlab::OAuth::User do
expect(gl_user.email).not_to eq(info_hash[:email])
end
- it "has user_synced_attributes_metadata set to nil" do
- expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
+ it "has email set as not synced" do
expect(gl_user.user_synced_attributes_metadata.email_synced).to be_falsey
end
+
+ it "does not have email set as read-only" do
+ expect(gl_user.read_only_attribute?(:email)).to be_falsey
+ end
end
end
@@ -508,11 +549,15 @@ describe Gitlab::OAuth::User do
expect(gl_user.email).to eq(info_hash[:email])
end
- it "has email_synced_attribute set to true" do
+ it "has email set as synced" do
expect(gl_user.user_synced_attributes_metadata.email_synced).to be(true)
end
- it "has my-provider as attributes_provider" do
+ it "has email set as read-only" do
+ expect(gl_user.read_only_attribute?(:email)).to be_truthy
+ end
+
+ it "has synced attributes provider set to my-provider" do
expect(gl_user.user_synced_attributes_metadata.provider).to eql 'my-provider'
end
end
@@ -524,7 +569,14 @@ describe Gitlab::OAuth::User do
it "does not update the user email" do
expect(gl_user.email).not_to eq(info_hash[:email])
- expect(gl_user.user_synced_attributes_metadata.email_synced).to be(false)
+ end
+
+ it "has email set as not synced" do
+ expect(gl_user.user_synced_attributes_metadata.email_synced).to be_falsey
+ end
+
+ it "does not have email set as read-only" do
+ expect(gl_user.read_only_attribute?(:email)).to be_falsey
end
end
end
diff --git a/spec/lib/gitlab/project_authorizations_spec.rb b/spec/lib/gitlab/project_authorizations_spec.rb
index 953cfbb8b88..f3cd6961e94 100644
--- a/spec/lib/gitlab/project_authorizations_spec.rb
+++ b/spec/lib/gitlab/project_authorizations_spec.rb
@@ -15,7 +15,7 @@ describe Gitlab::ProjectAuthorizations do
end
before do
- other_project.team << [user, :reporter]
+ other_project.add_reporter(user)
group.add_developer(user)
end
diff --git a/spec/lib/gitlab/project_search_results_spec.rb b/spec/lib/gitlab/project_search_results_spec.rb
index a424f0f5cfe..17937726f2c 100644
--- a/spec/lib/gitlab/project_search_results_spec.rb
+++ b/spec/lib/gitlab/project_search_results_spec.rb
@@ -179,7 +179,7 @@ describe Gitlab::ProjectSearchResults do
end
it 'does not list project confidential issues for project members with guest role' do
- project.team << [member, :guest]
+ project.add_guest(member)
results = described_class.new(member, project, query)
issues = results.objects('issues')
@@ -211,7 +211,7 @@ describe Gitlab::ProjectSearchResults do
end
it 'lists project confidential issues for project members' do
- project.team << [member, :developer]
+ project.add_developer(member)
results = described_class.new(member, project, query)
issues = results.objects('issues')
@@ -290,12 +290,12 @@ describe Gitlab::ProjectSearchResults do
let!(:private_project) { create(:project, :private, :repository, creator: creator, namespace: creator.namespace) }
let(:team_master) do
user = create(:user, username: 'private-project-master')
- private_project.team << [user, :master]
+ private_project.add_master(user)
user
end
let(:team_reporter) do
user = create(:user, username: 'private-project-reporter')
- private_project.team << [user, :reporter]
+ private_project.add_reporter(user)
user
end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 8ec3f55e6de..4139d1c650c 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -4,7 +4,7 @@ describe Gitlab::ReferenceExtractor do
let(:project) { create(:project) }
before do
- project.team << [project.creator, :developer]
+ project.add_developer(project.creator)
end
subject { described_class.new(project, project.creator) }
@@ -14,8 +14,8 @@ describe Gitlab::ReferenceExtractor do
@u_bar = create(:user, username: 'bar')
@u_offteam = create(:user, username: 'offteam')
- project.team << [@u_foo, :reporter]
- project.team << [@u_bar, :guest]
+ project.add_guest(@u_foo)
+ project.add_guest(@u_bar)
subject.analyze('@foo, @baduser, @bar, and @offteam')
expect(subject.users).to match_array([@u_foo, @u_bar, @u_offteam])
@@ -26,8 +26,8 @@ describe Gitlab::ReferenceExtractor do
@u_bar = create(:user, username: 'bar')
@u_offteam = create(:user, username: 'offteam')
- project.team << [@u_foo, :reporter]
- project.team << [@u_bar, :guest]
+ project.add_reporter(@u_foo)
+ project.add_reporter(@u_bar)
subject.analyze(%Q{
Inline code: `@foo`
@@ -228,7 +228,7 @@ describe Gitlab::ReferenceExtractor do
let(:issue) { create(:issue, project: other_project) }
before do
- other_project.team << [project.creator, :developer]
+ other_project.add_developer(project.creator)
end
it 'handles project issue references' do
@@ -246,7 +246,7 @@ describe Gitlab::ReferenceExtractor do
let(:text) { "Ref. #{issue.to_reference} and #{label.to_reference}" }
before do
- project.team << [project.creator, :developer]
+ project.add_developer(project.creator)
subject.analyze(text)
end
diff --git a/spec/lib/gitlab/search_results_spec.rb b/spec/lib/gitlab/search_results_spec.rb
index e44a7c23452..b5a9ac570e6 100644
--- a/spec/lib/gitlab/search_results_spec.rb
+++ b/spec/lib/gitlab/search_results_spec.rb
@@ -16,7 +16,7 @@ describe Gitlab::SearchResults do
context 'as a user with access' do
before do
- project.team << [user, :developer]
+ project.add_developer(user)
end
describe '#projects_count' do
@@ -51,6 +51,38 @@ describe Gitlab::SearchResults do
expect(results.objects('merge_requests')).to include merge_request_2
end
+
+ describe '#merge_requests' do
+ it 'includes project filter by default' do
+ expect(results).to receive(:project_ids_relation).and_call_original
+
+ results.objects('merge_requests')
+ end
+
+ it 'it skips project filter if default project context is used' do
+ allow(results).to receive(:default_project_filter).and_return(true)
+
+ expect(results).not_to receive(:project_ids_relation)
+
+ results.objects('merge_requests')
+ end
+ end
+
+ describe '#issues' do
+ it 'includes project filter by default' do
+ expect(results).to receive(:project_ids_relation).and_call_original
+
+ results.objects('issues')
+ end
+
+ it 'it skips project filter if default project context is used' do
+ allow(results).to receive(:default_project_filter).and_return(true)
+
+ expect(results).not_to receive(:project_ids_relation)
+
+ results.objects('issues')
+ end
+ end
end
it 'does not list issues on private projects' do
@@ -93,8 +125,8 @@ describe Gitlab::SearchResults do
end
it 'does not list confidential issues for project members with guest role' do
- project_1.team << [member, :guest]
- project_2.team << [member, :guest]
+ project_1.add_guest(member)
+ project_2.add_guest(member)
results = described_class.new(member, limit_projects, query)
issues = results.objects('issues')
@@ -135,8 +167,8 @@ describe Gitlab::SearchResults do
end
it 'lists confidential issues for project members' do
- project_1.team << [member, :developer]
- project_2.team << [member, :developer]
+ project_1.add_developer(member)
+ project_2.add_developer(member)
results = described_class.new(member, limit_projects, query)
issues = results.objects('issues')
diff --git a/spec/lib/gitlab/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index eec6858a5de..81d9e6a8f82 100644
--- a/spec/lib/gitlab/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
@@ -2,12 +2,19 @@ require 'spec_helper'
require 'stringio'
describe Gitlab::Shell do
- let(:project) { double('Project', id: 7, path: 'diaspora') }
+ set(:project) { create(:project, :repository) }
+
let(:gitlab_shell) { described_class.new }
let(:popen_vars) { { 'GIT_TERMINAL_PROMPT' => ENV['GIT_TERMINAL_PROMPT'] } }
+ let(:gitlab_projects) { double('gitlab_projects') }
+ let(:timeout) { Gitlab.config.gitlab_shell.git_timeout }
before do
allow(Project).to receive(:find).and_return(project)
+
+ allow(gitlab_shell).to receive(:gitlab_projects)
+ .with(project.repository_storage_path, project.disk_path + '.git')
+ .and_return(gitlab_projects)
end
it { is_expected.to respond_to :add_key }
@@ -44,38 +51,6 @@ describe Gitlab::Shell do
end
end
- describe 'projects commands' do
- let(:gitlab_shell_path) { File.expand_path('tmp/tests/gitlab-shell') }
- let(:projects_path) { File.join(gitlab_shell_path, 'bin/gitlab-projects') }
- let(:gitlab_shell_hooks_path) { File.join(gitlab_shell_path, 'hooks') }
-
- before do
- allow(Gitlab.config.gitlab_shell).to receive(:path).and_return(gitlab_shell_path)
- allow(Gitlab.config.gitlab_shell).to receive(:hooks_path).and_return(gitlab_shell_hooks_path)
- allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
- end
-
- describe '#mv_repository' do
- it 'executes the command' do
- expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
- [projects_path, 'mv-project', 'storage/path', 'project/path.git', 'new/path.git']
- )
- gitlab_shell.mv_repository('storage/path', 'project/path', 'new/path')
- end
- end
-
- describe '#add_key' do
- it 'removes trailing garbage' do
- allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
- expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
- [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
- )
-
- gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
- end
- end
- end
-
describe Gitlab::Shell::KeyAdder do
describe '#add_key' do
it 'removes trailing garbage' do
@@ -121,6 +96,17 @@ describe Gitlab::Shell do
allow(Gitlab.config.gitlab_shell).to receive(:git_timeout).and_return(800)
end
+ describe '#add_key' do
+ it 'removes trailing garbage' do
+ allow(gitlab_shell).to receive(:gitlab_shell_keys_path).and_return(:gitlab_shell_keys_path)
+ expect(gitlab_shell).to receive(:gitlab_shell_fast_execute).with(
+ [:gitlab_shell_keys_path, 'add-key', 'key-123', 'ssh-rsa foobar']
+ )
+
+ gitlab_shell.add_key('key-123', 'ssh-rsa foobar trailing garbage')
+ end
+ end
+
describe '#add_repository' do
shared_examples '#add_repository' do
let(:repository_storage) { 'default' }
@@ -162,83 +148,76 @@ describe Gitlab::Shell do
end
describe '#remove_repository' do
+ subject { gitlab_shell.remove_repository(project.repository_storage_path, project.disk_path) }
+
it 'returns true when the command succeeds' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
- nil, popen_vars).and_return([nil, 0])
+ expect(gitlab_projects).to receive(:rm_project) { true }
- expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be true
+ is_expected.to be_truthy
end
it 'returns false when the command fails' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'rm-project', 'current/storage', 'project/path.git'],
- nil, popen_vars).and_return(["error", 1])
+ expect(gitlab_projects).to receive(:rm_project) { false }
- expect(gitlab_shell.remove_repository('current/storage', 'project/path')).to be false
+ is_expected.to be_falsy
end
end
describe '#mv_repository' do
it 'returns true when the command succeeds' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
- nil, popen_vars).and_return([nil, 0])
+ expect(gitlab_projects).to receive(:mv_project).with('project/newpath.git') { true }
- expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be true
+ expect(gitlab_shell.mv_repository(project.repository_storage_path, project.disk_path, 'project/newpath')).to be_truthy
end
it 'returns false when the command fails' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'mv-project', 'current/storage', 'project/path.git', 'project/newpath.git'],
- nil, popen_vars).and_return(["error", 1])
+ expect(gitlab_projects).to receive(:mv_project).with('project/newpath.git') { false }
- expect(gitlab_shell.mv_repository('current/storage', 'project/path', 'project/newpath')).to be false
+ expect(gitlab_shell.mv_repository(project.repository_storage_path, project.disk_path, 'project/newpath')).to be_falsy
end
end
describe '#fork_repository' do
+ subject do
+ gitlab_shell.fork_repository(
+ project.repository_storage_path,
+ project.disk_path,
+ 'new/storage',
+ 'fork/path'
+ )
+ end
+
it 'returns true when the command succeeds' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'fork-repository', 'current/storage', 'project/path.git', 'new/storage', 'fork/path.git'],
- nil, popen_vars).and_return([nil, 0])
+ expect(gitlab_projects).to receive(:fork_repository).with('new/storage', 'fork/path.git') { true }
- expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'fork/path')).to be true
+ is_expected.to be_truthy
end
it 'return false when the command fails' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'fork-repository', 'current/storage', 'project/path.git', 'new/storage', 'fork/path.git'],
- nil, popen_vars).and_return(["error", 1])
+ expect(gitlab_projects).to receive(:fork_repository).with('new/storage', 'fork/path.git') { false }
- expect(gitlab_shell.fork_repository('current/storage', 'project/path', 'new/storage', 'fork/path')).to be false
+ is_expected.to be_falsy
end
end
shared_examples 'fetch_remote' do |gitaly_on|
- let(:project2) { create(:project, :repository) }
- let(:repository) { project2.repository }
+ let(:repository) { project.repository }
def fetch_remote(ssh_auth = nil)
- gitlab_shell.fetch_remote(repository.raw_repository, 'new/storage', ssh_auth: ssh_auth)
+ gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', ssh_auth: ssh_auth)
end
- def expect_popen(fail = false, vars = {})
- popen_args = [
- projects_path,
- 'fetch-remote',
- TestEnv.repos_path,
- repository.relative_path,
- 'new/storage',
- Gitlab.config.gitlab_shell.git_timeout.to_s
- ]
-
- return_value = fail ? ["error", 1] : [nil, 0]
+ def expect_gitlab_projects(fail = false, options = {})
+ expect(gitlab_projects).to receive(:fetch_remote).with(
+ 'remote-name',
+ timeout,
+ options
+ ).and_return(!fail)
- expect(Gitlab::Popen).to receive(:popen).with(popen_args, nil, popen_vars.merge(vars)).and_return(return_value)
+ allow(gitlab_projects).to receive(:output).and_return('error') if fail
end
- def expect_gitaly_call(fail, vars = {})
+ def expect_gitaly_call(fail, options = {})
receive_fetch_remote =
if fail
receive(:fetch_remote).and_raise(GRPC::NotFound)
@@ -250,12 +229,12 @@ describe Gitlab::Shell do
end
if gitaly_on
- def expect_call(fail, vars = {})
- expect_gitaly_call(fail, vars)
+ def expect_call(fail, options = {})
+ expect_gitaly_call(fail, options)
end
else
- def expect_call(fail, vars = {})
- expect_popen(fail, vars)
+ def expect_call(fail, options = {})
+ expect_gitlab_projects(fail, options)
end
end
@@ -271,20 +250,27 @@ describe Gitlab::Shell do
end
it 'returns true when the command succeeds' do
- expect_call(false)
+ expect_call(false, force: false, tags: true)
expect(fetch_remote).to be_truthy
end
it 'raises an exception when the command fails' do
- expect_call(true)
+ expect_call(true, force: false, tags: true)
expect { fetch_remote }.to raise_error(Gitlab::Shell::Error)
end
+ it 'allows forced and no_tags to be changed' do
+ expect_call(false, force: true, tags: false)
+
+ result = gitlab_shell.fetch_remote(repository.raw_repository, 'remote-name', forced: true, no_tags: true)
+ expect(result).to be_truthy
+ end
+
context 'SSH auth' do
it 'passes the SSH key if specified' do
- expect_call(false, 'GITLAB_SHELL_SSH_KEY' => 'foo')
+ expect_call(false, force: false, tags: true, ssh_key: 'foo')
ssh_auth = build_ssh_auth(ssh_key_auth?: true, ssh_private_key: 'foo')
@@ -292,7 +278,7 @@ describe Gitlab::Shell do
end
it 'does not pass an empty SSH key' do
- expect_call(false)
+ expect_call(false, force: false, tags: true)
ssh_auth = build_ssh_auth(ssh_key_auth: true, ssh_private_key: '')
@@ -300,7 +286,7 @@ describe Gitlab::Shell do
end
it 'does not pass the key unless SSH key auth is to be used' do
- expect_call(false)
+ expect_call(false, force: false, tags: true)
ssh_auth = build_ssh_auth(ssh_key_auth: false, ssh_private_key: 'foo')
@@ -308,7 +294,7 @@ describe Gitlab::Shell do
end
it 'passes the known_hosts data if specified' do
- expect_call(false, 'GITLAB_SHELL_KNOWN_HOSTS' => 'foo')
+ expect_call(false, force: false, tags: true, known_hosts: 'foo')
ssh_auth = build_ssh_auth(ssh_known_hosts: 'foo')
@@ -316,7 +302,7 @@ describe Gitlab::Shell do
end
it 'does not pass empty known_hosts data' do
- expect_call(false)
+ expect_call(false, force: false, tags: true)
ssh_auth = build_ssh_auth(ssh_known_hosts: '')
@@ -324,7 +310,7 @@ describe Gitlab::Shell do
end
it 'does not pass known_hosts data unless SSH is to be used' do
- expect_call(false, popen_vars)
+ expect_call(false, force: false, tags: true)
ssh_auth = build_ssh_auth(ssh_import?: false, ssh_known_hosts: 'foo')
@@ -342,20 +328,23 @@ describe Gitlab::Shell do
end
describe '#import_repository' do
+ let(:import_url) { 'https://gitlab.com/gitlab-org/gitlab-ce.git' }
+
it 'returns true when the command succeeds' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
- nil, popen_vars).and_return([nil, 0])
+ expect(gitlab_projects).to receive(:import_project).with(import_url, timeout) { true }
+
+ result = gitlab_shell.import_repository(project.repository_storage_path, project.disk_path, import_url)
- expect(gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git')).to be true
+ expect(result).to be_truthy
end
it 'raises an exception when the command fails' do
- expect(Gitlab::Popen).to receive(:popen)
- .with([projects_path, 'import-project', 'current/storage', 'project/path.git', 'https://gitlab.com/gitlab-org/gitlab-ce.git', "800"],
- nil, popen_vars).and_return(["error", 1])
+ allow(gitlab_projects).to receive(:output) { 'error' }
+ expect(gitlab_projects).to receive(:import_project) { false }
- expect { gitlab_shell.import_repository('current/storage', 'project/path', 'https://gitlab.com/gitlab-org/gitlab-ce.git') }.to raise_error(Gitlab::Shell::Error, "error")
+ expect do
+ gitlab_shell.import_repository(project.repository_storage_path, project.disk_path, import_url)
+ end.to raise_error(Gitlab::Shell::Error, "error")
end
end
end
diff --git a/spec/lib/gitlab/sidekiq_config_spec.rb b/spec/lib/gitlab/sidekiq_config_spec.rb
index 09f95be2213..0c66d764851 100644
--- a/spec/lib/gitlab/sidekiq_config_spec.rb
+++ b/spec/lib/gitlab/sidekiq_config_spec.rb
@@ -16,9 +16,30 @@ describe Gitlab::SidekiqConfig do
expect(queues).to include('post_receive')
expect(queues).to include('merge')
- expect(queues).to include('cronjob')
+ expect(queues).to include('cronjob:stuck_import_jobs')
expect(queues).to include('mailers')
expect(queues).to include('default')
end
end
+
+ describe '.expand_queues' do
+ it 'expands queue namespaces to concrete queue names' do
+ queues = described_class.expand_queues(%w[cronjob])
+
+ expect(queues).to include('cronjob:stuck_import_jobs')
+ expect(queues).to include('cronjob:stuck_merge_jobs')
+ end
+
+ it 'lets concrete queue names pass through' do
+ queues = described_class.expand_queues(%w[post_receive])
+
+ expect(queues).to include('post_receive')
+ end
+
+ it 'lets unknown queues pass through' do
+ queues = described_class.expand_queues(%w[unknown])
+
+ expect(queues).to include('unknown')
+ end
+ end
end
diff --git a/spec/lib/gitlab/sidekiq_versioning/manager_spec.rb b/spec/lib/gitlab/sidekiq_versioning/manager_spec.rb
new file mode 100644
index 00000000000..7debf70a16f
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_versioning/manager_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqVersioning::Manager do
+ before do
+ Sidekiq::Manager.prepend described_class
+ end
+
+ describe '#initialize' do
+ it 'listens on all expanded queues' do
+ manager = Sidekiq::Manager.new(queues: %w[post_receive repository_fork cronjob unknown])
+
+ queues = manager.options[:queues]
+
+ expect(queues).to include('post_receive')
+ expect(queues).to include('repository_fork')
+ expect(queues).to include('cronjob')
+ expect(queues).to include('cronjob:stuck_import_jobs')
+ expect(queues).to include('cronjob:stuck_merge_jobs')
+ expect(queues).to include('unknown')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/sidekiq_versioning_spec.rb b/spec/lib/gitlab/sidekiq_versioning_spec.rb
new file mode 100644
index 00000000000..fa6d42e730d
--- /dev/null
+++ b/spec/lib/gitlab/sidekiq_versioning_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe Gitlab::SidekiqVersioning, :sidekiq, :redis do
+ let(:foo_worker) do
+ Class.new do
+ def self.name
+ 'FooWorker'
+ end
+
+ include ApplicationWorker
+ end
+ end
+
+ let(:bar_worker) do
+ Class.new do
+ def self.name
+ 'BarWorker'
+ end
+
+ include ApplicationWorker
+ end
+ end
+
+ before do
+ allow(Gitlab::SidekiqConfig).to receive(:workers).and_return([foo_worker, bar_worker])
+ allow(Gitlab::SidekiqConfig).to receive(:worker_queues).and_return([foo_worker.queue, bar_worker.queue])
+ end
+
+ describe '.install!' do
+ it 'prepends SidekiqVersioning::Manager into Sidekiq::Manager' do
+ described_class.install!
+
+ expect(Sidekiq::Manager).to include(Gitlab::SidekiqVersioning::Manager)
+ end
+
+ it 'registers all versionless and versioned queues with Redis' do
+ described_class.install!
+
+ queues = Sidekiq::Queue.all.map(&:name)
+ expect(queues).to include('foo')
+ expect(queues).to include('bar')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/slash_commands/issue_new_spec.rb b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
index 75ae58d0582..3b077c58c50 100644
--- a/spec/lib/gitlab/slash_commands/issue_new_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_new_spec.rb
@@ -7,7 +7,7 @@ describe Gitlab::SlashCommands::IssueNew do
let(:regex_match) { described_class.match("issue create bird is the word") }
before do
- project.team << [user, :master]
+ project.add_master(user)
end
subject do
diff --git a/spec/lib/gitlab/slash_commands/issue_search_spec.rb b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
index 51f59216413..e41e5254dde 100644
--- a/spec/lib/gitlab/slash_commands/issue_search_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_search_spec.rb
@@ -21,7 +21,7 @@ describe Gitlab::SlashCommands::IssueSearch do
context 'the user has access' do
before do
- project.team << [user, :master]
+ project.add_master(user)
end
it 'returns all results' do
diff --git a/spec/lib/gitlab/slash_commands/issue_show_spec.rb b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
index 08c380ca8f1..e5834d5a2ee 100644
--- a/spec/lib/gitlab/slash_commands/issue_show_spec.rb
+++ b/spec/lib/gitlab/slash_commands/issue_show_spec.rb
@@ -8,7 +8,7 @@ describe Gitlab::SlashCommands::IssueShow do
let(:regex_match) { described_class.match("issue show #{issue.iid}") }
before do
- project.team << [user, :master]
+ project.add_master(user)
end
subject do
diff --git a/spec/lib/gitlab/tcp_checker_spec.rb b/spec/lib/gitlab/tcp_checker_spec.rb
new file mode 100644
index 00000000000..4acf0334496
--- /dev/null
+++ b/spec/lib/gitlab/tcp_checker_spec.rb
@@ -0,0 +1,32 @@
+require 'spec_helper'
+
+describe Gitlab::TcpChecker do
+ before do
+ @server = TCPServer.new('localhost', 0)
+ _, @port, _, @ip = @server.addr
+ end
+
+ after do
+ @server.close
+ end
+
+ subject(:checker) { described_class.new(@ip, @port) }
+
+ describe '#check' do
+ subject { checker.check }
+
+ it 'can connect to an open port' do
+ is_expected.to be_truthy
+
+ expect(checker.error).to be_nil
+ end
+
+ it 'fails to connect to a closed port' do
+ @server.close
+
+ is_expected.to be_falsy
+
+ expect(checker.error).to be_a(Errno::ECONNREFUSED)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index cd97416bcc9..7280acb6c82 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -8,19 +8,19 @@ describe Gitlab::UserAccess do
describe '#can_push_to_branch?' do
describe 'push to none protected branch' do
it 'returns true if user is a master' do
- project.team << [user, :master]
+ project.add_master(user)
expect(access.can_push_to_branch?('random_branch')).to be_truthy
end
it 'returns true if user is a developer' do
- project.team << [user, :developer]
+ project.add_developer(user)
expect(access.can_push_to_branch?('random_branch')).to be_truthy
end
it 'returns false if user is a reporter' do
- project.team << [user, :reporter]
+ project.add_reporter(user)
expect(access.can_push_to_branch?('random_branch')).to be_falsey
end
@@ -31,34 +31,34 @@ describe Gitlab::UserAccess do
let(:project_access) { described_class.new(user, project: empty_project) }
it 'returns true if user is master' do
- empty_project.team << [user, :master]
+ empty_project.add_master(user)
expect(project_access.can_push_to_branch?('master')).to be_truthy
end
it 'returns false if user is developer and project is fully protected' do
- empty_project.team << [user, :developer]
+ empty_project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_FULL)
expect(project_access.can_push_to_branch?('master')).to be_falsey
end
it 'returns false if user is developer and it is not allowed to push new commits but can merge into branch' do
- empty_project.team << [user, :developer]
+ empty_project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_MERGE)
expect(project_access.can_push_to_branch?('master')).to be_falsey
end
it 'returns true if user is developer and project is unprotected' do
- empty_project.team << [user, :developer]
+ empty_project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_NONE)
expect(project_access.can_push_to_branch?('master')).to be_truthy
end
it 'returns true if user is developer and project grants developers permission' do
- empty_project.team << [user, :developer]
+ empty_project.add_developer(user)
stub_application_setting(default_branch_protection: Gitlab::Access::PROTECTION_DEV_CAN_PUSH)
expect(project_access.can_push_to_branch?('master')).to be_truthy
@@ -70,25 +70,25 @@ describe Gitlab::UserAccess do
let(:not_existing_branch) { create :protected_branch, :developers_can_merge, project: project }
it 'returns true if user is a master' do
- project.team << [user, :master]
+ project.add_master(user)
expect(access.can_push_to_branch?(branch.name)).to be_truthy
end
it 'returns false if user is a developer' do
- project.team << [user, :developer]
+ project.add_developer(user)
expect(access.can_push_to_branch?(branch.name)).to be_falsey
end
it 'returns false if user is a reporter' do
- project.team << [user, :reporter]
+ project.add_reporter(user)
expect(access.can_push_to_branch?(branch.name)).to be_falsey
end
it 'returns false if branch does not exist' do
- project.team << [user, :developer]
+ project.add_developer(user)
expect(access.can_push_to_branch?(not_existing_branch.name)).to be_falsey
end
@@ -100,19 +100,19 @@ describe Gitlab::UserAccess do
end
it 'returns true if user is a master' do
- project.team << [user, :master]
+ project.add_master(user)
expect(access.can_push_to_branch?(@branch.name)).to be_truthy
end
it 'returns true if user is a developer' do
- project.team << [user, :developer]
+ project.add_developer(user)
expect(access.can_push_to_branch?(@branch.name)).to be_truthy
end
it 'returns false if user is a reporter' do
- project.team << [user, :reporter]
+ project.add_reporter(user)
expect(access.can_push_to_branch?(@branch.name)).to be_falsey
end
@@ -124,19 +124,19 @@ describe Gitlab::UserAccess do
end
it 'returns true if user is a master' do
- project.team << [user, :master]
+ project.add_master(user)
expect(access.can_merge_to_branch?(@branch.name)).to be_truthy
end
it 'returns true if user is a developer' do
- project.team << [user, :developer]
+ project.add_developer(user)
expect(access.can_merge_to_branch?(@branch.name)).to be_truthy
end
it 'returns false if user is a reporter' do
- project.team << [user, :reporter]
+ project.add_reporter(user)
expect(access.can_merge_to_branch?(@branch.name)).to be_falsey
end
diff --git a/spec/lib/gitlab/utils/strong_memoize_spec.rb b/spec/lib/gitlab/utils/strong_memoize_spec.rb
index 4a104ab6d97..473f8100771 100644
--- a/spec/lib/gitlab/utils/strong_memoize_spec.rb
+++ b/spec/lib/gitlab/utils/strong_memoize_spec.rb
@@ -49,4 +49,16 @@ describe Gitlab::Utils::StrongMemoize do
end
end
end
+
+ describe '#clear_memoization' do
+ let(:value) { 'mepmep' }
+
+ it 'removes the instance variable' do
+ object.method_name
+
+ object.clear_memoization(:method_name)
+
+ expect(object.instance_variable_defined?(:@method_name)).to be(false)
+ end
+ end
end
diff --git a/spec/lib/gitlab/view/presenter/factory_spec.rb b/spec/lib/gitlab/view/presenter/factory_spec.rb
index 70d2e22b48f..6120bafb2e3 100644
--- a/spec/lib/gitlab/view/presenter/factory_spec.rb
+++ b/spec/lib/gitlab/view/presenter/factory_spec.rb
@@ -27,5 +27,13 @@ describe Gitlab::View::Presenter::Factory do
expect(presenter).to be_a(Ci::BuildPresenter)
end
+
+ it 'uses the presenter_class if given on #initialize' do
+ MyCustomPresenter = Class.new(described_class)
+
+ presenter = described_class.new(build, presenter_class: MyCustomPresenter).fabricate!
+
+ expect(presenter).to be_a(MyCustomPresenter)
+ end
end
end
diff --git a/spec/lib/gitlab/visibility_level_spec.rb b/spec/lib/gitlab/visibility_level_spec.rb
index 48a67773de9..d85dac630b4 100644
--- a/spec/lib/gitlab/visibility_level_spec.rb
+++ b/spec/lib/gitlab/visibility_level_spec.rb
@@ -49,4 +49,31 @@ describe Gitlab::VisibilityLevel do
.to eq([Gitlab::VisibilityLevel::PUBLIC])
end
end
+
+ describe '.allowed_levels' do
+ it 'only includes the levels that arent restricted' do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
+
+ expect(described_class.allowed_levels)
+ .to contain_exactly(described_class::PRIVATE, described_class::PUBLIC)
+ end
+ end
+
+ describe '.closest_allowed_level' do
+ it 'picks INTERNAL instead of PUBLIC if public is restricted' do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC])
+
+ expect(described_class.closest_allowed_level(described_class::PUBLIC))
+ .to eq(described_class::INTERNAL)
+ end
+
+ it 'picks PRIVATE if nothing is available' do
+ stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC,
+ Gitlab::VisibilityLevel::INTERNAL,
+ Gitlab::VisibilityLevel::PRIVATE])
+
+ expect(described_class.closest_allowed_level(described_class::PUBLIC))
+ .to eq(described_class::PRIVATE)
+ end
+ end
end
diff --git a/spec/lib/google_api/cloud_platform/client_spec.rb b/spec/lib/google_api/cloud_platform/client_spec.rb
index ecb4034ec8b..f65e41dfea3 100644
--- a/spec/lib/google_api/cloud_platform/client_spec.rb
+++ b/spec/lib/google_api/cloud_platform/client_spec.rb
@@ -50,6 +50,30 @@ describe GoogleApi::CloudPlatform::Client do
end
end
+ describe '#projects_list' do
+ subject { client.projects_list }
+ let(:projects) { double }
+
+ before do
+ allow_any_instance_of(Google::Apis::CloudresourcemanagerV1::CloudResourceManagerService)
+ .to receive(:fetch_all).and_return(projects)
+ end
+
+ it { is_expected.to eq(projects) }
+ end
+
+ describe '#projects_get_billing_info' do
+ subject { client.projects_get_billing_info('project') }
+ let(:billing_info) { double }
+
+ before do
+ allow_any_instance_of(Google::Apis::CloudbillingV1::CloudbillingService)
+ .to receive(:get_project_billing_info).and_return(billing_info)
+ end
+
+ it { is_expected.to eq(billing_info) }
+ end
+
describe '#projects_zones_clusters_get' do
subject { client.projects_zones_clusters_get(spy, spy, spy) }
let(:gke_cluster) { double }