Commit 759f102d authored by Luke "Jared" Bennett's avatar Luke "Jared" Bennett

Merge branch 'master' into balsalmiq-support

parents adff7923 03f13af5
......@@ -19,8 +19,8 @@ variables:
before_script:
- bundle --version
- . scripts/utils.sh
- ./scripts/prepare_build.sh
- source scripts/utils.sh
- source scripts/prepare_build.sh
stages:
- prepare
......@@ -68,6 +68,13 @@ stages:
- //@gitlab-org/gitlab-ee
- //@gitlab/gitlab-ee
# Skip all jobs except the ones that begin with 'docs/'.
# Used for commits including ONLY documentation changes.
# https://docs.gitlab.com/ce/development/writing_documentation.html#testing
.except-docs: &except-docs
except:
- /^docs\/.*/
.rspec-knapsack: &rspec-knapsack
stage: test
<<: *dedicated-runner
......@@ -91,11 +98,13 @@ stages:
.rspec-knapsack-pg: &rspec-knapsack-pg
<<: *rspec-knapsack
<<: *use-pg
<<: *except-docs
.rspec-knapsack-mysql: &rspec-knapsack-mysql
<<: *rspec-knapsack
<<: *use-mysql
<<: *only-master-and-ee-or-mysql
<<: *except-docs
.spinach-knapsack: &spinach-knapsack
stage: test
......@@ -120,16 +129,19 @@ stages:
.spinach-knapsack-pg: &spinach-knapsack-pg
<<: *spinach-knapsack
<<: *use-pg
<<: *except-docs
.spinach-knapsack-mysql: &spinach-knapsack-mysql
<<: *spinach-knapsack
<<: *use-mysql
<<: *only-master-and-ee-or-mysql
<<: *except-docs
# Prepare and merge knapsack tests
knapsack:
<<: *knapsack-state
<<: *dedicated-runner
<<: *except-docs
stage: prepare
script:
- mkdir -p knapsack/${CI_PROJECT_NAME}/
......@@ -156,6 +168,7 @@ update-knapsack:
setup-test-env:
<<: *use-pg
<<: *dedicated-runner
<<: *except-docs
stage: prepare
script:
- node --version
......@@ -243,6 +256,7 @@ spinach mysql 9 10: *spinach-knapsack-mysql
.exec: &exec
<<: *ruby-static-analysis
<<: *dedicated-runner
<<: *except-docs
stage: test
script:
- bundle exec $CI_JOB_NAME
......@@ -250,6 +264,7 @@ spinach mysql 9 10: *spinach-knapsack-mysql
rubocop:
<<: *ruby-static-analysis
<<: *dedicated-runner
<<: *except-docs
stage: test
script:
- bundle exec "rubocop --require rubocop-rspec"
......@@ -266,6 +281,7 @@ rake downtime_check:
- master
- tags
- /^[\d-]+-stable(-ee)?$/
- /^docs\/*/
rake ee_compat_check:
<<: *exec
......@@ -296,10 +312,12 @@ rake ee_compat_check:
rake pg db:migrate:reset:
<<: *db-migrate-reset
<<: *use-pg
<<: *except-docs
rake mysql db:migrate:reset:
<<: *db-migrate-reset
<<: *use-mysql
<<: *except-docs
.db-rollback: &db-rollback
stage: test
......@@ -311,10 +329,12 @@ rake mysql db:migrate:reset:
rake pg db:rollback:
<<: *db-rollback
<<: *use-pg
<<: *except-docs
rake mysql db:rollback:
<<: *db-rollback
<<: *use-mysql
<<: *except-docs
.db-seed_fu: &db-seed_fu
stage: test
......@@ -336,14 +356,17 @@ rake mysql db:rollback:
rake pg db:seed_fu:
<<: *db-seed_fu
<<: *use-pg
<<: *except-docs
rake mysql db:seed_fu:
<<: *db-seed_fu
<<: *use-mysql
<<: *except-docs
rake gitlab:assets:compile:
stage: test
<<: *dedicated-runner
<<: *except-docs
dependencies: []
variables:
NODE_ENV: "production"
......@@ -367,6 +390,7 @@ rake karma:
stage: test
<<: *use-pg
<<: *dedicated-runner
<<: *except-docs
variables:
BABEL_ENV: "coverage"
script:
......@@ -447,6 +471,7 @@ coverage:
stage: post-test
services: []
<<: *dedicated-runner
<<: *except-docs
variables:
SETUP_DB: "false"
USE_BUNDLE_INSTALL: "true"
......@@ -462,6 +487,7 @@ coverage:
lint:javascript:
<<: *dedicated-runner
<<: *except-docs
stage: test
before_script: []
script:
......@@ -469,6 +495,7 @@ lint:javascript:
lint:javascript:report:
<<: *dedicated-runner
<<: *except-docs
stage: post-test
before_script: []
script:
......
Please read this!
Before opening a new issue, make sure to search for keywords in the issues
filtered by the "regression" or "bug" label:
- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=regression
- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=bug
and verify the issue you're about to submit isn't a duplicate.
Please remove this notice if you're confident your issue isn't a duplicate.
------
### Summary
(Summarize the bug encountered concisely)
......@@ -56,3 +70,5 @@ logs, and code as it's very hard to read otherwise.)
### Possible fixes
(If you can, link to the line of code that might be responsible for the problem)
/label ~bug
Please read this!
Before opening a new issue, make sure to search for keywords in the issues
filtered by the "feature proposal" label:
- https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name%5B%5D=feature+proposal
and verify the issue you're about to submit isn't a duplicate.
Please remove this notice if you're confident your issue isn't a duplicate.
------
### Description
(Include problem, use cases, benefits, and/or goals)
......@@ -15,3 +28,5 @@
3. How does someone use this
During implementation, this can then be copied and used as a starter for the documentation.)
/label ~"feature proposal"
......@@ -983,10 +983,12 @@ RSpec/ExpectActual:
# Checks the file and folder naming of the spec file.
RSpec/FilePath:
Enabled: false
CustomTransform:
RuboCop: rubocop
RSpec: rspec
Enabled: true
IgnoreMethods: true
Exclude:
- 'qa/**/*'
- 'spec/javascripts/fixtures/*'
- 'spec/requests/api/v3/*'
# Checks if there are focused specs.
RSpec/Focus:
......
......@@ -330,7 +330,7 @@ GEM
grape-entity (0.6.0)
activesupport
multi_json (>= 1.3.2)
grpc (1.1.2)
grpc (1.2.5)
google-protobuf (~> 3.1)
googleauth (~> 0.5.1)
haml (4.0.7)
......
......@@ -227,8 +227,8 @@
.award-control-icon-positive,
.award-control-icon-super-positive {
position: absolute;
left: 7px;
bottom: 9px;
left: 11px;
bottom: 7px;
opacity: 0;
@include transition(opacity, transform);
}
......
......@@ -61,11 +61,13 @@
.file-content {
background: $white-light;
&.image_file {
&.image_file,
&.video {
background: $file-image-bg;
text-align: center;
img {
img,
video {
padding: 20px;
max-width: 80%;
}
......
......@@ -38,6 +38,7 @@ module ServiceParams
:new_issue_url,
:notify,
:notify_only_broken_pipelines,
:notify_only_default_branch,
:password,
:priority,
:project_key,
......
if Rails.env.test?
class UnicornTestController < ActionController::Base
def pid
render plain: Process.pid.to_s
end
def kill
Process.kill(params[:signal], Process.pid)
render plain: 'Bye!'
end
end
end
......@@ -10,11 +10,12 @@ module EventsHelper
'deleted' => 'icon_trash_o'
}.freeze
def link_to_author(event)
def link_to_author(event, self_added: false)
author = event.author
if author
link_to author.name, user_path(author.username), title: author.name
name = self_added ? 'You' : author.name
link_to name, user_path(author.username), title: name
else
event.author_name
end
......
......@@ -74,7 +74,7 @@ module MarkupHelper
context[:project] ||= @project
html = markdown_unsafe(text, context)
banzai_postprocess(html, context)
prepare_for_rendering(html, context)
end
def markdown_field(object, field)
......@@ -82,13 +82,13 @@ module MarkupHelper
return '' unless object.present?
html = Banzai.render_field(object, field)
banzai_postprocess(html, object.banzai_render_context(field))
prepare_for_rendering(html, object.banzai_render_context(field))
end
def markup(file_name, text, context = {})
context[:project] ||= @project
html = context.delete(:rendered) || markup_unsafe(file_name, text, context)
banzai_postprocess(html, context)
prepare_for_rendering(html, context)
end
def render_wiki_content(wiki_page)
......@@ -107,14 +107,14 @@ module MarkupHelper
wiki_page.formatted_content.html_safe
end
banzai_postprocess(html, context)
prepare_for_rendering(html, context)
end
def markup_unsafe(file_name, text, context = {})
return '' unless text.present?
if gitlab_markdown?(file_name)
Hamlit::RailsHelpers.preserve(markdown_unsafe(text, context))
markdown_unsafe(text, context)
elsif asciidoc?(file_name)
asciidoc_unsafe(text)
elsif plain?(file_name)
......@@ -225,8 +225,7 @@ module MarkupHelper
Gitlab::OtherMarkup.render(file_name, text)
end
# Calls Banzai.post_process with some common context options
def banzai_postprocess(html, context = {})
def prepare_for_rendering(html, context = {})
return '' unless html.present?
context.merge!(
......@@ -239,7 +238,9 @@ module MarkupHelper
requested_path: @path
)
Banzai.post_process(html, context)
html = Banzai.post_process(html, context)
Hamlit::RailsHelpers.preserve(html)
end
extend self
......
......@@ -13,13 +13,13 @@ module TodosHelper
def todo_action_name(todo)
case todo.action
when Todo::ASSIGNED then 'assigned you'
when Todo::MENTIONED then 'mentioned you on'
when Todo::ASSIGNED then todo.self_added? ? 'assigned' : 'assigned you'
when Todo::MENTIONED then "mentioned #{todo_action_subject(todo)} on"
when Todo::BUILD_FAILED then 'The build failed for'
when Todo::MARKED then 'added a todo for'
when Todo::APPROVAL_REQUIRED then 'set you as an approver for'
when Todo::APPROVAL_REQUIRED then "set #{todo_action_subject(todo)} as an approver for"
when Todo::UNMERGEABLE then 'Could not merge'
when Todo::DIRECTLY_ADDRESSED then 'directly addressed you on'
when Todo::DIRECTLY_ADDRESSED then "directly addressed #{todo_action_subject(todo)} on"
end
end
......@@ -148,6 +148,10 @@ module TodosHelper
private
def todo_action_subject(todo)
todo.self_added? ? 'yourself' : 'you'
end
def show_todo_state?(todo)
(todo.target.is_a?(MergeRequest) || todo.target.is_a?(Issue)) && %w(closed merged).include?(todo.target.state)
end
......
......@@ -28,6 +28,8 @@ class Blob < SimpleDelegator
BlobViewer::Sketch,
BlobViewer::Balsamiq,
BlobViewer::Video,
BlobViewer::PDF,
BlobViewer::BinarySTL,
......
module BlobViewer
class Video < Base
include Rich
include ClientSide
self.partial_name = 'video'
self.extensions = UploaderHelper::VIDEO_EXT
self.binary = true
self.switcher_icon = 'film'
self.switcher_title = 'video'
end
end
......@@ -34,6 +34,7 @@ class Label < ActiveRecord::Base
scope :templates, -> { where(template: true) }
scope :with_title, ->(title) { where(title: title) }
scope :on_project_boards, ->(project_id) { joins(lists: :board).merge(List.movable).where(boards: { project_id: project_id }) }
def self.prioritized(project)
joins(:priorities)
......
......@@ -154,6 +154,11 @@ class Member < ActiveRecord::Base
def add_users(source, users, access_level, current_user: nil, expires_at: nil)
return [] unless users.present?
# Collect all user ids into separate array
# so we can use single sql query to get user objects
user_ids = users.select { |user| user =~ /\A\d+\Z/ }
users = users - user_ids + User.where(id: user_ids)
self.transaction do
users.map do |user|
add_user(
......
......@@ -84,6 +84,10 @@ class Todo < ActiveRecord::Base
action == BUILD_FAILED
end
def assigned?
action == ASSIGNED
end
def action_name
ACTION_NAMES[action]
end
......@@ -117,6 +121,14 @@ class Todo < ActiveRecord::Base
end
end
def self_added?
author == user
end
def self_assigned?
assigned? && self_added?
end
private
def keep_around_commit
......
......@@ -61,7 +61,7 @@ module Boards
if moving_to_list.movable?
moving_from_list.label_id
else
project.boards.joins(:lists).merge(List.movable).pluck(:label_id)
Label.on_project_boards(project.id).pluck(:label_id)
end
Array(label_ids).compact
......
......@@ -330,6 +330,28 @@ module SlashCommands
@updates[:target_branch] = branch_name if project.repository.branch_names.include?(branch_name)
end
desc 'Move issue from one column of the board to another'
params '~"Target column"'
condition do
issuable.is_a?(Issue) &&
current_user.can?(:"update_#{issuable.to_ability_name}", issuable) &&
issuable.project.boards.count == 1
end
command :board_move do |target_list_name|
label_ids = find_label_ids(target_list_name)
if label_ids.size == 1
label_id = label_ids.first
# Ensure this label corresponds to a list on the board
next unless Label.on_project_boards(issuable.project_id).where(id: label_id).exists?
@updates[:remove_label_ids] =
issuable.labels.on_project_boards(issuable.project_id).where.not(id: label_id).pluck(:id)
@updates[:add_label_ids] = [label_id]
end
end
def find_label_ids(labels_param)
label_ids_by_reference = extract_references(labels_param, :label).map(&:id)
labels_ids_by_name = LabelsFinder.new(current_user, project_id: project.id, name: labels_param.split).execute.select(:id)
......
......@@ -9,7 +9,7 @@
.title-item.author-name
- if todo.author
= link_to_author(todo)
= link_to_author(todo, self_added: todo.self_added?)
- else
(removed)
......@@ -22,6 +22,10 @@
- else
(removed)
- if todo.self_assigned?
.title-item.action-name
to yourself
.title-item
&middot;
......
......@@ -27,7 +27,6 @@
.row
.col-md-8
.documentation-index
= preserve do
= markdown(@help_index)
.col-md-4
.panel.panel-default
......
......@@ -2,7 +2,6 @@
%div{ class: container_class }
.wiki-holder.prepend-top-default.append-bottom-default
.wiki
= preserve do
= render_wiki_content(@wiki_home)
- else
- can_create_wiki = can?(current_user, :create_wiki, @project)
......
.file-content.video
%video{ src: blob_raw_url, controls: true, data: { setup: '{}' } }
......@@ -58,7 +58,6 @@
- if @issue.description.present?
.description{ class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : '' }
.wiki
= preserve do
= markdown_field(@issue, :description)
%textarea.hidden.js-task-list-field
= @issue.description
......
......@@ -6,7 +6,6 @@
- if @merge_request.description.present?
.description{ class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : '' }
.wiki
= preserve do
= markdown_field(@merge_request, :description)
%textarea.hidden.js-task-list-field
= @merge_request.description
......
......@@ -43,7 +43,6 @@
- if @milestone.description.present?
.description
.wiki
= preserve do
= markdown_field(@milestone, :description)
- if can?(current_user, :read_issue, @project) && @milestone.total_items_count(current_user).zero?
......
......@@ -75,7 +75,6 @@
= icon('trash-o', class: 'danger-highlight')
.note-body{ class: note_editable ? 'js-task-list-container' : '' }
.note-text.md
= preserve do
= note.redacted_note_html
= edited_time_ago_with_tooltip(note, placement: 'bottom', html_class: 'note_edited_ago', include_author: true)
- if note_editable
......
......@@ -24,7 +24,6 @@
- if release && release.description.present?
.description.prepend-top-default
.wiki
= preserve do
= markdown_field(release, :description)
.row-fixed-content.controls
......
......@@ -38,7 +38,6 @@
- if @release.description.present?
.description
.wiki
= preserve do
= markdown_field(@release, :description)
- else
This tag has no release notes.
......@@ -27,7 +27,6 @@
.wiki-holder.prepend-top-default.append-bottom-default
.wiki
= preserve do
= render_wiki_content(@page)
= render 'sidebar'
......@@ -8,7 +8,6 @@
.pull-right ##{issue.iid}
- if issue.description.present?
.description.term
= preserve do
= search_md_sanitize(issue, :description)
%span.light
#{issue.project.name_with_namespace}
......@@ -9,7 +9,6 @@
.pull-right= merge_request.to_reference
- if merge_request.description.present?
.description.term
= preserve do
= search_md_sanitize(merge_request, :description)
%span.light
#{merge_request.project.name_with_namespace}
......@@ -5,5 +5,4 @@
- if milestone.description.present?
.description.term
= preserve do
= search_md_sanitize(milestone, :description)
......@@ -22,5 +22,4 @@
.note-search-result
.term
= preserve do
= search_md_sanitize(note, :note)
......@@ -4,7 +4,6 @@
= render "projects/services/#{@service.to_param}/help", subject: subject
- elsif @service.help.present?
.well
= preserve do
= markdown @service.help
.service-settings
......
......@@ -64,7 +64,7 @@
%span.remaining-days= remaining_days
- if !project || can?(current_user, :read_issue, project)
.block
.block.issues
.sidebar-collapsed-icon
%strong
= icon('hashtag', 'aria-hidden': 'true')
......@@ -85,7 +85,7 @@
Closed:
= milestone.issues_visible_to_user(current_user).closed.count
.block
.block.merge-requests
.sidebar-collapsed-icon
%strong
= icon('exclamation', 'aria-hidden': 'true')
......
---
title: Improve text on todo list when the todo action comes from yourself
merge_request: 10594
author: Jacopo Beschi @jacopo-beschi
---
title: Add board_move slash command
merge_request: 10433
author: Alex Sanford
---
title: Add index on ci_runners.contacted_at
merge_request: 10876
author: blackst0ne
---
title: Display video blobs in-line like images
merge_request:
author:
---
title: Use GitLab Pages v0.4.1
merge_request:
author:
---
title: Ensure the chat notifications service properly saves the "Notify only default branch" setting
merge_request: 10959
author:
......@@ -36,10 +36,10 @@ if Rails.env.test?
RspecProfiling::Collectors::PSQL.prepend(RspecProfilingExt::PSQL)
config.collector = RspecProfiling::Collectors::PSQL
end
end
if ENV.has_key?('CI') && ENV['GITLAB_DATABASE'] == 'postgresql'
if ENV.key?('CI')
RspecProfiling::VCS::Git.prepend(RspecProfilingExt::Git)
RspecProfiling::Run.prepend(RspecProfilingExt::Run)
end
end
end
......@@ -99,5 +99,7 @@ Rails.application.routes.draw do
end
end
draw :test if Rails.env.test?
get '*unmatched_route', to: 'application#route_not_found'
end
get '/unicorn_test/pid' => 'unicorn_test#pid'
post '/unicorn_test/kill' => 'unicorn_test#kill'
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddIndexOnCiRunnersContactedAt < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
# Set this constant to true if this migration requires downtime.
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_index :ci_runners, :contacted_at
end
def down
remove_concurrent_index :ci_runners, :contacted_at if index_exists?(:ci_runners, :contacted_at)
end
end
......@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170426175636) do
ActiveRecord::Schema.define(version: 20170426181740) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
......@@ -296,6 +296,7 @@ ActiveRecord::Schema.define(version: 20170426175636) do
t.boolean "locked", default: false, null: false
end
add_index "ci_runners", ["contacted_at"], name: "index_ci_runners_on_contacted_at", using: :btree
add_index "ci_runners", ["is_shared"], name: "index_ci_runners_on_is_shared", using: :btree
add_index "ci_runners", ["locked"], name: "index_ci_runners_on_locked", using: :btree
add_index "ci_runners", ["token"], name: "index_ci_runners_on_token", using: :btree
......
......@@ -70,7 +70,7 @@ main: # 'main' is the GitLab 'provider ID' of this LDAP server
host: '_your_ldap_server'
# This port is an example, it is sometimes different but it is always an integer and not a string
port: 389
uid: 'sAMAccountName'
uid: 'sAMAccountName' # This should be the attribute, not the value that maps to uid.
method: 'plain' # "tls" or "ssl" or "plain"
# Examples: 'america\\momo' or 'CN=Gitlab Git,CN=Users,DC=mydomain,DC=com'
......
......@@ -70,3 +70,27 @@ All the docs follow the same [styleguide](doc_styleguide.md).
### Markdown
Currently GitLab docs use Redcarpet as [markdown](../user/markdown.md) engine, but there's an [open discussion](https://gitlab.com/gitlab-com/gitlab-docs/issues/50) for implementing Kramdown in the near future.
## Testing
We try to treat documentation as code, thus have implemented some testing.
Currently, the following tests are in place:
1. `docs:check:links`: Check that all internal (relative) links work correctly
1. `docs:check:apilint`: Check that the API docs follow some conventions
If your contribution contains **only** documentation changes, you can speed up
the CI process by prepending to the name of your branch: `docs/`. For example,
a valid name would be `docs/update-api-issues` and it will run only the docs
tests. If the name is `docs-update-api-issues`, the whole test suite will run
(including docs).
---
When you submit a merge request to GitLab Community Edition (CE), there is an
additional job called `rake ee_compat_check` that runs against Enterprise
Edition (EE) and checks if your changes can apply cleanly to the EE codebase.
If that job fails, read the instructions in the job log for what to do next.
Contributors do not need to submit their changes to EE, GitLab Inc. employees
on the other hand need to make sure that their changes apply cleanly to both
CE and EE.
......@@ -100,7 +100,7 @@ On failure, the endpoint will return a `500` HTTP status code. On success, the e
will return a valid successful HTTP status code, and a `success` message. Ideally your
uptime monitoring should look for the success message.
[ce-10416]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3888
[ce-10416]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/10416
[ce-3888]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/3888
[pingdom]: https://www.pingdom.com
[nagios-health]: https://nagios-plugins.org/doc/man/check_http.html
......
......@@ -36,3 +36,4 @@ do.
| `/remove_time_spent` | Remove time spent |
| `/target_branch <Branch Name>` | Set target branch for current merge request |
| `/award :emoji:` | Toggle award for :emoji: |
| `/board_move ~column` | Move issue to column on the board |
......@@ -21,7 +21,7 @@ class Spinach::Features::ProjectCommits < Spinach::FeatureSteps
expect(response_headers['Content-Type']).to have_content("application/atom+xml")
expect(body).to have_selector("title", text: "#{@project.name}:master commits")
expect(body).to have_selector("author email", text: commit.author_email)
expect(body).to have_selector("entry summary", text: commit.description[0..10].delete("\r"))
expect(body).to have_selector("entry summary", text: commit.description[0..10].delete("\r\n"))
end
step 'I click on tag link' do
......
......@@ -2,7 +2,7 @@ desc 'Security check via brakeman'
task :brakeman do
# We get 0 warnings at level 'w3' but we would like to reach 'w2'. Merge
# requests are welcome!
if system(*%w(brakeman --no-progress --skip-files lib/backup/repository.rb -w3 -z))
if system(*%w(brakeman --no-progress --skip-files lib/backup/repository.rb,app/controllers/unicorn_test_controller.rb -w3 -z))
puts 'Security check succeed'
else
puts 'Security check failed'
......
#!/bin/sh
. scripts/utils.sh
export SETUP_DB=${SETUP_DB:-true}
......@@ -32,7 +30,7 @@ sed -i 's/localhost/redis/g' config/resque.yml
cp config/gitlab.yml.example config/gitlab.yml
if [ "$USE_BUNDLE_INSTALL" != "false" ]; then
retry bundle install --clean $BUNDLE_INSTALL_FLAGS && bundle check
bundle install --clean $BUNDLE_INSTALL_FLAGS && bundle check
fi
# Only install knapsack after bundle install! Otherwise oddly some native
......
require 'spec_helper'
describe Projects::BlobController do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
sign_in(user)
project.team << [user, :master]
allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz'])
allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0'])
controller.instance_variable_set(:@project, project)
end
describe "GET show" do
render_views
before do
get(:show,
namespace_id: project.namespace,
project_id: project,
id: id)
end
context "valid branch, valid file" do
let(:id) { 'master/README.md' }
it { is_expected.to respond_with(:success) }
end
context "valid branch, invalid file" do
let(:id) { 'master/invalid-path.rb' }
it { is_expected.to respond_with(:not_found) }
end
context "invalid branch, valid file" do
let(:id) { 'invalid-branch/README.md' }
it { is_expected.to respond_with(:not_found) }
end
context "binary file" do
let(:id) { 'binary-encoding/encoding/binary-1.bin' }
it { is_expected.to respond_with(:success) }
end
end
describe 'GET show with tree path' do
render_views
before do
get(:show,
namespace_id: project.namespace,
project_id: project,
id: id)
controller.instance_variable_set(:@blob, nil)
end
context 'redirect to tree' do
let(:id) { 'markdown/doc' }
it 'redirects' do
expect(subject).
to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc")
end
end
end
end
require 'spec_helper'
describe Oauth::AuthorizationsController do
let(:user) { create(:user) }
let(:doorkeeper) do
Doorkeeper::Application.create(
name: "MyApp",
redirect_uri: 'http://example.com',
scopes: "")
end
let(:params) do
{
response_type: "code",
client_id: doorkeeper.uid,
redirect_uri: doorkeeper.redirect_uri,
state: 'state'
}
end
before do
sign_in(user)
end
describe 'GET #new' do
context 'without valid params' do
it 'returns 200 code and renders error view' do
get :new
expect(response).to have_http_status(200)
expect(response).to render_template('doorkeeper/authorizations/error')
end
end
context 'with valid params' do
it 'returns 200 code and renders view' do
get :new, params
expect(response).to have_http_status(200)
expect(response).to render_template('doorkeeper/authorizations/new')
end
it 'deletes session.user_return_to and redirects when skip authorization' do
request.session['user_return_to'] = 'http://example.com'
allow(controller).to receive(:skip_authorization?).and_return(true)
get :new, params
expect(request.session['user_return_to']).to be_nil
expect(response).to have_http_status(302)
end
end
end
end
......@@ -3,6 +3,57 @@ require 'rails_helper'
describe Projects::BlobController do
let(:project) { create(:project, :public, :repository) }
describe "GET show" do
render_views
context 'with file path' do
before do
get(:show,
namespace_id: project.namespace,
project_id: project,
id: id)
end
context "valid branch, valid file" do
let(:id) { 'master/README.md' }
it { is_expected.to respond_with(:success) }
end
context "valid branch, invalid file" do
let(:id) { 'master/invalid-path.rb' }
it { is_expected.to respond_with(:not_found) }
end
context "invalid branch, valid file" do
let(:id) { 'invalid-branch/README.md' }
it { is_expected.to respond_with(:not_found) }
end
context "binary file" do
let(:id) { 'binary-encoding/encoding/binary-1.bin' }
it { is_expected.to respond_with(:success) }
end
end
context 'with tree path' do
before do
get(:show,
namespace_id: project.namespace,
project_id: project,
id: id)
controller.instance_variable_set(:@blob, nil)
end
context 'redirect to tree' do
let(:id) { 'markdown/doc' }
it 'redirects' do
expect(subject).
to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc")
end
end
end
end
describe 'GET diff' do
let(:user) { create(:user) }
......
......@@ -53,7 +53,7 @@ describe "User Feed", feature: true do
end
it 'has XHTML summaries in issue descriptions' do
expect(body).to match /we have a bug!<\/p>\n\n<hr ?\/>\n\n<p dir="auto">I guess/
expect(body).to match /<hr ?\/>/
end
it 'has XHTML summaries in notes' do
......
......@@ -78,11 +78,10 @@ feature 'Project milestone', :feature do
it 'shows the total MR and issue counts' do
find('.milestone-sidebar .block', match: :first)
blocks = all('.milestone-sidebar .block')
aggregate_failures 'MR and issue blocks' do
expect(blocks[3]).to have_content 1
expect(blocks[4]).to have_content 0
expect(find('.milestone-sidebar .block.issues')).to have_content 1
expect(find('.milestone-sidebar .block.merge-requests')).to have_content 0
end
end
end
......
......@@ -9,7 +9,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
allowed_to_push_button = find(".js-allowed-to-push")
unless allowed_to_push_button.text == access_type_name
allowed_to_push_button.click
allowed_to_push_button.trigger('click')
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
end
end
......
......@@ -8,7 +8,7 @@ feature 'Projected Branches', feature: true, js: true do
before { login_as(user) }
def set_protected_branch_name(branch_name)
find(".js-protected-branch-select").click
find(".js-protected-branch-select").trigger('click')
find(".dropdown-input-field").set(branch_name)
click_on("Create wildcard #{branch_name}")
end
......
......@@ -45,8 +45,8 @@ describe 'Dashboard > User filters todos', feature: true, js: true do
wait_for_ajax
expect(find('.todos-list')).to have_content user_1.name
expect(find('.todos-list')).not_to have_content user_2.name
expect(find('.todos-list')).to have_content 'merge request'
expect(find('.todos-list')).not_to have_content 'issue'
end
it "shows only authors of existing todos" do
......
......@@ -99,6 +99,83 @@ describe 'Dashboard Todos', feature: true do
end
end
context 'User created todos for themself' do
before do
login_as(user)
end
context 'issue assigned todo' do
before do
create(:todo, :assigned, user: user, project: project, target: issue, author: user)
visit dashboard_todos_path
end
it 'shows issue assigned to yourself message' do
page.within('.js-todos-all') do
expect(page).to have_content("You assigned issue #{issue.to_reference(full: true)} to yourself")
end
end
end
context 'marked todo' do
before do
create(:todo, :marked, user: user, project: project, target: issue, author: user)
visit dashboard_todos_path
end
it 'shows you added a todo message' do
page.within('.js-todos-all') do
expect(page).to have_content("You added a todo for issue #{issue.to_reference(full: true)}")
expect(page).not_to have_content('to yourself')
end
end
end
context 'mentioned todo' do
before do
create(:todo, :mentioned, user: user, project: project, target: issue, author: user)
visit dashboard_todos_path
end
it 'shows you mentioned yourself message' do
page.within('.js-todos-all') do
expect(page).to have_content("You mentioned yourself on issue #{issue.to_reference(full: true)}")
expect(page).not_to have_content('to yourself')
end
end
end
context 'directly_addressed todo' do
before do
create(:todo, :directly_addressed, user: user, project: project, target: issue, author: user)
visit dashboard_todos_path
end
it 'shows you directly addressed yourself message' do
page.within('.js-todos-all') do
expect(page).to have_content("You directly addressed yourself on issue #{issue.to_reference(full: true)}")
expect(page).not_to have_content('to yourself')
end
end
end
context 'approval todo' do
let(:merge_request) { create(:merge_request) }
before do
create(:todo, :approval_required, user: user, project: project, target: merge_request, author: user)
visit dashboard_todos_path
end
it 'shows you set yourself as an approver message' do
page.within('.js-todos-all') do
expect(page).to have_content("You set yourself as an approver for merge request #{merge_request.to_reference(full: true)}")
expect(page).not_to have_content('to yourself')
end
end
end
end
context 'User has done todos', js: true do
before do
create(:todo, :mentioned, :done, user: user, project: project, target: issue, author: author)
......
......@@ -56,7 +56,7 @@ describe EventsHelper do
it 'preserves code color scheme' do
input = "```ruby\ndef test\n 'hello world'\nend\n```"
expected = '<pre class="code highlight js-syntax-highlight ruby">' \
expected = "\n<pre class=\"code highlight js-syntax-highlight ruby\">" \
"<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>\n" \
"</code></pre>"
expect(helper.event_note(input)).to eq(expected)
......
require 'spec_helper'
describe Gitlab::Checks::ChangeAccess, lib: true do
describe Gitlab::Checks::ForcePush, lib: true do
let(:project) { create(:project, :repository) }
context "exit code checking" do
it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0])
expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
expect { described_class.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
end
it "raises a runtime error if the `popen` call to git returns a non-zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError)
expect { described_class.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError)
end
end
end
require 'spec_helper'
describe Gitlab::UrlBuilder, lib: true do
describe '.build' do
context 'when passing a Commit' do
it 'returns a proper URL' do
commit = build_stubbed(:commit)
url = described_class.build(commit)
expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.path_with_namespace}/commit/#{commit.id}"
end
end
context 'when passing an Issue' do
it 'returns a proper URL' do
issue = build_stubbed(:issue, iid: 42)
url = described_class.build(issue)
expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}"
end
end
context 'when passing a MergeRequest' do
it 'returns a proper URL' do
merge_request = build_stubbed(:merge_request, iid: 42)
url = described_class.build(merge_request)
expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}"
end
end
context 'when passing a Note' do
context 'on a Commit' do
it 'returns a proper URL' do
note = build_stubbed(:note_on_commit)
url = described_class.build(note)
expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
end
end
context 'on a Commit Diff' do
it 'returns a proper URL' do
note = build_stubbed(:diff_note_on_commit)
url = described_class.build(note)
expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
end
end
context 'on an Issue' do
it 'returns a proper URL' do
issue = create(:issue, iid: 42)
note = build_stubbed(:note_on_issue, noteable: issue)
url = described_class.build(note)
expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}"
end
end
context 'on a MergeRequest' do
it 'returns a proper URL' do
merge_request = create(:merge_request, iid: 42)
note = build_stubbed(:note_on_merge_request, noteable: merge_request)
url = described_class.build(note)
expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
end
end
context 'on a MergeRequest Diff' do
it 'returns a proper URL' do
merge_request = create(:merge_request, iid: 42)
note = build_stubbed(:diff_note_on_merge_request, noteable: merge_request)
url = described_class.build(note)
expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
end
end
context 'on a ProjectSnippet' do
it 'returns a proper URL' do
project_snippet = create(:project_snippet)
note = build_stubbed(:note_on_project_snippet, noteable: project_snippet)
url = described_class.build(note)
expect(url).to eq "#{Settings.gitlab['url']}/#{project_snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}"
end
end
context 'on another object' do
it 'returns a proper URL' do
project = build_stubbed(:empty_project)
expect { described_class.build(project) }.
to raise_error(NotImplementedError, 'No URL builder defined for Project')
end
end
end
context 'when passing a WikiPage' do
it 'returns a proper URL' do
wiki_page = build(:wiki_page)
url = described_class.build(wiki_page)
expect(url).to eq "#{Gitlab.config.gitlab.url}#{wiki_page.wiki.wiki_base_path}/#{wiki_page.slug}"
end
end
end
end
require 'spec_helper'
require 'email_spec'
describe Notify, "merge request notifications" do
describe Emails::MergeRequests do
include EmailSpec::Matchers
describe "#resolved_all_discussions_email" do
......
require 'spec_helper'
require 'email_spec'
describe Notify do
describe Emails::Profile do
include EmailSpec::Matchers
include_context 'gitlab email notification'
......@@ -15,7 +15,6 @@ describe Notify do
end
end
describe 'profile notifications' do
describe 'for new users, the email' do
let(:example_site_path) { root_path }
let(:new_user) { create(:user, email: new_user_address, created_by_id: 1) }
......@@ -116,5 +115,4 @@ describe Notify do
is_expected.to have_body_text /#{profile_emails_path}/
end
end
end
end
require 'spec_helper'
describe Issue, "Awardable" do
describe Awardable do
let!(:issue) { create(:issue) }
let!(:award_emoji) { create(:award_emoji, :downvote, awardable: issue) }
describe "Associations" do
subject { build(:issue) }
it { is_expected.to have_many(:award_emoji).dependent(:destroy) }
end
......
require 'spec_helper'
describe DiffDiscussion, DiscussionOnDiff, model: true do
describe DiscussionOnDiff, model: true do
subject { create(:diff_note_on_merge_request).to_discussion }
describe "#truncated_diff_lines" do
......@@ -8,9 +8,9 @@ describe DiffDiscussion, DiscussionOnDiff, model: true do
context "when diff is greater than allowed number of truncated diff lines " do
it "returns fewer lines" do
expect(subject.diff_lines.count).to be > described_class::NUMBER_OF_TRUNCATED_DIFF_LINES
expect(subject.diff_lines.count).to be > DiffDiscussion::NUMBER_OF_TRUNCATED_DIFF_LINES
expect(truncated_lines.count).to be <= described_class::NUMBER_OF_TRUNCATED_DIFF_LINES
expect(truncated_lines.count).to be <= DiffDiscussion::NUMBER_OF_TRUNCATED_DIFF_LINES
end
end
......
require 'spec_helper'
describe Issue, "Issuable" do
describe Issuable do
let(:issuable_class) { Issue }
let(:issue) { create(:issue) }
let(:user) { create(:user) }
describe "Associations" do
subject { build(:issue) }
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:author) }
it { is_expected.to belong_to(:assignee) }
......@@ -23,10 +26,14 @@ describe Issue, "Issuable" do
end
describe 'Included modules' do
let(:described_class) { issuable_class }
it { is_expected.to include_module(Awardable) }
end
describe "Validation" do
subject { build(:issue) }
before do
allow(subject).to receive(:set_iid).and_return(false)
end
......@@ -39,9 +46,11 @@ describe Issue, "Issuable" do
end
describe "Scope" do
it { expect(described_class).to respond_to(:opened) }
it { expect(described_class).to respond_to(:closed) }
it { expect(described_class).to respond_to(:assigned) }
subject { build(:issue) }
it { expect(issuable_class).to respond_to(:opened) }
it { expect(issuable_class).to respond_to(:closed) }
it { expect(issuable_class).to respond_to(:assigned) }
end
describe 'author_name' do
......@@ -115,16 +124,16 @@ describe Issue, "Issuable" do
let!(:searchable_issue) { create(:issue, title: "Searchable issue") }
it 'returns notes with a matching title' do
expect(described_class.search(searchable_issue.title)).
expect(issuable_class.search(searchable_issue.title)).
to eq([searchable_issue])
end
it 'returns notes with a partially matching title' do
expect(described_class.search('able')).to eq([searchable_issue])
expect(issuable_class.search('able')).to eq([searchable_issue])
end
it 'returns notes with a matching title regardless of the casing' do
expect(described_class.search(searchable_issue.title.upcase)).
expect(issuable_class.search(searchable_issue.title.upcase)).
to eq([searchable_issue])
end
end
......@@ -135,31 +144,31 @@ describe Issue, "Issuable" do
end
it 'returns notes with a matching title' do
expect(described_class.full_search(searchable_issue.title)).
expect(issuable_class.full_search(searchable_issue.title)).
to eq([searchable_issue])
end
it 'returns notes with a partially matching title' do
expect(described_class.full_search('able')).to eq([searchable_issue])
expect(issuable_class.full_search('able')).to eq([searchable_issue])
end
it 'returns notes with a matching title regardless of the casing' do
expect(described_class.full_search(searchable_issue.title.upcase)).
expect(issuable_class.full_search(searchable_issue.title.upcase)).
to eq([searchable_issue])
end
it 'returns notes with a matching description' do
expect(described_class.full_search(searchable_issue.description)).
expect(issuable_class.full_search(searchable_issue.description)).
to eq([searchable_issue])
end
it 'returns notes with a partially matching description' do
expect(described_class.full_search(searchable_issue.description)).
expect(issuable_class.full_search(searchable_issue.description)).
to eq([searchable_issue])
end
it 'returns notes with a matching description regardless of the casing' do
expect(described_class.full_search(searchable_issue.description.upcase)).
expect(issuable_class.full_search(searchable_issue.description.upcase)).
to eq([searchable_issue])
end
end
......
require 'spec_helper'
describe MergeRequest, Noteable, model: true do
describe Noteable, model: true do
let!(:active_diff_note1) { create(:diff_note_on_merge_request) }
let(:project) { active_diff_note1.project }
subject { active_diff_note1.noteable }
......
require 'spec_helper'
describe Issue, 'RelativePositioning' do
describe RelativePositioning do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:issue1) { create(:issue, project: project) }
......
require 'spec_helper'
describe Issue, 'Spammable' do
describe Spammable do
let(:issue) { create(:issue, description: 'Test Desc.') }
describe 'Associations' do
subject { build(:issue) }
it { is_expected.to have_one(:user_agent_detail).dependent(:destroy) }
end
......
require 'spec_helper'
describe Milestone, "StripAttribute" do
describe StripAttribute do
let(:milestone) { create(:milestone) }
describe ".strip_attributes" do
......
......@@ -390,13 +390,15 @@ describe Member, models: true do
%w[project group].each do |source_type|
context "when source is a #{source_type}" do
let!(:source) { create(source_type, :public, :access_requestable) }
let!(:user) { create(:user) }
let!(:admin) { create(:admin) }
let(:user1) { create(:user) }
let(:user2) { create(:user) }
it 'returns a <Source>Member objects' do
members = described_class.add_users(source, [user], :master)
members = described_class.add_users(source, [user1, user2], :master)
expect(members).to be_a Array
expect(members.size).to eq(2)
expect(members.first).to be_a "#{source_type.classify}Member".constantize
expect(members.first).to be_persisted
end
......
......@@ -125,4 +125,50 @@ describe Todo, models: true do
expect(subject.target_reference).to eq issue.to_reference(full: true)
end
end
describe '#self_added?' do
let(:user_1) { build(:user) }
before do
subject.user = user_1
end
it 'is true when the user is the author' do
subject.author = user_1
expect(subject).to be_self_added
end
it 'is false when the user is not the author' do
subject.author = build(:user)
expect(subject).not_to be_self_added
end
end
describe '#self_assigned?' do
let(:user_1) { build(:user) }
before do
subject.user = user_1
subject.author = user_1
subject.action = Todo::ASSIGNED
end
it 'is true when todo is ASSIGNED and self_added' do
expect(subject).to be_self_assigned
end
it 'is false when the todo is not ASSIGNED' do
subject.action = Todo::MENTIONED
expect(subject).not_to be_self_assigned
end
it 'is false when todo is not self_added' do
subject.author = build(:user)
expect(subject).not_to be_self_assigned
end
end
end
require 'spec_helper'
describe IssuePolicy, models: true do
let(:user) { create(:user) }
let(:guest) { create(:user) }
let(:author) { create(:user) }
let(:assignee) { create(:user) }
let(:reporter) { create(:user) }
let(:group) { create(:group, :public) }
let(:reporter_from_group_link) { create(:user) }
describe '#rules' do
context 'using a regular issue' do
let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project) }
let(:policies) { described_class.abilities(user, issue).to_set }
def permissions(user, issue)
described_class.abilities(user, issue).to_set
end
context 'with a regular user' do
it 'includes the read_issue permission' do
expect(policies).to include(:read_issue)
context 'a private project' do
let(:non_member) { create(:user) }
let(:project) { create(:empty_project, :private) }
let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
let(:issue_no_assignee) { create(:issue, project: project) }
before do
project.team << [guest, :guest]
project.team << [author, :guest]
project.team << [assignee, :guest]
project.team << [reporter, :reporter]
group.add_reporter(reporter_from_group_link)
create(:project_group_link, group: group, project: project)
end
it 'does not include the admin_issue permission' do
expect(policies).not_to include(:admin_issue)
it 'does not allow non-members to read issues' do
expect(permissions(non_member, issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(non_member, issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'does not include the update_issue permission' do
expect(policies).not_to include(:update_issue)
it 'allows guests to read issues' do
expect(permissions(guest, issue)).to include(:read_issue)
expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin issues' do
expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
context 'with a user that is a project reporter' do
before do
project.team << [user, :reporter]
it 'allows reporters from group links to read, update, and admin issues' do
expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'includes the read_issue permission' do
expect(policies).to include(:read_issue)
it 'allows issue authors to read and update their issues' do
expect(permissions(author, issue)).to include(:read_issue, :update_issue)
expect(permissions(author, issue)).not_to include(:admin_issue)
expect(permissions(author, issue_no_assignee)).to include(:read_issue)
expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'includes the admin_issue permission' do
expect(policies).to include(:admin_issue)
it 'allows issue assignees to read and update their issues' do
expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, issue)).not_to include(:admin_issue)
expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'includes the update_issue permission' do
expect(policies).to include(:update_issue)
context 'with confidential issues' do
let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
it 'does not allow non-members to read confidential issues' do
expect(permissions(non_member, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(non_member, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'does not allow guests to read confidential issues' do
expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
context 'with a user that is a project guest' do
before do
project.team << [user, :guest]
it 'allows reporters to read, update, and admin confidential issues' do
expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'includes the read_issue permission' do
expect(policies).to include(:read_issue)
it 'allows reporters from group links to read, update, and admin confidential issues' do
expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'does not include the admin_issue permission' do
expect(policies).not_to include(:admin_issue)
it 'allows issue authors to read and update their confidential issues' do
expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'does not include the update_issue permission' do
expect(policies).not_to include(:update_issue)
it 'allows issue assignees to read and update their confidential issues' do
expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
end
end
context 'using a confidential issue' do
let(:issue) { create(:issue, :confidential) }
context 'a public project' do
let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
let(:issue_no_assignee) { create(:issue, project: project) }
context 'with a regular user' do
let(:policies) { described_class.abilities(user, issue).to_set }
before do
project.team << [guest, :guest]
project.team << [reporter, :reporter]
it 'does not include the read_issue permission' do
expect(policies).not_to include(:read_issue)
group.add_reporter(reporter_from_group_link)
create(:project_group_link, group: group, project: project)
end
it 'does not include the admin_issue permission' do
expect(policies).not_to include(:admin_issue)
it 'allows guests to read issues' do
expect(permissions(guest, issue)).to include(:read_issue)
expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'does not include the update_issue permission' do
expect(policies).not_to include(:update_issue)
it 'allows reporters to read, update, and admin issues' do
expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters from group links to read, update, and admin issues' do
expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
context 'with a user that is a project member' do
let(:policies) { described_class.abilities(user, issue).to_set }
it 'allows issue authors to read and update their issues' do
expect(permissions(author, issue)).to include(:read_issue, :update_issue)
expect(permissions(author, issue)).not_to include(:admin_issue)
before do
issue.project.team << [user, :reporter]
expect(permissions(author, issue_no_assignee)).to include(:read_issue)
expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'includes the read_issue permission' do
expect(policies).to include(:read_issue)
it 'allows issue assignees to read and update their issues' do
expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, issue)).not_to include(:admin_issue)
expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'includes the admin_issue permission' do
expect(policies).to include(:admin_issue)
context 'with confidential issues' do
let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
it 'does not allow guests to read confidential issues' do
expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'includes the update_issue permission' do
expect(policies).to include(:update_issue)
it 'allows reporters to read, update, and admin confidential issues' do
expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporter from group links to read, update, and admin confidential issues' do
expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
context 'without a user' do
let(:policies) { described_class.abilities(nil, issue).to_set }
it 'allows issue authors to read and update their confidential issues' do
expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
it 'does not include the read_issue permission' do
expect(policies).not_to include(:read_issue)
expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'does not include the admin_issue permission' do
expect(policies).not_to include(:admin_issue)
end
it 'allows issue assignees to read and update their confidential issues' do
expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
it 'does not include the update_issue permission' do
expect(policies).not_to include(:update_issue)
end
expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
end
end
......
require 'spec_helper'
describe IssuePolicy, models: true do
let(:guest) { create(:user) }
let(:author) { create(:user) }
let(:assignee) { create(:user) }
let(:reporter) { create(:user) }
let(:group) { create(:group, :public) }
let(:reporter_from_group_link) { create(:user) }
def permissions(user, issue)
IssuePolicy.abilities(user, issue).to_set
end
context 'a private project' do
let(:non_member) { create(:user) }
let(:project) { create(:empty_project, :private) }
let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
let(:issue_no_assignee) { create(:issue, project: project) }
before do
project.team << [guest, :guest]
project.team << [author, :guest]
project.team << [assignee, :guest]
project.team << [reporter, :reporter]
group.add_reporter(reporter_from_group_link)
create(:project_group_link, group: group, project: project)
end
it 'does not allow non-members to read issues' do
expect(permissions(non_member, issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(non_member, issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows guests to read issues' do
expect(permissions(guest, issue)).to include(:read_issue)
expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin issues' do
expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters from group links to read, update, and admin issues' do
expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their issues' do
expect(permissions(author, issue)).to include(:read_issue, :update_issue)
expect(permissions(author, issue)).not_to include(:admin_issue)
expect(permissions(author, issue_no_assignee)).to include(:read_issue)
expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their issues' do
expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, issue)).not_to include(:admin_issue)
expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
context 'with confidential issues' do
let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
it 'does not allow non-members to read confidential issues' do
expect(permissions(non_member, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(non_member, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'does not allow guests to read confidential issues' do
expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin confidential issues' do
expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters from group links to read, update, and admin confidential issues' do
expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their confidential issues' do
expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their confidential issues' do
expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
end
end
context 'a public project' do
let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
let(:issue_no_assignee) { create(:issue, project: project) }
before do
project.team << [guest, :guest]
project.team << [reporter, :reporter]
group.add_reporter(reporter_from_group_link)
create(:project_group_link, group: group, project: project)
end
it 'allows guests to read issues' do
expect(permissions(guest, issue)).to include(:read_issue)
expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin issues' do
expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters from group links to read, update, and admin issues' do
expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their issues' do
expect(permissions(author, issue)).to include(:read_issue, :update_issue)
expect(permissions(author, issue)).not_to include(:admin_issue)
expect(permissions(author, issue_no_assignee)).to include(:read_issue)
expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their issues' do
expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, issue)).not_to include(:admin_issue)
expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
end
context 'with confidential issues' do
let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
it 'does not allow guests to read confidential issues' do
expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporters to read, update, and admin confidential issues' do
expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows reporter from group links to read, update, and admin confidential issues' do
expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue authors to read and update their confidential issues' do
expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
it 'allows issue assignees to read and update their confidential issues' do
expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
end
end
end
require 'spec_helper'
describe API::API do
describe 'doorkeeper access' do
let!(:user) { create(:user) }
let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
......
require 'spec_helper'
describe API::API do
describe 'OAuth tokens' do
context 'Resource Owner Password Credentials' do
def request_oauth_token(user)
post '/oauth/token', username: user.username, password: user.password, grant_type: 'password'
......
require 'spec_helper'
describe Projects::EnvironmentsController, :routing do
describe 'environments routing', :routing do
let(:project) { create(:empty_project) }
let(:environment) do
......
require "spec_helper"
describe Profiles::NotificationsController do
describe "routing" do
describe "notifications routing" do
it "routes to #show" do
expect(get("/profile/notifications")).to route_to("profiles/notifications#show")
end
......@@ -9,5 +8,4 @@ describe Profiles::NotificationsController do
it "routes to #update" do
expect(put("/profile/notifications")).to route_to("profiles/notifications#update")
end
end
end
require 'spec_helper.rb'
class DummyService < Issues::BaseService
describe Issues::ResolveDiscussions, services: true do
class DummyService < Issues::BaseService
include ::Issues::ResolveDiscussions
def initialize(*args)
super
filter_resolve_discussion_params
end
end
end
describe DummyService, services: true do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
......@@ -23,7 +23,7 @@ describe DummyService, services: true do
let(:other_merge_request) { create(:merge_request, source_project: project, source_branch: "other") }
describe "#merge_request_for_resolving_discussion" do
let(:service) { described_class.new(project, user, merge_request_to_resolve_discussions_of: merge_request.iid) }
let(:service) { DummyService.new(project, user, merge_request_to_resolve_discussions_of: merge_request.iid) }
it "finds the merge request" do
expect(service.merge_request_to_resolve_discussions_of).to eq(merge_request)
......@@ -43,7 +43,7 @@ describe DummyService, services: true do
describe "#discussions_to_resolve" do
it "contains a single discussion when matching merge request and discussion are passed" do
service = described_class.new(
service = DummyService.new(
project,
user,
discussion_to_resolve: discussion.id,
......@@ -61,7 +61,7 @@ describe DummyService, services: true do
noteable: merge_request,
project: merge_request.target_project,
line_number: 15)])
service = described_class.new(
service = DummyService.new(
project,
user,
merge_request_to_resolve_discussions_of: merge_request.iid
......@@ -79,7 +79,7 @@ describe DummyService, services: true do
project: merge_request.target_project,
line_number: 15,
)])
service = described_class.new(
service = DummyService.new(
project,
user,
merge_request_to_resolve_discussions_of: merge_request.iid
......@@ -92,7 +92,7 @@ describe DummyService, services: true do
end
it "is empty when a discussion and another merge request are passed" do
service = described_class.new(
service = DummyService.new(
project,
user,
discussion_to_resolve: discussion.id,
......
......@@ -52,7 +52,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'unassign command' do
it 'populates assignee_id: nil if content contains /unassign' do
issuable.update(assignee_id: developer.id)
issuable.update!(assignee_id: developer.id)
_, updates = service.execute(content, issuable)
expect(updates).to eq(assignee_id: nil)
......@@ -70,7 +70,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'remove_milestone command' do
it 'populates milestone_id: nil if content contains /remove_milestone' do
issuable.update(milestone_id: milestone.id)
issuable.update!(milestone_id: milestone.id)
_, updates = service.execute(content, issuable)
expect(updates).to eq(milestone_id: nil)
......@@ -108,7 +108,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'unlabel command' do
it 'fetches label ids and populates remove_label_ids if content contains /unlabel' do
issuable.update(label_ids: [inprogress.id]) # populate the label
issuable.update!(label_ids: [inprogress.id]) # populate the label
_, updates = service.execute(content, issuable)
expect(updates).to eq(remove_label_ids: [inprogress.id])
......@@ -117,7 +117,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'multiple unlabel command' do
it 'fetches label ids and populates remove_label_ids if content contains mutiple /unlabel' do
issuable.update(label_ids: [inprogress.id, bug.id]) # populate the label
issuable.update!(label_ids: [inprogress.id, bug.id]) # populate the label
_, updates = service.execute(content, issuable)
expect(updates).to eq(remove_label_ids: [inprogress.id, bug.id])
......@@ -126,7 +126,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'unlabel command with no argument' do
it 'populates label_ids: [] if content contains /unlabel with no arguments' do
issuable.update(label_ids: [inprogress.id]) # populate the label
issuable.update!(label_ids: [inprogress.id]) # populate the label
_, updates = service.execute(content, issuable)
expect(updates).to eq(label_ids: [])
......@@ -135,7 +135,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'relabel command' do
it 'populates label_ids: [] if content contains /relabel' do
issuable.update(label_ids: [bug.id]) # populate the label
issuable.update!(label_ids: [bug.id]) # populate the label
inprogress # populate the label
_, updates = service.execute(content, issuable)
......@@ -187,7 +187,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'remove_due_date command' do
it 'populates due_date: nil if content contains /remove_due_date' do
issuable.update(due_date: Date.today)
issuable.update!(due_date: Date.today)
_, updates = service.execute(content, issuable)
expect(updates).to eq(due_date: nil)
......@@ -204,7 +204,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'unwip command' do
it 'returns wip_event: "unwip" if content contains /wip' do
issuable.update(title: issuable.wip_title)
issuable.update!(title: issuable.wip_title)
_, updates = service.execute(content, issuable)
expect(updates).to eq(wip_event: 'unwip')
......@@ -727,5 +727,75 @@ describe SlashCommands::InterpretService, services: true do
end
end
end
context '/board_move command' do
let(:todo) { create(:label, project: project, title: 'To Do') }
let(:inreview) { create(:label, project: project, title: 'In Review') }
let(:content) { %{/board_move ~"#{inreview.title}"} }
let!(:board) { create(:board, project: project) }
let!(:todo_list) { create(:list, board: board, label: todo) }
let!(:inreview_list) { create(:list, board: board, label: inreview) }
let!(:inprogress_list) { create(:list, board: board, label: inprogress) }
it 'populates remove_label_ids for all current board columns' do
issue.update!(label_ids: [todo.id, inprogress.id])
_, updates = service.execute(content, issue)
expect(updates[:remove_label_ids]).to match_array([todo.id, inprogress.id])
end
it 'populates add_label_ids with the id of the given label' do
_, updates = service.execute(content, issue)
expect(updates[:add_label_ids]).to eq([inreview.id])
end
it 'does not include the given label id in remove_label_ids' do
issue.update!(label_ids: [todo.id, inreview.id])
_, updates = service.execute(content, issue)
expect(updates[:remove_label_ids]).to match_array([todo.id])
end
it 'does not remove label ids that are not lists on the board' do
issue.update!(label_ids: [todo.id, bug.id])
_, updates = service.execute(content, issue)
expect(updates[:remove_label_ids]).to match_array([todo.id])
end
context 'if the project has multiple boards' do
let(:issuable) { issue }
before { create(:board, project: project) }
it_behaves_like 'empty command'
end
context 'if the given label does not exist' do
let(:issuable) { issue }
let(:content) { '/board_move ~"Fake Label"' }
it_behaves_like 'empty command'
end
context 'if multiple labels are given' do
let(:issuable) { issue }
let(:content) { %{/board_move ~"#{inreview.title}" ~"#{todo.title}"} }
it_behaves_like 'empty command'
end
context 'if the given label is not a list on the board' do
let(:issuable) { issue }
let(:content) { %{/board_move ~"#{bug.title}"} }
it_behaves_like 'empty command'
end
context 'if issuable is not an Issue' do
let(:issuable) { merge_request }
it_behaves_like 'empty command'
end
end
end
end
......@@ -13,8 +13,9 @@ rspec_profiling_is_configured =
ENV['RSPEC_PROFILING_POSTGRES_URL'] ||
ENV['RSPEC_PROFILING']
branch_can_be_profiled =
ENV['CI_COMMIT_REF_NAME'] == 'master' ||
ENV['CI_COMMIT_REF_NAME'] =~ /rspec-profile/
ENV['GITLAB_DATABASE'] == 'postgresql' &&
(ENV['CI_COMMIT_REF_NAME'] == 'master' ||
ENV['CI_COMMIT_REF_NAME'] =~ /rspec-profile/)
if rspec_profiling_is_configured && (!ENV.key?('CI') || branch_can_be_profiled)
require 'rspec_profiling/rspec'
......
require 'fileutils'
require 'excon'
require 'spec_helper'
describe 'Unicorn' do
before(:all) do
config_lines = File.read('config/unicorn.rb.example').split("\n")
# Remove these because they make setup harder.
config_lines = config_lines.reject do |line|
%w[
working_directory
worker_processes
listen
pid
stderr_path
stdout_path
].any? { |prefix| line.start_with?(prefix) }
end
config_lines << "working_directory '#{Rails.root}'"
# We want to have exactly 1 worker process because that makes it
# predictable which process will handle our requests.
config_lines << 'worker_processes 1'
@socket_path = File.join(Dir.pwd, 'tmp/tests/unicorn.socket')
config_lines << "listen '#{@socket_path}'"
ready_file = 'tmp/tests/unicorn-worker-ready'
FileUtils.rm_f(ready_file)
after_fork_index = config_lines.index { |l| l.start_with?('after_fork') }
config_lines.insert(after_fork_index + 1, "File.write('#{ready_file}', Process.pid)")
config_path = 'tmp/tests/unicorn.rb'
File.write(config_path, config_lines.join("\n") + "\n")
cmd = %W[unicorn -E test -c #{config_path} #{Rails.root.join('config.ru')}]
@unicorn_master_pid = spawn(*cmd)
wait_unicorn_boot!(@unicorn_master_pid, ready_file)
WebMock.allow_net_connect!
end
%w[SIGQUIT SIGTERM SIGKILL].each do |signal|
it "has a worker that self-terminates on signal #{signal}" do
response = Excon.get('unix:///unicorn_test/pid', socket: @socket_path)
expect(response.status).to eq(200)
worker_pid = response.body.to_i
expect(worker_pid).to be > 0
begin
Excon.post('unix:///unicorn_test/kill', socket: @socket_path, body: "signal=#{signal}")
rescue Excon::Error::Socket
# The connection may be closed abruptly
end
expect(pid_gone?(worker_pid)).to eq(true)
end
end
after(:all) do
WebMock.disable_net_connect!(allow_localhost: true)
Process.kill('TERM', @unicorn_master_pid)
end
def wait_unicorn_boot!(master_pid, ready_file)
# Unicorn should boot in under 60 seconds so 120 seconds seems like a good timeout.
timeout = 120
timeout.times do
return if File.exist?(ready_file)
pid = Process.waitpid(master_pid, Process::WNOHANG)
raise "unicorn failed to boot: #{$?}" unless pid.nil?
sleep 1
end
raise "unicorn boot timed out after #{timeout} seconds"
end
def pid_gone?(pid)
# Worker termination should take less than a second. That makes 10
# seconds a generous timeout.
10.times do
begin
Process.kill(0, pid)
rescue Errno::ESRCH
return true
end
sleep 1
end
false
end
end
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