Commit 667917ab authored by Gabriel Mazetto's avatar Gabriel Mazetto

Merge branch '9-5-stable' into security-9-5

parents f024f7ef c47ae372
......@@ -2,6 +2,14 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 9.5.1 (2017-08-23)
- [FIXED] Fix merge request pipeline status when pipeline has errors. !13664
- [FIXED] Commit rows would occasionally render with the wrong language.
- [FIXED] Fix caching of future broadcast messages.
- [FIXED] Only require Sidekiq throttling library when enabled, to reduce cache misses.
- Raise Housekeeping timeout to 24 hours. !13719
## 9.5.0 (2017-08-22)
- [FIXED] Fix timeouts when creating projects in groups with many members. !13508
......
......@@ -154,7 +154,7 @@ gem 'acts-as-taggable-on', '~> 4.0'
gem 'sidekiq', '~> 5.0'
gem 'sidekiq-cron', '~> 0.6.0'
gem 'redis-namespace', '~> 1.5.2'
gem 'sidekiq-limit_fetch', '~> 3.4'
gem 'sidekiq-limit_fetch', '~> 3.4', require: false
# Cron Parser
gem 'rufus-scheduler', '~> 3.4'
......
......@@ -97,7 +97,7 @@ gl.issueBoards.IssueCardInner = Vue.extend({
return `Avatar for ${assignee.name}`;
},
showLabel(label) {
if (!this.list || !label) return true;
if (!label.id) return false;
return true;
},
filterByLabel(label, e) {
......
......@@ -74,7 +74,8 @@ export default {
<tbody>
<repo-file-options
:is-mini="isMini"
:project-name="projectName"/>
:project-name="projectName"
/>
<repo-previous-directory
v-if="isRoot"
:prev-url="prevURL"
......@@ -84,7 +85,8 @@ export default {
:key="n"
:loading="loading"
:has-files="!!files.length"
:is-mini="isMini"/>
:is-mini="isMini"
/>
<repo-file
v-for="file in files"
:key="file.id"
......@@ -93,7 +95,8 @@ export default {
@linkclicked="fileClicked(file)"
:is-tree="isTree"
:has-files="!!files.length"
:active-file="activeFile"/>
:active-file="activeFile"
/>
</tbody>
</table>
</div>
......
......@@ -176,7 +176,7 @@ module EventsHelper
sanitize(
text,
tags: %w(a img gl-emoji b pre code p span),
attributes: Rails::Html::WhiteListSanitizer.allowed_attributes + ['style', 'data-name', 'data-unicode-version']
attributes: Rails::Html::WhiteListSanitizer.allowed_attributes + ['style', 'data-src', 'data-name', 'data-unicode-version']
)
end
......
......@@ -19,11 +19,21 @@ class BroadcastMessage < ActiveRecord::Base
after_commit :flush_redis_cache
def self.current
Rails.cache.fetch(CACHE_KEY) do
where('ends_at > :now AND starts_at <= :now', now: Time.zone.now)
.reorder(id: :asc)
.to_a
end
messages = Rails.cache.fetch(CACHE_KEY) { current_and_future_messages.to_a }
return messages if messages.empty?
now_or_future = messages.select(&:now_or_future?)
# If there are cached entries but none are to be displayed we'll purge the
# cache so we don't keep running this code all the time.
Rails.cache.delete(CACHE_KEY) if now_or_future.empty?
now_or_future.select(&:now?)
end
def self.current_and_future_messages
where('ends_at > :now', now: Time.zone.now).reorder(id: :asc)
end
def active?
......@@ -38,6 +48,18 @@ class BroadcastMessage < ActiveRecord::Base
ends_at < Time.zone.now
end
def now?
(starts_at..ends_at).cover?(Time.zone.now)
end
def future?
starts_at > Time.zone.now
end
def now_or_future?
now? || future?
end
def flush_redis_cache
Rails.cache.delete(CACHE_KEY)
end
......
......@@ -763,7 +763,7 @@ class Repository
index = Gitlab::Git::Index.new(raw_repository)
if start_commit
index.read_tree(start_commit.raw_commit.tree)
index.read_tree(start_commit.rugged_commit.tree)
parents = [start_commit.sha]
else
parents = []
......
......@@ -176,9 +176,14 @@ module Ci
end
def error(message, save: false)
pipeline.errors.add(:base, message)
pipeline.drop if save
pipeline
pipeline.tap do
pipeline.errors.add(:base, message)
if save
pipeline.drop
update_merge_requests_head_pipeline
end
end
end
def pipeline_created_counter
......
......@@ -9,7 +9,8 @@ module Projects
class HousekeepingService < BaseService
include Gitlab::CurrentSettings
LEASE_TIMEOUT = 3600
# Timeout set to 24h
LEASE_TIMEOUT = 86400
class LeaseTaken < StandardError
def to_s
......
......@@ -356,7 +356,9 @@
%fieldset
%legend Background Jobs
%p
These settings require a restart to take effect.
These settings require a
= link_to 'restart', help_page_path('administration/restart_gitlab')
to take effect.
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
......
......@@ -25,7 +25,7 @@
= hidden_field_tag :namespace_id, value: current_user.namespace_id
.form-group.col-xs-12.col-sm-6.project-path
= label_tag :path, 'Project name', class: 'label-light'
= text_field_tag :path, nil, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, autofocus: true, required: true
= text_field_tag :path, @path, placeholder: "my-awesome-project", class: "js-path-name form-control", tabindex: 2, autofocus: true, required: true
.row
.form-group.col-md-12
......@@ -33,7 +33,6 @@
.row
.form-group.col-sm-12
= hidden_field_tag :namespace_id, @namespace.id
= hidden_field_tag :path, @path
= label_tag :file, 'GitLab project export', class: 'label-light'
.form-group
= file_field_tag :file, class: ''
......
......@@ -5,7 +5,7 @@
- notes = commit.notes
- note_count = notes.user.count
- cache_key = [project.full_path, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits)]
- cache_key = [project.full_path, commit.id, current_application_settings, note_count, @path.presence, current_controller?(:commits), I18n.locale]
- cache_key.push(commit.status(ref)) if commit.status(ref)
= cache(cache_key, expires_in: 1.day) do
......
......@@ -237,8 +237,6 @@
.sub-section.rename-respository
%h4.warning-title
Rename repository
%p
Export this project with all its related data in order to move your project to a new GitLab instance. Once the export is finished, you can import the file from the "New Project" page.
= render 'projects/errors'
= form_for([@project.namespace.becomes(Namespace), @project]) do |f|
.form-group.project_name_holder
......
......@@ -649,6 +649,9 @@ test:
default:
path: tmp/tests/repositories/
gitaly_address: unix:tmp/tests/gitaly/gitaly.socket
failure_count_threshold: 999999
failure_wait_time: 0
storage_timeout: 30
broken:
path: tmp/tests/non-existent-repositories
gitaly_address: unix:tmp/tests/gitaly/gitaly.socket
......
......@@ -37,12 +37,12 @@ def validate_storages_config
storage_validation_error("#{name} is not a valid storage, because it has no `path` key. Refer to gitlab.yml.example for an updated example")
end
%w(failure_count_threshold failure_wait_time failure_reset_time storage_timeout).each do |setting|
%w(failure_count_threshold failure_reset_time storage_timeout).each do |setting|
# Falling back to the defaults is fine!
next if repository_storage[setting].nil?
unless repository_storage[setting].to_f > 0
storage_validation_error("#{setting}, for storage `#{name}` needs to be greater than 0")
storage_validation_error("`#{setting}` for storage `#{name}` needs to be greater than 0")
end
end
end
......
......@@ -10,10 +10,8 @@ end
#
module Gitlab
module StrongParameterScalars
GITLAB_PERMITTED_SCALAR_TYPES = [::UploadedFile].freeze
def permitted_scalar?(value)
super || GITLAB_PERMITTED_SCALAR_TYPES.any? { |type| value.is_a?(type) }
super || value.is_a?(::UploadedFile)
end
end
end
......
......@@ -76,7 +76,6 @@ var config = {
terminal: './terminal/terminal_bundle.js',
u2f: ['vendor/u2f'],
ui_development_kit: './ui_development_kit.js',
users: './users/index.js',
raven: './raven/index.js',
vue_merge_request_widget: './vue_merge_request_widget/index.js',
test: './test.js',
......
......@@ -55,6 +55,12 @@ By doing so:
- John mentions everyone from his team with `@john-team`
- John mentions only his marketing team with `@john-team/marketing`
## Issues and merge requests within a group
Issues and merge requests are part of projects. For a given group, view all the
[issues](../project/issues/index.md#issues-per-group) and [merge requests](../project/merge_requests/index.md#merge-requests-per-group) across all the projects in that group,
together in a single list view.
## Create a new group
You can create a group in GitLab from:
......
......@@ -162,6 +162,10 @@ are a tool for working faster and more effectively with your team,
by listing all user or group mentions, as well as issues and merge
requests you're assigned to.
## Search
[Search and filter](search/index.md) through groups, projects, issues, merge requests, files, code, and more.
## Snippets
[Snippets](snippets.md) are code blocks that you want to store in GitLab, from which
......
......@@ -7,7 +7,7 @@ of solving a problem.
It allows you, your team, and your collaborators to share
and discuss proposals before and while implementing them.
Issues and the GitLab Issue Tracker are available in all
GitLab Issues and the GitLab Issue Tracker are available in all
[GitLab Products](https://about.gitlab.com/products/) as
part of the [GitLab Workflow](https://about.gitlab.com/2016/10/25/gitlab-workflow-an-overview/).
......@@ -48,11 +48,27 @@ for feature proposals and another one for bug reports.
## Issue Tracker
The issue tracker is the collection of opened and closed issues created in a project.
The Issue Tracker is the collection of opened and closed issues created in a project.
It is available for all projects, from the moment the project is created.
![Issue tracker](img/issue_tracker.png)
Find the issue tracker by navigating to your **Project's homepage** > **Issues**.
Find the issue tracker by navigating to your **Project's Dashboard** > **Issues**.
### Issues per project
When you access your project's issues, GitLab will present them in a list,
and you can use the tabs available to quickly filter by open and closed issues.
![Project issues list view](img/project_issues_list_view.png)
You can also [search and filter](../../search/index.md#issues-and-merge-requests-per-project) the results more deeply with GitLab's search capacities.
### Issues per group
View all the issues in a group (that is, all the issues across all projects in that
group) by navigating to **Group > Issues**. This view also has the open and closed
issue tabs.
![Group Issues list view](img/group_issues_list_view.png)
## GitLab Issues Functionalities
......@@ -120,6 +136,12 @@ to find out more about this feature.
With [GitLab Enterprise Edition Starter](https://about.gitlab.com/gitlab-ee/), you can also
create various boards per project with [Multiple Issue Boards](https://docs.gitlab.com/ee/user/project/issue_board.html#multiple-issue-boards).
### External Issue Tracker
Alternatively to GitLab's built-in Issue Tracker, you can also use an [external
tracker](../../../integration/external-issue-tracker.md) such as Jira, Redmine,
or Bugzilla.
### Issue's API
Read through the [API documentation](../../../api/issues.md).
......@@ -56,6 +56,23 @@ B. Consider you're a web developer writing a webpage for your company's:
1. Once approved, your merge request is [squashed and merged](https://docs.gitlab.com/ee/user/project/merge_requests/squash_and_merge.html), and [deployed to staging with GitLab Pages](https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/) (Squash and Merge is available in GitLab Enterprise Edition Starter)
1. Your production team [cherry picks](#cherry-pick-changes) the merge commit into production
## Merge requests per project
View all the merge requests within a project by navigating to **Project > Merge Requests**.
When you access your project's merge requests, GitLab will present them in a list,
and you can use the tabs available to quickly filter by open and closed. You can also [search and filter the results](../../search/index.md#issues-and-merge-requests-per-project).
![Project merge requests list view](img/project_merge_requests_list_view.png)
## Merge requests per group
View all the merge requests in a group (that is, all the merge requests across all projects in that
group) by navigating to **Group > Merge Requests**. This view also has the open, merged, and closed
merge request tabs, from which you can [search and filter the results](../../search/index.md#issues-and-merge-requests-per-group).
![Group Issues list view](img/group_merge_requests_list_view.png)
## Authorization for merge requests
There are two main ways to have a merge request flow with GitLab:
......@@ -141,7 +158,6 @@ all your changes will be available to preview by anyone with the Review Apps lin
[Read more about Review Apps.](../../../ci/review_apps/index.md)
## Tips
Here are some tips that will help you be more efficient with merge requests in
......@@ -230,4 +246,4 @@ git checkout origin/merge-requests/1
```
[protected branches]: ../protected_branches.md
[ee]: https://about.gitlab.com/gitlab-ee/ "GitLab Enterprise Edition"
[ee]: https://about.gitlab.com/gitlab-ee/ "GitLab Enterprise Edition"
\ No newline at end of file
......@@ -27,7 +27,7 @@ on the search field on the top-right of your screen:
![shortcut to your issues and mrs](img/issues_mrs_shortcut.png)
## Issues and merge requests per project
### Issues and merge requests per project
If you want to search for issues present in a specific project, navigate to
a project's **Issues** tab, and click on the field **Search or filter results...**. It will
......@@ -40,7 +40,7 @@ The same process is valid for merge requests. Navigate to your project's **Merge
and click **Search or filter results...**. Merge requests can be filtered by author, assignee,
milestone, and label.
## Issues and merge requests per group
### Issues and merge requests per group
Similar to **Issues and merge requests per project**, you can also search for issues
within a group. Navigate to a group's **Issues** tab and query search results in
......@@ -48,6 +48,10 @@ the same way as you do for projects.
![filter issues in a group](img/group_issues_filter.png)
The same process is valid for merge requests. Navigate to your project's **Merge Requests** tab.
The search and filter UI currently uses dropdowns. In a future release, the same
dynamic UI as above will be carried over here.
## Search history
You can view recent searches by clicking on the little arrow-clock icon, which is to the left of the search input. Click the search entry to run that search again. This feature is available for issues and merge requests. Searches are stored locally in your browser.
......
......@@ -77,8 +77,8 @@ EOM
def initialize(merge_request, project)
@merge_request = merge_request
@our_commit = merge_request.source_branch_head.raw.raw_commit
@their_commit = merge_request.target_branch_head.raw.raw_commit
@our_commit = merge_request.source_branch_head.raw.rugged_commit
@their_commit = merge_request.target_branch_head.raw.rugged_commit
@project = project
end
end
......
......@@ -14,7 +14,7 @@ module Gitlab
attr_accessor *SERIALIZE_KEYS # rubocop:disable Lint/AmbiguousOperator
delegate :tree, to: :raw_commit
delegate :tree, to: :rugged_commit
def ==(other)
return false unless other.is_a?(Gitlab::Git::Commit)
......@@ -287,7 +287,7 @@ module Gitlab
# empty repo. See Repository#diff for keys allowed in the +options+
# hash.
def diff_from_parent(options = {})
Commit.diff_from_parent(raw_commit, options)
Commit.diff_from_parent(rugged_commit, options)
end
def deltas
......@@ -335,7 +335,7 @@ module Gitlab
def to_patch(options = {})
begin
raw_commit.to_mbox(options)
rugged_commit.to_mbox(options)
rescue Rugged::InvalidError => ex
if ex.message =~ /commit \w+ is a merge commit/i
'Patch format is not currently supported for merge commits.'
......@@ -383,6 +383,14 @@ module Gitlab
encode! @committer_email
end
def rugged_commit
@rugged_commit ||= if raw_commit.is_a?(Rugged::Commit)
raw_commit
else
@repository.rev_parse_target(id)
end
end
private
def init_from_hash(hash)
......
......@@ -4,6 +4,7 @@ module Gitlab
class GitAccess
UnauthorizedError = Class.new(StandardError)
NotFoundError = Class.new(StandardError)
ProjectMovedError = Class.new(NotFoundError)
ERROR_MESSAGES = {
upload: 'You are not allowed to upload code for this project.',
......@@ -90,18 +91,18 @@ module Gitlab
end
def check_project_moved!
if redirected_path
url = protocol == 'ssh' ? project.ssh_url_to_repo : project.http_url_to_repo
message = <<-MESSAGE.strip_heredoc
Project '#{redirected_path}' was moved to '#{project.full_path}'.
return unless redirected_path
Please update your Git remote and try again:
url = protocol == 'ssh' ? project.ssh_url_to_repo : project.http_url_to_repo
message = <<-MESSAGE.strip_heredoc
Project '#{redirected_path}' was moved to '#{project.full_path}'.
git remote set-url origin #{url}
MESSAGE
Please update your Git remote and try again:
raise NotFoundError, message
end
git remote set-url origin #{url}
MESSAGE
raise ProjectMovedError, message
end
def check_command_disabled!(cmd)
......
......@@ -100,5 +100,9 @@ module Gitlab
path = Rails.root.join(SERVER_VERSION_FILE)
path.read.chomp
end
def self.encode(s)
s.dup.force_encoding(Encoding::ASCII_8BIT)
end
end
end
......@@ -63,8 +63,8 @@ module Gitlab
def tree_entries(repository, revision, path)
request = Gitaly::GetTreeEntriesRequest.new(
repository: @gitaly_repo,
revision: revision,
path: path.presence || '.'
revision: GitalyClient.encode(revision),
path: path.present? ? GitalyClient.encode(path) : '.'
)
response = GitalyClient.call(@repository.storage, :commit_service, :get_tree_entries, request)
......
......@@ -3,6 +3,8 @@ module Gitlab
class << self
def execute!
if Gitlab::CurrentSettings.sidekiq_throttling_enabled?
require 'sidekiq-limit_fetch'
Gitlab::CurrentSettings.current_application_settings.sidekiq_throttling_queues.each do |queue|
Sidekiq::Queue[queue].limit = queue_limit
end
......
......@@ -3,11 +3,13 @@ require 'spec_helper'
feature 'Import/Export - project import integration test', js: true do
include Select2Helper
let(:user) { create(:user) }
let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') }
let(:export_path) { "#{Dir.tmpdir}/import_file_spec" }
background do
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
gitlab_sign_in(user)
end
after(:each) do
......@@ -18,57 +20,67 @@ feature 'Import/Export - project import integration test', js: true do
let(:user) { create(:admin) }
let!(:namespace) { create(:namespace, name: "asd", owner: user) }
before do
gitlab_sign_in(user)
end
context 'prefilled the path' do
scenario 'user imports an exported project successfully' do
visit new_project_path
scenario 'user imports an exported project successfully' do
visit new_project_path
select2(namespace.id, from: '#project_namespace_id')
fill_in :project_path, with: 'test-project-path', visible: true
click_link 'GitLab export'
select2(namespace.id, from: '#project_namespace_id')
fill_in :project_path, with: 'test-project-path', visible: true
click_link 'GitLab export'
expect(page).to have_content('Import an exported GitLab project')
expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=test-project-path")
expect(Gitlab::ImportExport).to receive(:import_upload_path).with(filename: /\A\h{32}_test-project-path\z/).and_call_original
expect(page).to have_content('Import an exported GitLab project')
expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=test-project-path")
expect(Gitlab::ImportExport).to receive(:import_upload_path).with(filename: /\A\h{32}_test-project-path\z/).and_call_original
attach_file('file', file)
attach_file('file', file)
expect { click_on 'Import project' }.to change { Project.count }.by(1)
expect { click_on 'Import project' }.to change { Project.count }.from(0).to(1)
project = Project.last
expect(project).not_to be_nil
expect(project.issues).not_to be_empty
expect(project.merge_requests).not_to be_empty
expect(project_hook_exists?(project)).to be true
expect(wiki_exists?(project)).to be true
expect(project.import_status).to eq('finished')
project = Project.last
expect(project).not_to be_nil
expect(project.issues).not_to be_empty
expect(project.merge_requests).not_to be_empty
expect(project_hook_exists?(project)).to be true
expect(wiki_exists?(project)).to be true
expect(project.import_status).to eq('finished')
end
end
scenario 'invalid project' do
project = create(:project, namespace: namespace)
context 'path is not prefilled' do
scenario 'user imports an exported project successfully' do
visit new_project_path
click_link 'GitLab export'
visit new_project_path
fill_in :path, with: 'test-project-path', visible: true
attach_file('file', file)
select2(namespace.id, from: '#project_namespace_id')
fill_in :project_path, with: project.name, visible: true
click_link 'GitLab export'
attach_file('file', file)
click_on 'Import project'
expect { click_on 'Import project' }.to change { Project.count }.by(1)
page.within('.flash-container') do
expect(page).to have_content('Project could not be imported')
project = Project.last
expect(project).not_to be_nil
expect(page).to have_content("Project 'test-project-path' is being imported")
end
end
end
context 'when limited to the default user namespace' do
let(:user) { create(:user) }
before do
gitlab_sign_in(user)
scenario 'invalid project' do
namespace = create(:namespace, name: "asd", owner: user)
project = create(:project, namespace: namespace)
visit new_project_path
select2(namespace.id, from: '#project_namespace_id')
fill_in :project_path, with: project.name, visible: true
click_link 'GitLab export'
attach_file('file', file)
click_on 'Import project'
page.within('.flash-container') do
expect(page).to have_content('Project could not be imported')
end
end
context 'when limited to the default user namespace' do
scenario 'passes correct namespace ID in the URL' do
visit new_project_path
......
......@@ -62,6 +62,12 @@ describe EventsHelper do
expect(helper.event_note(input)).to eq(expected)
end
it 'preserves data-src for lazy images' do
input = "![ImageTest](/uploads/test.png)"
image_url = "data-src=\"/uploads/test.png\""
expect(helper.event_note(input)).to match(image_url)
end
context 'labels formatting' do
let(:input) { 'this should be ~label_1' }
......
......@@ -278,6 +278,25 @@ describe('Issue card component', () => {
nodes.includes(label1.color),
).toBe(true);
});
it('does not render label if label does not have an ID', (done) => {
component.issue.addLabel(new ListLabel({
title: 'closed',
}));
Vue.nextTick()
.then(() => {
expect(
component.$el.querySelectorAll('.label').length,
).toBe(2);
expect(
component.$el.textContent,
).not.toContain('closed');
done();
})
.catch(done.fail);
});
});
});
});
require 'spec_helper'
describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state: true, broken_storage: true do
let(:circuit_breaker) { described_class.new('default') }
let(:storage_name) { 'default' }
let(:circuit_breaker) { described_class.new(storage_name) }
let(:hostname) { Gitlab::Environment.hostname }
let(:cache_key) { "storage_accessible:default:#{hostname}" }
let(:cache_key) { "storage_accessible:#{storage_name}:#{hostname}" }
before do
# Override test-settings for the circuitbreaker with something more realistic
# for these specs.
stub_storage_settings('default' => {
'path' => TestEnv.repos_path,
'failure_count_threshold' => 10,
'failure_wait_time' => 30,
'failure_reset_time' => 1800,
'storage_timeout' => 5
},
'broken' => {
'path' => 'tmp/tests/non-existent-repositories',
'failure_count_threshold' => 10,
'failure_wait_time' => 30,
'failure_reset_time' => 1800,
'storage_timeout' => 5
}
)
end
def value_from_redis(name)
Gitlab::Git::Storage.redis.with do |redis|
......@@ -96,14 +117,14 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state:
end
describe '#circuit_broken?' do
it 'is closed when there is no last failure' do
it 'is working when there is no last failure' do
set_in_redis(:last_failure, nil)
set_in_redis(:failure_count, 0)
expect(circuit_breaker.circuit_broken?).to be_falsey
end
it 'is open when there was a recent failure' do
it 'is broken when there was a recent failure' do
Timecop.freeze do
set_in_redis(:last_failure, 1.second.ago.to_f)
set_in_redis(:failure_count, 1)
......@@ -112,16 +133,34 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state:
end
end
it 'is open when there are to many failures' do
it 'is broken when there are too many failures' do
set_in_redis(:last_failure, 1.day.ago.to_f)
set_in_redis(:failure_count, 200)
expect(circuit_breaker.circuit_broken?).to be_truthy
end
context 'the `failure_wait_time` is set to 0' do
before do
stub_storage_settings('default' => {
'failure_wait_time' => 0,
'path' => TestEnv.repos_path
})
end
it 'is working even when there is a recent failure' do
Timecop.freeze do
set_in_redis(:last_failure, 0.seconds.ago.to_f)
set_in_redis(:failure_count, 1)
expect(circuit_breaker.circuit_broken?).to be_falsey
end
end
end
end
describe "storage_available?" do
context 'when the storage is available' do
context 'the storage is available' do
it 'tracks that the storage was accessible an raises the error' do
expect(circuit_breaker).to receive(:track_storage_accessible)
......@@ -136,8 +175,8 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state:
end
end
context 'when storage is not available' do
let(:circuit_breaker) { described_class.new('broken') }
context 'storage is not available' do
let(:storage_name) { 'broken' }
it 'tracks that the storage was inaccessible' do
expect(circuit_breaker).to receive(:track_storage_inaccessible)
......@@ -158,8 +197,8 @@ describe Gitlab::Git::Storage::CircuitBreaker, clean_gitlab_redis_shared_state:
end
end
context 'when the storage is not available' do
let(:circuit_breaker) { described_class.new('broken') }
context 'the storage is not available' do
let(:storage_name) { 'broken' }
it 'raises an error' do
expect(circuit_breaker).to receive(:track_storage_inaccessible)
......
This diff is collapsed.
......@@ -119,5 +119,19 @@ describe Gitlab::GitalyClient::CommitService do
client.tree_entries(repository, revision, path)
end
context 'with UTF-8 params strings' do
let(:revision) { "branch\u011F" }
let(:path) { "foo/\u011F.txt" }
it 'handles string encodings correctly' do
expect_any_instance_of(Gitaly::CommitService::Stub)
.to receive(:get_tree_entries)
.with(gitaly_request_with_path(storage_name, relative_path), kind_of(Hash))
.and_return([])
client.tree_entries(repository, revision, path)
end
end
end
end
require 'spec_helper'
describe Gitlab::SidekiqThrottler do
before do
Sidekiq.options[:concurrency] = 35
stub_application_setting(
sidekiq_throttling_enabled: true,
sidekiq_throttling_factor: 0.1,
sidekiq_throttling_queues: %w[build project_cache]
)
end
describe '#execute!' do
it 'sets limits on the selected queues' do
described_class.execute!
context 'when job throttling is enabled' do
before do
Sidekiq.options[:concurrency] = 35
stub_application_setting(
sidekiq_throttling_enabled: true,
sidekiq_throttling_factor: 0.1,
sidekiq_throttling_queues: %w[build project_cache]
)
end
it 'requires sidekiq-limit_fetch' do
expect(described_class).to receive(:require).with('sidekiq-limit_fetch').and_call_original
described_class.execute!
end
it 'sets limits on the selected queues' do
described_class.execute!
expect(Sidekiq::Queue['build'].limit).to eq 4
expect(Sidekiq::Queue['project_cache'].limit).to eq 4
end
it 'does not set limits on other queues' do
described_class.execute!
expect(Sidekiq::Queue['build'].limit).to eq 4
expect(Sidekiq::Queue['project_cache'].limit).to eq 4
expect(Sidekiq::Queue['merge'].limit).to be_nil
end
end
it 'does not set limits on other queues' do
described_class.execute!
context 'when job throttling is disabled' do
it 'does not require sidekiq-limit_fetch' do
expect(described_class).not_to receive(:require).with('sidekiq-limit_fetch')
expect(Sidekiq::Queue['merge'].limit).to be_nil
described_class.execute!
end
end
end
end
......@@ -6,7 +6,7 @@ require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_
describe MigrateProcessCommitWorkerJobs do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:commit) { project.commit.raw.raw_commit }
let(:commit) { project.commit.raw.rugged_commit }
describe 'Project' do
describe 'find_including_path' do
......
......@@ -53,6 +53,29 @@ describe BroadcastMessage do
2.times { described_class.current }
end
it 'includes messages that need to be displayed in the future' do
create(:broadcast_message)
future = create(
:broadcast_message,
starts_at: Time.now + 10.minutes,
ends_at: Time.now + 20.minutes
)
expect(described_class.current.length).to eq(1)
Timecop.travel(future.starts_at) do
expect(described_class.current.length).to eq(2)
end
end
it 'does not clear the cache if only a future message should be displayed' do
create(:broadcast_message, :future)
expect(Rails.cache).not_to receive(:delete)
expect(described_class.current.length).to eq(0)
end
end
describe '#active?' do
......
......@@ -55,10 +55,15 @@ describe Ci::CreatePipelineService do
context 'when merge requests already exist for this source branch' do
it 'updates head pipeline of each merge request' do
merge_request_1 = create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project)
merge_request_2 = create(:merge_request, source_branch: 'master', target_branch: "branch_2", source_project: project)
merge_request_1 = create(:merge_request, source_branch: 'master',
target_branch: "branch_1",
source_project: project)
head_pipeline = pipeline
merge_request_2 = create(:merge_request, source_branch: 'master',
target_branch: "branch_2",
source_project: project)
head_pipeline = execute_service
expect(merge_request_1.reload.head_pipeline).to eq(head_pipeline)
expect(merge_request_2.reload.head_pipeline).to eq(head_pipeline)
......@@ -66,9 +71,11 @@ describe Ci::CreatePipelineService do
context 'when there is no pipeline for source branch' do
it "does not update merge request head pipeline" do
merge_request = create(:merge_request, source_branch: 'other_branch', target_branch: "branch_1", source_project: project)
merge_request = create(:merge_request, source_branch: 'feature',
target_branch: "branch_1",
source_project: project)
head_pipeline = pipeline
head_pipeline = execute_service
expect(merge_request.reload.head_pipeline).not_to eq(head_pipeline)
end
......@@ -76,13 +83,19 @@ describe Ci::CreatePipelineService do
context 'when merge request target project is different from source project' do
let!(:target_project) { create(:project, :repository) }
let!(:forked_project_link) { create(:forked_project_link, forked_to_project: project, forked_from_project: target_project) }
let!(:forked_project_link) do
create(:forked_project_link, forked_to_project: project,
forked_from_project: target_project)
end
it 'updates head pipeline for merge request' do
merge_request =
create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project, target_project: target_project)
merge_request = create(:merge_request, source_branch: 'master',
target_branch: "branch_1",
source_project: project,
target_project: target_project)
head_pipeline = pipeline
head_pipeline = execute_service
expect(merge_request.reload.head_pipeline).to eq(head_pipeline)
end
......@@ -90,15 +103,36 @@ describe Ci::CreatePipelineService do
context 'when the pipeline is not the latest for the branch' do
it 'does not update merge request head pipeline' do
merge_request = create(:merge_request, source_branch: 'master', target_branch: "branch_1", source_project: project)
merge_request = create(:merge_request, source_branch: 'master',
target_branch: "branch_1",
source_project: project)
allow_any_instance_of(Ci::Pipeline).to receive(:latest?).and_return(false)
allow_any_instance_of(Ci::Pipeline)
.to receive(:latest?).and_return(false)
pipeline
execute_service
expect(merge_request.reload.head_pipeline).to be_nil
end
end
context 'when pipeline has errors' do
before do
stub_ci_pipeline_yaml_file('some invalid syntax')
end
it 'updates merge request head pipeline reference' do
merge_request = create(:merge_request, source_branch: 'master',
target_branch: 'feature',
source_project: project)
head_pipeline = execute_service
expect(head_pipeline).to be_persisted
expect(head_pipeline.yaml_errors).to be_present
expect(merge_request.reload.head_pipeline).to eq head_pipeline
end
end
end
context 'auto-cancel enabled' do
......
......@@ -39,14 +39,17 @@ module StubConfiguration
end
def stub_storage_settings(messages)
# Default storage is always required
messages['default'] ||= Gitlab.config.repositories.storages.default
messages.each do |storage_name, storage_settings|
storage_settings['path'] ||= TestEnv.repos_path
storage_settings['failure_count_threshold'] ||= 10
storage_settings['failure_wait_time'] ||= 30
storage_settings['failure_reset_time'] ||= 1800
storage_settings['storage_timeout'] ||= 5
end
allow(Gitlab.config.repositories).to receive(:storages).and_return(messages)
allow(Gitlab.config.repositories).to receive(:storages).and_return(Settingslogic.new(messages))
end
private
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment