summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2016-12-14 15:18:46 +0000
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2016-12-14 15:18:46 +0000
commit4bdfb0391a578847fde5589eb44ac6737c9e4b64 (patch)
tree4af12a6ef4f7ead85c2d80a48687f42c492564fa /spec
parent161d7c02d4ff49d6d91b982faee61b5de00d2631 (diff)
parentb70b962892b2428557d95a9639fbcead4fe546fd (diff)
downloadgitlab-ce-4bdfb0391a578847fde5589eb44ac6737c9e4b64.tar.gz
Merge branch 'master' into 'dz-remove-namespaces-path-uniq'
Merge Request - https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8013 # Conflicts: # db/schema.rb
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/releases_controller_spec.rb55
-rw-r--r--spec/factories/ci/builds.rb13
-rw-r--r--spec/factories/groups.rb4
-rw-r--r--spec/features/admin/admin_groups_spec.rb2
-rw-r--r--spec/features/admin/admin_projects_spec.rb6
-rw-r--r--spec/features/admin/admin_settings_spec.rb53
-rw-r--r--spec/features/dashboard/datetime_on_tooltips_spec.rb2
-rw-r--r--spec/features/issues/gfm_autocomplete_spec.rb67
-rw-r--r--spec/features/projects/builds_spec.rb37
-rw-r--r--spec/features/projects/files/creating_a_file_spec.rb44
-rw-r--r--spec/features/security/admin_access_spec.rb2
-rw-r--r--spec/finders/snippets_finder_spec.rb84
-rw-r--r--spec/javascripts/awards_handler_spec.js10
-rw-r--r--spec/javascripts/fixtures/awards_handler.html.haml52
-rw-r--r--spec/javascripts/fixtures/pipeline_graph.html.haml15
-rw-r--r--spec/javascripts/pipelines_spec.js.es625
-rw-r--r--spec/javascripts/project_title_spec.js16
-rw-r--r--spec/javascripts/smart_interval_spec.js.es635
-rw-r--r--spec/lib/banzai/filter/relative_link_filter_spec.rb2
-rw-r--r--spec/lib/gitlab/allowable_spec.rb27
-rw-r--r--spec/lib/gitlab/ci/status/build/cancelable_spec.rb86
-rw-r--r--spec/lib/gitlab/ci/status/build/common_spec.rb37
-rw-r--r--spec/lib/gitlab/ci/status/build/factory_spec.rb141
-rw-r--r--spec/lib/gitlab/ci/status/build/play_spec.rb82
-rw-r--r--spec/lib/gitlab/ci/status/build/retryable_spec.rb86
-rw-r--r--spec/lib/gitlab/ci/status/build/stop_spec.rb84
-rw-r--r--spec/lib/gitlab/ci/status/canceled_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/created_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/extended_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/status/factory_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/status/failed_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/pending_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/common_spec.rb33
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/factory_spec.rb9
-rw-r--r--spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/running_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/skipped_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/status/stage/common_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/status/stage/factory_spec.rb15
-rw-r--r--spec/lib/gitlab/ci/status/success_spec.rb8
-rw-r--r--spec/lib/gitlab/routing_spec.rb23
-rw-r--r--spec/migrations/migrate_process_commit_worker_jobs_spec.rb27
-rw-r--r--spec/models/build_spec.rb91
-rw-r--r--spec/models/ci/pipeline_spec.rb20
-rw-r--r--spec/models/ci/stage_spec.rb4
-rw-r--r--spec/models/commit_status_spec.rb9
-rw-r--r--spec/models/concerns/routable_spec.rb14
-rw-r--r--spec/models/generic_commit_status_spec.rb16
-rw-r--r--spec/models/group_spec.rb7
-rw-r--r--spec/models/user_spec.rb11
-rw-r--r--spec/requests/api/branches_spec.rb31
-rw-r--r--spec/requests/api/commits_spec.rb70
-rw-r--r--spec/requests/api/groups_spec.rb22
-rw-r--r--spec/requests/api/helpers_spec.rb (renamed from spec/requests/api/api_helpers_spec.rb)85
-rw-r--r--spec/requests/api/merge_requests_spec.rb16
-rw-r--r--spec/requests/api/services_spec.rb5
-rw-r--r--spec/requests/api/snippets_spec.rb157
-rw-r--r--spec/requests/api/users_spec.rb27
-rw-r--r--spec/routing/admin_routing_spec.rb14
-rw-r--r--spec/services/system_note_service_spec.rb2
-rw-r--r--spec/support/login_helpers.rb3
-rw-r--r--spec/support/services_shared_context.rb6
-rw-r--r--spec/views/projects/commit/_commit_box.html.haml_spec.rb2
-rw-r--r--spec/views/projects/pipelines/show.html.haml_spec.rb2
64 files changed, 1625 insertions, 268 deletions
diff --git a/spec/controllers/projects/releases_controller_spec.rb b/spec/controllers/projects/releases_controller_spec.rb
new file mode 100644
index 00000000000..9fd5c3b85f6
--- /dev/null
+++ b/spec/controllers/projects/releases_controller_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Projects::ReleasesController do
+ let!(:project) { create(:project) }
+ let!(:user) { create(:user) }
+ let!(:release) { create(:release, project: project) }
+ let!(:tag) { release.tag }
+
+ before do
+ project.team << [user, :developer]
+ sign_in(user)
+ end
+
+ describe 'GET #edit' do
+ it 'initializes a new release' do
+ tag_id = release.tag
+ project.releases.destroy_all
+
+ get :edit, namespace_id: project.namespace.path, project_id: project.path, tag_id: tag_id
+
+ release = assigns(:release)
+ expect(release).not_to be_nil
+ expect(release).not_to be_persisted
+ end
+
+ it 'retrieves an existing release' do
+ get :edit, namespace_id: project.namespace.path, project_id: project.path, tag_id: release.tag
+
+ release = assigns(:release)
+ expect(release).not_to be_nil
+ expect(release).to be_persisted
+ end
+ end
+
+ describe 'PUT #update' do
+ it 'updates release note description' do
+ update_release('description updated')
+
+ release = project.releases.find_by_tag(tag)
+ expect(release.description).to eq("description updated")
+ end
+
+ it 'deletes release note when description is null' do
+ expect { update_release('') }.to change(project.releases, :count).by(-1)
+ end
+ end
+
+ def update_release(description)
+ put :update,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ tag_id: release.tag,
+ release: { description: description }
+ end
+end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index c443af09075..62466c06194 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -12,12 +12,14 @@ FactoryGirl.define do
started_at 'Di 29. Okt 09:51:28 CET 2013'
finished_at 'Di 29. Okt 09:53:28 CET 2013'
commands 'ls -a'
+
options do
{
image: "ruby:2.1",
services: ["postgres"]
}
end
+
yaml_variables do
[
{ key: :DB_NAME, value: 'postgres', public: true }
@@ -60,15 +62,20 @@ FactoryGirl.define do
end
trait :teardown_environment do
- options do
- { environment: { action: 'stop' } }
- end
+ environment 'staging'
+ options environment: { name: 'staging',
+ action: 'stop' }
end
trait :allowed_to_fail do
allow_failure true
end
+ trait :playable do
+ skipped
+ manual
+ end
+
after(:build) do |build, evaluator|
build.project = build.pipeline.project
end
diff --git a/spec/factories/groups.rb b/spec/factories/groups.rb
index ebd3595ea64..ece6beb9fa9 100644
--- a/spec/factories/groups.rb
+++ b/spec/factories/groups.rb
@@ -19,5 +19,9 @@ FactoryGirl.define do
trait :access_requestable do
request_access_enabled true
end
+
+ trait :nested do
+ parent factory: :group
+ end
end
end
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
index f6d625fa7f6..0aa01fc499a 100644
--- a/spec/features/admin/admin_groups_spec.rb
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -21,7 +21,7 @@ feature 'Admin Groups', feature: true do
scenario 'shows the visibility level radio populated with the group visibility_level value' do
group = create(:group, :private)
- visit edit_admin_group_path(group)
+ visit admin_group_edit_path(group)
expect_selected_visibility(group.visibility_level)
end
diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb
index 30ded9202a4..a36bfd574cb 100644
--- a/spec/features/admin/admin_projects_spec.rb
+++ b/spec/features/admin/admin_projects_spec.rb
@@ -8,11 +8,11 @@ describe "Admin::Projects", feature: true do
describe "GET /admin/projects" do
before do
- visit admin_namespaces_projects_path
+ visit admin_projects_path
end
it "is ok" do
- expect(current_path).to eq(admin_namespaces_projects_path)
+ expect(current_path).to eq(admin_projects_path)
end
it "has projects list" do
@@ -22,7 +22,7 @@ describe "Admin::Projects", feature: true do
describe "GET /admin/projects/:id" do
before do
- visit admin_namespaces_projects_path
+ visit admin_projects_path
click_link "#{@project.name}"
end
diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb
new file mode 100644
index 00000000000..8cd66f189be
--- /dev/null
+++ b/spec/features/admin/admin_settings_spec.rb
@@ -0,0 +1,53 @@
+require 'spec_helper'
+
+feature 'Admin updates settings', feature: true do
+ before(:each) do
+ login_as :admin
+ visit admin_application_settings_path
+ end
+
+ scenario 'Change application settings' do
+ uncheck 'Gravatar enabled'
+ fill_in 'Home page URL', with: 'https://about.gitlab.com/'
+ fill_in 'Help page text', with: 'Example text'
+ click_button 'Save'
+
+ expect(current_application_settings.gravatar_enabled).to be_falsey
+ expect(current_application_settings.home_page_url).to eq "https://about.gitlab.com/"
+ expect(page).to have_content "Application settings saved successfully"
+ end
+
+ scenario 'Change Slack Service template settings' do
+ click_link 'Service Templates'
+ click_link 'Slack'
+ fill_in 'Webhook', with: 'http://localhost'
+ fill_in 'Username', with: 'test_user'
+ fill_in 'service_push_channel', with: '#test_channel'
+ page.check('Notify only broken builds')
+
+ check_all_events
+ click_on 'Save'
+
+ expect(page).to have_content 'Application settings saved successfully'
+
+ click_link 'Slack'
+
+ page.all('input[type=checkbox]').each do |checkbox|
+ expect(checkbox).to be_checked
+ end
+ expect(find_field('Webhook').value).to eq 'http://localhost'
+ expect(find_field('Username').value).to eq 'test_user'
+ expect(find('#service_push_channel').value).to eq '#test_channel'
+ end
+
+ def check_all_events
+ page.check('Active')
+ page.check('Push')
+ page.check('Tag push')
+ page.check('Note')
+ page.check('Issue')
+ page.check('Merge request')
+ page.check('Build')
+ page.check('Pipeline')
+ end
+end
diff --git a/spec/features/dashboard/datetime_on_tooltips_spec.rb b/spec/features/dashboard/datetime_on_tooltips_spec.rb
index 365cb445df1..44dfc2dff45 100644
--- a/spec/features/dashboard/datetime_on_tooltips_spec.rb
+++ b/spec/features/dashboard/datetime_on_tooltips_spec.rb
@@ -36,7 +36,7 @@ feature 'Tooltips on .timeago dates', feature: true, js: true do
visit user_snippets_path(user)
wait_for_ajax()
- page.find('.js-timeago').hover
+ page.find('.js-timeago.snippet-created-ago').hover
end
it 'has the datetime formated correctly' do
diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb
index c421da97d76..cd0512a37e6 100644
--- a/spec/features/issues/gfm_autocomplete_spec.rb
+++ b/spec/features/issues/gfm_autocomplete_spec.rb
@@ -2,8 +2,9 @@ require 'rails_helper'
feature 'GFM autocomplete', feature: true, js: true do
include WaitForAjax
- let(:user) { create(:user) }
+ let(:user) { create(:user, username: 'someone.special') }
let(:project) { create(:project) }
+ let(:label) { create(:label, project: project, title: 'special+') }
let(:issue) { create(:issue, project: project) }
before do
@@ -23,21 +24,69 @@ feature 'GFM autocomplete', feature: true, js: true do
expect(page).to have_selector('.atwho-container')
end
- it 'opens autocomplete menu when field is prefixed with non-text character' do
+ it 'doesnt open autocomplete menu character is prefixed with text' do
page.within '.timeline-content-form' do
- find('#note_note').native.send_keys('')
+ find('#note_note').native.send_keys('testing')
find('#note_note').native.send_keys('@')
end
- expect(page).to have_selector('.atwho-container')
+ expect(page).not_to have_selector('.atwho-view')
end
- it 'doesnt open autocomplete menu character is prefixed with text' do
- page.within '.timeline-content-form' do
- find('#note_note').native.send_keys('testing')
- find('#note_note').native.send_keys('@')
+ context 'if a selected value has special characters' do
+ it 'wraps the result in double quotes' do
+ note = find('#note_note')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('')
+ note.native.send_keys("~#{label.title[0]}")
+ sleep 1
+ note.click
+ end
+
+ label_item = find('.atwho-view li', text: label.title)
+
+ expect_to_wrap(true, label_item, note, label.title)
end
- expect(page).not_to have_selector('.atwho-view')
+ it 'doesn\'t wrap for assignee values' do
+ note = find('#note_note')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('')
+ note.native.send_keys("@#{user.username[0]}")
+ sleep 1
+ note.click
+ end
+
+ user_item = find('.atwho-view li', text: user.username)
+
+ expect_to_wrap(false, user_item, note, user.username)
+ end
+
+ it 'doesn\'t wrap for emoji values' do
+ note = find('#note_note')
+ page.within '.timeline-content-form' do
+ note.native.send_keys('')
+ note.native.send_keys(":cartwheel")
+ sleep 1
+ note.click
+ end
+
+ emoji_item = find('.atwho-view li', text: 'cartwheel_tone1')
+
+ expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1')
+ end
+
+ def expect_to_wrap(should_wrap, item, note, value)
+ expect(item).to have_content(value)
+ expect(item).not_to have_content("\"#{value}\"")
+
+ item.click
+
+ if should_wrap
+ expect(note.value).to include("\"#{value}\"")
+ else
+ expect(note.value).not_to include("\"#{value}\"")
+ end
+ end
end
end
diff --git a/spec/features/projects/builds_spec.rb b/spec/features/projects/builds_spec.rb
index a0ccc472d11..8c4d4320dc5 100644
--- a/spec/features/projects/builds_spec.rb
+++ b/spec/features/projects/builds_spec.rb
@@ -227,6 +227,43 @@ feature 'Builds', :feature do
expect(page).to have_selector('.js-build-value', text: 'TRIGGER_VALUE_1')
end
end
+
+ context 'when build starts environment' do
+ let(:environment) { create(:environment, project: project) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+
+ context 'build is successfull and has deployment' do
+ let(:deployment) { create(:deployment) }
+ let(:build) { create(:ci_build, :success, environment: environment.name, deployments: [deployment], pipeline: pipeline) }
+
+ it 'shows a link for the build' do
+ visit namespace_project_build_path(project.namespace, project, build)
+
+ expect(page).to have_link environment.name
+ end
+ end
+
+ context 'build is complete and not successfull' do
+ let(:build) { create(:ci_build, :failed, environment: environment.name, pipeline: pipeline) }
+
+ it 'shows a link for the build' do
+ visit namespace_project_build_path(project.namespace, project, build)
+
+ expect(page).to have_link environment.name
+ end
+ end
+
+ context 'build creates a new deployment' do
+ let!(:deployment) { create(:deployment, environment: environment, sha: project.commit.id) }
+ let(:build) { create(:ci_build, :success, environment: environment.name, pipeline: pipeline) }
+
+ it 'shows a link to lastest deployment' do
+ visit namespace_project_build_path(project.namespace, project, build)
+
+ expect(page).to have_link('latest deployment')
+ end
+ end
+ end
end
describe "POST /:project/builds/:id/cancel" do
diff --git a/spec/features/projects/files/creating_a_file_spec.rb b/spec/features/projects/files/creating_a_file_spec.rb
new file mode 100644
index 00000000000..ae448706130
--- /dev/null
+++ b/spec/features/projects/files/creating_a_file_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+feature 'User wants to create a file', feature: true do
+ include WaitForAjax
+
+ let(:project) { create(:project) }
+ let(:user) { create(:user) }
+
+ background do
+ project.team << [user, :master]
+ login_as user
+ visit namespace_project_new_blob_path(project.namespace, project, project.default_branch)
+ end
+
+ def submit_new_file(options)
+ file_name = find('#file_name')
+ file_name.set options[:file_name] || 'README.md'
+
+ file_content = find('#file-content')
+ file_content.set options[:file_content] || 'Some content'
+
+ click_button 'Commit Changes'
+ end
+
+ scenario 'file name contains Chinese characters' do
+ submit_new_file(file_name: '测试.md')
+ expect(page).to have_content 'The file has been successfully created.'
+ end
+
+ scenario 'directory name contains Chinese characters' do
+ submit_new_file(file_name: '中文/测试.md')
+ expect(page).to have_content 'The file has been successfully created.'
+ end
+
+ scenario 'file name contains invalid characters' do
+ submit_new_file(file_name: '\\')
+ expect(page).to have_content 'Your changes could not be committed, because the file name can contain only'
+ end
+
+ scenario 'file name contains directory traversal' do
+ submit_new_file(file_name: '../README.md')
+ expect(page).to have_content 'Your changes could not be committed, because the file name cannot include directory traversal.'
+ end
+end
diff --git a/spec/features/security/admin_access_spec.rb b/spec/features/security/admin_access_spec.rb
index fe8cd7b7602..e180ca53eb5 100644
--- a/spec/features/security/admin_access_spec.rb
+++ b/spec/features/security/admin_access_spec.rb
@@ -4,7 +4,7 @@ describe "Admin::Projects", feature: true do
include AccessMatchers
describe "GET /admin/projects" do
- subject { admin_namespaces_projects_path }
+ subject { admin_projects_path }
it { is_expected.to be_allowed_for :admin }
it { is_expected.to be_denied_for :user }
diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb
index 28bdc18e840..975e99c5807 100644
--- a/spec/finders/snippets_finder_spec.rb
+++ b/spec/finders/snippets_finder_spec.rb
@@ -9,65 +9,74 @@ describe SnippetsFinder do
let(:project2) { create(:empty_project, :private, group: group) }
context ':all filter' do
- before do
- @snippet1 = create(:personal_snippet, :private)
- @snippet2 = create(:personal_snippet, :internal)
- @snippet3 = create(:personal_snippet, :public)
- end
+ let!(:snippet1) { create(:personal_snippet, :private) }
+ let!(:snippet2) { create(:personal_snippet, :internal) }
+ let!(:snippet3) { create(:personal_snippet, :public) }
it "returns all private and internal snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :all)
- expect(snippets).to include(@snippet2, @snippet3)
- expect(snippets).not_to include(@snippet1)
+ expect(snippets).to include(snippet2, snippet3)
+ expect(snippets).not_to include(snippet1)
end
it "returns all public snippets" do
snippets = SnippetsFinder.new.execute(nil, filter: :all)
- expect(snippets).to include(@snippet3)
- expect(snippets).not_to include(@snippet1, @snippet2)
+ expect(snippets).to include(snippet3)
+ expect(snippets).not_to include(snippet1, snippet2)
end
end
- context ':by_user filter' do
- before do
- @snippet1 = create(:personal_snippet, :private, author: user)
- @snippet2 = create(:personal_snippet, :internal, author: user)
- @snippet3 = create(:personal_snippet, :public, author: user)
+ context ':public filter' do
+ let!(:snippet1) { create(:personal_snippet, :private) }
+ let!(:snippet2) { create(:personal_snippet, :internal) }
+ let!(:snippet3) { create(:personal_snippet, :public) }
+
+ it "returns public public snippets" do
+ snippets = SnippetsFinder.new.execute(nil, filter: :public)
+
+ expect(snippets).to include(snippet3)
+ expect(snippets).not_to include(snippet1, snippet2)
end
+ end
+
+ context ':by_user filter' do
+ let!(:snippet1) { create(:personal_snippet, :private, author: user) }
+ let!(:snippet2) { create(:personal_snippet, :internal, author: user) }
+ let!(:snippet3) { create(:personal_snippet, :public, author: user) }
it "returns all public and internal snippets" do
snippets = SnippetsFinder.new.execute(user1, filter: :by_user, user: user)
- expect(snippets).to include(@snippet2, @snippet3)
- expect(snippets).not_to include(@snippet1)
+ expect(snippets).to include(snippet2, snippet3)
+ expect(snippets).not_to include(snippet1)
end
it "returns internal snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_internal")
- expect(snippets).to include(@snippet2)
- expect(snippets).not_to include(@snippet1, @snippet3)
+ expect(snippets).to include(snippet2)
+ expect(snippets).not_to include(snippet1, snippet3)
end
it "returns private snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_private")
- expect(snippets).to include(@snippet1)
- expect(snippets).not_to include(@snippet2, @snippet3)
+ expect(snippets).to include(snippet1)
+ expect(snippets).not_to include(snippet2, snippet3)
end
it "returns public snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_public")
- expect(snippets).to include(@snippet3)
- expect(snippets).not_to include(@snippet1, @snippet2)
+ expect(snippets).to include(snippet3)
+ expect(snippets).not_to include(snippet1, snippet2)
end
it "returns all snippets" do
snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user)
- expect(snippets).to include(@snippet1, @snippet2, @snippet3)
+ expect(snippets).to include(snippet1, snippet2, snippet3)
end
it "returns only public snippets if unauthenticated user" do
snippets = SnippetsFinder.new.execute(nil, filter: :by_user, user: user)
- expect(snippets).to include(@snippet3)
- expect(snippets).not_to include(@snippet2, @snippet1)
+ expect(snippets).to include(snippet3)
+ expect(snippets).not_to include(snippet2, snippet1)
end
end
@@ -84,16 +93,39 @@ describe SnippetsFinder do
expect(snippets).not_to include(@snippet1, @snippet2)
end
- it "returns public and internal snippets for none project members" do
+ it "returns public and internal snippets for non project members" do
snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
expect(snippets).to include(@snippet2, @snippet3)
expect(snippets).not_to include(@snippet1)
end
+ it "returns public snippets for non project members" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_public")
+ expect(snippets).to include(@snippet3)
+ expect(snippets).not_to include(@snippet1, @snippet2)
+ end
+
+ it "returns internal snippets for non project members" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_internal")
+ expect(snippets).to include(@snippet2)
+ expect(snippets).not_to include(@snippet1, @snippet3)
+ end
+
+ it "does not return private snippets for non project members" do
+ snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_private")
+ expect(snippets).not_to include(@snippet1, @snippet2, @snippet3)
+ end
+
it "returns all snippets for project members" do
project1.team << [user, :developer]
snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
expect(snippets).to include(@snippet1, @snippet2, @snippet3)
end
+
+ it "returns private snippets for project members" do
+ project1.team << [user, :developer]
+ snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_private")
+ expect(snippets).to include(@snippet1)
+ end
end
end
diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js
index ac1404f6e1c..7b2e3db6218 100644
--- a/spec/javascripts/awards_handler_spec.js
+++ b/spec/javascripts/awards_handler_spec.js
@@ -33,9 +33,9 @@
};
describe('AwardsHandler', function() {
- fixture.preload('awards_handler.html');
+ fixture.preload('issues/open-issue.html.raw');
beforeEach(function() {
- fixture.load('awards_handler.html');
+ fixture.load('issues/open-issue.html.raw');
awardsHandler = new AwardsHandler;
spyOn(awardsHandler, 'postEmoji').and.callFake((function(_this) {
return function(url, emoji, cb) {
@@ -113,7 +113,7 @@
});
describe('::getAwardUrl', function() {
return it('should return the url for request', function() {
- return expect(awardsHandler.getAwardUrl()).toBe('/gitlab-org/gitlab-test/issues/8/toggle_award_emoji');
+ return expect(awardsHandler.getAwardUrl()).toBe('http://test.host/frontend-fixtures/issues-project/issues/1/toggle_award_emoji');
});
});
describe('::addAward and ::checkMutuality', function() {
@@ -209,7 +209,7 @@
$('.js-add-award').eq(0).click();
$menu = $('.emoji-menu');
$block = $('.js-awards-block');
- $emoji = $menu.find(".emoji-menu-list-item " + selector);
+ $emoji = $menu.find('.emoji-menu-list:not(.frequent-emojis) ' + selector);
expect($emoji.length).toBe(1);
expect($block.find(selector).length).toBe(0);
$emoji.click();
@@ -224,7 +224,7 @@
openEmojiMenuAndAddEmoji();
$('.js-add-award').eq(0).click();
$block = $('.js-awards-block');
- $emoji = $('.emoji-menu').find(".emoji-menu-list-item " + selector);
+ $emoji = $('.emoji-menu').find(".emoji-menu-list:not(.frequent-emojis) " + selector);
$emoji.click();
return expect($block.find(selector).length).toBe(0);
});
diff --git a/spec/javascripts/fixtures/awards_handler.html.haml b/spec/javascripts/fixtures/awards_handler.html.haml
deleted file mode 100644
index 1ef2e8f8624..00000000000
--- a/spec/javascripts/fixtures/awards_handler.html.haml
+++ /dev/null
@@ -1,52 +0,0 @@
-.issue-details.issuable-details
- .detail-page-description.content-block
- %h2.title Quibusdam sint officiis earum molestiae ipsa autem voluptatem nisi rem.
- .description.js-task-list-container.is-task-list-enabled
- .wiki
- %p Qui exercitationem magnam optio quae fuga earum odio.
- %textarea.hidden.js-task-list-field Qui exercitationem magnam optio quae fuga earum odio.
- %small.edited-text
- .content-block.content-block-small
- .awards.js-awards-block{"data-award-url" => "/gitlab-org/gitlab-test/issues/8/toggle_award_emoji"}
- %button.award-control.btn.js-emoji-btn{"data-placement" => "bottom", "data-title" => "", :type => "button"}
- .icon.emoji-icon.emoji-1F44D{"data-aliases" => "", "data-emoji" => "thumbsup", "data-unicode-name" => "1F44D", :title => "thumbsup"}
- %span.award-control-text.js-counter 0
- %button.award-control.btn.js-emoji-btn{"data-placement" => "bottom", "data-title" => "", :type => "button"}
- .icon.emoji-icon.emoji-1F44E{"data-aliases" => "", "data-emoji" => "thumbsdown", "data-unicode-name" => "1F44E", :title => "thumbsdown"}
- %span.award-control-text.js-counter 0
- .award-menu-holder.js-award-holder
- %button.btn.award-control.js-add-award{:type => "button"}
- %i.fa.fa-smile-o.award-control-icon.award-control-icon-normal
- %i.fa.fa-spinner.fa-spin.award-control-icon.award-control-icon-loading
- %span.award-control-text Add
- %section.issuable-discussion
- #notes
- %ul#notes-list.notes.main-notes-list.timeline
- %li#note_348.note.note-row-348.timeline-entry{"data-author-id" => "18", "data-editable" => ""}
- .timeline-entry-inner
- .timeline-icon
- %a{:href => "/u/agustin"}
- %img.avatar.s40{:alt => "", :src => "#"}/
- .timeline-content
- .note-header
- %a.author_link{:href => "/u/agustin"}
- %span.author Brenna Stokes
- .inline.note-headline-light
- @agustin commented
- %a{:href => "#note_348"}
- %time 11 days ago
- .note-actions
- %span.note-role Reporter
- %a.note-action-button.note-emoji-button.js-add-award.js-note-emoji{"data-position" => "right", :href => "#", :title => "Award Emoji"}
- %i.fa.fa-spinner.fa-spin
- %i.fa.fa-smile-o.link-highlight
- .js-task-list-container.note-body.is-task-list-enabled
- .note-text
- %p Suscipit sunt quia quisquam sed eveniet ipsam.
- .note-awards
- .awards.hidden.js-awards-block{"data-award-url" => "/gitlab-org/gitlab-test/notes/348/toggle_award_emoji"}
- .award-menu-holder.js-award-holder
- %button.btn.award-control.js-add-award{:type => "button"}
- %i.fa.fa-smile-o.award-control-icon.award-control-icon-normal
- %i.fa.fa-spinner.fa-spin.award-control-icon.award-control-icon-loading
- %span.award-control-text Add
diff --git a/spec/javascripts/fixtures/pipeline_graph.html.haml b/spec/javascripts/fixtures/pipeline_graph.html.haml
new file mode 100644
index 00000000000..deca50ceaa7
--- /dev/null
+++ b/spec/javascripts/fixtures/pipeline_graph.html.haml
@@ -0,0 +1,15 @@
+%div.pipeline-visualization.js-pipeline-graph
+ %ul.stage-column-list
+ %li.stage-column
+ .stage-name
+ %a{:href => "/"}
+ Test
+ .builds-container
+ %ul
+ %li.build
+ .curve
+ .build-content
+ %a
+ %svg
+ .ci-status-text
+ stop_review
diff --git a/spec/javascripts/pipelines_spec.js.es6 b/spec/javascripts/pipelines_spec.js.es6
new file mode 100644
index 00000000000..85c9cf4b4f1
--- /dev/null
+++ b/spec/javascripts/pipelines_spec.js.es6
@@ -0,0 +1,25 @@
+//= require pipelines
+
+(() => {
+ describe('Pipelines', () => {
+ fixture.preload('pipeline_graph');
+
+ beforeEach(() => {
+ fixture.load('pipeline_graph');
+ });
+
+ it('should be defined', () => {
+ expect(window.gl.Pipelines).toBeDefined();
+ });
+
+ it('should create a `Pipelines` instance without options', () => {
+ expect(() => { new window.gl.Pipelines(); }).not.toThrow(); //eslint-disable-line
+ });
+
+ it('should create a `Pipelines` instance with options', () => {
+ const pipelines = new window.gl.Pipelines({ foo: 'bar' });
+
+ expect(pipelines.pipelineGraph).toBeDefined();
+ });
+ });
+})();
diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js
index 49211a6b852..65de1756201 100644
--- a/spec/javascripts/project_title_spec.js
+++ b/spec/javascripts/project_title_spec.js
@@ -21,16 +21,18 @@
return this.project = new Project();
});
return describe('project list', function() {
+ var fakeAjaxResponse = function fakeAjaxResponse(req) {
+ var d;
+ expect(req.url).toBe('/api/v3/projects.json?simple=true');
+ d = $.Deferred();
+ d.resolve(this.projects_data);
+ return d.promise();
+ };
+
beforeEach((function(_this) {
return function() {
_this.projects_data = fixture.load('projects.json')[0];
- return spyOn(jQuery, 'ajax').and.callFake(function(req) {
- var d;
- expect(req.url).toBe('/api/v3/projects.json?simple=true');
- d = $.Deferred();
- d.resolve(_this.projects_data);
- return d.promise();
- });
+ return spyOn(jQuery, 'ajax').and.callFake(fakeAjaxResponse.bind(_this));
};
})(this));
it('to show on toggle click', (function(_this) {
diff --git a/spec/javascripts/smart_interval_spec.js.es6 b/spec/javascripts/smart_interval_spec.js.es6
index ed6166a25a8..1b7ca97cde4 100644
--- a/spec/javascripts/smart_interval_spec.js.es6
+++ b/spec/javascripts/smart_interval_spec.js.es6
@@ -14,8 +14,9 @@
startingInterval: DEFAULT_STARTING_INTERVAL,
maxInterval: DEFAULT_MAX_INTERVAL,
incrementByFactorOf: DEFAULT_INCREMENT_FACTOR,
- delayStartBy: 0,
lazyStart: false,
+ immediateExecution: false,
+ hiddenInterval: null,
};
if (config) {
@@ -114,14 +115,31 @@
expect(interval.state.intervalId).toBeTruthy();
// simulates triggering of visibilitychange event
- interval.state.pageVisibility = 'hidden';
- interval.handleVisibilityChange();
+ interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } });
expect(interval.state.intervalId).toBeUndefined();
done();
}, DEFAULT_SHORT_TIMEOUT);
});
+ it('should change to the hidden interval when page is not visible', function (done) {
+ const HIDDEN_INTERVAL = 1500;
+ const interval = createDefaultSmartInterval({ hiddenInterval: HIDDEN_INTERVAL });
+
+ setTimeout(() => {
+ expect(interval.state.intervalId).toBeTruthy();
+ expect(interval.getCurrentInterval() >= DEFAULT_STARTING_INTERVAL &&
+ interval.getCurrentInterval() <= DEFAULT_MAX_INTERVAL).toBeTruthy();
+
+ // simulates triggering of visibilitychange event
+ interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } });
+
+ expect(interval.state.intervalId).toBeTruthy();
+ expect(interval.getCurrentInterval()).toBe(HIDDEN_INTERVAL);
+ done();
+ }, DEFAULT_SHORT_TIMEOUT);
+ });
+
it('should resume when page is becomes visible at the previous interval', function (done) {
const interval = this.smartInterval;
@@ -129,14 +147,12 @@
expect(interval.state.intervalId).toBeTruthy();
// simulates triggering of visibilitychange event
- interval.state.pageVisibility = 'hidden';
- interval.handleVisibilityChange();
+ interval.handleVisibilityChange({ target: { visibilityState: 'hidden' } });
expect(interval.state.intervalId).toBeUndefined();
// simulates triggering of visibilitychange event
- interval.state.pageVisibility = 'visible';
- interval.handleVisibilityChange();
+ interval.handleVisibilityChange({ target: { visibilityState: 'visible' } });
expect(interval.state.intervalId).toBeTruthy();
@@ -154,6 +170,11 @@
done();
}, DEFAULT_SHORT_TIMEOUT);
});
+
+ it('should execute callback before first interval', function () {
+ const interval = createDefaultSmartInterval({ immediateExecution: true });
+ expect(interval.cfg.immediateExecution).toBeFalsy();
+ });
});
});
})(window.gl || (window.gl = {}));
diff --git a/spec/lib/banzai/filter/relative_link_filter_spec.rb b/spec/lib/banzai/filter/relative_link_filter_spec.rb
index 2bfa51deb20..df2dd173b57 100644
--- a/spec/lib/banzai/filter/relative_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/relative_link_filter_spec.rb
@@ -175,7 +175,7 @@ describe Banzai::Filter::RelativeLinkFilter, lib: true do
allow_any_instance_of(described_class).to receive(:uri_type).and_return(:raw)
doc = filter(image(escaped))
- expect(doc.at_css('img')['src']).to match '/raw/'
+ expect(doc.at_css('img')['src']).to eq "/#{project_path}/raw/#{Addressable::URI.escape(ref)}/#{escaped}"
end
context 'when requested path is a file in the repo' do
diff --git a/spec/lib/gitlab/allowable_spec.rb b/spec/lib/gitlab/allowable_spec.rb
new file mode 100644
index 00000000000..87733d53e92
--- /dev/null
+++ b/spec/lib/gitlab/allowable_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Gitlab::Allowable do
+ subject do
+ Class.new.include(described_class).new
+ end
+
+ describe '#can?' do
+ let(:user) { create(:user) }
+
+ context 'when user is allowed to do something' do
+ let(:project) { create(:empty_project, :public) }
+
+ it 'reports correct ability to perform action' do
+ expect(subject.can?(user, :read_project, project)).to be true
+ end
+ end
+
+ context 'when user is not allowed to do something' do
+ let(:project) { create(:empty_project, :private) }
+
+ it 'reports correct ability to perform action' do
+ expect(subject.can?(user, :read_project, project)).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/cancelable_spec.rb b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
new file mode 100644
index 00000000000..9376bce17a1
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/cancelable_spec.rb
@@ -0,0 +1,86 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Cancelable do
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject do
+ described_class.new(status)
+ end
+
+ describe '#text' do
+ it 'does not override status text' do
+ expect(status).to receive(:text)
+
+ subject.text
+ end
+ end
+
+ describe '#icon' do
+ it 'does not override status icon' do
+ expect(status).to receive(:icon)
+
+ subject.icon
+ end
+ end
+
+ describe '#label' do
+ it 'does not override status label' do
+ expect(status).to receive(:label)
+
+ subject.label
+ end
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/cancel" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'ban' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Cancel' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is cancelable' do
+ let(:build) do
+ create(:ci_build, :running)
+ end
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not cancelable' do
+ let(:build) { create(:ci_build, :success) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/common_spec.rb b/spec/lib/gitlab/ci/status/build/common_spec.rb
new file mode 100644
index 00000000000..40b96b1807b
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/common_spec.rb
@@ -0,0 +1,37 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Common do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:project) { build.project }
+
+ subject do
+ Gitlab::Ci::Status::Core
+ .new(build, user)
+ .extend(described_class)
+ end
+
+ describe '#has_action?' do
+ it { is_expected.not_to have_action }
+ end
+
+ describe '#has_details?' do
+ context 'when user has access to read build' do
+ before { project.team << [user, :developer] }
+
+ it { is_expected.to have_details }
+ end
+
+ context 'when user does not have access to read build' do
+ before { project.update(public_builds: false) }
+
+ it { is_expected.not_to have_details }
+ end
+ end
+
+ describe '#details_path' do
+ it 'links to the build details page' do
+ expect(subject.details_path).to include "builds/#{build.id}"
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/factory_spec.rb b/spec/lib/gitlab/ci/status/build/factory_spec.rb
new file mode 100644
index 00000000000..dccb29b5ef6
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/factory_spec.rb
@@ -0,0 +1,141 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Factory do
+ let(:user) { create(:user) }
+ let(:project) { build.project }
+
+ subject { described_class.new(build, user) }
+ let(:status) { subject.fabricate! }
+
+ before { project.team << [user, :developer] }
+
+ context 'when build is successful' do
+ let(:build) { create(:ci_build, :success) }
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'passed'
+ expect(status.icon).to eq 'icon_status_success'
+ expect(status.label).to eq 'passed'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is failed' do
+ let(:build) { create(:ci_build, :failed) }
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'failed'
+ expect(status.icon).to eq 'icon_status_failed'
+ expect(status.label).to eq 'failed'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is a canceled' do
+ let(:build) { create(:ci_build, :canceled) }
+
+ it 'fabricates a retryable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Retryable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'canceled'
+ expect(status.icon).to eq 'icon_status_canceled'
+ expect(status.label).to eq 'canceled'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is running' do
+ let(:build) { create(:ci_build, :running) }
+
+ it 'fabricates a canceable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'running'
+ expect(status.icon).to eq 'icon_status_running'
+ expect(status.label).to eq 'running'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is pending' do
+ let(:build) { create(:ci_build, :pending) }
+
+ it 'fabricates a cancelable build status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Cancelable
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'pending'
+ expect(status.icon).to eq 'icon_status_pending'
+ expect(status.label).to eq 'pending'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is skipped' do
+ let(:build) { create(:ci_build, :skipped) }
+
+ it 'fabricates a core skipped status' do
+ expect(status).to be_a Gitlab::Ci::Status::Skipped
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'skipped'
+ expect(status.icon).to eq 'icon_status_skipped'
+ expect(status.label).to eq 'skipped'
+ expect(status).to have_details
+ expect(status).not_to have_action
+ end
+ end
+
+ context 'when build is a manual action' do
+ context 'when build is a play action' do
+ let(:build) { create(:ci_build, :playable) }
+
+ it 'fabricates a core skipped status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Play
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'manual'
+ expect(status.icon).to eq 'icon_status_manual'
+ expect(status.label).to eq 'manual play action'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+
+ context 'when build is an environment stop action' do
+ let(:build) { create(:ci_build, :playable, :teardown_environment) }
+
+ it 'fabricates a core skipped status' do
+ expect(status).to be_a Gitlab::Ci::Status::Build::Stop
+ end
+
+ it 'fabricates status with correct details' do
+ expect(status.text).to eq 'manual'
+ expect(status.icon).to eq 'icon_status_manual'
+ expect(status.label).to eq 'manual stop action'
+ expect(status).to have_details
+ expect(status).to have_action
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/play_spec.rb b/spec/lib/gitlab/ci/status/build/play_spec.rb
new file mode 100644
index 00000000000..4ddf04a8e11
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/play_spec.rb
@@ -0,0 +1,82 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Play do
+ let(:status) { double('core') }
+ let(:user) { double('user') }
+
+ subject { described_class.new(status) }
+
+ describe '#text' do
+ it { expect(subject.text).to eq 'manual' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'manual play action' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_manual' }
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/play" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'play' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Play' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is playable' do
+ context 'when build stops an environment' do
+ let(:build) do
+ create(:ci_build, :playable, :teardown_environment)
+ end
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+
+ context 'when build does not stop an environment' do
+ let(:build) { create(:ci_build, :playable) }
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+ end
+
+ context 'when build is not playable' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/retryable_spec.rb b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
new file mode 100644
index 00000000000..d61e5bbaa6b
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/retryable_spec.rb
@@ -0,0 +1,86 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Retryable do
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject do
+ described_class.new(status)
+ end
+
+ describe '#text' do
+ it 'does not override status text' do
+ expect(status).to receive(:text)
+
+ subject.text
+ end
+ end
+
+ describe '#icon' do
+ it 'does not override status icon' do
+ expect(status).to receive(:icon)
+
+ subject.icon
+ end
+ end
+
+ describe '#label' do
+ it 'does not override status label' do
+ expect(status).to receive(:label)
+
+ subject.label
+ end
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/retry" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'refresh' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Retry' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is retryable' do
+ let(:build) do
+ create(:ci_build, :success)
+ end
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build is not retryable' do
+ let(:build) { create(:ci_build, :running) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/build/stop_spec.rb b/spec/lib/gitlab/ci/status/build/stop_spec.rb
new file mode 100644
index 00000000000..59a85b55f90
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/build/stop_spec.rb
@@ -0,0 +1,84 @@
+require 'spec_helper'
+
+describe Gitlab::Ci::Status::Build::Stop do
+ let(:status) { double('core status') }
+ let(:user) { double('user') }
+
+ subject do
+ described_class.new(status)
+ end
+
+ describe '#text' do
+ it { expect(subject.text).to eq 'manual' }
+ end
+
+ describe '#label' do
+ it { expect(subject.label).to eq 'manual stop action' }
+ end
+
+ describe '#icon' do
+ it { expect(subject.icon).to eq 'icon_status_manual' }
+ end
+
+ describe 'action details' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build) }
+ let(:status) { Gitlab::Ci::Status::Core.new(build, user) }
+
+ describe '#has_action?' do
+ context 'when user is allowed to update build' do
+ before { build.project.team << [user, :developer] }
+
+ it { is_expected.to have_action }
+ end
+
+ context 'when user is not allowed to update build' do
+ it { is_expected.not_to have_action }
+ end
+ end
+
+ describe '#action_path' do
+ it { expect(subject.action_path).to include "#{build.id}/play" }
+ end
+
+ describe '#action_icon' do
+ it { expect(subject.action_icon).to eq 'stop' }
+ end
+
+ describe '#action_title' do
+ it { expect(subject.action_title).to eq 'Stop' }
+ end
+ end
+
+ describe '.matches?' do
+ subject { described_class.matches?(build, user) }
+
+ context 'when build is playable' do
+ context 'when build stops an environment' do
+ let(:build) do
+ create(:ci_build, :playable, :teardown_environment)
+ end
+
+ it 'is a correct match' do
+ expect(subject).to be true
+ end
+ end
+
+ context 'when build does not stop an environment' do
+ let(:build) { create(:ci_build, :playable) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+
+ context 'when build is not playable' do
+ let(:build) { create(:ci_build) }
+
+ it 'does not match' do
+ expect(subject).to be false
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/canceled_spec.rb b/spec/lib/gitlab/ci/status/canceled_spec.rb
index 619ecbcba67..4639278ad45 100644
--- a/spec/lib/gitlab/ci/status/canceled_spec.rb
+++ b/spec/lib/gitlab/ci/status/canceled_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Canceled do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'canceled' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Canceled do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_canceled' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: canceled' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/created_spec.rb b/spec/lib/gitlab/ci/status/created_spec.rb
index 157302c65a8..2ce176a29d6 100644
--- a/spec/lib/gitlab/ci/status/created_spec.rb
+++ b/spec/lib/gitlab/ci/status/created_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Created do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'created' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Created do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_created' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: created' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/extended_spec.rb b/spec/lib/gitlab/ci/status/extended_spec.rb
index 120e121aae5..c2d74ca5cde 100644
--- a/spec/lib/gitlab/ci/status/extended_spec.rb
+++ b/spec/lib/gitlab/ci/status/extended_spec.rb
@@ -2,11 +2,11 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Extended do
subject do
- Class.new.extend(described_class)
+ Class.new.include(described_class)
end
it 'requires subclass to implement matcher' do
- expect { subject.matches?(double) }
+ expect { subject.matches?(double, double) }
.to raise_error(NotImplementedError)
end
end
diff --git a/spec/lib/gitlab/ci/status/factory_spec.rb b/spec/lib/gitlab/ci/status/factory_spec.rb
index d5bd7f7102b..f92a1c149bf 100644
--- a/spec/lib/gitlab/ci/status/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/factory_spec.rb
@@ -2,15 +2,17 @@ require 'spec_helper'
describe Gitlab::Ci::Status::Factory do
subject do
- described_class.new(object)
+ described_class.new(resource, user)
end
+ let(:user) { create(:user) }
+
let(:status) { subject.fabricate! }
context 'when object has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do
- let(:object) { double(status: core_status) }
+ let(:resource) { double(status: core_status) }
it "fabricates a core status #{core_status}" do
expect(status).to be_a(
diff --git a/spec/lib/gitlab/ci/status/failed_spec.rb b/spec/lib/gitlab/ci/status/failed_spec.rb
index 0b3cb8168e6..9d527e6a7ef 100644
--- a/spec/lib/gitlab/ci/status/failed_spec.rb
+++ b/spec/lib/gitlab/ci/status/failed_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Failed do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'failed' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Failed do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_failed' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: failed' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/pending_spec.rb b/spec/lib/gitlab/ci/status/pending_spec.rb
index 57c901c1202..d03f595d3c7 100644
--- a/spec/lib/gitlab/ci/status/pending_spec.rb
+++ b/spec/lib/gitlab/ci/status/pending_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Pending do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'pending' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Pending do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_pending' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: pending' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
index 21adee3f8e7..d665674bf70 100644
--- a/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/common_spec.rb
@@ -1,23 +1,36 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Common do
- let(:pipeline) { create(:ci_pipeline) }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project, :private) }
+ let(:pipeline) { create(:ci_pipeline, project: project) }
subject do
- Class.new(Gitlab::Ci::Status::Core)
- .new(pipeline).extend(described_class)
+ Gitlab::Ci::Status::Core
+ .new(pipeline, user)
+ .extend(described_class)
end
- it 'does not have action' do
- expect(subject).not_to have_action
+ describe '#has_action?' do
+ it { is_expected.not_to have_action }
end
- it 'has details' do
- expect(subject).to have_details
+ describe '#has_details?' do
+ context 'when user has access to read pipeline' do
+ before { project.team << [user, :developer] }
+
+ it { is_expected.to have_details }
+ end
+
+ context 'when user does not have access to read pipeline' do
+ it { is_expected.not_to have_details }
+ end
end
- it 'links to the pipeline details page' do
- expect(subject.details_path)
- .to include "pipelines/#{pipeline.id}"
+ describe '#details_path' do
+ it 'links to the pipeline details page' do
+ expect(subject.details_path)
+ .to include "pipelines/#{pipeline.id}"
+ end
end
end
diff --git a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
index d6243940f2e..d4a2dc7fcc1 100644
--- a/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/factory_spec.rb
@@ -1,14 +1,21 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Pipeline::Factory do
+ let(:user) { create(:user) }
+ let(:project) { pipeline.project }
+
subject do
- described_class.new(pipeline)
+ described_class.new(pipeline, user)
end
let(:status) do
subject.fabricate!
end
+ before do
+ project.team << [user, :developer]
+ end
+
context 'when pipeline has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do
diff --git a/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb b/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
index 02e526e3de2..7e3383c307f 100644
--- a/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
+++ b/spec/lib/gitlab/ci/status/pipeline/success_with_warnings_spec.rb
@@ -29,13 +29,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end
it 'is a correct match' do
- expect(described_class.matches?(pipeline)).to eq true
+ expect(described_class.matches?(pipeline, double)).to eq true
end
end
context 'when pipeline does not have warnings' do
it 'does not match' do
- expect(described_class.matches?(pipeline)).to eq false
+ expect(described_class.matches?(pipeline, double)).to eq false
end
end
end
@@ -51,13 +51,13 @@ describe Gitlab::Ci::Status::Pipeline::SuccessWithWarnings do
end
it 'does not match' do
- expect(described_class.matches?(pipeline)).to eq false
+ expect(described_class.matches?(pipeline, double)).to eq false
end
end
context 'when pipeline does not have warnings' do
it 'does not match' do
- expect(described_class.matches?(pipeline)).to eq false
+ expect(described_class.matches?(pipeline, double)).to eq false
end
end
end
diff --git a/spec/lib/gitlab/ci/status/running_spec.rb b/spec/lib/gitlab/ci/status/running_spec.rb
index c023f1872cc..9f47090d396 100644
--- a/spec/lib/gitlab/ci/status/running_spec.rb
+++ b/spec/lib/gitlab/ci/status/running_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Running do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'running' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Running do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_running' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: running' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/skipped_spec.rb b/spec/lib/gitlab/ci/status/skipped_spec.rb
index d4f7f4b3b70..94601648a8d 100644
--- a/spec/lib/gitlab/ci/status/skipped_spec.rb
+++ b/spec/lib/gitlab/ci/status/skipped_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Skipped do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'skipped' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Skipped do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_skipped' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: skipped' }
- end
end
diff --git a/spec/lib/gitlab/ci/status/stage/common_spec.rb b/spec/lib/gitlab/ci/status/stage/common_spec.rb
index f3259c6f23e..8814a7614a0 100644
--- a/spec/lib/gitlab/ci/status/stage/common_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/common_spec.rb
@@ -1,26 +1,43 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Common do
- let(:pipeline) { create(:ci_empty_pipeline) }
- let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+
+ let(:stage) do
+ build(:ci_stage, pipeline: pipeline, name: 'test')
+ end
subject do
Class.new(Gitlab::Ci::Status::Core)
- .new(stage).extend(described_class)
+ .new(stage, user).extend(described_class)
end
it 'does not have action' do
expect(subject).not_to have_action
end
- it 'has details' do
- expect(subject).to have_details
- end
-
it 'links to the pipeline details page' do
expect(subject.details_path)
.to include "pipelines/#{pipeline.id}"
expect(subject.details_path)
.to include "##{stage.name}"
end
+
+ context 'when user has permission to read pipeline' do
+ before do
+ project.team << [user, :master]
+ end
+
+ it 'has details' do
+ expect(subject).to have_details
+ end
+ end
+
+ context 'when user does not have permission to read pipeline' do
+ it 'does not have details' do
+ expect(subject).not_to have_details
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/status/stage/factory_spec.rb b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
index 17929665c83..6f8721d30c2 100644
--- a/spec/lib/gitlab/ci/status/stage/factory_spec.rb
+++ b/spec/lib/gitlab/ci/status/stage/factory_spec.rb
@@ -1,17 +1,26 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Stage::Factory do
- let(:pipeline) { create(:ci_empty_pipeline) }
- let(:stage) { build(:ci_stage, pipeline: pipeline, name: 'test') }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:pipeline) { create(:ci_empty_pipeline, project: project) }
+
+ let(:stage) do
+ build(:ci_stage, pipeline: pipeline, name: 'test')
+ end
subject do
- described_class.new(stage)
+ described_class.new(stage, user)
end
let(:status) do
subject.fabricate!
end
+ before do
+ project.team << [user, :developer]
+ end
+
context 'when stage has a core status' do
HasStatus::AVAILABLE_STATUSES.each do |core_status|
context "when core status is #{core_status}" do
diff --git a/spec/lib/gitlab/ci/status/success_spec.rb b/spec/lib/gitlab/ci/status/success_spec.rb
index 9e261a3aa5f..90f9f615e0d 100644
--- a/spec/lib/gitlab/ci/status/success_spec.rb
+++ b/spec/lib/gitlab/ci/status/success_spec.rb
@@ -1,7 +1,9 @@
require 'spec_helper'
describe Gitlab::Ci::Status::Success do
- subject { described_class.new(double('subject')) }
+ subject do
+ described_class.new(double('subject'), double('user'))
+ end
describe '#text' do
it { expect(subject.label).to eq 'passed' }
@@ -14,8 +16,4 @@ describe Gitlab::Ci::Status::Success do
describe '#icon' do
it { expect(subject.icon).to eq 'icon_status_success' }
end
-
- describe '#title' do
- it { expect(subject.title).to eq 'Double: passed' }
- end
end
diff --git a/spec/lib/gitlab/routing_spec.rb b/spec/lib/gitlab/routing_spec.rb
new file mode 100644
index 00000000000..01d5acfc15b
--- /dev/null
+++ b/spec/lib/gitlab/routing_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe Gitlab::Routing do
+ context 'when module is included' do
+ subject do
+ Class.new.include(described_class).new
+ end
+
+ it 'makes it possible to access url helpers' do
+ expect(subject).to respond_to(:namespace_project_path)
+ end
+ end
+
+ context 'when module is not included' do
+ subject do
+ Class.new.include(described_class.url_helpers).new
+ end
+
+ it 'exposes url helpers module through a method' do
+ expect(subject).to respond_to(:namespace_project_path)
+ end
+ end
+end
diff --git a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
index 52428547a9f..6a93deb5412 100644
--- a/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
+++ b/spec/migrations/migrate_process_commit_worker_jobs_spec.rb
@@ -1,3 +1,5 @@
+# encoding: utf-8
+
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20161124141322_migrate_process_commit_worker_jobs.rb')
@@ -59,6 +61,10 @@ describe MigrateProcessCommitWorkerJobs do
Sidekiq.redis { |r| r.llen('queue:process_commit') }
end
+ def pop_job
+ JSON.load(Sidekiq.redis { |r| r.lpop('queue:process_commit') })
+ end
+
before do
Sidekiq.redis do |redis|
job = JSON.dump(args: [project.id, user.id, commit.oid])
@@ -92,11 +98,28 @@ describe MigrateProcessCommitWorkerJobs do
expect(job_count).to eq(1)
end
+ it 'encodes data to UTF-8' do
+ allow_any_instance_of(Rugged::Repository).to receive(:lookup).
+ with(commit.oid).
+ and_return(commit)
+
+ allow(commit).to receive(:message).
+ and_return('김치'.force_encoding('BINARY'))
+
+ migration.up
+
+ job = pop_job
+
+ # We don't care so much about what is being stored, instead we just want
+ # to make sure the encoding is right so that JSON encoding the data
+ # doesn't produce any errors.
+ expect(job['args'][2]['message'].encoding).to eq(Encoding::UTF_8)
+ end
+
context 'a migrated job' do
let(:job) do
migration.up
-
- JSON.load(Sidekiq.redis { |r| r.lpop('queue:process_commit') })
+ pop_job
end
let(:commit_hash) do
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index d4970e38f7c..7f39aff7639 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -899,21 +899,87 @@ describe Ci::Build, models: true do
end
end
+ describe '#cancelable?' do
+ subject { build }
+
+ context 'when build is cancelable' do
+ context 'when build is pending' do
+ it { is_expected.to be_cancelable }
+ end
+
+ context 'when build is running' do
+ before do
+ build.run!
+ end
+
+ it { is_expected.to be_cancelable }
+ end
+ end
+
+ context 'when build is not cancelable' do
+ context 'when build is successful' do
+ before do
+ build.success!
+ end
+
+ it { is_expected.not_to be_cancelable }
+ end
+
+ context 'when build is failed' do
+ before do
+ build.drop!
+ end
+
+ it { is_expected.not_to be_cancelable }
+ end
+ end
+ end
+
describe '#retryable?' do
- context 'when build is running' do
- before do
- build.run!
+ subject { build }
+
+ context 'when build is retryable' do
+ context 'when build is successful' do
+ before do
+ build.success!
+ end
+
+ it { is_expected.to be_retryable }
+ end
+
+ context 'when build is failed' do
+ before do
+ build.drop!
+ end
+
+ it { is_expected.to be_retryable }
end
- it { expect(build).not_to be_retryable }
+ context 'when build is canceled' do
+ before do
+ build.cancel!
+ end
+
+ it { is_expected.to be_retryable }
+ end
end
- context 'when build is finished' do
- before do
- build.success!
+ context 'when build is not retryable' do
+ context 'when build is running' do
+ before do
+ build.run!
+ end
+
+ it { is_expected.not_to be_retryable }
end
- it { expect(build).to be_retryable }
+ context 'when build is skipped' do
+ before do
+ build.skip!
+ end
+
+ it { is_expected.not_to be_retryable }
+ end
end
end
@@ -1180,4 +1246,13 @@ describe Ci::Build, models: true do
it { is_expected.to eq('review/master') }
end
end
+
+ describe '#detailed_status' do
+ let(:user) { create(:user) }
+
+ it 'returns a detailed status' do
+ expect(build.detailed_status(user))
+ .to be_a Gitlab::Ci::Status::Build::Cancelable
+ end
+ end
end
diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb
index 8158e71dd55..e78ae14b737 100644
--- a/spec/models/ci/pipeline_spec.rb
+++ b/spec/models/ci/pipeline_spec.rb
@@ -442,11 +442,15 @@ describe Ci::Pipeline, models: true do
end
describe '#detailed_status' do
+ let(:user) { create(:user) }
+
+ subject { pipeline.detailed_status(user) }
+
context 'when pipeline is created' do
let(:pipeline) { create(:ci_pipeline, status: :created) }
it 'returns detailed status for created pipeline' do
- expect(pipeline.detailed_status.text).to eq 'created'
+ expect(subject.text).to eq 'created'
end
end
@@ -454,7 +458,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :pending) }
it 'returns detailed status for pending pipeline' do
- expect(pipeline.detailed_status.text).to eq 'pending'
+ expect(subject.text).to eq 'pending'
end
end
@@ -462,7 +466,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :running) }
it 'returns detailed status for running pipeline' do
- expect(pipeline.detailed_status.text).to eq 'running'
+ expect(subject.text).to eq 'running'
end
end
@@ -470,7 +474,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :success) }
it 'returns detailed status for successful pipeline' do
- expect(pipeline.detailed_status.text).to eq 'passed'
+ expect(subject.text).to eq 'passed'
end
end
@@ -478,7 +482,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :failed) }
it 'returns detailed status for failed pipeline' do
- expect(pipeline.detailed_status.text).to eq 'failed'
+ expect(subject.text).to eq 'failed'
end
end
@@ -486,7 +490,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :canceled) }
it 'returns detailed status for canceled pipeline' do
- expect(pipeline.detailed_status.text).to eq 'canceled'
+ expect(subject.text).to eq 'canceled'
end
end
@@ -494,7 +498,7 @@ describe Ci::Pipeline, models: true do
let(:pipeline) { create(:ci_pipeline, status: :skipped) }
it 'returns detailed status for skipped pipeline' do
- expect(pipeline.detailed_status.text).to eq 'skipped'
+ expect(subject.text).to eq 'skipped'
end
end
@@ -506,7 +510,7 @@ describe Ci::Pipeline, models: true do
end
it 'retruns detailed status for successful pipeline with warnings' do
- expect(pipeline.detailed_status.label).to eq 'passed with warnings'
+ expect(subject.label).to eq 'passed with warnings'
end
end
end
diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb
index f232761dba2..8fff38f7cda 100644
--- a/spec/models/ci/stage_spec.rb
+++ b/spec/models/ci/stage_spec.rb
@@ -68,7 +68,9 @@ describe Ci::Stage, models: true do
end
describe '#detailed_status' do
- subject { stage.detailed_status }
+ let(:user) { create(:user) }
+
+ subject { stage.detailed_status(user) }
context 'when build is created' do
let!(:stage_build) { create_job(:ci_build, status: :created) }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
index 1ec08c2a9d0..701f3323c0f 100644
--- a/spec/models/commit_status_spec.rb
+++ b/spec/models/commit_status_spec.rb
@@ -234,4 +234,13 @@ describe CommitStatus, models: true do
end
end
end
+
+ describe '#detailed_status' do
+ let(:user) { create(:user) }
+
+ it 'returns a detailed status' do
+ expect(commit_status.detailed_status(user))
+ .to be_a Gitlab::Ci::Status::Success
+ end
+ end
end
diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb
index 0acefc0c1d5..b556135532f 100644
--- a/spec/models/concerns/routable_spec.rb
+++ b/spec/models/concerns/routable_spec.rb
@@ -3,6 +3,10 @@ require 'spec_helper'
describe Group, 'Routable' do
let!(:group) { create(:group) }
+ describe 'Validations' do
+ it { is_expected.to validate_presence_of(:route) }
+ end
+
describe 'Associations' do
it { is_expected.to have_one(:route).dependent(:destroy) }
end
@@ -35,16 +39,16 @@ describe Group, 'Routable' do
it { expect(described_class.find_by_full_path('unknown')).to eq(nil) }
end
- describe '.where_paths_in' do
+ describe '.where_full_path_in' do
context 'without any paths' do
it 'returns an empty relation' do
- expect(described_class.where_paths_in([])).to eq([])
+ expect(described_class.where_full_path_in([])).to eq([])
end
end
context 'without any valid paths' do
it 'returns an empty relation' do
- expect(described_class.where_paths_in(%w[unknown])).to eq([])
+ expect(described_class.where_full_path_in(%w[unknown])).to eq([])
end
end
@@ -52,13 +56,13 @@ describe Group, 'Routable' do
let!(:nested_group) { create(:group, parent: group) }
it 'returns the projects matching the paths' do
- result = described_class.where_paths_in([group.to_param, nested_group.to_param])
+ result = described_class.where_full_path_in([group.to_param, nested_group.to_param])
expect(result).to contain_exactly(group, nested_group)
end
it 'returns projects regardless of the casing of paths' do
- result = described_class.where_paths_in([group.to_param.upcase, nested_group.to_param.upcase])
+ result = described_class.where_full_path_in([group.to_param.upcase, nested_group.to_param.upcase])
expect(result).to contain_exactly(group, nested_group)
end
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
index 615cfe3142b..6004bfdb7b7 100644
--- a/spec/models/generic_commit_status_spec.rb
+++ b/spec/models/generic_commit_status_spec.rb
@@ -1,8 +1,11 @@
require 'spec_helper'
describe GenericCommitStatus, models: true do
- let(:pipeline) { FactoryGirl.create :ci_pipeline }
- let(:generic_commit_status) { FactoryGirl.create :generic_commit_status, pipeline: pipeline }
+ let(:pipeline) { create(:ci_pipeline) }
+
+ let(:generic_commit_status) do
+ create(:generic_commit_status, pipeline: pipeline)
+ end
describe '#context' do
subject { generic_commit_status.context }
@@ -17,6 +20,15 @@ describe GenericCommitStatus, models: true do
it { is_expected.to eq([:external]) }
end
+ describe '#detailed_status' do
+ let(:user) { create(:user) }
+
+ it 'returns detailed status object' do
+ expect(generic_commit_status.detailed_status(user))
+ .to be_a Gitlab::Ci::Status::Success
+ end
+ end
+
describe 'set_default_values' do
before do
generic_commit_status.context = nil
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 40f1cf92e00..893c6827a91 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -270,4 +270,11 @@ describe Group, models: true do
expect(group.web_url).to include("groups/#{group.name}")
end
end
+
+ describe 'nested group' do
+ subject { create(:group, :nested) }
+
+ it { is_expected.to be_valid }
+ it { expect(subject.parent).to be_kind_of(Group) }
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index bad6ed9e146..8b20ee81614 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -727,17 +727,6 @@ describe User, models: true do
end
end
- describe 'by_username_or_id' do
- let(:user1) { create(:user, username: 'foo') }
-
- it "gets the correct user" do
- expect(User.by_username_or_id(user1.id)).to eq(user1)
- expect(User.by_username_or_id('foo')).to eq(user1)
- expect(User.by_username_or_id(-1)).to be_nil
- expect(User.by_username_or_id('bar')).to be_nil
- end
- end
-
describe '.find_by_ssh_key_id' do
context 'using an existing SSH key ID' do
let(:user) { create(:user) }
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 55b8c8c0c69..2878e0cb59b 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -11,6 +11,7 @@ describe API::Branches, api: true do
let!(:guest) { create(:project_member, :guest, user: user2, project: project) }
let!(:branch_name) { 'feature' }
let!(:branch_sha) { '0b4bc9a49b562e85de7cc9e834518ea6828729b9' }
+ let!(:branch_with_dot) { CreateBranchService.new(project, user).execute("with.1.2.3", "master") }
describe "GET /projects/:id/repository/branches" do
it "returns an array of project branches" do
@@ -37,6 +38,13 @@ describe API::Branches, api: true do
expect(json_response['developers_can_merge']).to eq(false)
end
+ it "returns the branch information for a single branch with dots in the name" do
+ get api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq("with.1.2.3")
+ end
+
context 'on a merged branch' do
it "returns the branch information for a single branch" do
get api("/projects/#{project.id}/repository/branches/merge-test", user)
@@ -71,6 +79,14 @@ describe API::Branches, api: true do
expect(json_response['developers_can_merge']).to eq(false)
end
+ it "protects a single branch with dots in the name" do
+ put api("/projects/#{project.id}/repository/branches/with.1.2.3/protect", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq("with.1.2.3")
+ expect(json_response['protected']).to eq(true)
+ end
+
it 'protects a single branch and developers can push' do
put api("/projects/#{project.id}/repository/branches/#{branch_name}/protect", user),
developers_can_push: true
@@ -220,6 +236,14 @@ describe API::Branches, api: true do
expect(json_response['protected']).to eq(false)
end
+ it "update branches with dots in branch name" do
+ put api("/projects/#{project.id}/repository/branches/with.1.2.3/unprotect", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['name']).to eq("with.1.2.3")
+ expect(json_response['protected']).to eq(false)
+ end
+
it "returns success when unprotect branch" do
put api("/projects/#{project.id}/repository/branches/unknown/unprotect", user)
expect(response).to have_http_status(404)
@@ -292,6 +316,13 @@ describe API::Branches, api: true do
expect(json_response['branch_name']).to eq(branch_name)
end
+ it "removes a branch with dots in the branch name" do
+ delete api("/projects/#{project.id}/repository/branches/with.1.2.3", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response['branch_name']).to eq("with.1.2.3")
+ end
+
it 'returns 404 if branch not exists' do
delete api("/projects/#{project.id}/repository/branches/foobar", user)
expect(response).to have_http_status(404)
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index e497bce6943..964cded917c 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -456,6 +456,76 @@ describe API::Commits, api: true do
end
end
+ describe 'POST :id/repository/commits/:sha/cherry_pick' do
+ let(:master_pickable_commit) { project.commit('7d3b0f7cff5f37573aea97cebfd5692ea1689924') }
+
+ context 'authorized user' do
+ it 'cherry picks a commit' do
+ post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'master'
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(master_pickable_commit.title)
+ expect(json_response['message']).to eq(master_pickable_commit.message)
+ expect(json_response['author_name']).to eq(master_pickable_commit.author_name)
+ expect(json_response['committer_name']).to eq(user.name)
+ end
+
+ it 'returns 400 if commit is already included in the target branch' do
+ post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'markdown'
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq('Sorry, we cannot cherry-pick this commit automatically.
+ A cherry-pick may have already been performed with this commit, or a more recent commit may have updated some of its content.')
+ end
+
+ it 'returns 400 if you are not allowed to push to the target branch' do
+ project.team << [user2, :developer]
+ protected_branch = create(:protected_branch, project: project, name: 'feature')
+
+ post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user2), branch: protected_branch.name
+
+ expect(response).to have_http_status(400)
+ expect(json_response['message']).to eq('You are not allowed to push into this branch')
+ end
+
+ it 'returns 400 for missing parameters' do
+ post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user)
+
+ expect(response).to have_http_status(400)
+ expect(json_response['error']).to eq('branch is missing')
+ end
+
+ it 'returns 404 if commit is not found' do
+ post api("/projects/#{project.id}/repository/commits/abcd0123/cherry_pick", user), branch: 'master'
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Commit Not Found')
+ end
+
+ it 'returns 404 if branch is not found' do
+ post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user), branch: 'foo'
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Branch Not Found')
+ end
+
+ it 'returns 400 for missing parameters' do
+ post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick", user)
+
+ expect(response).to have_http_status(400)
+ expect(json_response['error']).to eq('branch is missing')
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'does not cherry pick the commit' do
+ post api("/projects/#{project.id}/repository/commits/#{master_pickable_commit.id}/cherry_pick"), branch: 'master'
+
+ expect(response).to have_http_status(401)
+ end
+ end
+ end
+
describe 'Post comment to commit' do
context 'authorized user' do
it 'returns comment' do
diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb
index 548ed8e1892..a75ba824e85 100644
--- a/spec/requests/api/groups_spec.rb
+++ b/spec/requests/api/groups_spec.rb
@@ -243,6 +243,28 @@ describe API::Groups, api: true do
expect(json_response.length).to eq(2)
project_names = json_response.map { |proj| proj['name' ] }
expect(project_names).to match_array([project1.name, project3.name])
+ expect(json_response.first['default_branch']).to be_present
+ end
+
+ it "returns the group's projects with simple representation" do
+ get api("/groups/#{group1.id}/projects", user1), simple: true
+
+ expect(response).to have_http_status(200)
+ expect(json_response.length).to eq(2)
+ project_names = json_response.map { |proj| proj['name' ] }
+ expect(project_names).to match_array([project1.name, project3.name])
+ expect(json_response.first['default_branch']).not_to be_present
+ end
+
+ it 'filters the groups projects' do
+ public_project = create(:project, :public, path: 'test1', group: group1)
+
+ get api("/groups/#{group1.id}/projects", user1), visibility: 'public'
+
+ expect(response).to have_http_status(200)
+ expect(json_response).to be_an(Array)
+ expect(json_response.length).to eq(1)
+ expect(json_response.first['name']).to eq(public_project.name)
end
it "does not return a non existing group" do
diff --git a/spec/requests/api/api_helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 3f34309f419..4035fd97af5 100644
--- a/spec/requests/api/api_helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -2,7 +2,6 @@ require 'spec_helper'
describe API::Helpers, api: true do
include API::Helpers
- include ApiHelpers
include SentryHelper
let(:user) { create(:user) }
@@ -13,18 +12,18 @@ describe API::Helpers, api: true do
let(:env) { { 'REQUEST_METHOD' => 'GET' } }
let(:request) { Rack::Request.new(env) }
- def set_env(token_usr, identifier)
+ def set_env(user_or_token, identifier)
clear_env
clear_param
- env[API::Helpers::PRIVATE_TOKEN_HEADER] = token_usr.private_token
- env[API::Helpers::SUDO_HEADER] = identifier
+ env[API::Helpers::PRIVATE_TOKEN_HEADER] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
+ env[API::Helpers::SUDO_HEADER] = identifier.to_s
end
- def set_param(token_usr, identifier)
+ def set_param(user_or_token, identifier)
clear_env
clear_param
- params[API::Helpers::PRIVATE_TOKEN_PARAM] = token_usr.private_token
- params[API::Helpers::SUDO_PARAM] = identifier
+ params[API::Helpers::PRIVATE_TOKEN_PARAM] = user_or_token.respond_to?(:private_token) ? user_or_token.private_token : user_or_token
+ params[API::Helpers::SUDO_PARAM] = identifier.to_s
end
def clear_env
@@ -163,6 +162,13 @@ describe API::Helpers, api: true do
expect(current_user).to eq(user)
end
+ it 'memoize the current_user: sudo permissions are not run against the sudoed user' do
+ set_env(admin, user.id)
+
+ expect(current_user).to eq(user)
+ expect(current_user).to eq(user)
+ end
+
it 'handles sudo to oneself' do
set_env(admin, admin.id)
@@ -294,33 +300,48 @@ describe API::Helpers, api: true do
end
end
- describe '.sudo_identifier' do
- it "returns integers when input is an int" do
- set_env(admin, '123')
- expect(sudo_identifier).to eq(123)
- set_env(admin, '0001234567890')
- expect(sudo_identifier).to eq(1234567890)
-
- set_param(admin, '123')
- expect(sudo_identifier).to eq(123)
- set_param(admin, '0001234567890')
- expect(sudo_identifier).to eq(1234567890)
+ describe '.sudo?' do
+ context 'when no sudo env or param is passed' do
+ before do
+ doorkeeper_guard_returns(nil)
+ end
+
+ it 'returns false' do
+ expect(sudo?).to be_falsy
+ end
end
- it "returns string when input is an is not an int" do
- set_env(admin, '12.30')
- expect(sudo_identifier).to eq("12.30")
- set_env(admin, 'hello')
- expect(sudo_identifier).to eq('hello')
- set_env(admin, ' 123')
- expect(sudo_identifier).to eq(' 123')
-
- set_param(admin, '12.30')
- expect(sudo_identifier).to eq("12.30")
- set_param(admin, 'hello')
- expect(sudo_identifier).to eq('hello')
- set_param(admin, ' 123')
- expect(sudo_identifier).to eq(' 123')
+ context 'when sudo env or param is passed', 'user is not an admin' do
+ before do
+ set_env(user, '123')
+ end
+
+ it 'returns an 403 Forbidden' do
+ expect { sudo? }.to raise_error '403 - {"message"=>"403 Forbidden - Must be admin to use sudo"}'
+ end
+ end
+
+ context 'when sudo env or param is passed', 'user is admin' do
+ context 'personal access token is used' do
+ before do
+ personal_access_token = create(:personal_access_token, user: admin)
+ set_env(personal_access_token.token, user.id)
+ end
+
+ it 'returns an 403 Forbidden' do
+ expect { sudo? }.to raise_error '403 - {"message"=>"403 Forbidden - Private token must be specified in order to use sudo"}'
+ end
+ end
+
+ context 'private access token is used' do
+ before do
+ set_env(admin.private_token, user.id)
+ end
+
+ it 'returns true' do
+ expect(sudo?).to be_truthy
+ end
+ end
end
end
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 75b270aa93c..f032d1b683d 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -533,6 +533,22 @@ describe API::MergeRequests, api: true do
expect(json_response['labels']).to include '?'
expect(json_response['labels']).to include '&'
end
+
+ it 'does not update state when title is empty' do
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), state_event: 'close', title: nil
+
+ merge_request.reload
+ expect(response).to have_http_status(400)
+ expect(merge_request.state).to eq('opened')
+ end
+
+ it 'does not update state when target_branch is empty' do
+ put api("/projects/#{project.id}/merge_requests/#{merge_request.id}", user), state_event: 'close', target_branch: nil
+
+ merge_request.reload
+ expect(response).to have_http_status(400)
+ expect(merge_request.state).to eq('opened')
+ end
end
describe "POST /projects/:id/merge_requests/:merge_request_id/comments" do
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index d30361f53d4..668e39f9dba 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -2,6 +2,7 @@ require "spec_helper"
describe API::Services, api: true do
include ApiHelpers
+
let(:user) { create(:user) }
let(:admin) { create(:admin) }
let(:user2) { create(:user) }
@@ -98,7 +99,7 @@ describe API::Services, api: true do
post api("/projects/#{project.id}/services/idonotexist/trigger")
expect(response).to have_http_status(404)
- expect(json_response["message"]).to eq("404 Service Not Found")
+ expect(json_response["error"]).to eq("404 Not Found")
end
end
@@ -114,7 +115,7 @@ describe API::Services, api: true do
end
it 'when the service is inactive' do
- post api("/projects/#{project.id}/services/mattermost_slash_commands/trigger")
+ post api("/projects/#{project.id}/services/mattermost_slash_commands/trigger"), params
expect(response).to have_http_status(404)
end
diff --git a/spec/requests/api/snippets_spec.rb b/spec/requests/api/snippets_spec.rb
new file mode 100644
index 00000000000..f6fb6ea5506
--- /dev/null
+++ b/spec/requests/api/snippets_spec.rb
@@ -0,0 +1,157 @@
+require 'rails_helper'
+
+describe API::Snippets, api: true do
+ include ApiHelpers
+ let!(:user) { create(:user) }
+
+ describe 'GET /snippets/' do
+ it 'returns snippets available' do
+ public_snippet = create(:personal_snippet, :public, author: user)
+ private_snippet = create(:personal_snippet, :private, author: user)
+ internal_snippet = create(:personal_snippet, :internal, author: user)
+
+ get api("/snippets/", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly(
+ public_snippet.id,
+ internal_snippet.id,
+ private_snippet.id)
+ expect(json_response.last).to have_key('web_url')
+ expect(json_response.last).to have_key('raw_url')
+ end
+
+ it 'hides private snippets from regular user' do
+ create(:personal_snippet, :private)
+
+ get api("/snippets/", user)
+ expect(response).to have_http_status(200)
+ expect(json_response.size).to eq(0)
+ end
+ end
+
+ describe 'GET /snippets/public' do
+ let!(:other_user) { create(:user) }
+ let!(:public_snippet) { create(:personal_snippet, :public, author: user) }
+ let!(:private_snippet) { create(:personal_snippet, :private, author: user) }
+ let!(:internal_snippet) { create(:personal_snippet, :internal, author: user) }
+ let!(:public_snippet_other) { create(:personal_snippet, :public, author: other_user) }
+ let!(:private_snippet_other) { create(:personal_snippet, :private, author: other_user) }
+ let!(:internal_snippet_other) { create(:personal_snippet, :internal, author: other_user) }
+
+ it 'returns all snippets with public visibility from all users' do
+ get api("/snippets/public", user)
+
+ expect(response).to have_http_status(200)
+ expect(json_response.map { |snippet| snippet['id']} ).to contain_exactly(
+ public_snippet.id,
+ public_snippet_other.id)
+ expect(json_response.map{ |snippet| snippet['web_url']} ).to include(
+ "http://localhost/snippets/#{public_snippet.id}",
+ "http://localhost/snippets/#{public_snippet_other.id}")
+ expect(json_response.map{ |snippet| snippet['raw_url']} ).to include(
+ "http://localhost/snippets/#{public_snippet.id}/raw",
+ "http://localhost/snippets/#{public_snippet_other.id}/raw")
+ end
+ end
+
+ describe 'GET /snippets/:id/raw' do
+ let(:snippet) { create(:personal_snippet, author: user) }
+
+ it 'returns raw text' do
+ get api("/snippets/#{snippet.id}/raw", user)
+
+ expect(response).to have_http_status(200)
+ expect(response.content_type).to eq 'text/plain'
+ expect(response.body).to eq(snippet.content)
+ end
+
+ it 'returns 404 for invalid snippet id' do
+ delete api("/snippets/1234", user)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Snippet Not Found')
+ end
+ end
+
+ describe 'POST /snippets/' do
+ let(:params) do
+ {
+ title: 'Test Title',
+ file_name: 'test.rb',
+ content: 'puts "hello world"',
+ visibility_level: Gitlab::VisibilityLevel::PUBLIC
+ }
+ end
+
+ it 'creates a new snippet' do
+ expect do
+ post api("/snippets/", user), params
+ end.to change { PersonalSnippet.count }.by(1)
+
+ expect(response).to have_http_status(201)
+ expect(json_response['title']).to eq(params[:title])
+ expect(json_response['file_name']).to eq(params[:file_name])
+ end
+
+ it 'returns 400 for missing parameters' do
+ params.delete(:title)
+
+ post api("/snippets/", user), params
+
+ expect(response).to have_http_status(400)
+ end
+ end
+
+ describe 'PUT /snippets/:id' do
+ let(:other_user) { create(:user) }
+ let(:public_snippet) { create(:personal_snippet, :public, author: user) }
+ it 'updates snippet' do
+ new_content = 'New content'
+
+ put api("/snippets/#{public_snippet.id}", user), content: new_content
+
+ expect(response).to have_http_status(200)
+ public_snippet.reload
+ expect(public_snippet.content).to eq(new_content)
+ end
+
+ it 'returns 404 for invalid snippet id' do
+ put api("/snippets/1234", user), title: 'foo'
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Snippet Not Found')
+ end
+
+ it "returns 404 for another user's snippet" do
+ put api("/snippets/#{public_snippet.id}", other_user), title: 'fubar'
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Snippet Not Found')
+ end
+
+ it 'returns 400 for missing parameters' do
+ put api("/snippets/1234", user)
+
+ expect(response).to have_http_status(400)
+ end
+ end
+
+ describe 'DELETE /snippets/:id' do
+ let!(:public_snippet) { create(:personal_snippet, :public, author: user) }
+ it 'deletes snippet' do
+ expect do
+ delete api("/snippets/#{public_snippet.id}", user)
+
+ expect(response).to have_http_status(204)
+ end.to change { PersonalSnippet.count }.by(-1)
+ end
+
+ it 'returns 404 for invalid snippet id' do
+ delete api("/snippets/1234", user)
+
+ expect(response).to have_http_status(404)
+ expect(json_response['message']).to eq('404 Snippet Not Found')
+ end
+ end
+end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index c37dbfa0a33..9e317f3a7e9 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -651,13 +651,12 @@ describe API::Users, api: true do
end
describe "GET /user" do
- let(:personal_access_token) { create(:personal_access_token, user: user) }
- let(:private_token) { user.private_token }
+ let(:personal_access_token) { create(:personal_access_token, user: user).token }
context 'with regular user' do
context 'with personal access token' do
it 'returns 403 without private token when sudo is defined' do
- get api("/user?private_token=#{personal_access_token.token}&sudo=#{user.id}")
+ get api("/user?private_token=#{personal_access_token}&sudo=123")
expect(response).to have_http_status(403)
end
@@ -665,7 +664,7 @@ describe API::Users, api: true do
context 'with private token' do
it 'returns 403 without private token when sudo defined' do
- get api("/user?private_token=#{private_token}&sudo=#{user.id}")
+ get api("/user?private_token=#{user.private_token}&sudo=123")
expect(response).to have_http_status(403)
end
@@ -676,40 +675,44 @@ describe API::Users, api: true do
expect(response).to have_http_status(200)
expect(response).to match_response_schema('user/public')
+ expect(json_response['id']).to eq(user.id)
end
end
context 'with admin' do
- let(:user) { create(:admin) }
+ let(:admin_personal_access_token) { create(:personal_access_token, user: admin).token }
context 'with personal access token' do
it 'returns 403 without private token when sudo defined' do
- get api("/user?private_token=#{personal_access_token.token}&sudo=#{user.id}")
+ get api("/user?private_token=#{admin_personal_access_token}&sudo=#{user.id}")
expect(response).to have_http_status(403)
end
- it 'returns current user without private token when sudo not defined' do
- get api("/user?private_token=#{personal_access_token.token}")
+ it 'returns initial current user without private token when sudo not defined' do
+ get api("/user?private_token=#{admin_personal_access_token}")
expect(response).to have_http_status(200)
expect(response).to match_response_schema('user/public')
+ expect(json_response['id']).to eq(admin.id)
end
end
context 'with private token' do
- it 'returns current user with private token when sudo defined' do
- get api("/user?private_token=#{private_token}&sudo=#{user.id}")
+ it 'returns sudoed user with private token when sudo defined' do
+ get api("/user?private_token=#{admin.private_token}&sudo=#{user.id}")
expect(response).to have_http_status(200)
expect(response).to match_response_schema('user/login')
+ expect(json_response['id']).to eq(user.id)
end
- it 'returns current user without private token when sudo not defined' do
- get api("/user?private_token=#{private_token}")
+ it 'returns initial current user without private token when sudo not defined' do
+ get api("/user?private_token=#{admin.private_token}")
expect(response).to have_http_status(200)
expect(response).to match_response_schema('user/public')
+ expect(json_response['id']).to eq(admin.id)
end
end
end
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index 69eeb45ed71..661b671301e 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -66,7 +66,8 @@ describe Admin::ProjectsController, "routing" do
end
it "to #show" do
- expect(get("/admin/projects/gitlab")).to route_to('admin/projects#show', namespace_id: 'gitlab')
+ expect(get("/admin/projects/gitlab/gitlab-ce")).to route_to('admin/projects#show', namespace_id: 'gitlab', id: 'gitlab-ce')
+ expect(get("/admin/projects/gitlab/subgroup/gitlab-ce")).to route_to('admin/projects#show', namespace_id: 'gitlab/subgroup', id: 'gitlab-ce')
end
end
@@ -119,3 +120,14 @@ describe Admin::HealthCheckController, "routing" do
expect(get("/admin/health_check")).to route_to('admin/health_check#show')
end
end
+
+describe Admin::GroupsController, "routing" do
+ it "to #index" do
+ expect(get("/admin/groups")).to route_to('admin/groups#index')
+ end
+
+ it "to #show" do
+ expect(get("/admin/groups/gitlab")).to route_to('admin/groups#show', id: 'gitlab')
+ expect(get("/admin/groups/gitlab/subgroup")).to route_to('admin/groups#show', id: 'gitlab/subgroup')
+ end
+end
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 90b7e62bc6f..0e8adb68721 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -694,7 +694,7 @@ describe SystemNoteService, services: true do
describe "existing reference" do
before do
- message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.path_with_namespace}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]:\n'#{commit.title}'"
+ message = "[#{author.name}|http://localhost/#{author.username}] mentioned this issue in [a commit of #{project.path_with_namespace}|http://localhost/#{project.path_with_namespace}/commit/#{commit.id}]:\n'#{commit.title.chomp}'"
allow_any_instance_of(JIRA::Resource::Issue).to receive(:comments).and_return([OpenStruct.new(body: message)])
end
diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb
index c0b3e83244d..ad1eed5b369 100644
--- a/spec/support/login_helpers.rb
+++ b/spec/support/login_helpers.rb
@@ -75,7 +75,8 @@ module LoginHelpers
def logout
find(".header-user-dropdown-toggle").click
click_link "Sign out"
- expect(page).to have_content('Signed out successfully')
+ # check the sign_in button
+ expect(page).to have_button('Sign in')
end
# Logout without JavaScript driver
diff --git a/spec/support/services_shared_context.rb b/spec/support/services_shared_context.rb
index d1c999cad4d..66c93890e31 100644
--- a/spec/support/services_shared_context.rb
+++ b/spec/support/services_shared_context.rb
@@ -16,8 +16,14 @@ Service.available_services_names.each do |service|
hash.merge!(k => 'secrettoken')
elsif k =~ /^(.*_url|url|webhook)/
hash.merge!(k => "http://example.com")
+ elsif service_klass.method_defined?("#{k}?")
+ hash.merge!(k => true)
elsif service == 'irker' && k == :recipients
hash.merge!(k => 'irc://irc.network.net:666/#channel')
+ elsif service == 'irker' && k == :server_port
+ hash.merge!(k => 1234)
+ elsif service == 'jira' && k == :jira_issue_transition_id
+ hash.merge!(k => 1234)
else
hash.merge!(k => "someword")
end
diff --git a/spec/views/projects/commit/_commit_box.html.haml_spec.rb b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
index 16bf0698c4b..e741e3cf9b6 100644
--- a/spec/views/projects/commit/_commit_box.html.haml_spec.rb
+++ b/spec/views/projects/commit/_commit_box.html.haml_spec.rb
@@ -13,7 +13,7 @@ describe 'projects/commit/_commit_box.html.haml' do
it 'shows the commit SHA' do
render
- expect(rendered).to have_text("Commit #{Commit.truncate_sha(project.commit.sha)}")
+ expect(rendered).to have_text("#{Commit.truncate_sha(project.commit.sha)}")
end
it 'shows the last pipeline that ran for the commit' do
diff --git a/spec/views/projects/pipelines/show.html.haml_spec.rb b/spec/views/projects/pipelines/show.html.haml_spec.rb
index bf027499c94..a066ea078e6 100644
--- a/spec/views/projects/pipelines/show.html.haml_spec.rb
+++ b/spec/views/projects/pipelines/show.html.haml_spec.rb
@@ -28,7 +28,7 @@ describe 'projects/pipelines/show' do
it 'shows a graph with grouped stages' do
render
- expect(rendered).to have_css('.pipeline-graph')
+ expect(rendered).to have_css('.js-pipeline-graph')
expect(rendered).to have_css('.grouped-pipeline-dropdown')
# stages