summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2015-10-18 11:31:49 +0200
committerDouwe Maan <douwe@gitlab.com>2015-10-18 11:31:49 +0200
commitdf9062d0b50d08a8a484b9780aeb92c53bead530 (patch)
tree13985b14daf1b1614b35aade3f74a0c80f8eb10c /spec
parentae4fbae26cefbf10848719ee8c06d418c348420c (diff)
parent38785046f7ec7d834e22add66e4be88f6e985355 (diff)
downloadgitlab-ce-df9062d0b50d08a8a484b9780aeb92c53bead530.tar.gz
Merge branch 'master' into jrochkind/gitlab-ce-fix_2839_send_abuse_report_notify
Diffstat (limited to 'spec')
-rw-r--r--spec/benchmarks/finders/trending_projects_finder_spec.rb14
-rw-r--r--spec/benchmarks/models/project_spec.rb50
-rw-r--r--spec/benchmarks/models/project_team_spec.rb23
-rw-r--r--spec/benchmarks/models/user_spec.rb42
-rw-r--r--spec/controllers/ci/commits_controller_spec.rb23
-rw-r--r--spec/controllers/projects/repositories_controller_spec.rb28
-rw-r--r--spec/controllers/projects/tree_controller_spec.rb36
-rw-r--r--spec/controllers/projects/uploads_controller_spec.rb4
-rw-r--r--spec/factories/ci/builds.rb7
-rw-r--r--spec/factories/ci/commits.rb54
-rw-r--r--spec/factories/commit_statuses.rb15
-rw-r--r--spec/features/builds_spec.rb89
-rw-r--r--spec/features/ci/builds_spec.rb61
-rw-r--r--spec/features/ci/commits_spec.rb70
-rw-r--r--spec/features/ci/projects_spec.rb20
-rw-r--r--spec/features/ci_web_hooks_spec.rb27
-rw-r--r--spec/features/commits_spec.rb61
-rw-r--r--spec/features/markdown_spec.rb2
-rw-r--r--spec/features/projects_spec.rb2
-rw-r--r--spec/finders/issues_finder_spec.rb20
-rw-r--r--spec/finders/trending_projects_finder_spec.rb39
-rw-r--r--spec/helpers/application_helper_spec.rb9
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb27
-rw-r--r--spec/helpers/projects_helper_spec.rb14
-rw-r--r--spec/helpers/runners_helper_spec.rb2
-rw-r--r--spec/javascripts/behaviors/quick_submit_spec.js.coffee70
-rw-r--r--spec/javascripts/fixtures/behaviors/quick_submit.html.haml6
-rw-r--r--spec/javascripts/fixtures/line_highlighter.html.haml2
-rw-r--r--spec/javascripts/line_highlighter_spec.js.coffee2
-rw-r--r--spec/javascripts/spec_helper.coffee1
-rw-r--r--spec/lib/ci/gitlab_ci_yaml_processor_spec.rb46
-rw-r--r--spec/lib/gitlab/backend/shell_spec.rb13
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb10
-rw-r--r--spec/lib/gitlab/database_spec.rb17
-rw-r--r--spec/lib/gitlab/email/attachment_uploader_spec.rb1
-rw-r--r--spec/lib/gitlab/ldap/user_spec.rb21
-rw-r--r--spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb70
-rw-r--r--spec/lib/gitlab/markdown/commit_reference_filter_spec.rb66
-rw-r--r--spec/lib/gitlab/markdown/cross_project_reference_spec.rb36
-rw-r--r--spec/lib/gitlab/markdown/issue_reference_filter_spec.rb76
-rw-r--r--spec/lib/gitlab/markdown/label_reference_filter_spec.rb18
-rw-r--r--spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb66
-rw-r--r--spec/lib/gitlab/markdown/redactor_filter_spec.rb91
-rw-r--r--spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb89
-rw-r--r--spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb64
-rw-r--r--spec/lib/gitlab/markdown/upload_link_filter_spec.rb75
-rw-r--r--spec/lib/gitlab/markdown/user_reference_filter_spec.rb55
-rw-r--r--spec/lib/gitlab/reference_extractor_spec.rb14
-rw-r--r--spec/lib/gitlab/uploads_transfer_spec.rb50
-rw-r--r--spec/models/build_spec.rb (renamed from spec/models/ci/build_spec.rb)291
-rw-r--r--spec/models/ci/commit_spec.rb360
-rw-r--r--spec/models/ci/project_services/hip_chat_message_spec.rb83
-rw-r--r--spec/models/ci/project_services/mail_service_spec.rb (renamed from spec/models/ci/mail_service_spec.rb)13
-rw-r--r--spec/models/ci/project_services/slack_message_spec.rb97
-rw-r--r--spec/models/ci/project_spec.rb31
-rw-r--r--spec/models/ci/runner_spec.rb67
-rw-r--r--spec/models/commit_spec.rb4
-rw-r--r--spec/models/commit_status_spec.rb164
-rw-r--r--spec/models/concerns/case_sensitivity_spec.rb189
-rw-r--r--spec/models/concerns/mentionable_spec.rb2
-rw-r--r--spec/models/generic_commit_status_spec.rb39
-rw-r--r--spec/models/issue_spec.rb2
-rw-r--r--spec/models/merge_request_spec.rb11
-rw-r--r--spec/models/note_spec.rb5
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb94
-rw-r--r--spec/models/project_services/gitlab_ci_service_spec.rb7
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb93
-rw-r--r--spec/models/project_spec.rb38
-rw-r--r--spec/models/service_spec.rb121
-rw-r--r--spec/requests/api/commit_status_spec.rb135
-rw-r--r--spec/requests/api/commits_spec.rb13
-rw-r--r--spec/requests/api/merge_requests_spec.rb5
-rw-r--r--spec/requests/api/repositories_spec.rb9
-rw-r--r--spec/requests/api/services_spec.rb33
-rw-r--r--spec/requests/ci/api/builds_spec.rb17
-rw-r--r--spec/requests/ci/api/commits_spec.rb3
-rw-r--r--spec/requests/ci/api/triggers_spec.rb20
-rw-r--r--spec/requests/ci/builds_spec.rb17
-rw-r--r--spec/requests/ci/commits_spec.rb16
-rw-r--r--spec/services/archive_repository_service_spec.rb67
-rw-r--r--spec/services/ci/create_commit_service_spec.rb67
-rw-r--r--spec/services/ci/create_trigger_request_service_spec.rb35
-rw-r--r--spec/services/git_push_service_spec.rb10
-rw-r--r--spec/services/merge_requests/refresh_service_spec.rb21
-rw-r--r--spec/services/projects/download_service_spec.rb2
-rw-r--r--spec/services/projects/transfer_service_spec.rb2
-rw-r--r--spec/services/projects/upload_service_spec.rb4
-rw-r--r--spec/services/system_hooks_service_spec.rb4
-rw-r--r--spec/services/system_note_service_spec.rb12
-rw-r--r--spec/spec_helper.rb7
-rw-r--r--spec/support/filter_spec_helper.rb23
-rw-r--r--spec/support/markdown_feature.rb32
-rw-r--r--spec/support/matchers/benchmark_matchers.rb61
-rw-r--r--spec/support/mentionable_shared_examples.rb17
-rw-r--r--spec/support/services_shared_context.rb8
-rw-r--r--spec/support/setup_builds_storage.rb6
-rw-r--r--spec/support/stub_gitlab_calls.rb8
-rw-r--r--spec/support/test_env.rb2
-rw-r--r--spec/workers/repository_archive_worker_spec.rb79
99 files changed, 2898 insertions, 1246 deletions
diff --git a/spec/benchmarks/finders/trending_projects_finder_spec.rb b/spec/benchmarks/finders/trending_projects_finder_spec.rb
new file mode 100644
index 00000000000..551ce21840d
--- /dev/null
+++ b/spec/benchmarks/finders/trending_projects_finder_spec.rb
@@ -0,0 +1,14 @@
+require 'spec_helper'
+
+describe TrendingProjectsFinder, benchmark: true do
+ describe '#execute' do
+ let(:finder) { described_class.new }
+ let(:user) { create(:user) }
+
+ # to_a is used to force actually running the query (instead of just building
+ # it).
+ benchmark_subject { finder.execute(user).non_archived.to_a }
+
+ it { is_expected.to iterate_per_second(500) }
+ end
+end
diff --git a/spec/benchmarks/models/project_spec.rb b/spec/benchmarks/models/project_spec.rb
new file mode 100644
index 00000000000..cee0949edc5
--- /dev/null
+++ b/spec/benchmarks/models/project_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Project, benchmark: true do
+ describe '.trending' do
+ let(:group) { create(:group) }
+ let(:project1) { create(:empty_project, :public, group: group) }
+ let(:project2) { create(:empty_project, :public, group: group) }
+
+ let(:iterations) { 500 }
+
+ before do
+ 2.times do
+ create(:note_on_commit, project: project1)
+ end
+
+ create(:note_on_commit, project: project2)
+ end
+
+ describe 'without an explicit start date' do
+ benchmark_subject { described_class.trending.to_a }
+
+ it { is_expected.to iterate_per_second(iterations) }
+ end
+
+ describe 'with an explicit start date' do
+ let(:date) { 1.month.ago }
+
+ benchmark_subject { described_class.trending(date).to_a }
+
+ it { is_expected.to iterate_per_second(iterations) }
+ end
+ end
+
+ describe '.find_with_namespace' do
+ let(:group) { create(:group, name: 'sisinmaru') }
+ let(:project) { create(:project, name: 'maru', namespace: group) }
+
+ describe 'using a capitalized namespace' do
+ benchmark_subject { described_class.find_with_namespace('sisinmaru/MARU') }
+
+ it { is_expected.to iterate_per_second(600) }
+ end
+
+ describe 'using a lowercased namespace' do
+ benchmark_subject { described_class.find_with_namespace('sisinmaru/maru') }
+
+ it { is_expected.to iterate_per_second(600) }
+ end
+ end
+end
diff --git a/spec/benchmarks/models/project_team_spec.rb b/spec/benchmarks/models/project_team_spec.rb
new file mode 100644
index 00000000000..8b039ef7317
--- /dev/null
+++ b/spec/benchmarks/models/project_team_spec.rb
@@ -0,0 +1,23 @@
+require 'spec_helper'
+
+describe ProjectTeam, benchmark: true do
+ describe '#max_member_access' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, group: group) }
+ let(:user) { create(:user) }
+
+ before do
+ project.team << [user, :master]
+
+ 5.times do
+ project.team << [create(:user), :reporter]
+
+ project.group.add_user(create(:user), :reporter)
+ end
+ end
+
+ benchmark_subject { project.team.max_member_access(user.id) }
+
+ it { is_expected.to iterate_per_second(35000) }
+ end
+end
diff --git a/spec/benchmarks/models/user_spec.rb b/spec/benchmarks/models/user_spec.rb
new file mode 100644
index 00000000000..cc5c3904193
--- /dev/null
+++ b/spec/benchmarks/models/user_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe User, benchmark: true do
+ describe '.by_login' do
+ before do
+ %w{Alice Bob Eve}.each do |name|
+ create(:user,
+ email: "#{name}@gitlab.com",
+ username: name,
+ name: name)
+ end
+ end
+
+ # The iteration count is based on the query taking little over 1 ms when
+ # using PostgreSQL.
+ let(:iterations) { 900 }
+
+ describe 'using a capitalized username' do
+ benchmark_subject { User.by_login('Alice') }
+
+ it { is_expected.to iterate_per_second(iterations) }
+ end
+
+ describe 'using a lowercase username' do
+ benchmark_subject { User.by_login('alice') }
+
+ it { is_expected.to iterate_per_second(iterations) }
+ end
+
+ describe 'using a capitalized Email address' do
+ benchmark_subject { User.by_login('Alice@gitlab.com') }
+
+ it { is_expected.to iterate_per_second(iterations) }
+ end
+
+ describe 'using a lowercase Email address' do
+ benchmark_subject { User.by_login('alice@gitlab.com') }
+
+ it { is_expected.to iterate_per_second(iterations) }
+ end
+ end
+end
diff --git a/spec/controllers/ci/commits_controller_spec.rb b/spec/controllers/ci/commits_controller_spec.rb
deleted file mode 100644
index cc39ce7687c..00000000000
--- a/spec/controllers/ci/commits_controller_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require "spec_helper"
-
-describe Ci::CommitsController do
- describe "GET /status" do
- it "returns status of commit" do
- commit = FactoryGirl.create :ci_commit
- get :status, id: commit.sha, ref_id: commit.ref, project_id: commit.project.id
-
- expect(response).to be_success
- expect(response.code).to eq('200')
- JSON.parse(response.body)["status"] == "pending"
- end
-
- it "returns not_found status" do
- commit = FactoryGirl.create :ci_commit
- get :status, id: commit.sha, ref_id: "deploy", project_id: commit.project.id
-
- expect(response).to be_success
- expect(response.code).to eq('200')
- JSON.parse(response.body)["status"] == "not_found"
- end
- end
-end
diff --git a/spec/controllers/projects/repositories_controller_spec.rb b/spec/controllers/projects/repositories_controller_spec.rb
index 91856ed0cc0..18a30033ed8 100644
--- a/spec/controllers/projects/repositories_controller_spec.rb
+++ b/spec/controllers/projects/repositories_controller_spec.rb
@@ -33,33 +33,5 @@ describe Projects::RepositoriesController do
expect(response.status).to eq(404)
end
end
-
- context "when the service doesn't return a path" do
-
- before do
- allow(service).to receive(:execute).and_return(nil)
- end
-
- it "reloads the page" do
- get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
-
- expect(response).to redirect_to(archive_namespace_project_repository_path(project.namespace, project, ref: "master", format: "zip"))
- end
- end
-
- context "when the service returns a path" do
-
- let(:path) { Rails.root.join("spec/fixtures/dk.png").to_s }
-
- before do
- allow(service).to receive(:execute).and_return(path)
- end
-
- it "sends the file" do
- get :archive, namespace_id: project.namespace.path, project_id: project.path, ref: "master", format: "zip"
-
- expect(response.body).to eq(File.binread(path))
- end
- end
end
end
diff --git a/spec/controllers/projects/tree_controller_spec.rb b/spec/controllers/projects/tree_controller_spec.rb
index 53915856357..a474574c6e5 100644
--- a/spec/controllers/projects/tree_controller_spec.rb
+++ b/spec/controllers/projects/tree_controller_spec.rb
@@ -88,4 +88,40 @@ describe Projects::TreeController do
end
end
end
+
+ describe '#create_dir' do
+ render_views
+
+ before do
+ post(:create_dir,
+ namespace_id: project.namespace.to_param,
+ project_id: project.to_param,
+ id: 'master',
+ dir_name: path,
+ new_branch: target_branch,
+ commit_message: 'Test commit message')
+ end
+
+ context 'successful creation' do
+ let(:path) { 'files/new_dir'}
+ let(:target_branch) { 'master-test'}
+
+ it 'redirects to the new directory' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/blob/#{target_branch}/#{path}")
+ expect(flash[:notice]).to eq('The directory has been successfully created')
+ end
+ end
+
+ context 'unsuccessful creation' do
+ let(:path) { 'README.md' }
+ let(:target_branch) { 'master'}
+
+ it 'does not allow overwriting of existing files' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/blob/master")
+ expect(flash[:alert]).to eq('Directory already exists as a file')
+ end
+ end
+ end
end
diff --git a/spec/controllers/projects/uploads_controller_spec.rb b/spec/controllers/projects/uploads_controller_spec.rb
index f51abfedae5..93c4494c660 100644
--- a/spec/controllers/projects/uploads_controller_spec.rb
+++ b/spec/controllers/projects/uploads_controller_spec.rb
@@ -33,7 +33,7 @@ describe Projects::UploadsController do
it 'returns a content with original filename, new link, and correct type.' do
expect(response.body).to match '\"alt\":\"rails_sample\"'
- expect(response.body).to match "\"url\":\"http://localhost/#{project.path_with_namespace}/uploads"
+ expect(response.body).to match "\"url\":\"/uploads"
expect(response.body).to match '\"is_image\":true'
end
end
@@ -49,7 +49,7 @@ describe Projects::UploadsController do
it 'returns a content with original filename, new link, and correct type.' do
expect(response.body).to match '\"alt\":\"doc_sample.txt\"'
- expect(response.body).to match "\"url\":\"http://localhost/#{project.path_with_namespace}/uploads"
+ expect(response.body).to match "\"url\":\"/uploads"
expect(response.body).to match '\"is_image\":false'
end
end
diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb
index 99da5a18776..2fcd70182b9 100644
--- a/spec/factories/ci/builds.rb
+++ b/spec/factories/ci/builds.rb
@@ -27,6 +27,9 @@
FactoryGirl.define do
factory :ci_build, class: Ci::Build do
+ name 'test'
+ ref 'master'
+ tag false
started_at 'Di 29. Okt 09:51:28 CET 2013'
finished_at 'Di 29. Okt 09:53:28 CET 2013'
commands 'ls -a'
@@ -43,5 +46,9 @@ FactoryGirl.define do
started_at nil
finished_at nil
end
+
+ factory :ci_build_tag do
+ tag true
+ end
end
end
diff --git a/spec/factories/ci/commits.rb b/spec/factories/ci/commits.rb
index 9c7a0e9cbe0..79e000b7ccb 100644
--- a/spec/factories/ci/commits.rb
+++ b/spec/factories/ci/commits.rb
@@ -17,60 +17,32 @@
# Read about factories at https://github.com/thoughtbot/factory_girl
FactoryGirl.define do
- factory :ci_commit, class: Ci::Commit do
- ref 'master'
- before_sha '76de212e80737a608d939f648d959671fb0a0142'
+ factory :ci_empty_commit, class: Ci::Commit do
sha '97de212e80737a608d939f648d959671fb0a0142'
- push_data do
- {
- ref: 'refs/heads/master',
- before: '76de212e80737a608d939f648d959671fb0a0142',
- after: '97de212e80737a608d939f648d959671fb0a0142',
- user_name: 'Git User',
- user_email: 'git@example.com',
- repository: {
- name: 'test-data',
- url: 'ssh://git@gitlab.com/test/test-data.git',
- description: '',
- homepage: 'http://gitlab.com/test/test-data'
- },
- commits: [
- {
- id: '97de212e80737a608d939f648d959671fb0a0142',
- message: 'Test commit message',
- timestamp: '2014-09-23T13:12:25+02:00',
- url: 'https://gitlab.com/test/test-data/commit/97de212e80737a608d939f648d959671fb0a0142',
- author: {
- name: 'Git User',
- email: 'git@user.com'
- }
- }
- ],
- total_commits_count: 1,
- ci_yaml_file: File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
- }
- end
gl_project factory: :empty_project
factory :ci_commit_without_jobs do
- after(:create) do |commit, evaluator|
- commit.push_data[:ci_yaml_file] = YAML.dump({})
- commit.save
+ after(:build) do |commit|
+ allow(commit).to receive(:ci_yaml_file) { YAML.dump({}) }
end
end
factory :ci_commit_with_one_job do
- after(:create) do |commit, evaluator|
- commit.push_data[:ci_yaml_file] = YAML.dump({ rspec: { script: "ls" } })
- commit.save
+ after(:build) do |commit|
+ allow(commit).to receive(:ci_yaml_file) { YAML.dump({ rspec: { script: "ls" } }) }
end
end
factory :ci_commit_with_two_jobs do
- after(:create) do |commit, evaluator|
- commit.push_data[:ci_yaml_file] = YAML.dump({ rspec: { script: "ls" }, spinach: { script: "ls" } })
- commit.save
+ after(:build) do |commit|
+ allow(commit).to receive(:ci_yaml_file) { YAML.dump({ rspec: { script: "ls" }, spinach: { script: "ls" } }) }
+ end
+ end
+
+ factory :ci_commit do
+ after(:build) do |commit|
+ allow(commit).to receive(:ci_yaml_file) { File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) }
end
end
end
diff --git a/spec/factories/commit_statuses.rb b/spec/factories/commit_statuses.rb
new file mode 100644
index 00000000000..52de437052d
--- /dev/null
+++ b/spec/factories/commit_statuses.rb
@@ -0,0 +1,15 @@
+FactoryGirl.define do
+ factory :commit_status, class: CommitStatus do
+ started_at 'Di 29. Okt 09:51:28 CET 2013'
+ finished_at 'Di 29. Okt 09:53:28 CET 2013'
+ name 'default'
+ status 'success'
+ description 'commit status'
+ commit factory: :ci_commit
+
+ factory :generic_commit_status, class: GenericCommitStatus do
+ name 'generic'
+ description 'external commit status'
+ end
+ end
+end
diff --git a/spec/features/builds_spec.rb b/spec/features/builds_spec.rb
new file mode 100644
index 00000000000..154857e77fe
--- /dev/null
+++ b/spec/features/builds_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+describe "Builds" do
+ before do
+ login_as(:user)
+ @commit = FactoryGirl.create :ci_commit
+ @build = FactoryGirl.create :ci_build, commit: @commit
+ @gl_project = @commit.project.gl_project
+ @gl_project.team << [@user, :master]
+ end
+
+ describe "GET /:project/builds" do
+ context "Running scope" do
+ before do
+ @build.run!
+ visit namespace_project_builds_path(@gl_project.namespace, @gl_project)
+ end
+
+ it { expect(page).to have_content 'Running' }
+ it { expect(page).to have_content 'Cancel all' }
+ it { expect(page).to have_content @build.short_sha }
+ it { expect(page).to have_content @build.ref }
+ it { expect(page).to have_content @build.name }
+ end
+
+ context "Finished scope" do
+ before do
+ @build.run!
+ visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :finished)
+ end
+
+ it { expect(page).to have_content 'No builds to show' }
+ it { expect(page).to have_content 'Cancel all' }
+ end
+
+ context "All builds" do
+ before do
+ @gl_project.ci_builds.running_or_pending.each(&:success)
+ visit namespace_project_builds_path(@gl_project.namespace, @gl_project, scope: :all)
+ end
+
+ it { expect(page).to have_content 'All' }
+ it { expect(page).to have_content @build.short_sha }
+ it { expect(page).to have_content @build.ref }
+ it { expect(page).to have_content @build.name }
+ it { expect(page).to_not have_content 'Cancel all' }
+ end
+ end
+
+ describe "GET /:project/builds/:id/cancel_all" do
+ before do
+ @build.run!
+ visit cancel_all_namespace_project_builds_path(@gl_project.namespace, @gl_project)
+ end
+
+ it { expect(page).to have_content 'No builds to show' }
+ it { expect(page).to_not have_content 'Cancel all' }
+ end
+
+ describe "GET /:project/builds/:id" do
+ before do
+ visit namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ end
+
+ it { expect(page).to have_content @commit.sha[0..7] }
+ it { expect(page).to have_content @commit.git_commit_message }
+ it { expect(page).to have_content @commit.git_author_name }
+ end
+
+ describe "GET /:project/builds/:id/cancel" do
+ before do
+ @build.run!
+ visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ end
+
+ it { expect(page).to have_content 'canceled' }
+ it { expect(page).to have_content 'Retry' }
+ end
+
+ describe "POST /:project/builds/:id/retry" do
+ before do
+ visit cancel_namespace_project_build_path(@gl_project.namespace, @gl_project, @build)
+ click_link 'Retry'
+ end
+
+ it { expect(page).to have_content 'pending' }
+ it { expect(page).to have_content 'Cancel' }
+ end
+end
diff --git a/spec/features/ci/builds_spec.rb b/spec/features/ci/builds_spec.rb
deleted file mode 100644
index d65699dbefa..00000000000
--- a/spec/features/ci/builds_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require 'spec_helper'
-
-describe "Builds" do
- context :private_project do
- before do
- @commit = FactoryGirl.create :ci_commit
- @build = FactoryGirl.create :ci_build, commit: @commit
- login_as :user
- @commit.project.gl_project.team << [@user, :master]
- end
-
- describe "GET /:project/builds/:id" do
- before do
- visit ci_project_build_path(@commit.project, @build)
- end
-
- it { expect(page).to have_content @commit.sha[0..7] }
- it { expect(page).to have_content @commit.git_commit_message }
- it { expect(page).to have_content @commit.git_author_name }
- end
-
- describe "GET /:project/builds/:id/cancel" do
- before do
- @build.run!
- visit cancel_ci_project_build_path(@commit.project, @build)
- end
-
- it { expect(page).to have_content 'canceled' }
- it { expect(page).to have_content 'Retry' }
- end
-
- describe "POST /:project/builds/:id/retry" do
- before do
- @build.cancel!
- visit ci_project_build_path(@commit.project, @build)
- click_link 'Retry'
- end
-
- it { expect(page).to have_content 'pending' }
- it { expect(page).to have_content 'Cancel' }
- end
- end
-
- context :public_project do
- describe "Show page public accessible" do
- before do
- @commit = FactoryGirl.create :ci_commit
- @commit.project.public = true
- @commit.project.save
-
- @runner = FactoryGirl.create :ci_specific_runner
- @build = FactoryGirl.create :ci_build, commit: @commit, runner: @runner
-
- stub_gitlab_calls
- visit ci_project_build_path(@commit.project, @build)
- end
-
- it { expect(page).to have_content @commit.sha[0..7] }
- end
- end
-end
diff --git a/spec/features/ci/commits_spec.rb b/spec/features/ci/commits_spec.rb
deleted file mode 100644
index 657a9dabe9e..00000000000
--- a/spec/features/ci/commits_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require 'spec_helper'
-
-describe "Commits" do
- include Ci::CommitsHelper
-
- context "Authenticated user" do
- before do
- @commit = FactoryGirl.create :ci_commit
- @build = FactoryGirl.create :ci_build, commit: @commit
- login_as :user
- @commit.project.gl_project.team << [@user, :master]
- end
-
- describe "GET /:project/commits/:sha" do
- before do
- visit ci_commit_path(@commit)
- end
-
- it { expect(page).to have_content @commit.sha[0..7] }
- it { expect(page).to have_content @commit.git_commit_message }
- it { expect(page).to have_content @commit.git_author_name }
- end
-
- describe "Cancel commit" do
- it "cancels commit" do
- visit ci_commit_path(@commit)
- click_on "Cancel"
-
- expect(page).to have_content "canceled"
- end
- end
-
- describe ".gitlab-ci.yml not found warning" do
- it "does not show warning" do
- visit ci_commit_path(@commit)
-
- expect(page).not_to have_content ".gitlab-ci.yml not found in this commit"
- end
-
- it "shows warning" do
- @commit.push_data[:ci_yaml_file] = nil
- @commit.save
-
- visit ci_commit_path(@commit)
-
- expect(page).to have_content ".gitlab-ci.yml not found in this commit"
- end
- end
- end
-
- context "Public pages" do
- before do
- @commit = FactoryGirl.create :ci_commit
- @commit.project.public = true
- @commit.project.save
-
- @build = FactoryGirl.create :ci_build, commit: @commit
- end
-
- describe "GET /:project/commits/:sha" do
- before do
- visit ci_commit_path(@commit)
- end
-
- it { expect(page).to have_content @commit.sha[0..7] }
- it { expect(page).to have_content @commit.git_commit_message }
- it { expect(page).to have_content @commit.git_author_name }
- end
- end
-end
diff --git a/spec/features/ci/projects_spec.rb b/spec/features/ci/projects_spec.rb
deleted file mode 100644
index c633acf85fb..00000000000
--- a/spec/features/ci/projects_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require 'spec_helper'
-
-describe "Projects" do
- let(:user) { create(:user) }
-
- before do
- login_as(user)
- @project = FactoryGirl.create :ci_project, name: "GitLab / gitlab-shell"
- @project.gl_project.team << [user, :master]
- end
-
- describe "GET /ci/projects/:id" do
- before do
- visit ci_project_path(@project)
- end
-
- it { expect(page).to have_content @project.name }
- it { expect(page).to have_content 'All commits' }
- end
-end
diff --git a/spec/features/ci_web_hooks_spec.rb b/spec/features/ci_web_hooks_spec.rb
new file mode 100644
index 00000000000..efae0a42c1e
--- /dev/null
+++ b/spec/features/ci_web_hooks_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe 'CI web hooks' do
+ let(:user) { create(:user) }
+ before { login_as(user) }
+
+ before do
+ @project = FactoryGirl.create :ci_project
+ @gl_project = @project.gl_project
+ @gl_project.team << [user, :master]
+ visit namespace_project_ci_web_hooks_path(@gl_project.namespace, @gl_project)
+ end
+
+ context 'create a trigger' do
+ before do
+ fill_in 'web_hook_url', with: 'http://example.com'
+ click_on 'Add Web Hook'
+ end
+
+ it { expect(@project.web_hooks.count).to eq(1) }
+
+ it 'revokes the trigger' do
+ click_on 'Remove'
+ expect(@project.web_hooks.count).to eq(0)
+ end
+ end
+end
diff --git a/spec/features/commits_spec.rb b/spec/features/commits_spec.rb
new file mode 100644
index 00000000000..1adc2cdf70a
--- /dev/null
+++ b/spec/features/commits_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe "Commits" do
+ include CiStatusHelper
+
+ let(:project) { create(:project) }
+
+ describe "CI" do
+ before do
+ login_as :user
+ project.team << [@user, :master]
+ @ci_project = project.ensure_gitlab_ci_project
+ @commit = FactoryGirl.create :ci_commit, gl_project: project, sha: project.commit.sha
+ @build = FactoryGirl.create :ci_build, commit: @commit
+ @generic_status = FactoryGirl.create :generic_commit_status, commit: @commit
+ end
+
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
+
+ describe "GET /:project/commits/:sha" do
+ before do
+ visit ci_status_path(@commit)
+ end
+
+ it { expect(page).to have_content @commit.sha[0..7] }
+ it { expect(page).to have_content @commit.git_commit_message }
+ it { expect(page).to have_content @commit.git_author_name }
+ end
+
+ describe "Cancel all builds" do
+ it "cancels commit" do
+ visit ci_status_path(@commit)
+ click_on "Cancel all"
+ expect(page).to have_content "canceled"
+ end
+ end
+
+ describe "Cancel build" do
+ it "cancels build" do
+ visit ci_status_path(@commit)
+ click_on "Cancel"
+ expect(page).to have_content "canceled"
+ end
+ end
+
+ describe ".gitlab-ci.yml not found warning" do
+ it "does not show warning" do
+ visit ci_status_path(@commit)
+ expect(page).not_to have_content ".gitlab-ci.yml not found in this commit"
+ end
+
+ it "shows warning" do
+ stub_ci_commit_yaml_file(nil)
+ visit ci_status_path(@commit)
+ expect(page).to have_content ".gitlab-ci.yml not found in this commit"
+ end
+ end
+ end
+end
diff --git a/spec/features/markdown_spec.rb b/spec/features/markdown_spec.rb
index c557a1061af..fdd8cf07b12 100644
--- a/spec/features/markdown_spec.rb
+++ b/spec/features/markdown_spec.rb
@@ -220,7 +220,7 @@ describe 'GitLab Markdown', feature: true do
end
end
- # `markdown` calls these two methods
+ # Fake a `current_user` helper
def current_user
@feat.user
end
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index a362c54b9ad..aac93b17a38 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -50,7 +50,7 @@ feature 'Project', feature: true do
end
def remove_project
- click_link "Remove project"
+ click_button "Remove project"
fill_in 'confirm_name_input', with: project.path
click_button 'Confirm'
end
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index db20b23f87d..b1648055462 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -6,9 +6,11 @@ describe IssuesFinder do
let(:project1) { create(:project) }
let(:project2) { create(:project) }
let(:milestone) { create(:milestone, project: project1) }
+ let(:label) { create(:label, project: project2) }
let(:issue1) { create(:issue, author: user, assignee: user, project: project1, milestone: milestone) }
let(:issue2) { create(:issue, author: user, assignee: user, project: project2) }
let(:issue3) { create(:issue, author: user2, assignee: user2, project: project2) }
+ let!(:label_link) { create(:label_link, label: label, target: issue2) }
before do
project1.team << [user, :master]
@@ -48,6 +50,24 @@ describe IssuesFinder do
expect(issues).to eq([issue1])
end
+ it 'should filter by no milestone id' do
+ params = { scope: "all", milestone_title: Milestone::None.title, state: 'opened' }
+ issues = IssuesFinder.new(user, params).execute
+ expect(issues).to match_array([issue2, issue3])
+ end
+
+ it 'should filter by label name' do
+ params = { scope: "all", label_name: label.title, state: 'opened' }
+ issues = IssuesFinder.new(user, params).execute
+ expect(issues).to eq([issue2])
+ end
+
+ it 'should filter by no label name' do
+ params = { scope: "all", label_name: Label::None.title, state: 'opened' }
+ issues = IssuesFinder.new(user, params).execute
+ expect(issues).to match_array([issue1, issue3])
+ end
+
it 'should be empty for unauthorized user' do
params = { scope: "all", state: 'opened' }
issues = IssuesFinder.new(nil, params).execute
diff --git a/spec/finders/trending_projects_finder_spec.rb b/spec/finders/trending_projects_finder_spec.rb
new file mode 100644
index 00000000000..a49cbfd5160
--- /dev/null
+++ b/spec/finders/trending_projects_finder_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe TrendingProjectsFinder do
+ let(:user) { build(:user) }
+
+ describe '#execute' do
+ describe 'without an explicit start date' do
+ subject { described_class.new }
+
+ it 'returns the trending projects' do
+ relation = double(:ar_relation)
+
+ allow(subject).to receive(:projects_for)
+ .with(user)
+ .and_return(relation)
+
+ allow(relation).to receive(:trending)
+ .with(an_instance_of(ActiveSupport::TimeWithZone))
+ end
+ end
+
+ describe 'with an explicit start date' do
+ let(:date) { 2.months.ago }
+
+ subject { described_class.new }
+
+ it 'returns the trending projects' do
+ relation = double(:ar_relation)
+
+ allow(subject).to receive(:projects_for)
+ .with(user)
+ .and_return(relation)
+
+ allow(relation).to receive(:trending)
+ .with(date)
+ end
+ end
+ end
+end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 742420f550e..1dfae0fbd3f 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -99,6 +99,15 @@ describe ApplicationHelper do
helper.avatar_icon('foo@example.com', 20)
end
+
+ describe 'using a User' do
+ it 'should return an URL for the avatar' do
+ user = create(:user, avatar: File.open(avatar_file_path))
+
+ expect(helper.avatar_icon(user).to_s).
+ to match("/uploads/user/avatar/#{user.id}/banana_sample.gif")
+ end
+ end
end
describe 'gravatar_icon' do
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 20ae29e2bd3..762ec25c4f5 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -11,12 +11,15 @@ describe GitlabMarkdownHelper do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:snippet) { create(:project_snippet, project: project) }
- # Helper expects a current_user method.
- let(:current_user) { user }
-
before do
+ # Ensure the generated reference links aren't redacted
+ project.team << [user, :master]
+
# Helper expects a @project instance variable
- @project = project
+ helper.instance_variable_set(:@project, project)
+
+ # Stub the `current_user` helper
+ allow(helper).to receive(:current_user).and_return(user)
end
describe "#markdown" do
@@ -25,23 +28,23 @@ describe GitlabMarkdownHelper do
it "should link to the merge request" do
expected = namespace_project_merge_request_path(project.namespace, project, merge_request)
- expect(markdown(actual)).to match(expected)
+ expect(helper.markdown(actual)).to match(expected)
end
it "should link to the commit" do
expected = namespace_project_commit_path(project.namespace, project, commit)
- expect(markdown(actual)).to match(expected)
+ expect(helper.markdown(actual)).to match(expected)
end
it "should link to the issue" do
expected = namespace_project_issue_path(project.namespace, project, issue)
- expect(markdown(actual)).to match(expected)
+ expect(helper.markdown(actual)).to match(expected)
end
end
describe "override default project" do
let(:actual) { issue.to_reference }
- let(:second_project) { create(:project) }
+ let(:second_project) { create(:project, :public) }
let(:second_issue) { create(:issue, project: second_project) }
it 'should link to the issue' do
@@ -56,7 +59,7 @@ describe GitlabMarkdownHelper do
let(:issues) { create_list(:issue, 2, project: project) }
it 'should handle references nested in links with all the text' do
- actual = link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", commit_path)
+ actual = helper.link_to_gfm("This should finally fix #{issues[0].to_reference} and #{issues[1].to_reference} for real", commit_path)
doc = Nokogiri::HTML.parse(actual)
# Make sure we didn't create invalid markup
@@ -86,7 +89,7 @@ describe GitlabMarkdownHelper do
end
it 'should forward HTML options' do
- actual = link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
+ actual = helper.link_to_gfm("Fixed in #{commit.id}", commit_path, class: 'foo')
doc = Nokogiri::HTML.parse(actual)
expect(doc.css('a')).to satisfy do |v|
@@ -97,13 +100,13 @@ describe GitlabMarkdownHelper do
it "escapes HTML passed in as the body" do
actual = "This is a <h1>test</h1> - see #{issues[0].to_reference}"
- expect(link_to_gfm(actual, commit_path)).
+ expect(helper.link_to_gfm(actual, commit_path)).
to match('&lt;h1&gt;test&lt;/h1&gt;')
end
it 'ignores reference links when they are the entire body' do
text = issues[0].to_reference
- act = link_to_gfm(text, '/foo')
+ act = helper.link_to_gfm(text, '/foo')
expect(act).to eq %Q(<a href="/foo">#{issues[0].to_reference}</a>)
end
diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb
index 53e56ebff44..f2efb528aeb 100644
--- a/spec/helpers/projects_helper_spec.rb
+++ b/spec/helpers/projects_helper_spec.rb
@@ -70,4 +70,18 @@ describe ProjectsHelper do
expect(helper.send(:readme_cache_key)).to eq("#{project.path_with_namespace}-nil-readme")
end
end
+
+ describe 'link_to_member' do
+ let(:group) { create(:group) }
+ let(:project) { create(:empty_project, group: group) }
+ let(:user) { create(:user) }
+
+ describe 'using the default options' do
+ it 'returns an HTML link to the user' do
+ link = helper.link_to_member(project, user)
+
+ expect(link).to match(%r{/u/#{user.username}})
+ end
+ end
+ end
end
diff --git a/spec/helpers/runners_helper_spec.rb b/spec/helpers/runners_helper_spec.rb
index b3d635a1932..35f91b7decf 100644
--- a/spec/helpers/runners_helper_spec.rb
+++ b/spec/helpers/runners_helper_spec.rb
@@ -12,7 +12,7 @@ describe RunnersHelper do
end
it "returns online text" do
- runner = FactoryGirl.build(:ci_runner, contacted_at: 1.hour.ago, active: true)
+ runner = FactoryGirl.build(:ci_runner, contacted_at: 1.second.ago, active: true)
expect(runner_status_icon(runner)).to include("Runner is online")
end
end
diff --git a/spec/javascripts/behaviors/quick_submit_spec.js.coffee b/spec/javascripts/behaviors/quick_submit_spec.js.coffee
new file mode 100644
index 00000000000..09708c12ed4
--- /dev/null
+++ b/spec/javascripts/behaviors/quick_submit_spec.js.coffee
@@ -0,0 +1,70 @@
+#= require behaviors/quick_submit
+
+describe 'Quick Submit behavior', ->
+ fixture.preload('behaviors/quick_submit.html')
+
+ beforeEach ->
+ fixture.load('behaviors/quick_submit.html')
+
+ # Prevent a form submit from moving us off the testing page
+ $('form').submit (e) -> e.preventDefault()
+
+ @spies = {
+ submit: spyOnEvent('form', 'submit')
+ }
+
+ it 'does not respond to other keyCodes', ->
+ $('input').trigger(keydownEvent(keyCode: 32))
+
+ expect(@spies.submit).not.toHaveBeenTriggered()
+
+ it 'does not respond to Enter alone', ->
+ $('input').trigger(keydownEvent(ctrlKey: false, metaKey: false))
+
+ expect(@spies.submit).not.toHaveBeenTriggered()
+
+ it 'does not respond to repeated events', ->
+ $('input').trigger(keydownEvent(repeat: true))
+
+ expect(@spies.submit).not.toHaveBeenTriggered()
+
+ it 'disables submit buttons', ->
+ $('textarea').trigger(keydownEvent())
+
+ expect($('input[type=submit]')).toBeDisabled()
+ expect($('button[type=submit]')).toBeDisabled()
+
+ # We cannot stub `navigator.userAgent` for CI's `rake teaspoon` task, so we'll
+ # only run the tests that apply to the current platform
+ if navigator.userAgent.match(/Macintosh/)
+ it 'responds to Meta+Enter', ->
+ $('input').trigger(keydownEvent())
+
+ expect(@spies.submit).toHaveBeenTriggered()
+
+ it 'excludes other modifier keys', ->
+ $('input').trigger(keydownEvent(altKey: true))
+ $('input').trigger(keydownEvent(ctrlKey: true))
+ $('input').trigger(keydownEvent(shiftKey: true))
+
+ expect(@spies.submit).not.toHaveBeenTriggered()
+ else
+ it 'responds to Ctrl+Enter', ->
+ $('input').trigger(keydownEvent())
+
+ expect(@spies.submit).toHaveBeenTriggered()
+
+ it 'excludes other modifier keys', ->
+ $('input').trigger(keydownEvent(altKey: true))
+ $('input').trigger(keydownEvent(metaKey: true))
+ $('input').trigger(keydownEvent(shiftKey: true))
+
+ expect(@spies.submit).not.toHaveBeenTriggered()
+
+ keydownEvent = (options) ->
+ if navigator.userAgent.match(/Macintosh/)
+ defaults = { keyCode: 13, metaKey: true }
+ else
+ defaults = { keyCode: 13, ctrlKey: true }
+
+ $.Event('keydown', $.extend({}, defaults, options))
diff --git a/spec/javascripts/fixtures/behaviors/quick_submit.html.haml b/spec/javascripts/fixtures/behaviors/quick_submit.html.haml
new file mode 100644
index 00000000000..b80a28a33ea
--- /dev/null
+++ b/spec/javascripts/fixtures/behaviors/quick_submit.html.haml
@@ -0,0 +1,6 @@
+%form{ action: '/foo' }
+ %input.js-quick-submit{ type: 'text' }
+ %textarea.js-quick-submit
+
+ %input{ type: 'submit'} Submit
+ %button.btn{ type: 'submit' } Submit
diff --git a/spec/javascripts/fixtures/line_highlighter.html.haml b/spec/javascripts/fixtures/line_highlighter.html.haml
index da1ebcdb23c..514877340e4 100644
--- a/spec/javascripts/fixtures/line_highlighter.html.haml
+++ b/spec/javascripts/fixtures/line_highlighter.html.haml
@@ -1,4 +1,4 @@
-#tree-content-holder
+#blob-content-holder
.file-content
.line-numbers
- 1.upto(25) do |i|
diff --git a/spec/javascripts/line_highlighter_spec.js.coffee b/spec/javascripts/line_highlighter_spec.js.coffee
index 57453c716a5..a073f21e7bc 100644
--- a/spec/javascripts/line_highlighter_spec.js.coffee
+++ b/spec/javascripts/line_highlighter_spec.js.coffee
@@ -39,7 +39,7 @@ describe 'LineHighlighter', ->
expect(spy).toHaveBeenPrevented()
it 'handles garbage input from the hash', ->
- func = -> new LineHighlighter('#tree-content-holder')
+ func = -> new LineHighlighter('#blob-content-holder')
expect(func).not.toThrow()
describe '#clickHandler', ->
diff --git a/spec/javascripts/spec_helper.coffee b/spec/javascripts/spec_helper.coffee
index 47b41dd2c81..90b02a6aec5 100644
--- a/spec/javascripts/spec_helper.coffee
+++ b/spec/javascripts/spec_helper.coffee
@@ -9,6 +9,7 @@
# require the specific files that are being used in the spec that tests them.
#= require jquery
+#= require jquery.turbolinks
#= require bootstrap
#= require underscore
diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
index 49482ac2b12..2260a6f8130 100644
--- a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
+++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb
@@ -17,13 +17,15 @@ module Ci
expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({
stage: "test",
+ stage_idx: 1,
except: nil,
name: :rspec,
only: nil,
- script: "pwd\nrspec",
- tags: [],
+ commands: "pwd\nrspec",
+ tag_list: [],
options: {},
- allow_failure: false
+ allow_failure: false,
+ when: "on_success"
})
end
@@ -115,15 +117,17 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
except: nil,
stage: "test",
+ stage_idx: 1,
name: :rspec,
only: nil,
- script: "pwd\nrspec",
- tags: [],
+ commands: "pwd\nrspec",
+ tag_list: [],
options: {
image: "ruby:2.1",
services: ["mysql"]
},
- allow_failure: false
+ allow_failure: false,
+ when: "on_success"
})
end
@@ -141,15 +145,17 @@ module Ci
expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
except: nil,
stage: "test",
+ stage_idx: 1,
name: :rspec,
only: nil,
- script: "pwd\nrspec",
- tags: [],
+ commands: "pwd\nrspec",
+ tag_list: [],
options: {
image: "ruby:2.5",
services: ["postgresql"]
},
- allow_failure: false
+ allow_failure: false,
+ when: "on_success"
})
end
end
@@ -171,6 +177,21 @@ module Ci
end
end
+ describe "When" do
+ %w(on_success on_failure always).each do |when_state|
+ it "returns #{when_state} when defined" do
+ config = YAML.dump({
+ rspec: { script: "rspec", when: when_state }
+ })
+
+ config_processor = GitlabCiYamlProcessor.new(config)
+ builds = config_processor.builds_for_stage_and_ref("test", "master")
+ expect(builds.size).to eq(1)
+ expect(builds.first[:when]).to eq(when_state)
+ end
+ end
+ end
+
describe "Error handling" do
it "indicates that object is invalid" do
expect{GitlabCiYamlProcessor.new("invalid_yaml\n!ccdvlf%612334@@@@")}.to raise_error(GitlabCiYamlProcessor::ValidationError)
@@ -308,6 +329,13 @@ module Ci
GitlabCiYamlProcessor.new(config)
end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings")
end
+
+ it "returns errors if job when is not on_success, on_failure or always" do
+ config = YAML.dump({ rspec: { script: "test", when: 1 } })
+ expect do
+ GitlabCiYamlProcessor.new(config)
+ end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always")
+ end
end
end
end
diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/backend/shell_spec.rb
index b6d04330599..b60e23454d6 100644
--- a/spec/lib/gitlab/backend/shell_spec.rb
+++ b/spec/lib/gitlab/backend/shell_spec.rb
@@ -15,4 +15,17 @@ describe Gitlab::Shell do
it { is_expected.to respond_to :fork_repository }
it { expect(gitlab_shell.url_to_repo('diaspora')).to eq(Gitlab.config.gitlab_shell.ssh_path_prefix + "diaspora.git") }
+
+ describe Gitlab::Shell::KeyAdder do
+ describe '#add_key' do
+ it 'normalizes space characters in the key' do
+ io = spy
+ adder = described_class.new(io)
+
+ adder.add_key('key-42', "sha-rsa foo\tbar\tbaz")
+
+ expect(io).to have_received(:puts).with("key-42\tsha-rsa foo bar baz")
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 5d7ff4f6122..21254f778d3 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -140,28 +140,28 @@ describe Gitlab::ClosingIssueExtractor do
message = "Closes #{reference} and fix #{reference2}"
expect(subject.closed_by_message(message)).
- to eq([issue, other_issue])
+ to match_array([issue, other_issue])
end
it 'fetches comma-separated issues references in single line message' do
message = "Closes #{reference}, closes #{reference2}"
expect(subject.closed_by_message(message)).
- to eq([issue, other_issue])
+ to match_array([issue, other_issue])
end
it 'fetches comma-separated issues numbers in single line message' do
message = "Closes #{reference}, #{reference2} and #{reference3}"
expect(subject.closed_by_message(message)).
- to eq([issue, other_issue, third_issue])
+ to match_array([issue, other_issue, third_issue])
end
it 'fetches issues in multi-line message' do
message = "Awesome commit (closes #{reference})\nAlso fixes #{reference2}"
expect(subject.closed_by_message(message)).
- to eq([issue, other_issue])
+ to match_array([issue, other_issue])
end
it 'fetches issues in hybrid message' do
@@ -169,7 +169,7 @@ describe Gitlab::ClosingIssueExtractor do
"Also fixing issues #{reference2}, #{reference3} and #4"
expect(subject.closed_by_message(message)).
- to eq([issue, other_issue, third_issue])
+ to match_array([issue, other_issue, third_issue])
end
end
end
diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb
new file mode 100644
index 00000000000..7cdebdf209a
--- /dev/null
+++ b/spec/lib/gitlab/database_spec.rb
@@ -0,0 +1,17 @@
+require 'spec_helper'
+
+describe Gitlab::Database do
+ # These are just simple smoke tests to check if the methods work (regardless
+ # of what they may return).
+ describe '.mysql?' do
+ subject { described_class.mysql? }
+
+ it { is_expected.to satisfy { |val| val == true || val == false } }
+ end
+
+ describe '.postgresql?' do
+ subject { described_class.postgresql? }
+
+ it { is_expected.to satisfy { |val| val == true || val == false } }
+ end
+end
diff --git a/spec/lib/gitlab/email/attachment_uploader_spec.rb b/spec/lib/gitlab/email/attachment_uploader_spec.rb
index e8208e15e29..8fb432367b6 100644
--- a/spec/lib/gitlab/email/attachment_uploader_spec.rb
+++ b/spec/lib/gitlab/email/attachment_uploader_spec.rb
@@ -13,7 +13,6 @@ describe Gitlab::Email::AttachmentUploader do
expect(link).not_to be_nil
expect(link[:is_image]).to be_truthy
expect(link[:alt]).to eq("bricks")
- expect(link[:url]).to include("/#{project.path_with_namespace}")
expect(link[:url]).to include("bricks.png")
end
end
diff --git a/spec/lib/gitlab/ldap/user_spec.rb b/spec/lib/gitlab/ldap/user_spec.rb
index fd2e5f6d0e1..b5b56a34952 100644
--- a/spec/lib/gitlab/ldap/user_spec.rb
+++ b/spec/lib/gitlab/ldap/user_spec.rb
@@ -13,6 +13,17 @@ describe Gitlab::LDAP::User do
let(:auth_hash) do
OmniAuth::AuthHash.new(uid: 'my-uid', provider: 'ldapmain', info: info)
end
+ let(:ldap_user_upper_case) { Gitlab::LDAP::User.new(auth_hash_upper_case) }
+ let(:info_upper_case) do
+ {
+ name: 'John',
+ email: 'John@Example.com', # Email address has upper case chars
+ nickname: 'john'
+ }
+ end
+ let(:auth_hash_upper_case) do
+ OmniAuth::AuthHash.new(uid: 'my-uid', provider: 'ldapmain', info: info_upper_case)
+ end
describe :changed? do
it "marks existing ldap user as changed" do
@@ -57,6 +68,16 @@ describe Gitlab::LDAP::User do
expect(existing_user.id).to eql ldap_user.gl_user.id
end
+ it 'connects to existing ldap user if the extern_uid changes and email address has upper case characters' do
+ existing_user = create(:omniauth_user, email: 'john@example.com', extern_uid: 'old-uid', provider: 'ldapmain')
+ expect{ ldap_user_upper_case.save }.not_to change{ User.count }
+
+ existing_user.reload
+ expect(existing_user.ldap_identity.extern_uid).to eql 'my-uid'
+ expect(existing_user.ldap_identity.provider).to eql 'ldapmain'
+ expect(existing_user.id).to eql ldap_user.gl_user.id
+ end
+
it 'maintains an identity per provider' do
existing_user = create(:omniauth_user, email: 'john@example.com', provider: 'twitter')
expect(existing_user.identities.count).to eql(1)
diff --git a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
index 3c6c84a0416..e5b8d723fe5 100644
--- a/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_range_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
describe CommitRangeReferenceFilter do
include FilterSpecHelper
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
let(:commit1) { project.commit }
let(:commit2) { project.commit("HEAD~2") }
@@ -75,12 +75,20 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit_range'
end
- it 'includes a data-project-id attribute' do
+ it 'includes a data-project attribute' do
doc = filter("See #{reference}")
link = doc.css('a').first
- expect(link).to have_attribute('data-project-id')
- expect(link.attr('data-project-id')).to eq project.id.to_s
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-commit-range attribute' do
+ doc = filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-commit-range')
+ expect(link.attr('data-commit-range')).to eq range.to_reference
end
it 'supports an :only_path option' do
@@ -92,59 +100,45 @@ module Gitlab::Markdown
end
it 'adds to the results hash' do
- result = pipeline_result("See #{reference}")
+ result = reference_pipeline_result("See #{reference}")
expect(result[:references][:commit_range]).not_to be_empty
end
end
context 'cross-project reference' do
let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, namespace: namespace) }
+ let(:project2) { create(:project, :public, namespace: namespace) }
let(:reference) { range.to_reference(project) }
before do
range.project = project2
end
- context 'when user can access reference' do
- before { allow_cross_reference! }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
- end
-
- it 'links with adjacent text' do
- doc = filter("Fixed (#{reference}.)")
-
- exp = Regexp.escape("#{project2.to_reference}@#{range.to_s}")
- expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
- end
+ it 'links to a valid reference' do
+ doc = filter("See #{reference}")
- it 'ignores invalid commit IDs on the referenced project' do
- exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
- expect(filter(act).to_html).to eq exp
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_compare_url(project2.namespace, project2, range.to_param)
+ end
- exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
- expect(filter(act).to_html).to eq exp
- end
+ it 'links with adjacent text' do
+ doc = filter("Fixed (#{reference}.)")
- it 'adds to the results hash' do
- result = pipeline_result("See #{reference}")
- expect(result[:references][:commit_range]).not_to be_empty
- end
+ exp = Regexp.escape("#{project2.to_reference}@#{range.to_s}")
+ expect(doc.to_html).to match(/\(<a.+>#{exp}<\/a>\.\)/)
end
- context 'when user cannot access reference' do
- before { disallow_cross_reference! }
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Fixed #{project2.to_reference}@#{commit1.id.reverse}...#{commit2.id}"
+ expect(filter(act).to_html).to eq exp
- it 'ignores valid references' do
- exp = act = "See #{reference}"
+ exp = act = "Fixed #{project2.to_reference}@#{commit1.id}...#{commit2.id.reverse}"
+ expect(filter(act).to_html).to eq exp
+ end
- expect(filter(act).to_html).to eq exp
- end
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit_range]).not_to be_empty
end
end
end
diff --git a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
index 9ed438252b3..d080efbf3d4 100644
--- a/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/commit_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
describe CommitReferenceFilter do
include FilterSpecHelper
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
let(:commit) { project.commit }
it 'requires project context' do
@@ -71,12 +71,20 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-commit'
end
- it 'includes a data-project-id attribute' do
+ it 'includes a data-project attribute' do
doc = filter("See #{reference}")
link = doc.css('a').first
- expect(link).to have_attribute('data-project-id')
- expect(link.attr('data-project-id')).to eq project.id.to_s
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-commit attribute' do
+ doc = filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-commit')
+ expect(link.attr('data-commit')).to eq commit.id
end
it 'supports an :only_path context' do
@@ -88,53 +96,39 @@ module Gitlab::Markdown
end
it 'adds to the results hash' do
- result = pipeline_result("See #{reference}")
+ result = reference_pipeline_result("See #{reference}")
expect(result[:references][:commit]).not_to be_empty
end
end
context 'cross-project reference' do
let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, namespace: namespace) }
+ let(:project2) { create(:project, :public, namespace: namespace) }
let(:commit) { project2.commit }
let(:reference) { commit.to_reference(project) }
- context 'when user can access reference' do
- before { allow_cross_reference! }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
- end
-
- it 'links with adjacent text' do
- doc = filter("Fixed (#{reference}.)")
+ it 'links to a valid reference' do
+ doc = filter("See #{reference}")
- exp = Regexp.escape(project2.to_reference)
- expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
- end
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_commit_url(project2.namespace, project2, commit.id)
+ end
- it 'ignores invalid commit IDs on the referenced project' do
- exp = act = "Committed #{invalidate_reference(reference)}"
- expect(filter(act).to_html).to eq exp
- end
+ it 'links with adjacent text' do
+ doc = filter("Fixed (#{reference}.)")
- it 'adds to the results hash' do
- result = pipeline_result("See #{reference}")
- expect(result[:references][:commit]).not_to be_empty
- end
+ exp = Regexp.escape(project2.to_reference)
+ expect(doc.to_html).to match(/\(<a.+>#{exp}@#{commit.short_id}<\/a>\.\)/)
end
- context 'when user cannot access reference' do
- before { disallow_cross_reference! }
-
- it 'ignores valid references' do
- exp = act = "See #{reference}"
+ it 'ignores invalid commit IDs on the referenced project' do
+ exp = act = "Committed #{invalidate_reference(reference)}"
+ expect(filter(act).to_html).to eq exp
+ end
- expect(filter(act).to_html).to eq exp
- end
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("See #{reference}")
+ expect(result[:references][:commit]).not_to be_empty
end
end
end
diff --git a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb b/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
index 4698d6138c2..8d4f9e403a6 100644
--- a/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
+++ b/spec/lib/gitlab/markdown/cross_project_reference_spec.rb
@@ -2,20 +2,16 @@ require 'spec_helper'
module Gitlab::Markdown
describe CrossProjectReference do
- # context in the html-pipeline sense, not in the rspec sense
- let(:context) do
- {
- current_user: double('user'),
- project: double('project')
- }
- end
-
include described_class
describe '#project_from_ref' do
context 'when no project was referenced' do
it 'returns the project from context' do
- expect(project_from_ref(nil)).to eq context[:project]
+ project = double
+
+ allow(self).to receive(:context).and_return({ project: project })
+
+ expect(project_from_ref(nil)).to eq project
end
end
@@ -26,29 +22,13 @@ module Gitlab::Markdown
end
context 'when referenced project exists' do
- let(:project2) { double('referenced project') }
+ it 'returns the referenced project' do
+ project2 = double('referenced project')
- before do
expect(Project).to receive(:find_with_namespace).
with('cross/reference').and_return(project2)
- end
-
- context 'and the user has permission to read it' do
- it 'returns the referenced project' do
- expect(self).to receive(:user_can_reference_project?).
- with(project2).and_return(true)
-
- expect(project_from_ref('cross/reference')).to eq project2
- end
- end
-
- context 'and the user does not have permission to read it' do
- it 'returns nil' do
- expect(self).to receive(:user_can_reference_project?).
- with(project2).and_return(false)
- expect(project_from_ref('cross/reference')).to be_nil
- end
+ expect(project_from_ref('cross/reference')).to eq project2
end
end
end
diff --git a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
index 1dd54f58588..94c80ae6611 100644
--- a/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/issue_reference_filter_spec.rb
@@ -8,7 +8,7 @@ module Gitlab::Markdown
IssuesHelper
end
- let(:project) { create(:empty_project) }
+ let(:project) { create(:empty_project, :public) }
let(:issue) { create(:issue, project: project) }
it 'requires project context' do
@@ -68,12 +68,20 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-issue'
end
- it 'includes a data-project-id attribute' do
+ it 'includes a data-project attribute' do
doc = filter("Issue #{reference}")
link = doc.css('a').first
- expect(link).to have_attribute('data-project-id')
- expect(link.attr('data-project-id')).to eq project.id.to_s
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-issue attribute' do
+ doc = filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-issue')
+ expect(link.attr('data-issue')).to eq issue.id.to_s
end
it 'supports an :only_path context' do
@@ -85,60 +93,46 @@ module Gitlab::Markdown
end
it 'adds to the results hash' do
- result = pipeline_result("Fixed #{reference}")
+ result = reference_pipeline_result("Fixed #{reference}")
expect(result[:references][:issue]).to eq [issue]
end
end
context 'cross-project reference' do
let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:empty_project, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:issue) { create(:issue, project: project2) }
let(:reference) { issue.to_reference(project) }
- context 'when user can access reference' do
- before { allow_cross_reference! }
-
- it 'ignores valid references when cross-reference project uses external tracker' do
- expect_any_instance_of(Project).to receive(:get_issue).
- with(issue.iid).and_return(nil)
-
- exp = act = "Issue #{reference}"
- expect(filter(act).to_html).to eq exp
- end
+ it 'ignores valid references when cross-reference project uses external tracker' do
+ expect_any_instance_of(Project).to receive(:get_issue).
+ with(issue.iid).and_return(nil)
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq helper.url_for_issue(issue.iid, project2)
- end
-
- it 'links with adjacent text' do
- doc = filter("Fixed (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
+ exp = act = "Issue #{reference}"
+ expect(filter(act).to_html).to eq exp
+ end
- it 'ignores invalid issue IDs on the referenced project' do
- exp = act = "Fixed #{invalidate_reference(reference)}"
+ it 'links to a valid reference' do
+ doc = filter("See #{reference}")
- expect(filter(act).to_html).to eq exp
- end
+ expect(doc.css('a').first.attr('href')).
+ to eq helper.url_for_issue(issue.iid, project2)
+ end
- it 'adds to the results hash' do
- result = pipeline_result("Fixed #{reference}")
- expect(result[:references][:issue]).to eq [issue]
- end
+ it 'links with adjacent text' do
+ doc = filter("Fixed (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
end
- context 'when user cannot access reference' do
- before { disallow_cross_reference! }
+ it 'ignores invalid issue IDs on the referenced project' do
+ exp = act = "Fixed #{invalidate_reference(reference)}"
- it 'ignores valid references' do
- exp = act = "See #{reference}"
+ expect(filter(act).to_html).to eq exp
+ end
- expect(filter(act).to_html).to eq exp
- end
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Fixed #{reference}")
+ expect(result[:references][:issue]).to eq [issue]
end
end
end
diff --git a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
index e32089de376..fc21b65a843 100644
--- a/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/label_reference_filter_spec.rb
@@ -5,7 +5,7 @@ module Gitlab::Markdown
describe LabelReferenceFilter do
include FilterSpecHelper
- let(:project) { create(:empty_project) }
+ let(:project) { create(:empty_project, :public) }
let(:label) { create(:label, project: project) }
let(:reference) { label.to_reference }
@@ -25,12 +25,20 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-label'
end
- it 'includes a data-project-id attribute' do
+ it 'includes a data-project attribute' do
doc = filter("Label #{reference}")
link = doc.css('a').first
- expect(link).to have_attribute('data-project-id')
- expect(link.attr('data-project-id')).to eq project.id.to_s
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-label attribute' do
+ doc = filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-label')
+ expect(link.attr('data-label')).to eq label.id.to_s
end
it 'supports an :only_path context' do
@@ -42,7 +50,7 @@ module Gitlab::Markdown
end
it 'adds to the results hash' do
- result = pipeline_result("Label #{reference}")
+ result = reference_pipeline_result("Label #{reference}")
expect(result[:references][:label]).to eq [label]
end
diff --git a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
index 66616b93368..3ef6cdfff33 100644
--- a/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/merge_request_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
describe MergeRequestReferenceFilter do
include FilterSpecHelper
- let(:project) { create(:project) }
+ let(:project) { create(:project, :public) }
let(:merge) { create(:merge_request, source_project: project) }
it 'requires project context' do
@@ -56,12 +56,20 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-merge_request'
end
- it 'includes a data-project-id attribute' do
+ it 'includes a data-project attribute' do
doc = filter("Merge #{reference}")
link = doc.css('a').first
- expect(link).to have_attribute('data-project-id')
- expect(link.attr('data-project-id')).to eq project.id.to_s
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-merge-request attribute' do
+ doc = filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-merge-request')
+ expect(link.attr('data-merge-request')).to eq merge.id.to_s
end
it 'supports an :only_path context' do
@@ -73,53 +81,39 @@ module Gitlab::Markdown
end
it 'adds to the results hash' do
- result = pipeline_result("Merge #{reference}")
+ result = reference_pipeline_result("Merge #{reference}")
expect(result[:references][:merge_request]).to eq [merge]
end
end
context 'cross-project reference' do
let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:project, namespace: namespace) }
+ let(:project2) { create(:project, :public, namespace: namespace) }
let(:merge) { create(:merge_request, source_project: project2) }
let(:reference) { merge.to_reference(project) }
- context 'when user can access reference' do
- before { allow_cross_reference! }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_merge_request_url(project2.namespace,
- project, merge)
- end
-
- it 'links with adjacent text' do
- doc = filter("Merge (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid merge IDs on the referenced project' do
- exp = act = "Merge #{invalidate_reference(reference)}"
+ it 'links to a valid reference' do
+ doc = filter("See #{reference}")
- expect(filter(act).to_html).to eq exp
- end
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_merge_request_url(project2.namespace,
+ project, merge)
+ end
- it 'adds to the results hash' do
- result = pipeline_result("Merge #{reference}")
- expect(result[:references][:merge_request]).to eq [merge]
- end
+ it 'links with adjacent text' do
+ doc = filter("Merge (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
end
- context 'when user cannot access reference' do
- before { disallow_cross_reference! }
+ it 'ignores invalid merge IDs on the referenced project' do
+ exp = act = "Merge #{invalidate_reference(reference)}"
- it 'ignores valid references' do
- exp = act = "See #{reference}"
+ expect(filter(act).to_html).to eq exp
+ end
- expect(filter(act).to_html).to eq exp
- end
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Merge #{reference}")
+ expect(result[:references][:merge_request]).to eq [merge]
end
end
end
diff --git a/spec/lib/gitlab/markdown/redactor_filter_spec.rb b/spec/lib/gitlab/markdown/redactor_filter_spec.rb
new file mode 100644
index 00000000000..eea3f1cf370
--- /dev/null
+++ b/spec/lib/gitlab/markdown/redactor_filter_spec.rb
@@ -0,0 +1,91 @@
+require 'spec_helper'
+
+module Gitlab::Markdown
+ describe RedactorFilter do
+ include ActionView::Helpers::UrlHelper
+ include FilterSpecHelper
+
+ it 'ignores non-GFM links' do
+ html = %(See <a href="https://google.com/">Google</a>)
+ doc = filter(html, current_user: double)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ def reference_link(data)
+ link_to('text', '', class: 'gfm', data: data)
+ end
+
+ context 'with data-project' do
+ it 'removes unpermitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+
+ link = reference_link(project: project.id, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 0
+ end
+
+ it 'allows permitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+ project.team << [user, :master]
+
+ link = reference_link(project: project.id, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'handles invalid Project references' do
+ link = reference_link(project: 12345, reference_filter: Gitlab::Markdown::ReferenceFilter.name)
+
+ expect { filter(link) }.not_to raise_error
+ end
+ end
+
+ context "for user references" do
+
+ context 'with data-group' do
+ it 'removes unpermitted Group references' do
+ user = create(:user)
+ group = create(:group)
+
+ link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 0
+ end
+
+ it 'allows permitted Group references' do
+ user = create(:user)
+ group = create(:group)
+ group.add_developer(user)
+
+ link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+ doc = filter(link, current_user: user)
+
+ expect(doc.css('a').length).to eq 1
+ end
+
+ it 'handles invalid Group references' do
+ link = reference_link(group: 12345, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+
+ expect { filter(link) }.not_to raise_error
+ end
+ end
+
+ context 'with data-user' do
+ it 'allows any User reference' do
+ user = create(:user)
+
+ link = reference_link(user: user.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+ doc = filter(link)
+
+ expect(doc.css('a').length).to eq 1
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb b/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb
new file mode 100644
index 00000000000..4fa473ad191
--- /dev/null
+++ b/spec/lib/gitlab/markdown/reference_gatherer_filter_spec.rb
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+module Gitlab::Markdown
+ describe ReferenceGathererFilter do
+ include ActionView::Helpers::UrlHelper
+ include FilterSpecHelper
+
+ def reference_link(data)
+ link_to('text', '', class: 'gfm', data: data)
+ end
+
+ context "for issue references" do
+
+ context 'with data-project' do
+ it 'removes unpermitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+ issue = create(:issue, project: project)
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:issue]).to be_empty
+ end
+
+ it 'allows permitted Project references' do
+ user = create(:user)
+ project = create(:empty_project)
+ issue = create(:issue, project: project)
+ project.team << [user, :master]
+
+ link = reference_link(project: project.id, issue: issue.id, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:issue]).to eq([issue])
+ end
+
+ it 'handles invalid Project references' do
+ link = reference_link(project: 12345, issue: 12345, reference_filter: Gitlab::Markdown::IssueReferenceFilter.name)
+
+ expect { pipeline_result(link) }.not_to raise_error
+ end
+ end
+ end
+
+ context "for user references" do
+
+ context 'with data-group' do
+ it 'removes unpermitted Group references' do
+ user = create(:user)
+ group = create(:group)
+
+ link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:user]).to be_empty
+ end
+
+ it 'allows permitted Group references' do
+ user = create(:user)
+ group = create(:group)
+ group.add_developer(user)
+
+ link = reference_link(group: group.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+ result = pipeline_result(link, current_user: user)
+
+ expect(result[:references][:user]).to eq([user])
+ end
+
+ it 'handles invalid Group references' do
+ link = reference_link(group: 12345, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+
+ expect { pipeline_result(link) }.not_to raise_error
+ end
+ end
+
+ context 'with data-user' do
+ it 'allows any User reference' do
+ user = create(:user)
+
+ link = reference_link(user: user.id, reference_filter: Gitlab::Markdown::UserReferenceFilter.name)
+ result = pipeline_result(link)
+
+ expect(result[:references][:user]).to eq([user])
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
index fd3f0d20fad..9d9652dba46 100644
--- a/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/snippet_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
describe SnippetReferenceFilter do
include FilterSpecHelper
- let(:project) { create(:empty_project) }
+ let(:project) { create(:empty_project, :public) }
let(:snippet) { create(:project_snippet, project: project) }
let(:reference) { snippet.to_reference }
@@ -55,12 +55,20 @@ module Gitlab::Markdown
expect(doc.css('a').first.attr('class')).to eq 'gfm gfm-snippet'
end
- it 'includes a data-project-id attribute' do
+ it 'includes a data-project attribute' do
doc = filter("Snippet #{reference}")
link = doc.css('a').first
- expect(link).to have_attribute('data-project-id')
- expect(link.attr('data-project-id')).to eq project.id.to_s
+ expect(link).to have_attribute('data-project')
+ expect(link.attr('data-project')).to eq project.id.to_s
+ end
+
+ it 'includes a data-snippet attribute' do
+ doc = filter("See #{reference}")
+ link = doc.css('a').first
+
+ expect(link).to have_attribute('data-snippet')
+ expect(link.attr('data-snippet')).to eq snippet.id.to_s
end
it 'supports an :only_path context' do
@@ -72,52 +80,38 @@ module Gitlab::Markdown
end
it 'adds to the results hash' do
- result = pipeline_result("Snippet #{reference}")
+ result = reference_pipeline_result("Snippet #{reference}")
expect(result[:references][:snippet]).to eq [snippet]
end
end
context 'cross-project reference' do
let(:namespace) { create(:namespace, name: 'cross-reference') }
- let(:project2) { create(:empty_project, namespace: namespace) }
+ let(:project2) { create(:empty_project, :public, namespace: namespace) }
let(:snippet) { create(:project_snippet, project: project2) }
let(:reference) { snippet.to_reference(project) }
- context 'when user can access reference' do
- before { allow_cross_reference! }
-
- it 'links to a valid reference' do
- doc = filter("See #{reference}")
-
- expect(doc.css('a').first.attr('href')).
- to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
- end
-
- it 'links with adjacent text' do
- doc = filter("See (#{reference}.)")
- expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
- end
-
- it 'ignores invalid snippet IDs on the referenced project' do
- exp = act = "See #{invalidate_reference(reference)}"
+ it 'links to a valid reference' do
+ doc = filter("See #{reference}")
- expect(filter(act).to_html).to eq exp
- end
+ expect(doc.css('a').first.attr('href')).
+ to eq urls.namespace_project_snippet_url(project2.namespace, project2, snippet)
+ end
- it 'adds to the results hash' do
- result = pipeline_result("Snippet #{reference}")
- expect(result[:references][:snippet]).to eq [snippet]
- end
+ it 'links with adjacent text' do
+ doc = filter("See (#{reference}.)")
+ expect(doc.to_html).to match(/\(<a.+>#{Regexp.escape(reference)}<\/a>\.\)/)
end
- context 'when user cannot access reference' do
- before { disallow_cross_reference! }
+ it 'ignores invalid snippet IDs on the referenced project' do
+ exp = act = "See #{invalidate_reference(reference)}"
- it 'ignores valid references' do
- exp = act = "See #{reference}"
+ expect(filter(act).to_html).to eq exp
+ end
- expect(filter(act).to_html).to eq exp
- end
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Snippet #{reference}")
+ expect(result[:references][:snippet]).to eq [snippet]
end
end
end
diff --git a/spec/lib/gitlab/markdown/upload_link_filter_spec.rb b/spec/lib/gitlab/markdown/upload_link_filter_spec.rb
new file mode 100644
index 00000000000..9ae45a6f559
--- /dev/null
+++ b/spec/lib/gitlab/markdown/upload_link_filter_spec.rb
@@ -0,0 +1,75 @@
+# encoding: UTF-8
+
+require 'spec_helper'
+
+module Gitlab::Markdown
+ describe UploadLinkFilter do
+ def filter(doc, contexts = {})
+ contexts.reverse_merge!({
+ project: project
+ })
+
+ described_class.call(doc, contexts)
+ end
+
+ def image(path)
+ %(<img src="#{path}" />)
+ end
+
+ def link(path)
+ %(<a href="#{path}">#{path}</a>)
+ end
+
+ let(:project) { create(:project) }
+
+ shared_examples :preserve_unchanged do
+ it 'does not modify any relative URL in anchor' do
+ doc = filter(link('README.md'))
+ expect(doc.at_css('a')['href']).to eq 'README.md'
+ end
+
+ it 'does not modify any relative URL in image' do
+ doc = filter(image('files/images/logo-black.png'))
+ expect(doc.at_css('img')['src']).to eq 'files/images/logo-black.png'
+ end
+ end
+
+ it 'does not raise an exception on invalid URIs' do
+ act = link("://foo")
+ expect { filter(act) }.not_to raise_error
+ end
+
+ context 'with a valid repository' do
+ it 'rebuilds relative URL for a link' do
+ doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+ expect(doc.at_css('a')['href']).
+ to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ end
+
+ it 'rebuilds relative URL for an image' do
+ doc = filter(link('/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg'))
+ expect(doc.at_css('a')['href']).
+ to eq "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/e90decf88d8f96fe9e1389afc2e4a91f/test.jpg"
+ end
+
+ it 'does not modify absolute URL' do
+ doc = filter(link('http://example.com'))
+ expect(doc.at_css('a')['href']).to eq 'http://example.com'
+ end
+
+ it 'supports Unicode filenames' do
+ path = '/uploads/한글.png'
+ escaped = Addressable::URI.escape(path)
+
+ # Stub these methods so the file doesn't actually need to be in the repo
+ allow_any_instance_of(described_class).
+ to receive(:file_exists?).and_return(true)
+ allow_any_instance_of(described_class).
+ to receive(:image?).with(path).and_return(true)
+
+ doc = filter(image(escaped))
+ expect(doc.at_css('img')['src']).to match "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/uploads/%ED%95%9C%EA%B8%80.png"
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
index b2155fab59b..d9e0d7c42db 100644
--- a/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
+++ b/spec/lib/gitlab/markdown/user_reference_filter_spec.rb
@@ -4,7 +4,7 @@ module Gitlab::Markdown
describe UserReferenceFilter do
include FilterSpecHelper
- let(:project) { create(:empty_project) }
+ let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
let(:reference) { user.to_reference }
@@ -39,7 +39,7 @@ module Gitlab::Markdown
end
it 'adds to the results hash' do
- result = pipeline_result("Hey #{reference}")
+ result = reference_pipeline_result("Hey #{reference}")
expect(result[:references][:user]).to eq [project.creator]
end
end
@@ -64,59 +64,40 @@ module Gitlab::Markdown
expect(doc.css('a').length).to eq 1
end
- it 'includes a data-user-id attribute' do
+ it 'includes a data-user attribute' do
doc = filter("Hey #{reference}")
link = doc.css('a').first
- expect(link).to have_attribute('data-user-id')
- expect(link.attr('data-user-id')).to eq user.namespace.owner_id.to_s
+ expect(link).to have_attribute('data-user')
+ expect(link.attr('data-user')).to eq user.namespace.owner_id.to_s
end
it 'adds to the results hash' do
- result = pipeline_result("Hey #{reference}")
+ result = reference_pipeline_result("Hey #{reference}")
expect(result[:references][:user]).to eq [user]
end
end
context 'mentioning a group' do
let(:group) { create(:group) }
- let(:user) { create(:user) }
let(:reference) { group.to_reference }
- context 'that the current user can read' do
- before do
- group.add_developer(user)
- end
-
- it 'links to the Group' do
- doc = filter("Hey #{reference}", current_user: user)
- expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
- end
-
- it 'includes a data-group-id attribute' do
- doc = filter("Hey #{reference}", current_user: user)
- link = doc.css('a').first
+ it 'links to the Group' do
+ doc = filter("Hey #{reference}")
+ expect(doc.css('a').first.attr('href')).to eq urls.group_url(group)
+ end
- expect(link).to have_attribute('data-group-id')
- expect(link.attr('data-group-id')).to eq group.id.to_s
- end
+ it 'includes a data-group attribute' do
+ doc = filter("Hey #{reference}")
+ link = doc.css('a').first
- it 'adds to the results hash' do
- result = pipeline_result("Hey #{reference}", current_user: user)
- expect(result[:references][:user]).to eq group.users
- end
+ expect(link).to have_attribute('data-group')
+ expect(link.attr('data-group')).to eq group.id.to_s
end
- context 'that the current user cannot read' do
- it 'ignores references to the Group' do
- doc = filter("Hey #{reference}", current_user: user)
- expect(doc.to_html).to eq "Hey #{reference}"
- end
-
- it 'does not add to the results hash' do
- result = pipeline_result("Hey #{reference}", current_user: user)
- expect(result[:references][:user]).to eq []
- end
+ it 'adds to the results hash' do
+ result = reference_pipeline_result("Hey #{reference}")
+ expect(result[:references][:user]).to eq group.users
end
end
diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb
index 088e34f050c..ad84d2274e8 100644
--- a/spec/lib/gitlab/reference_extractor_spec.rb
+++ b/spec/lib/gitlab/reference_extractor_spec.rb
@@ -13,7 +13,7 @@ describe Gitlab::ReferenceExtractor do
project.team << [@u_bar, :guest]
subject.analyze('@foo, @baduser, @bar, and @offteam')
- expect(subject.users).to eq([@u_foo, @u_bar, @u_offteam])
+ expect(subject.users).to match_array([@u_foo, @u_bar, @u_offteam])
end
it 'ignores user mentions inside specific elements' do
@@ -37,7 +37,7 @@ describe Gitlab::ReferenceExtractor do
> @offteam
})
- expect(subject.users).to eq([])
+ expect(subject.users).to match_array([])
end
it 'accesses valid issue objects' do
@@ -45,7 +45,7 @@ describe Gitlab::ReferenceExtractor do
@i1 = create(:issue, project: project)
subject.analyze("#{@i0.to_reference}, #{@i1.to_reference}, and #{Issue.reference_prefix}999.")
- expect(subject.issues).to eq([@i0, @i1])
+ expect(subject.issues).to match_array([@i0, @i1])
end
it 'accesses valid merge requests' do
@@ -53,7 +53,7 @@ describe Gitlab::ReferenceExtractor do
@m1 = create(:merge_request, source_project: project, target_project: project, source_branch: 'feature_conflict')
subject.analyze("!999, !#{@m1.iid}, and !#{@m0.iid}.")
- expect(subject.merge_requests).to eq([@m1, @m0])
+ expect(subject.merge_requests).to match_array([@m1, @m0])
end
it 'accesses valid labels' do
@@ -62,7 +62,7 @@ describe Gitlab::ReferenceExtractor do
@l2 = create(:label)
subject.analyze("~#{@l0.id}, ~999, ~#{@l2.id}, ~#{@l1.id}")
- expect(subject.labels).to eq([@l0, @l1])
+ expect(subject.labels).to match_array([@l0, @l1])
end
it 'accesses valid snippets' do
@@ -71,7 +71,7 @@ describe Gitlab::ReferenceExtractor do
@s2 = create(:project_snippet)
subject.analyze("$#{@s0.id}, $999, $#{@s2.id}, $#{@s1.id}")
- expect(subject.snippets).to eq([@s0, @s1])
+ expect(subject.snippets).to match_array([@s0, @s1])
end
it 'accesses valid commits' do
@@ -109,7 +109,7 @@ describe Gitlab::ReferenceExtractor do
subject.analyze("this refers issue #{issue.to_reference(project)}")
extracted = subject.issues
expect(extracted.size).to eq(1)
- expect(extracted).to eq([issue])
+ expect(extracted).to match_array([issue])
end
end
end
diff --git a/spec/lib/gitlab/uploads_transfer_spec.rb b/spec/lib/gitlab/uploads_transfer_spec.rb
new file mode 100644
index 00000000000..260364a513e
--- /dev/null
+++ b/spec/lib/gitlab/uploads_transfer_spec.rb
@@ -0,0 +1,50 @@
+require 'spec_helper'
+
+describe Gitlab::UploadsTransfer do
+ before do
+ @root_dir = File.join(Rails.root, "public", "uploads")
+ @upload_transfer = Gitlab::UploadsTransfer.new
+
+ @project_path_was = "test_project_was"
+ @project_path = "test_project"
+ @namespace_path_was = "test_namespace_was"
+ @namespace_path = "test_namespace"
+ end
+
+ after do
+ FileUtils.rm_rf([
+ File.join(@root_dir, @namespace_path),
+ File.join(@root_dir, @namespace_path_was)
+ ])
+ end
+
+ describe '#move_project' do
+ it "moves project upload to another namespace" do
+ FileUtils.mkdir_p(File.join(@root_dir, @namespace_path_was, @project_path))
+ @upload_transfer.move_project(@project_path, @namespace_path_was, @namespace_path)
+
+ expected_path = File.join(@root_dir, @namespace_path, @project_path)
+ expect(Dir.exist?(expected_path)).to be_truthy
+ end
+ end
+
+ describe '#rename_project' do
+ it "renames project" do
+ FileUtils.mkdir_p(File.join(@root_dir, @namespace_path, @project_path_was))
+ @upload_transfer.rename_project(@project_path_was, @project_path, @namespace_path)
+
+ expected_path = File.join(@root_dir, @namespace_path, @project_path)
+ expect(Dir.exist?(expected_path)).to be_truthy
+ end
+ end
+
+ describe '#rename_namespace' do
+ it "renames namespace" do
+ FileUtils.mkdir_p(File.join(@root_dir, @namespace_path_was, @project_path))
+ @upload_transfer.rename_namespace(@namespace_path_was, @namespace_path)
+
+ expected_path = File.join(@root_dir, @namespace_path, @project_path)
+ expect(Dir.exist?(expected_path)).to be_truthy
+ end
+ end
+end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/build_spec.rb
index ca070a14975..7f5abb83ac2 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -31,13 +31,8 @@ describe Ci::Build do
let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
let(:build) { FactoryGirl.create :ci_build, commit: commit }
- it { is_expected.to belong_to(:commit) }
- it { is_expected.to validate_presence_of :status }
+ it { is_expected.to validate_presence_of :ref }
- it { is_expected.to respond_to :success? }
- it { is_expected.to respond_to :failed? }
- it { is_expected.to respond_to :running? }
- it { is_expected.to respond_to :pending? }
it { is_expected.to respond_to :trace_html }
describe :first_pending do
@@ -64,72 +59,6 @@ describe Ci::Build do
end
end
- describe :started? do
- subject { build.started? }
-
- context 'without started_at' do
- before { build.started_at = nil }
-
- it { is_expected.to be_falsey }
- end
-
- %w(running success failed).each do |status|
- context "if build status is #{status}" do
- before { build.status = status }
-
- it { is_expected.to be_truthy }
- end
- end
-
- %w(pending canceled).each do |status|
- context "if build status is #{status}" do
- before { build.status = status }
-
- it { is_expected.to be_falsey }
- end
- end
- end
-
- describe :active? do
- subject { build.active? }
-
- %w(pending running).each do |state|
- context "if build.status is #{state}" do
- before { build.status = state }
-
- it { is_expected.to be_truthy }
- end
- end
-
- %w(success failed canceled).each do |state|
- context "if build.status is #{state}" do
- before { build.status = state }
-
- it { is_expected.to be_falsey }
- end
- end
- end
-
- describe :complete? do
- subject { build.complete? }
-
- %w(success failed canceled).each do |state|
- context "if build.status is #{state}" do
- before { build.status = state }
-
- it { is_expected.to be_truthy }
- end
- end
-
- %w(pending running).each do |state|
- context "if build.status is #{state}" do
- before { build.status = state }
-
- it { is_expected.to be_falsey }
- end
- end
- end
-
describe :ignored? do
subject { build.ignored? }
@@ -197,31 +126,6 @@ describe Ci::Build do
it { is_expected.to eq(commit.project.timeout) }
end
- describe :duration do
- subject { build.duration }
-
- it { is_expected.to eq(120.0) }
-
- context 'if the building process has not started yet' do
- before do
- build.started_at = nil
- build.finished_at = nil
- end
-
- it { is_expected.to be_nil }
- end
-
- context 'if the building process has started' do
- before do
- build.started_at = Time.now - 1.minute
- build.finished_at = nil
- end
-
- it { is_expected.to be_a(Float) }
- it { is_expected.to be > 0.0 }
- end
- end
-
describe :options do
let(:options) do
{
@@ -236,30 +140,6 @@ describe Ci::Build do
it { is_expected.to eq(options) }
end
- describe :ref do
- subject { build.ref }
-
- it { is_expected.to eq(commit.ref) }
- end
-
- describe :sha do
- subject { build.sha }
-
- it { is_expected.to eq(commit.sha) }
- end
-
- describe :short_sha do
- subject { build.short_sha }
-
- it { is_expected.to eq(commit.short_sha) }
- end
-
- describe :before_sha do
- subject { build.before_sha }
-
- it { is_expected.to eq(commit.before_sha) }
- end
-
describe :allow_git_fetch do
subject { build.allow_git_fetch }
@@ -320,13 +200,34 @@ describe Ci::Build do
context 'returns variables' do
subject { build.variables }
- let(:variables) do
+ let(:predefined_variables) do
+ [
+ { key: :CI_BUILD_NAME, value: 'test', public: true },
+ { key: :CI_BUILD_STAGE, value: 'stage', public: true },
+ ]
+ end
+
+ let(:yaml_variables) do
[
{ key: :DB_NAME, value: 'postgres', public: true }
]
end
- it { is_expected.to eq(variables) }
+ before { build.update_attributes(stage: 'stage') }
+
+ it { is_expected.to eq(predefined_variables + yaml_variables) }
+
+ context 'for tag' do
+ let(:tag_variable) do
+ [
+ { key: :CI_BUILD_TAG, value: 'master', public: true }
+ ]
+ end
+
+ before { build.update_attributes(tag: true) }
+
+ it { is_expected.to eq(tag_variable + predefined_variables + yaml_variables) }
+ end
context 'and secure variables' do
let(:secure_variables) do
@@ -339,7 +240,7 @@ describe Ci::Build do
build.project.variables << Ci::Variable.new(key: 'SECRET_KEY', value: 'secret_value')
end
- it { is_expected.to eq(variables + secure_variables) }
+ it { is_expected.to eq(predefined_variables + yaml_variables + secure_variables) }
context 'and trigger variables' do
let(:trigger) { FactoryGirl.create :ci_trigger, project: project }
@@ -349,14 +250,154 @@ describe Ci::Build do
{ key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false }
]
end
+ let(:predefined_trigger_variable) do
+ [
+ { key: :CI_BUILD_TRIGGERED, value: 'true', public: true }
+ ]
+ end
before do
build.trigger_request = trigger_request
end
- it { is_expected.to eq(variables + secure_variables + trigger_variables) }
+ it { is_expected.to eq(predefined_variables + predefined_trigger_variable + yaml_variables + secure_variables + trigger_variables) }
+ end
+ end
+ end
+ end
+
+ describe :project_recipients do
+ let(:pusher_email) { 'pusher@gitlab.test' }
+ let(:user) { User.new(notification_email: pusher_email) }
+ subject { build.project_recipients }
+
+ before do
+ build.update_attributes(user: user)
+ end
+
+ it 'should return pusher_email as only recipient when no additional recipients are given' do
+ project.update_attributes(email_add_pusher: true,
+ email_recipients: '')
+ is_expected.to eq([pusher_email])
+ end
+
+ it 'should return pusher_email and additional recipients' do
+ project.update_attributes(email_add_pusher: true,
+ email_recipients: 'rec1 rec2')
+ is_expected.to eq(['rec1', 'rec2', pusher_email])
+ end
+
+ it 'should return recipients' do
+ project.update_attributes(email_add_pusher: false,
+ email_recipients: 'rec1 rec2')
+ is_expected.to eq(['rec1', 'rec2'])
+ end
+
+ it 'should return unique recipients only' do
+ project.update_attributes(email_add_pusher: true,
+ email_recipients: "rec1 rec1 #{pusher_email}")
+ is_expected.to eq(['rec1', pusher_email])
+ end
+ end
+
+ describe :can_be_served? do
+ let(:runner) { FactoryGirl.create :ci_specific_runner }
+
+ before { build.project.runners << runner }
+
+ context 'runner without tags' do
+ it 'can handle builds without tags' do
+ expect(build.can_be_served?(runner)).to be_truthy
+ end
+
+ it 'cannot handle build with tags' do
+ build.tag_list = ['aa']
+ expect(build.can_be_served?(runner)).to be_falsey
+ end
+ end
+
+ context 'runner with tags' do
+ before { runner.tag_list = ['bb', 'cc'] }
+
+ it 'can handle builds without tags' do
+ expect(build.can_be_served?(runner)).to be_truthy
+ end
+
+ it 'can handle build with matching tags' do
+ build.tag_list = ['bb']
+ expect(build.can_be_served?(runner)).to be_truthy
+ end
+
+ it 'cannot handle build with not matching tags' do
+ build.tag_list = ['aa']
+ expect(build.can_be_served?(runner)).to be_falsey
+ end
+ end
+ end
+
+ describe :any_runners_online? do
+ subject { build.any_runners_online? }
+
+ context 'when no runners' do
+ it { is_expected.to be_falsey }
+ end
+
+ context 'if there are runner' do
+ let(:runner) { FactoryGirl.create :ci_specific_runner }
+
+ before do
+ build.project.runners << runner
+ runner.update_attributes(contacted_at: 1.second.ago)
+ end
+
+ it { is_expected.to be_truthy }
+
+ it 'that is inactive' do
+ runner.update_attributes(active: false)
+ is_expected.to be_falsey
+ end
+
+ it 'that is not online' do
+ runner.update_attributes(contacted_at: nil)
+ is_expected.to be_falsey
+ end
+
+ it 'that cannot handle build' do
+ expect_any_instance_of(Ci::Build).to receive(:can_be_served?).and_return(false)
+ is_expected.to be_falsey
+ end
+
+ end
+ end
+
+ describe :show_warning? do
+ subject { build.show_warning? }
+
+ %w(pending).each do |state|
+ context "if commit_status.status is #{state}" do
+ before { build.status = state }
+
+ it { is_expected.to be_truthy }
+
+ context "and there are specific runner" do
+ let(:runner) { FactoryGirl.create :ci_specific_runner, contacted_at: 1.second.ago }
+
+ before do
+ build.project.runners << runner
+ runner.save
+ end
+
+ it { is_expected.to be_falsey }
end
end
end
+
+ %w(success failed canceled running).each do |state|
+ context "if commit_status.status is #{state}" do
+ before { build.status = state }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
end
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index c04bbcbadc7..44dbd083f06 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -21,20 +21,35 @@ describe Ci::Commit do
let(:project) { FactoryGirl.create :ci_project }
let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
- let(:commit_with_project) { FactoryGirl.create :ci_commit, gl_project: gl_project }
- let(:config_processor) { Ci::GitlabCiYamlProcessor.new(gitlab_ci_yaml) }
it { is_expected.to belong_to(:gl_project) }
+ it { is_expected.to have_many(:statuses) }
+ it { is_expected.to have_many(:trigger_requests) }
it { is_expected.to have_many(:builds) }
- it { is_expected.to validate_presence_of :before_sha }
it { is_expected.to validate_presence_of :sha }
- it { is_expected.to validate_presence_of :ref }
- it { is_expected.to validate_presence_of :push_data }
it { is_expected.to respond_to :git_author_name }
it { is_expected.to respond_to :git_author_email }
it { is_expected.to respond_to :short_sha }
+ describe :ordered do
+ let(:project) { FactoryGirl.create :empty_project }
+
+ it 'returns ordered list of commits' do
+ commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
+ commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
+ expect(project.ci_commits.ordered).to eq([commit2, commit1])
+ end
+
+ it 'returns commits ordered by committed_at and id, with nulls last' do
+ commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
+ commit2 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
+ commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
+ commit4 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
+ expect(project.ci_commits.ordered).to eq([commit2, commit4, commit3, commit1])
+ end
+ end
+
describe :last_build do
subject { commit.last_build }
before do
@@ -52,57 +67,12 @@ describe Ci::Commit do
@second = FactoryGirl.create :ci_build, commit: commit
end
- it "creates new build" do
+ it "creates only a new build" do
expect(commit.builds.count(:all)).to eq 2
+ expect(commit.statuses.count(:all)).to eq 2
commit.retry
expect(commit.builds.count(:all)).to eq 3
- end
- end
-
- describe :project_recipients do
-
- context 'always sending notification' do
- it 'should return commit_pusher_email as only recipient when no additional recipients are given' do
- project = FactoryGirl.create :ci_project,
- email_add_pusher: true,
- email_recipients: ''
- gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
- commit = FactoryGirl.create :ci_commit, gl_project: gl_project
- expected = 'commit_pusher_email'
- allow(commit).to receive(:push_data) { { user_email: expected } }
- expect(commit.project_recipients).to eq([expected])
- end
-
- it 'should return commit_pusher_email and additional recipients' do
- project = FactoryGirl.create :ci_project,
- email_add_pusher: true,
- email_recipients: 'rec1 rec2'
- gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
- commit = FactoryGirl.create :ci_commit, gl_project: gl_project
- expected = 'commit_pusher_email'
- allow(commit).to receive(:push_data) { { user_email: expected } }
- expect(commit.project_recipients).to eq(['rec1', 'rec2', expected])
- end
-
- it 'should return recipients' do
- project = FactoryGirl.create :ci_project,
- email_add_pusher: false,
- email_recipients: 'rec1 rec2'
- gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
- commit = FactoryGirl.create :ci_commit, gl_project: gl_project
- expect(commit.project_recipients).to eq(['rec1', 'rec2'])
- end
-
- it 'should return unique recipients only' do
- project = FactoryGirl.create :ci_project,
- email_add_pusher: true,
- email_recipients: 'rec1 rec1 rec2'
- gl_project = FactoryGirl.create :empty_project, gitlab_ci_project: project
- commit = FactoryGirl.create :ci_commit, gl_project: gl_project
- expected = 'rec2'
- allow(commit).to receive(:push_data) { { user_email: expected } }
- expect(commit.project_recipients).to eq(['rec1', 'rec2'])
- end
+ expect(commit.statuses.count(:all)).to eq 3
end
end
@@ -117,63 +87,122 @@ describe Ci::Commit do
end
end
- describe :compare? do
- subject { commit_with_project.compare? }
-
- context 'if commit.before_sha are not nil' do
- it { is_expected.to be_truthy }
- end
- end
-
describe :short_sha do
- subject { commit.short_before_sha }
+ subject { commit.short_sha }
it 'has 8 items' do
expect(subject.size).to eq(8)
end
- it { expect(commit.before_sha).to start_with(subject) }
+ it { expect(commit.sha).to start_with(subject) }
end
- describe :short_sha do
- subject { commit.short_sha }
+ describe :stage do
+ subject { commit.stage }
- it 'has 8 items' do
- expect(subject.size).to eq(8)
+ before do
+ @second = FactoryGirl.create :commit_status, commit: commit, name: 'deploy', stage: 'deploy', stage_idx: 1, status: 'pending'
+ @first = FactoryGirl.create :commit_status, commit: commit, name: 'test', stage: 'test', stage_idx: 0, status: 'pending'
+ end
+
+ it 'returns first running stage' do
+ is_expected.to eq('test')
+ end
+
+ context 'first build succeeded' do
+ before do
+ @first.success
+ end
+
+ it 'returns last running stage' do
+ is_expected.to eq('deploy')
+ end
+ end
+
+ context 'all builds succeeded' do
+ before do
+ @first.success
+ @second.success
+ end
+
+ it 'returns nil' do
+ is_expected.to be_nil
+ end
end
- it { expect(commit.sha).to start_with(subject) }
end
describe :create_next_builds do
+ end
+
+ describe :refs do
+ subject { commit.refs }
+
before do
- allow(commit).to receive(:config_processor).and_return(config_processor)
+ FactoryGirl.create :commit_status, commit: commit, name: 'deploy'
+ FactoryGirl.create :commit_status, commit: commit, name: 'deploy', ref: 'develop'
+ FactoryGirl.create :commit_status, commit: commit, name: 'deploy', ref: 'master'
end
- it "creates builds for next type" do
- expect(commit.create_builds).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(2)
+ it 'returns all refs' do
+ is_expected.to contain_exactly('master', 'develop', nil)
+ end
+ end
- expect(commit.create_next_builds(nil)).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(4)
+ describe :retried do
+ subject { commit.retried }
- expect(commit.create_next_builds(nil)).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(5)
+ before do
+ @commit1 = FactoryGirl.create :ci_build, commit: commit, name: 'deploy'
+ @commit2 = FactoryGirl.create :ci_build, commit: commit, name: 'deploy'
+ end
- expect(commit.create_next_builds(nil)).to be_falsey
+ it 'returns old builds' do
+ is_expected.to contain_exactly(@commit1)
end
end
describe :create_builds do
- before do
- allow(commit).to receive(:config_processor).and_return(config_processor)
+ let!(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
+
+ def create_builds(trigger_request = nil)
+ commit.create_builds('master', false, nil, trigger_request)
+ end
+
+ def create_next_builds
+ commit.create_next_builds(commit.builds.order(:id).last)
end
it 'creates builds' do
- expect(commit.create_builds).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(2)
+ expect(create_builds).to be_truthy
+ commit.builds.update_all(status: "success")
+ expect(commit.builds.count(:all)).to eq(2)
+
+ expect(create_next_builds).to be_truthy
+ commit.builds.update_all(status: "success")
+ expect(commit.builds.count(:all)).to eq(4)
+
+ expect(create_next_builds).to be_truthy
+ commit.builds.update_all(status: "success")
+ expect(commit.builds.count(:all)).to eq(5)
+
+ expect(create_next_builds).to be_falsey
+ end
+
+ context 'for different ref' do
+ def create_develop_builds
+ commit.create_builds('develop', false, nil, nil)
+ end
+
+ it 'creates builds' do
+ expect(create_builds).to be_truthy
+ commit.builds.update_all(status: "success")
+ expect(commit.builds.count(:all)).to eq(2)
+
+ expect(create_develop_builds).to be_truthy
+ commit.builds.update_all(status: "success")
+ expect(commit.builds.count(:all)).to eq(4)
+ expect(commit.refs.size).to eq(2)
+ expect(commit.builds.pluck(:name).uniq.size).to eq(2)
+ end
end
context 'for build triggers' do
@@ -181,46 +210,165 @@ describe Ci::Commit do
let(:trigger_request) { FactoryGirl.create :ci_trigger_request, commit: commit, trigger: trigger }
it 'creates builds' do
- expect(commit.create_builds(trigger_request)).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(2)
+ expect(create_builds(trigger_request)).to be_truthy
+ expect(commit.builds.count(:all)).to eq(2)
end
it 'rebuilds commit' do
- expect(commit.create_builds).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(2)
+ expect(create_builds).to be_truthy
+ expect(commit.builds.count(:all)).to eq(2)
- expect(commit.create_builds(trigger_request)).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(4)
+ expect(create_builds(trigger_request)).to be_truthy
+ expect(commit.builds.count(:all)).to eq(4)
end
it 'creates next builds' do
- expect(commit.create_builds(trigger_request)).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(2)
+ expect(create_builds(trigger_request)).to be_truthy
+ expect(commit.builds.count(:all)).to eq(2)
+ commit.builds.update_all(status: "success")
- expect(commit.create_next_builds(trigger_request)).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(4)
+ expect(create_next_builds).to be_truthy
+ expect(commit.builds.count(:all)).to eq(4)
end
context 'for [ci skip]' do
before do
- commit.push_data[:commits][0][:message] = 'skip this commit [ci skip]'
- commit.save
+ allow(commit).to receive(:git_commit_message) { 'message [ci skip]' }
end
it 'rebuilds commit' do
expect(commit.status).to eq('skipped')
- expect(commit.create_builds(trigger_request)).to be_truthy
- commit.builds.reload
- expect(commit.builds.size).to eq(2)
- expect(commit.status).to eq('pending')
+ expect(create_builds).to be_truthy
+
+ # since everything in Ci::Commit is cached we need to fetch a new object
+ new_commit = Ci::Commit.find_by_id(commit.id)
+ expect(new_commit.status).to eq('pending')
end
end
end
+
+ context 'properly creates builds when "when" is defined' do
+ let(:yaml) do
+ {
+ stages: ["build", "test", "test_failure", "deploy", "cleanup"],
+ build: {
+ stage: "build",
+ script: "BUILD",
+ },
+ test: {
+ stage: "test",
+ script: "TEST",
+ },
+ test_failure: {
+ stage: "test_failure",
+ script: "ON test failure",
+ when: "on_failure",
+ },
+ deploy: {
+ stage: "deploy",
+ script: "PUBLISH",
+ },
+ cleanup: {
+ stage: "cleanup",
+ script: "TIDY UP",
+ when: "always",
+ }
+ }
+ end
+
+ before do
+ stub_ci_commit_yaml_file(YAML.dump(yaml))
+ end
+
+ it 'properly creates builds' do
+ expect(create_builds).to be_truthy
+ expect(commit.builds.pluck(:name)).to contain_exactly('build')
+ expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'success', 'success')
+ expect(commit.status).to eq('success')
+ end
+
+ it 'properly creates builds when test fails' do
+ expect(create_builds).to be_truthy
+ expect(commit.builds.pluck(:name)).to contain_exactly('build')
+ expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+ commit.builds.running_or_pending.each(&:drop)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'success', 'success')
+ expect(commit.status).to eq('failed')
+ end
+
+ it 'properly creates builds when test and test_failure fails' do
+ expect(create_builds).to be_truthy
+ expect(commit.builds.pluck(:name)).to contain_exactly('build')
+ expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+ commit.builds.running_or_pending.each(&:drop)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'pending')
+ commit.builds.running_or_pending.each(&:drop)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'test_failure', 'cleanup')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'failed', 'failed', 'success')
+ expect(commit.status).to eq('failed')
+ end
+
+ it 'properly creates builds when deploy fails' do
+ expect(create_builds).to be_truthy
+ expect(commit.builds.pluck(:name)).to contain_exactly('build')
+ expect(commit.builds.pluck(:status)).to contain_exactly('pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'pending')
+ commit.builds.running_or_pending.each(&:drop)
+
+ expect(commit.builds.pluck(:name)).to contain_exactly('build', 'test', 'deploy', 'cleanup')
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'pending')
+ commit.builds.running_or_pending.each(&:success)
+
+ expect(commit.builds.pluck(:status)).to contain_exactly('success', 'success', 'failed', 'success')
+ expect(commit.status).to eq('failed')
+ end
+ end
end
describe "#finished_at" do
diff --git a/spec/models/ci/project_services/hip_chat_message_spec.rb b/spec/models/ci/project_services/hip_chat_message_spec.rb
index 1903c036924..e23d6ae2c28 100644
--- a/spec/models/ci/project_services/hip_chat_message_spec.rb
+++ b/spec/models/ci/project_services/hip_chat_message_spec.rb
@@ -3,70 +3,37 @@ require 'spec_helper'
describe Ci::HipChatMessage do
subject { Ci::HipChatMessage.new(build) }
- context "One build" do
- let(:commit) { FactoryGirl.create(:ci_commit_with_one_job) }
+ let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
- let(:build) do
- commit.create_builds
- commit.builds.first
- end
-
- context 'when build succeeds' do
- it 'returns a successful message' do
- build.update(status: "success")
-
- expect( subject.status_color ).to eq 'green'
- expect( subject.notify? ).to be_falsey
- expect( subject.to_s ).to match(/Build '[^']+' #\d+/)
- expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./)
- end
- end
-
- context 'when build fails' do
- it 'returns a failure message' do
- build.update(status: "failed")
-
- expect( subject.status_color ).to eq 'red'
- expect( subject.notify? ).to be_truthy
- expect( subject.to_s ).to match(/Build '[^']+' #\d+/)
- expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./)
- end
- end
+ let(:build) do
+ commit.builds.first
end
- context "Several builds" do
- let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
-
- let(:build) do
- commit.builds.first
- end
-
- context 'when all matrix builds succeed' do
- it 'returns a successful message' do
- commit.create_builds
- commit.builds.update_all(status: "success")
- commit.reload
+ context 'when all matrix builds succeed' do
+ it 'returns a successful message' do
+ commit.create_builds('master', false, nil)
+ commit.builds.update_all(status: "success")
+ commit.reload
- expect( subject.status_color ).to eq 'green'
- expect( subject.notify? ).to be_falsey
- expect( subject.to_s ).to match(/Commit #\d+/)
- expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./)
- end
+ expect(subject.status_color).to eq 'green'
+ expect(subject.notify?).to be_falsey
+ expect(subject.to_s).to match(/Commit #\d+/)
+ expect(subject.to_s).to match(/Successful in \d+ second\(s\)\./)
end
+ end
- context 'when at least one matrix build fails' do
- it 'returns a failure message' do
- commit.create_builds
- first_build = commit.builds.first
- second_build = commit.builds.last
- first_build.update(status: "success")
- second_build.update(status: "failed")
-
- expect( subject.status_color ).to eq 'red'
- expect( subject.notify? ).to be_truthy
- expect( subject.to_s ).to match(/Commit #\d+/)
- expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./)
- end
+ context 'when at least one matrix build fails' do
+ it 'returns a failure message' do
+ commit.create_builds('master', false, nil)
+ first_build = commit.builds.first
+ second_build = commit.builds.last
+ first_build.update(status: "success")
+ second_build.update(status: "failed")
+
+ expect(subject.status_color).to eq 'red'
+ expect(subject.notify?).to be_truthy
+ expect(subject.to_s).to match(/Commit #\d+/)
+ expect(subject.to_s).to match(/Failed in \d+ second\(s\)\./)
end
end
end
diff --git a/spec/models/ci/mail_service_spec.rb b/spec/models/ci/project_services/mail_service_spec.rb
index 0d9f85959ba..d9b3d34ff15 100644
--- a/spec/models/ci/mail_service_spec.rb
+++ b/spec/models/ci/project_services/mail_service_spec.rb
@@ -29,12 +29,13 @@ describe Ci::MailService do
describe 'Sends email for' do
let(:mail) { Ci::MailService.new }
+ let(:user) { User.new(notification_email: 'git@example.com')}
describe 'failed build' do
let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true) }
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
+ let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
before do
allow(mail).to receive_messages(
@@ -57,7 +58,7 @@ describe Ci::MailService do
let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) }
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
before do
allow(mail).to receive_messages(
@@ -85,7 +86,7 @@ describe Ci::MailService do
end
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
before do
allow(mail).to receive_messages(
@@ -114,7 +115,7 @@ describe Ci::MailService do
end
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
before do
allow(mail).to receive_messages(
@@ -143,7 +144,7 @@ describe Ci::MailService do
end
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ let(:build) { FactoryGirl.create(:ci_build, status: 'success', commit: commit, user: user) }
before do
allow(mail).to receive_messages(
@@ -166,7 +167,7 @@ describe Ci::MailService do
end
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
let(:commit) { FactoryGirl.create(:ci_commit, gl_project: gl_project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
+ let(:build) { FactoryGirl.create(:ci_build, status: 'failed', commit: commit, user: user) }
before do
allow(mail).to receive_messages(
diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb
index 7b541802d7d..8adda6c86cc 100644
--- a/spec/models/ci/project_services/slack_message_spec.rb
+++ b/spec/models/ci/project_services/slack_message_spec.rb
@@ -3,80 +3,41 @@ require 'spec_helper'
describe Ci::SlackMessage do
subject { Ci::SlackMessage.new(commit) }
- context "One build" do
- let(:commit) { FactoryGirl.create(:ci_commit_with_one_job) }
+ let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
- let(:build) do
- commit.create_builds
- commit.builds.first
- end
-
- context 'when build succeeded' do
- let(:color) { 'good' }
+ context 'when all matrix builds succeeded' do
+ let(:color) { 'good' }
- it 'returns a message with succeeded build' do
- build.update(status: "success")
+ it 'returns a message with success' do
+ commit.create_builds('master', false, nil)
+ commit.builds.update_all(status: "success")
+ commit.reload
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Build')
- expect(subject.fallback).to include("\##{build.id}")
- expect(subject.fallback).to include('succeeded')
- expect(subject.attachments.first[:fields]).to be_empty
- end
- end
-
- context 'when build failed' do
- let(:color) { 'danger' }
-
- it 'returns a message with failed build' do
- build.update(status: "failed")
-
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Build')
- expect(subject.fallback).to include("\##{build.id}")
- expect(subject.fallback).to include('failed')
- expect(subject.attachments.first[:fields]).to be_empty
- end
+ expect(subject.color).to eq(color)
+ expect(subject.fallback).to include('Commit')
+ expect(subject.fallback).to include("\##{commit.id}")
+ expect(subject.fallback).to include('succeeded')
+ expect(subject.attachments.first[:fields]).to be_empty
end
end
- context "Several builds" do
- let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
-
- context 'when all matrix builds succeeded' do
- let(:color) { 'good' }
-
- it 'returns a message with success' do
- commit.create_builds
- commit.builds.update_all(status: "success")
- commit.reload
-
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Commit')
- expect(subject.fallback).to include("\##{commit.id}")
- expect(subject.fallback).to include('succeeded')
- expect(subject.attachments.first[:fields]).to be_empty
- end
- end
-
- context 'when one of matrix builds failed' do
- let(:color) { 'danger' }
-
- it 'returns a message with information about failed build' do
- commit.create_builds
- first_build = commit.builds.first
- second_build = commit.builds.last
- first_build.update(status: "success")
- second_build.update(status: "failed")
-
- expect(subject.color).to eq(color)
- expect(subject.fallback).to include('Commit')
- expect(subject.fallback).to include("\##{commit.id}")
- expect(subject.fallback).to include('failed')
- expect(subject.attachments.first[:fields].size).to eq(1)
- expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
- expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
- end
+ context 'when one of matrix builds failed' do
+ let(:color) { 'danger' }
+
+ it 'returns a message with information about failed build' do
+ commit.create_builds('master', false, nil)
+ first_build = commit.builds.first
+ second_build = commit.builds.last
+ first_build.update(status: "success")
+ second_build.update(status: "failed")
+
+ expect(subject.color).to eq(color)
+ expect(subject.fallback).to include('Commit')
+ expect(subject.fallback).to include("\##{commit.id}")
+ expect(subject.fallback).to include('failed')
+ expect(subject.attachments.first[:fields].size).to eq(1)
+ expect(subject.attachments.first[:fields].first[:title]).to eq(second_build.name)
+ expect(subject.attachments.first[:fields].first[:value]).to include("\##{second_build.id}")
end
end
end
diff --git a/spec/models/ci/project_spec.rb b/spec/models/ci/project_spec.rb
index dec4720a711..490c6a67982 100644
--- a/spec/models/ci/project_spec.rb
+++ b/spec/models/ci/project_spec.rb
@@ -131,24 +131,6 @@ describe Ci::Project do
end
end
- describe 'ordered commits' do
- let(:project) { FactoryGirl.create :empty_project }
-
- it 'returns ordered list of commits' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
- expect(project.ci_commits).to eq([commit2, commit1])
- end
-
- it 'returns commits ordered by committed_at and id, with nulls last' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
- commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: project
- commit4 = FactoryGirl.create :ci_commit, committed_at: nil, gl_project: project
- expect(project.ci_commits).to eq([commit2, commit4, commit3, commit1])
- end
- end
-
context :valid_project do
let(:commit) { FactoryGirl.create(:ci_commit) }
@@ -259,5 +241,18 @@ describe Ci::Project do
FactoryGirl.create(:ci_shared_runner)
expect(project.any_runners?).to be_falsey
end
+
+ it "checks the presence of specific runner" do
+ project = FactoryGirl.create(:ci_project)
+ specific_runner = FactoryGirl.create(:ci_specific_runner)
+ project.runners << specific_runner
+ expect(project.any_runners? { |runner| runner == specific_runner }).to be_truthy
+ end
+
+ it "checks the presence of shared runner" do
+ project = FactoryGirl.create(:ci_project, shared_runners_enabled: true)
+ shared_runner = FactoryGirl.create(:ci_shared_runner)
+ expect(project.any_runners? { |runner| runner == shared_runner }).to be_truthy
+ end
end
end
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 757593a7ab8..f8a51c29dc2 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -32,7 +32,7 @@ describe Ci::Runner do
end
it 'should return the token if the description is an empty string' do
- runner = FactoryGirl.build(:ci_runner, description: '')
+ runner = FactoryGirl.build(:ci_runner, description: '', token: 'token')
expect(runner.display_name).to eq runner.token
end
end
@@ -48,6 +48,71 @@ describe Ci::Runner do
it { expect(shared_runner.only_for?(project)).to be_truthy }
end
+ describe :online do
+ subject { Ci::Runner.online }
+
+ before do
+ @runner1 = FactoryGirl.create(:ci_shared_runner, contacted_at: 1.year.ago)
+ @runner2 = FactoryGirl.create(:ci_shared_runner, contacted_at: 1.second.ago)
+ end
+
+ it { is_expected.to eq([@runner2])}
+ end
+
+ describe :online? do
+ let(:runner) { FactoryGirl.create(:ci_shared_runner) }
+
+ subject { runner.online? }
+
+ context 'never contacted' do
+ before { runner.contacted_at = nil }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'contacted long time ago time' do
+ before { runner.contacted_at = 1.year.ago }
+
+ it { is_expected.to be_falsey }
+ end
+
+ context 'contacted 1s ago' do
+ before { runner.contacted_at = 1.second.ago }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ describe :status do
+ let(:runner) { FactoryGirl.create(:ci_shared_runner, contacted_at: 1.second.ago) }
+
+ subject { runner.status }
+
+ context 'never connected' do
+ before { runner.contacted_at = nil }
+
+ it { is_expected.to eq(:not_connected) }
+ end
+
+ context 'contacted 1s ago' do
+ before { runner.contacted_at = 1.second.ago }
+
+ it { is_expected.to eq(:online) }
+ end
+
+ context 'contacted long time ago' do
+ before { runner.contacted_at = 1.year.ago }
+
+ it { is_expected.to eq(:offline) }
+ end
+
+ context 'inactive' do
+ before { runner.active = false }
+
+ it { is_expected.to eq(:paused) }
+ end
+ end
+
describe "belongs_to_one_project?" do
it "returns false if there are two projects runner assigned to" do
runner = FactoryGirl.create(:ci_specific_runner)
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index e303a97e6b5..90be9324951 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -89,9 +89,9 @@ eos
end
it_behaves_like 'a mentionable' do
- subject { commit }
+ subject { create(:project).commit }
- let(:author) { create(:user, email: commit.author_email) }
+ let(:author) { create(:user, email: subject.author_email) }
let(:backref_text) { "commit #{subject.id}" }
let(:set_mentionable_text) do
->(txt) { allow(subject).to receive(:safe_message).and_return(txt) }
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
new file mode 100644
index 00000000000..c96a606fdaa
--- /dev/null
+++ b/spec/models/commit_status_spec.rb
@@ -0,0 +1,164 @@
+require 'spec_helper'
+
+describe CommitStatus do
+ let(:commit) { FactoryGirl.create :ci_commit }
+ let(:commit_status) { FactoryGirl.create :commit_status, commit: commit }
+
+ it { is_expected.to belong_to(:commit) }
+ it { is_expected.to belong_to(:user) }
+ it { is_expected.to validate_presence_of(:name) }
+ it { is_expected.to validate_inclusion_of(:status).in_array(%w(pending running failed success canceled)) }
+
+ it { is_expected.to delegate_method(:sha).to(:commit) }
+ it { is_expected.to delegate_method(:short_sha).to(:commit) }
+ it { is_expected.to delegate_method(:gl_project).to(:commit) }
+
+ it { is_expected.to respond_to :success? }
+ it { is_expected.to respond_to :failed? }
+ it { is_expected.to respond_to :running? }
+ it { is_expected.to respond_to :pending? }
+
+ describe :author do
+ subject { commit_status.author }
+ before { commit_status.author = User.new }
+
+ it { is_expected.to eq(commit_status.user) }
+ end
+
+ describe :started? do
+ subject { commit_status.started? }
+
+ context 'without started_at' do
+ before { commit_status.started_at = nil }
+
+ it { is_expected.to be_falsey }
+ end
+
+ %w(running success failed).each do |status|
+ context "if commit status is #{status}" do
+ before { commit_status.status = status }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ %w(pending canceled).each do |status|
+ context "if commit status is #{status}" do
+ before { commit_status.status = status }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+
+ describe :active? do
+ subject { commit_status.active? }
+
+ %w(pending running).each do |state|
+ context "if commit_status.status is #{state}" do
+ before { commit_status.status = state }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ %w(success failed canceled).each do |state|
+ context "if commit_status.status is #{state}" do
+ before { commit_status.status = state }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+
+ describe :complete? do
+ subject { commit_status.complete? }
+
+ %w(success failed canceled).each do |state|
+ context "if commit_status.status is #{state}" do
+ before { commit_status.status = state }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ %w(pending running).each do |state|
+ context "if commit_status.status is #{state}" do
+ before { commit_status.status = state }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+ end
+
+ describe :duration do
+ subject { commit_status.duration }
+
+ it { is_expected.to eq(120.0) }
+
+ context 'if the building process has not started yet' do
+ before do
+ commit_status.started_at = nil
+ commit_status.finished_at = nil
+ end
+
+ it { is_expected.to be_nil }
+ end
+
+ context 'if the building process has started' do
+ before do
+ commit_status.started_at = Time.now - 1.minute
+ commit_status.finished_at = nil
+ end
+
+ it { is_expected.to be_a(Float) }
+ it { is_expected.to be > 0.0 }
+ end
+ end
+
+ describe :latest do
+ subject { CommitStatus.latest.order(:id) }
+
+ before do
+ @commit1 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'running'
+ @commit2 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'cc', status: 'pending'
+ @commit3 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'cc', status: 'success'
+ @commit4 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'bb', status: 'success'
+ @commit5 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'success'
+ end
+
+ it 'return unique statuses' do
+ is_expected.to eq([@commit2, @commit3, @commit4, @commit5])
+ end
+ end
+
+ describe :for_ref do
+ subject { CommitStatus.for_ref('bb').order(:id) }
+
+ before do
+ @commit1 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'running'
+ @commit2 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'cc', status: 'pending'
+ @commit3 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: nil, status: 'success'
+ end
+
+ it 'return statuses with equal and nil ref set' do
+ is_expected.to eq([@commit1])
+ end
+ end
+
+ describe :running_or_pending do
+ subject { CommitStatus.running_or_pending.order(:id) }
+
+ before do
+ @commit1 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: 'bb', status: 'running'
+ @commit2 = FactoryGirl.create :commit_status, commit: commit, name: 'cc', ref: 'cc', status: 'pending'
+ @commit3 = FactoryGirl.create :commit_status, commit: commit, name: 'aa', ref: nil, status: 'success'
+ @commit4 = FactoryGirl.create :commit_status, commit: commit, name: 'dd', ref: nil, status: 'failed'
+ @commit5 = FactoryGirl.create :commit_status, commit: commit, name: 'ee', ref: nil, status: 'canceled'
+ end
+
+ it 'return statuses that are running or pending' do
+ is_expected.to eq([@commit1, @commit2])
+ end
+ end
+end
diff --git a/spec/models/concerns/case_sensitivity_spec.rb b/spec/models/concerns/case_sensitivity_spec.rb
new file mode 100644
index 00000000000..f7ed30f8198
--- /dev/null
+++ b/spec/models/concerns/case_sensitivity_spec.rb
@@ -0,0 +1,189 @@
+require 'spec_helper'
+
+describe CaseSensitivity do
+ describe '.iwhere' do
+ let(:connection) { ActiveRecord::Base.connection }
+ let(:model) { Class.new { include CaseSensitivity } }
+
+ describe 'using PostgreSQL' do
+ before do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(true)
+ allow(Gitlab::Database).to receive(:mysql?).and_return(false)
+ end
+
+ describe 'with a single column/value pair' do
+ it 'returns the criteria for a column and a value' do
+ criteria = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:foo).
+ and_return('"foo"')
+
+ expect(model).to receive(:where).
+ with(%q{LOWER("foo") = LOWER(:value)}, value: 'bar').
+ and_return(criteria)
+
+ expect(model.iwhere(foo: 'bar')).to eq(criteria)
+ end
+
+ it 'returns the criteria for a column with a table, and a value' do
+ criteria = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:'foo.bar').
+ and_return('"foo"."bar"')
+
+ expect(model).to receive(:where).
+ with(%q{LOWER("foo"."bar") = LOWER(:value)}, value: 'bar').
+ and_return(criteria)
+
+ expect(model.iwhere(:'foo.bar' => 'bar')).to eq(criteria)
+ end
+ end
+
+ describe 'with multiple column/value pairs' do
+ it 'returns the criteria for a column and a value' do
+ initial = double(:criteria)
+ final = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:foo).
+ and_return('"foo"')
+
+ expect(connection).to receive(:quote_table_name).
+ with(:bar).
+ and_return('"bar"')
+
+ expect(model).to receive(:where).
+ with(%q{LOWER("foo") = LOWER(:value)}, value: 'bar').
+ and_return(initial)
+
+ expect(initial).to receive(:where).
+ with(%q{LOWER("bar") = LOWER(:value)}, value: 'baz').
+ and_return(final)
+
+ got = model.iwhere(foo: 'bar', bar: 'baz')
+
+ expect(got).to eq(final)
+ end
+
+ it 'returns the criteria for a column with a table, and a value' do
+ initial = double(:criteria)
+ final = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:'foo.bar').
+ and_return('"foo"."bar"')
+
+ expect(connection).to receive(:quote_table_name).
+ with(:'foo.baz').
+ and_return('"foo"."baz"')
+
+ expect(model).to receive(:where).
+ with(%q{LOWER("foo"."bar") = LOWER(:value)}, value: 'bar').
+ and_return(initial)
+
+ expect(initial).to receive(:where).
+ with(%q{LOWER("foo"."baz") = LOWER(:value)}, value: 'baz').
+ and_return(final)
+
+ got = model.iwhere(:'foo.bar' => 'bar',
+ :'foo.baz' => 'baz')
+
+ expect(got).to eq(final)
+ end
+ end
+ end
+
+ describe 'using MySQL' do
+ before do
+ allow(Gitlab::Database).to receive(:postgresql?).and_return(false)
+ allow(Gitlab::Database).to receive(:mysql?).and_return(true)
+ end
+
+ describe 'with a single column/value pair' do
+ it 'returns the criteria for a column and a value' do
+ criteria = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:foo).
+ and_return('`foo`')
+
+ expect(model).to receive(:where).
+ with(%q{`foo` = :value}, value: 'bar').
+ and_return(criteria)
+
+ expect(model.iwhere(foo: 'bar')).to eq(criteria)
+ end
+
+ it 'returns the criteria for a column with a table, and a value' do
+ criteria = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:'foo.bar').
+ and_return('`foo`.`bar`')
+
+ expect(model).to receive(:where).
+ with(%q{`foo`.`bar` = :value}, value: 'bar').
+ and_return(criteria)
+
+ expect(model.iwhere(:'foo.bar' => 'bar')).
+ to eq(criteria)
+ end
+ end
+
+ describe 'with multiple column/value pairs' do
+ it 'returns the criteria for a column and a value' do
+ initial = double(:criteria)
+ final = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:foo).
+ and_return('`foo`')
+
+ expect(connection).to receive(:quote_table_name).
+ with(:bar).
+ and_return('`bar`')
+
+ expect(model).to receive(:where).
+ with(%q{`foo` = :value}, value: 'bar').
+ and_return(initial)
+
+ expect(initial).to receive(:where).
+ with(%q{`bar` = :value}, value: 'baz').
+ and_return(final)
+
+ got = model.iwhere(foo: 'bar', bar: 'baz')
+
+ expect(got).to eq(final)
+ end
+
+ it 'returns the criteria for a column with a table, and a value' do
+ initial = double(:criteria)
+ final = double(:criteria)
+
+ expect(connection).to receive(:quote_table_name).
+ with(:'foo.bar').
+ and_return('`foo`.`bar`')
+
+ expect(connection).to receive(:quote_table_name).
+ with(:'foo.baz').
+ and_return('`foo`.`baz`')
+
+ expect(model).to receive(:where).
+ with(%q{`foo`.`bar` = :value}, value: 'bar').
+ and_return(initial)
+
+ expect(initial).to receive(:where).
+ with(%q{`foo`.`baz` = :value}, value: 'baz').
+ and_return(final)
+
+ got = model.iwhere(:'foo.bar' => 'bar',
+ :'foo.baz' => 'baz')
+
+ expect(got).to eq(final)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/concerns/mentionable_spec.rb b/spec/models/concerns/mentionable_spec.rb
index 2d6fe003215..6179882e935 100644
--- a/spec/models/concerns/mentionable_spec.rb
+++ b/spec/models/concerns/mentionable_spec.rb
@@ -25,7 +25,7 @@ describe Issue, "Mentionable" do
it 'correctly removes already-mentioned Commits' do
expect(SystemNoteService).not_to receive(:cross_reference)
- issue.create_cross_references!(project, author, [commit2])
+ issue.create_cross_references!(author, [commit2])
end
end
diff --git a/spec/models/generic_commit_status_spec.rb b/spec/models/generic_commit_status_spec.rb
new file mode 100644
index 00000000000..f442fa5fbe5
--- /dev/null
+++ b/spec/models/generic_commit_status_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe GenericCommitStatus do
+ let(:commit) { FactoryGirl.create :ci_commit }
+ let(:generic_commit_status) { FactoryGirl.create :generic_commit_status, commit: commit }
+
+ describe :context do
+ subject { generic_commit_status.context }
+ before { generic_commit_status.context = 'my_context' }
+
+ it { is_expected.to eq(generic_commit_status.name) }
+ end
+
+ describe :tags do
+ subject { generic_commit_status.tags }
+
+ it { is_expected.to eq([:external]) }
+ end
+
+ describe :set_default_values do
+ before do
+ generic_commit_status.context = nil
+ generic_commit_status.stage = nil
+ generic_commit_status.save
+ end
+
+ describe :context do
+ subject { generic_commit_status.context }
+
+ it { is_expected.to_not be_nil }
+ end
+
+ describe :stage do
+ subject { generic_commit_status.stage }
+
+ it { is_expected.to_not be_nil }
+ end
+ end
+end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index cf336d82957..623332cd2f9 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -69,7 +69,7 @@ describe Issue do
end
it_behaves_like 'an editable mentionable' do
- subject { create(:issue, project: project) }
+ subject { create(:issue) }
let(:backref_text) { "issue #{subject.to_reference}" }
let(:set_mentionable_text) { ->(txt){ subject.description = txt } }
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 17a49013d25..6aaf1c036b0 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -165,6 +165,17 @@ describe MergeRequest do
end
end
+ describe "#hook_attrs" do
+ it "has all the required keys" do
+ attrs = subject.hook_attrs
+ attrs = attrs.to_h
+ expect(attrs).to include(:source)
+ expect(attrs).to include(:target)
+ expect(attrs).to include(:last_commit)
+ expect(attrs).to include(:work_in_progress)
+ end
+ end
+
it_behaves_like 'an editable mentionable' do
subject { create(:merge_request) }
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 3a0b194ba1e..75564839dcf 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -192,10 +192,9 @@ describe Note do
end
it_behaves_like 'an editable mentionable' do
- subject { create :note, noteable: issue, project: project }
+ subject { create :note, noteable: issue, project: issue.project }
- let(:project) { create(:project) }
- let(:issue) { create :issue, project: project }
+ let(:issue) { create :issue }
let(:backref_text) { issue.gfm_reference }
let(:set_mentionable_text) { ->(txt) { subject.note = txt } }
end
diff --git a/spec/models/project_services/bamboo_service_spec.rb b/spec/models/project_services/bamboo_service_spec.rb
new file mode 100644
index 00000000000..c34b2487ecf
--- /dev/null
+++ b/spec/models/project_services/bamboo_service_spec.rb
@@ -0,0 +1,94 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
+#
+
+require 'spec_helper'
+
+describe BambooService, models: true do
+ describe "Associations" do
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
+ end
+
+ describe "Execute" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ context "when a password was previously set" do
+ before do
+ @bamboo_service = BambooService.create(
+ project: create(:project),
+ properties: {
+ bamboo_url: 'http://gitlab.com',
+ username: 'mic',
+ password: "password"
+ }
+ )
+ end
+
+ it "reset password if url changed" do
+ @bamboo_service.bamboo_url = 'http://gitlab1.com'
+ @bamboo_service.save
+ expect(@bamboo_service.password).to be_nil
+ end
+
+ it "does not reset password if username changed" do
+ @bamboo_service.username = "some_name"
+ @bamboo_service.save
+ expect(@bamboo_service.password).to eq("password")
+ end
+
+ it "does not reset password if new url is set together with password, even if it's the same password" do
+ @bamboo_service.bamboo_url = 'http://gitlab_edited.com'
+ @bamboo_service.password = 'password'
+ @bamboo_service.save
+ expect(@bamboo_service.password).to eq("password")
+ expect(@bamboo_service.bamboo_url).to eq("http://gitlab_edited.com")
+ end
+
+ it "should reset password if url changed, even if setter called multiple times" do
+ @bamboo_service.bamboo_url = 'http://gitlab1.com'
+ @bamboo_service.bamboo_url = 'http://gitlab1.com'
+ @bamboo_service.save
+ expect(@bamboo_service.password).to be_nil
+ end
+ end
+
+ context "when no password was previously set" do
+ before do
+ @bamboo_service = BambooService.create(
+ project: create(:project),
+ properties: {
+ bamboo_url: 'http://gitlab.com',
+ username: 'mic'
+ }
+ )
+ end
+
+ it "saves password if new url is set together with password" do
+ @bamboo_service.bamboo_url = 'http://gitlab_edited.com'
+ @bamboo_service.password = 'password'
+ @bamboo_service.save
+ expect(@bamboo_service.password).to eq("password")
+ expect(@bamboo_service.bamboo_url).to eq("http://gitlab_edited.com")
+ end
+
+ end
+ end
+end
diff --git a/spec/models/project_services/gitlab_ci_service_spec.rb b/spec/models/project_services/gitlab_ci_service_spec.rb
index 683a403a907..842089ebe0d 100644
--- a/spec/models/project_services/gitlab_ci_service_spec.rb
+++ b/spec/models/project_services/gitlab_ci_service_spec.rb
@@ -39,8 +39,7 @@ describe GitlabCiService do
end
describe :build_page do
- it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/refs/master/commits/2ab7834c")}
- it { expect(@service.build_page("issue#2", 'master')).to eq("http://localhost/ci/projects/#{@ci_project.id}/refs/master/commits/issue%232")}
+ it { expect(@service.build_page("2ab7834c", 'master')).to eq("http://localhost/#{@ci_project.gl_project.path_with_namespace}/commit/2ab7834c/ci")}
end
describe "execute" do
@@ -48,8 +47,8 @@ describe GitlabCiService do
let(:project) { create(:project, name: 'project') }
let(:push_sample_data) { Gitlab::PushDataBuilder.build_sample(project, user) }
- it "calls ci_yaml_file" do
- expect(@service).to receive(:ci_yaml_file).with(push_sample_data[:checkout_sha])
+ it "calls CreateCommitService" do
+ expect_any_instance_of(Ci::CreateCommitService).to receive(:execute).with(@ci_project, user, push_sample_data)
@service.execute(push_sample_data)
end
diff --git a/spec/models/project_services/teamcity_service_spec.rb b/spec/models/project_services/teamcity_service_spec.rb
new file mode 100644
index 00000000000..f26b47a856c
--- /dev/null
+++ b/spec/models/project_services/teamcity_service_spec.rb
@@ -0,0 +1,93 @@
+# == Schema Information
+#
+# Table name: services
+#
+# id :integer not null, primary key
+# type :string(255)
+# title :string(255)
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+# active :boolean default(FALSE), not null
+# properties :text
+# template :boolean default(FALSE)
+# push_events :boolean default(TRUE)
+# issues_events :boolean default(TRUE)
+# merge_requests_events :boolean default(TRUE)
+# tag_push_events :boolean default(TRUE)
+# note_events :boolean default(TRUE), not null
+#
+
+require 'spec_helper'
+
+describe TeamcityService, models: true do
+ describe "Associations" do
+ it { is_expected.to belong_to :project }
+ it { is_expected.to have_one :service_hook }
+ end
+
+ describe "Execute" do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+
+ context "when a password was previously set" do
+ before do
+ @teamcity_service = TeamcityService.create(
+ project: create(:project),
+ properties: {
+ teamcity_url: 'http://gitlab.com',
+ username: 'mic',
+ password: "password"
+ }
+ )
+ end
+
+ it "reset password if url changed" do
+ @teamcity_service.teamcity_url = 'http://gitlab1.com'
+ @teamcity_service.save
+ expect(@teamcity_service.password).to be_nil
+ end
+
+ it "does not reset password if username changed" do
+ @teamcity_service.username = "some_name"
+ @teamcity_service.save
+ expect(@teamcity_service.password).to eq("password")
+ end
+
+ it "does not reset password if new url is set together with password, even if it's the same password" do
+ @teamcity_service.teamcity_url = 'http://gitlab_edited.com'
+ @teamcity_service.password = 'password'
+ @teamcity_service.save
+ expect(@teamcity_service.password).to eq("password")
+ expect(@teamcity_service.teamcity_url).to eq("http://gitlab_edited.com")
+ end
+
+ it "should reset password if url changed, even if setter called multiple times" do
+ @teamcity_service.teamcity_url = 'http://gitlab1.com'
+ @teamcity_service.teamcity_url = 'http://gitlab1.com'
+ @teamcity_service.save
+ expect(@teamcity_service.password).to be_nil
+ end
+ end
+
+ context "when no password was previously set" do
+ before do
+ @teamcity_service = TeamcityService.create(
+ project: create(:project),
+ properties: {
+ teamcity_url: 'http://gitlab.com',
+ username: 'mic'
+ }
+ )
+ end
+
+ it "saves password if new url is set together with password" do
+ @teamcity_service.teamcity_url = 'http://gitlab_edited.com'
+ @teamcity_service.password = 'password'
+ @teamcity_service.save
+ expect(@teamcity_service.password).to eq("password")
+ expect(@teamcity_service.teamcity_url).to eq("http://gitlab_edited.com")
+ end
+ end
+ end
+end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 8b5d2c3a1c1..f93935ebe3b 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -423,4 +423,42 @@ describe Project do
it { expect(project.gitlab_ci?).to be_truthy }
it { expect(project.gitlab_ci_project).to be_a(Ci::Project) }
end
+
+ describe '.trending' do
+ let(:group) { create(:group) }
+ let(:project1) { create(:empty_project, :public, group: group) }
+ let(:project2) { create(:empty_project, :public, group: group) }
+
+ before do
+ 2.times do
+ create(:note_on_commit, project: project1)
+ end
+
+ create(:note_on_commit, project: project2)
+ end
+
+ describe 'without an explicit start date' do
+ subject { described_class.trending.to_a }
+
+ it 'sorts Projects by the amount of notes in descending order' do
+ expect(subject).to eq([project1, project2])
+ end
+ end
+
+ describe 'with an explicit start date' do
+ let(:date) { 2.months.ago }
+
+ subject { described_class.trending(date).to_a }
+
+ before do
+ 2.times do
+ create(:note_on_commit, project: project2, created_at: date)
+ end
+ end
+
+ it 'sorts Projects by the amount of notes in descending order' do
+ expect(subject).to eq([project2, project1])
+ end
+ end
+ end
end
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index a213ffe6c4b..692e5fda3ba 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -103,4 +103,125 @@ describe Service do
end
end
end
+
+ describe "{property}_changed?" do
+ let(:service) do
+ BambooService.create(
+ project: create(:project),
+ properties: {
+ bamboo_url: 'http://gitlab.com',
+ username: 'mic',
+ password: "password"
+ }
+ )
+ end
+
+ it "returns false when the property has not been assigned a new value" do
+ service.username = "key_changed"
+ expect(service.bamboo_url_changed?).to be_falsy
+ end
+
+ it "returns true when the property has been assigned a different value" do
+ service.bamboo_url = "http://example.com"
+ expect(service.bamboo_url_changed?).to be_truthy
+ end
+
+ it "returns true when the property has been assigned a different value twice" do
+ service.bamboo_url = "http://example.com"
+ service.bamboo_url = "http://example.com"
+ expect(service.bamboo_url_changed?).to be_truthy
+ end
+
+ it "returns false when the property has been re-assigned the same value" do
+ service.bamboo_url = 'http://gitlab.com'
+ expect(service.bamboo_url_changed?).to be_falsy
+ end
+
+ it "returns false when the property has been assigned a new value then saved" do
+ service.bamboo_url = 'http://example.com'
+ service.save
+ expect(service.bamboo_url_changed?).to be_falsy
+ end
+ end
+
+ describe "{property}_touched?" do
+ let(:service) do
+ BambooService.create(
+ project: create(:project),
+ properties: {
+ bamboo_url: 'http://gitlab.com',
+ username: 'mic',
+ password: "password"
+ }
+ )
+ end
+
+ it "returns false when the property has not been assigned a new value" do
+ service.username = "key_changed"
+ expect(service.bamboo_url_touched?).to be_falsy
+ end
+
+ it "returns true when the property has been assigned a different value" do
+ service.bamboo_url = "http://example.com"
+ expect(service.bamboo_url_touched?).to be_truthy
+ end
+
+ it "returns true when the property has been assigned a different value twice" do
+ service.bamboo_url = "http://example.com"
+ service.bamboo_url = "http://example.com"
+ expect(service.bamboo_url_touched?).to be_truthy
+ end
+
+ it "returns true when the property has been re-assigned the same value" do
+ service.bamboo_url = 'http://gitlab.com'
+ expect(service.bamboo_url_touched?).to be_truthy
+ end
+
+ it "returns false when the property has been assigned a new value then saved" do
+ service.bamboo_url = 'http://example.com'
+ service.save
+ expect(service.bamboo_url_changed?).to be_falsy
+ end
+ end
+
+ describe "{property}_was" do
+ let(:service) do
+ BambooService.create(
+ project: create(:project),
+ properties: {
+ bamboo_url: 'http://gitlab.com',
+ username: 'mic',
+ password: "password"
+ }
+ )
+ end
+
+
+ it "returns nil when the property has not been assigned a new value" do
+ service.username = "key_changed"
+ expect(service.bamboo_url_was).to be_nil
+ end
+
+ it "returns the previous value when the property has been assigned a different value" do
+ service.bamboo_url = "http://example.com"
+ expect(service.bamboo_url_was).to eq('http://gitlab.com')
+ end
+
+ it "returns initial value when the property has been re-assigned the same value" do
+ service.bamboo_url = 'http://gitlab.com'
+ expect(service.bamboo_url_was).to eq('http://gitlab.com')
+ end
+
+ it "returns initial value when the property has been assigned multiple values" do
+ service.bamboo_url = "http://example.com"
+ service.bamboo_url = "http://example2.com"
+ expect(service.bamboo_url_was).to eq('http://gitlab.com')
+ end
+
+ it "returns nil when the property has been assigned a new value then saved" do
+ service.bamboo_url = 'http://example.com'
+ service.save
+ expect(service.bamboo_url_was).to be_nil
+ end
+ end
end
diff --git a/spec/requests/api/commit_status_spec.rb b/spec/requests/api/commit_status_spec.rb
new file mode 100644
index 00000000000..b9e6dfc15a7
--- /dev/null
+++ b/spec/requests/api/commit_status_spec.rb
@@ -0,0 +1,135 @@
+require 'spec_helper'
+
+describe API::API, api: true do
+ include ApiHelpers
+ let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+ let!(:project) { create(:project, creator_id: user.id) }
+ let!(:reporter) { create(:project_member, user: user, project: project, access_level: ProjectMember::REPORTER) }
+ let!(:guest) { create(:project_member, user: user2, project: project, access_level: ProjectMember::GUEST) }
+ let(:commit) { project.repository.commit }
+ let!(:ci_commit) { project.ensure_ci_commit(commit.id) }
+ let(:commit_status) { create(:commit_status, commit: ci_commit) }
+
+ describe "GET /projects/:id/repository/commits/:sha/statuses" do
+ context "reporter user" do
+ let(:statuses_id) { json_response.map { |status| status['id'] } }
+
+ before do
+ @status1 = create(:commit_status, commit: ci_commit, status: 'running')
+ @status2 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'pending')
+ @status3 = create(:commit_status, commit: ci_commit, name: 'coverage', ref: 'develop', status: 'running')
+ @status4 = create(:commit_status, commit: ci_commit, name: 'coverage', status: 'success')
+ @status5 = create(:commit_status, commit: ci_commit, ref: 'develop', status: 'success')
+ @status6 = create(:commit_status, commit: ci_commit, status: 'success')
+ end
+
+ it "should return latest commit statuses" do
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user)
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(@status3.id, @status4.id, @status5.id, @status6.id)
+ end
+
+ it "should return all commit statuses" do
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?all=1", user)
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(@status1.id, @status2.id, @status3.id, @status4.id, @status5.id, @status6.id)
+ end
+
+ it "should return latest commit statuses for specific ref" do
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?ref=develop", user)
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(@status3.id, @status5.id)
+ end
+
+ it "should return latest commit statuses for specific name" do
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses?name=coverage", user)
+ expect(response.status).to eq(200)
+
+ expect(json_response).to be_an Array
+ expect(statuses_id).to contain_exactly(@status3.id, @status4.id)
+ end
+ end
+
+ context "guest user" do
+ it "should not return project commits" do
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses", user2)
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context "unauthorized user" do
+ it "should not return project commits" do
+ get api("/projects/#{project.id}/repository/commits/#{commit.id}/statuses")
+ expect(response.status).to eq(401)
+ end
+ end
+ end
+
+ describe 'POST /projects/:id/statuses/:sha' do
+ let(:post_url) { "/projects/#{project.id}/statuses/#{commit.id}" }
+
+ context 'reporter user' do
+ context 'should create commit status' do
+ it 'with only required parameters' do
+ post api(post_url, user), state: 'success'
+ expect(response.status).to eq(201)
+ expect(json_response['sha']).to eq(commit.id)
+ expect(json_response['status']).to eq('success')
+ expect(json_response['name']).to eq('default')
+ expect(json_response['ref']).to be_nil
+ expect(json_response['target_url']).to be_nil
+ expect(json_response['description']).to be_nil
+ end
+
+ it 'with all optional parameters' do
+ post api(post_url, user), state: 'success', context: 'coverage', ref: 'develop', target_url: 'url', description: 'test'
+ expect(response.status).to eq(201)
+ expect(json_response['sha']).to eq(commit.id)
+ expect(json_response['status']).to eq('success')
+ expect(json_response['name']).to eq('coverage')
+ expect(json_response['ref']).to eq('develop')
+ expect(json_response['target_url']).to eq('url')
+ expect(json_response['description']).to eq('test')
+ end
+ end
+
+ context 'should not create commit status' do
+ it 'with invalid state' do
+ post api(post_url, user), state: 'invalid'
+ expect(response.status).to eq(400)
+ end
+
+ it 'without state' do
+ post api(post_url, user)
+ expect(response.status).to eq(400)
+ end
+
+ it 'invalid commit' do
+ post api("/projects/#{project.id}/statuses/invalid_sha", user), state: 'running'
+ expect(response.status).to eq(404)
+ end
+ end
+ end
+
+ context 'guest user' do
+ it 'should not create commit status' do
+ post api(post_url, user2)
+ expect(response.status).to eq(403)
+ end
+ end
+
+ context 'unauthorized user' do
+ it 'should not create commit status' do
+ post api(post_url)
+ expect(response.status).to eq(401)
+ end
+ end
+ end
+end
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index a1c248c636e..49acc3368f4 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -47,6 +47,19 @@ describe API::API, api: true do
get api("/projects/#{project.id}/repository/commits/invalid_sha", user)
expect(response.status).to eq(404)
end
+
+ it "should return not_found for CI status" do
+ get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+ expect(response.status).to eq(200)
+ expect(json_response['status']).to eq('not_found')
+ end
+
+ it "should return status for CI" do
+ ci_commit = project.ensure_ci_commit(project.repository.commit.sha)
+ get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user)
+ expect(response.status).to eq(200)
+ expect(json_response['status']).to eq(ci_commit.status)
+ end
end
context "unauthorized user" do
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 35b3d3e296a..a68c7b1e461 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -379,9 +379,14 @@ describe API::API, api: true do
describe "POST /projects/:id/merge_request/:merge_request_id/comments" do
it "should return comment" do
+ original_count = merge_request.notes.size
+
post api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user), note: "My comment"
expect(response.status).to eq(201)
expect(json_response['note']).to eq('My comment')
+ expect(json_response['author']['name']).to eq(user.name)
+ expect(json_response['author']['username']).to eq(user.username)
+ expect(merge_request.notes.size).to eq(original_count + 1)
end
it "should return 400 if note is missing" do
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 09a79553f72..1149f7e7989 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -166,24 +166,21 @@ describe API::API, api: true do
get api("/projects/#{project.id}/repository/archive", user)
repo_name = project.repository.name.gsub("\.git", "")
expect(response.status).to eq(200)
- expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.tar.gz\"/)
- expect(response.content_type).to eq(MIME::Types.type_for('file.tar.gz').first.content_type)
+ expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/)
end
it "should get the archive.zip" do
get api("/projects/#{project.id}/repository/archive.zip", user)
repo_name = project.repository.name.gsub("\.git", "")
expect(response.status).to eq(200)
- expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.zip\"/)
- expect(response.content_type).to eq(MIME::Types.type_for('file.zip').first.content_type)
+ expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/)
end
it "should get the archive.tar.bz2" do
get api("/projects/#{project.id}/repository/archive.tar.bz2", user)
repo_name = project.repository.name.gsub("\.git", "")
expect(response.status).to eq(200)
- expect(response.headers['Content-Disposition']).to match(/filename\=\"#{repo_name}\-[^\.]+\.tar.bz2\"/)
- expect(response.content_type).to eq(MIME::Types.type_for('file.tar.bz2').first.content_type)
+ expect(json_response['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/)
end
it "should return 404 for invalid sha" do
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 9aa60826f21..c0226605a23 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -3,6 +3,8 @@ require "spec_helper"
describe API::API, api: true do
include ApiHelpers
let(:user) { create(:user) }
+ let(:admin) { create(:admin) }
+ let(:user2) { create(:user) }
let(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
Service.available_services_names.each do |service|
@@ -51,11 +53,40 @@ describe API::API, api: true do
describe "GET /projects/:id/services/#{service.dasherize}" do
include_context service
- it "should get #{service} settings" do
+ # inject some properties into the service
+ before do
+ project.build_missing_services
+ service_object = project.send(service_method)
+ service_object.properties = service_attrs
+ service_object.save
+ end
+
+ it 'should return authentication error when unauthenticated' do
+ get api("/projects/#{project.id}/services/#{dashed_service}")
+ expect(response.status).to eq(401)
+ end
+
+ it "should return all properties of service #{service} when authenticated as admin" do
+ get api("/projects/#{project.id}/services/#{dashed_service}", admin)
+
+ expect(response.status).to eq(200)
+ expect(json_response['properties'].keys.map(&:to_sym)).to match_array(service_attrs_list.map)
+ end
+
+ it "should return properties of service #{service} other than passwords when authenticated as project owner" do
get api("/projects/#{project.id}/services/#{dashed_service}", user)
expect(response.status).to eq(200)
+ expect(json_response['properties'].keys.map(&:to_sym)).to match_array(service_attrs_list_without_passwords)
end
+
+ it "should return error when authenticated but not a project owner" do
+ project.team << [user2, :developer]
+ get api("/projects/#{project.id}/services/#{dashed_service}", user2)
+
+ expect(response.status).to eq(403)
+ end
+
end
end
end
diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb
index bad250fbf48..88218a93e1f 100644
--- a/spec/requests/ci/api/builds_spec.rb
+++ b/spec/requests/ci/api/builds_spec.rb
@@ -7,6 +7,10 @@ describe Ci::API::API do
let(:project) { FactoryGirl.create(:ci_project) }
let(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
+
describe "Builds API for runners" do
let(:shared_runner) { FactoryGirl.create(:ci_runner, token: "SharedRunner") }
let(:shared_project) { FactoryGirl.create(:ci_project, name: "SharedProject") }
@@ -19,7 +23,7 @@ describe Ci::API::API do
describe "POST /builds/register" do
it "should start a build" do
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
- commit.create_builds
+ commit.create_builds('master', false, nil)
build = commit.builds.first
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
@@ -55,7 +59,7 @@ describe Ci::API::API do
it "returns options" do
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
- commit.create_builds
+ commit.create_builds('master', false, nil)
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
@@ -65,13 +69,15 @@ describe Ci::API::API do
it "returns variables" do
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
- commit.create_builds
+ commit.create_builds('master', false, nil)
project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
expect(response.status).to eq(201)
expect(json_response["variables"]).to eq([
+ { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
+ { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
{ "key" => "DB_NAME", "value" => "postgres", "public" => true },
{ "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
])
@@ -82,13 +88,16 @@ describe Ci::API::API do
commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
trigger_request = FactoryGirl.create(:ci_trigger_request_with_variables, commit: commit, trigger: trigger)
- commit.create_builds(trigger_request)
+ commit.create_builds('master', false, nil, trigger_request)
project.variables << Ci::Variable.new(key: "SECRET_KEY", value: "secret_value")
post ci_api("/builds/register"), token: runner.token, info: { platform: :darwin }
expect(response.status).to eq(201)
expect(json_response["variables"]).to eq([
+ { "key" => "CI_BUILD_NAME", "value" => "spinach", "public" => true },
+ { "key" => "CI_BUILD_STAGE", "value" => "test", "public" => true },
+ { "key" => "CI_BUILD_TRIGGERED", "value" => "true", "public" => true },
{ "key" => "DB_NAME", "value" => "postgres", "public" => true },
{ "key" => "SECRET_KEY", "value" => "secret_value", "public" => false },
{ "key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false },
diff --git a/spec/requests/ci/api/commits_spec.rb b/spec/requests/ci/api/commits_spec.rb
index a41c321a300..6049135fd10 100644
--- a/spec/requests/ci/api/commits_spec.rb
+++ b/spec/requests/ci/api/commits_spec.rb
@@ -44,8 +44,7 @@ describe Ci::API::API, 'Commits' do
"email" => "jordi@softcatala.org",
}
}
- ],
- ci_yaml_file: gitlab_ci_yaml
+ ]
}
end
diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb
index bbe98e7dacd..93617fc4b3f 100644
--- a/spec/requests/ci/api/triggers_spec.rb
+++ b/spec/requests/ci/api/triggers_spec.rb
@@ -5,8 +5,8 @@ describe Ci::API::API do
describe 'POST /projects/:project_id/refs/:ref/trigger' do
let!(:trigger_token) { 'secure token' }
- let!(:project) { FactoryGirl.create(:ci_project) }
- let!(:gl_project) { FactoryGirl.create(:empty_project, gitlab_ci_project: project) }
+ let!(:gl_project) { FactoryGirl.create(:project) }
+ let!(:project) { FactoryGirl.create(:ci_project, gl_project: gl_project) }
let!(:project2) { FactoryGirl.create(:ci_project) }
let!(:trigger) { FactoryGirl.create(:ci_trigger, project: project, token: trigger_token) }
let(:options) do
@@ -15,6 +15,10 @@ describe Ci::API::API do
}
end
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
+
context 'Handles errors' do
it 'should return bad request if token is missing' do
post ci_api("/projects/#{project.id}/refs/master/trigger")
@@ -33,15 +37,13 @@ describe Ci::API::API do
end
context 'Have a commit' do
- before do
- @commit = FactoryGirl.create(:ci_commit, gl_project: gl_project)
- end
+ let(:commit) { project.commits.last }
it 'should create builds' do
post ci_api("/projects/#{project.id}/refs/master/trigger"), options
expect(response.status).to eq(201)
- @commit.builds.reload
- expect(@commit.builds.size).to eq(2)
+ commit.builds.reload
+ expect(commit.builds.size).to eq(2)
end
it 'should return bad request with no builds created if there\'s no commit for that ref' do
@@ -70,8 +72,8 @@ describe Ci::API::API do
it 'create trigger request with variables' do
post ci_api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: variables)
expect(response.status).to eq(201)
- @commit.builds.reload
- expect(@commit.builds.first.trigger_request.variables).to eq(variables)
+ commit.builds.reload
+ expect(commit.builds.first.trigger_request.variables).to eq(variables)
end
end
end
diff --git a/spec/requests/ci/builds_spec.rb b/spec/requests/ci/builds_spec.rb
deleted file mode 100644
index f68116c52aa..00000000000
--- a/spec/requests/ci/builds_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require 'spec_helper'
-
-describe "Builds" do
- before do
- @commit = FactoryGirl.create :ci_commit
- @build = FactoryGirl.create :ci_build, commit: @commit
- end
-
- describe "GET /:project/builds/:id/status.json" do
- before do
- get status_ci_project_build_path(@commit.project, @build), format: :json
- end
-
- it { expect(response.status).to eq(200) }
- it { expect(response.body).to include(@build.sha) }
- end
-end
diff --git a/spec/requests/ci/commits_spec.rb b/spec/requests/ci/commits_spec.rb
deleted file mode 100644
index 3ab8c915dfd..00000000000
--- a/spec/requests/ci/commits_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require 'spec_helper'
-
-describe "Commits" do
- before do
- @commit = FactoryGirl.create :ci_commit
- end
-
- describe "GET /:project/refs/:ref_name/commits/:id/status.json" do
- before do
- get status_ci_project_ref_commits_path(@commit.project, @commit.ref, @commit.sha), format: :json
- end
-
- it { expect(response.status).to eq(200) }
- it { expect(response.body).to include(@commit.sha) }
- end
-end
diff --git a/spec/services/archive_repository_service_spec.rb b/spec/services/archive_repository_service_spec.rb
index 0ec70c51b3a..1cc7b240216 100644
--- a/spec/services/archive_repository_service_spec.rb
+++ b/spec/services/archive_repository_service_spec.rb
@@ -13,7 +13,7 @@ describe ArchiveRepositoryService do
context "when the repository doesn't have an archive file path" do
before do
- allow(project.repository).to receive(:archive_file_path).and_return(nil)
+ allow(project.repository).to receive(:archive_metadata).and_return(Hash.new)
end
it "raises an error" do
@@ -21,70 +21,5 @@ describe ArchiveRepositoryService do
end
end
- context "when the repository has an archive file path" do
- let(:file_path) { "/archive.zip" }
- let(:pid_file_path) { "/archive.zip.pid" }
-
- before do
- allow(project.repository).to receive(:archive_file_path).and_return(file_path)
- allow(project.repository).to receive(:archive_pid_file_path).and_return(pid_file_path)
- end
-
- context "when the archive file already exists" do
- before do
- allow(File).to receive(:exist?).with(file_path).and_return(true)
- end
-
- it "returns the file path" do
- expect(subject.execute(timeout: 0.0)).to eq(file_path)
- end
- end
-
- context "when the archive file doesn't exist yet" do
- before do
- allow(File).to receive(:exist?).with(file_path).and_return(false)
- allow(File).to receive(:exist?).with(pid_file_path).and_return(true)
- end
-
- context "when the archive pid file doesn't exist yet" do
- before do
- allow(File).to receive(:exist?).with(pid_file_path).and_return(false)
- end
-
- it "queues the RepositoryArchiveWorker" do
- expect(RepositoryArchiveWorker).to receive(:perform_async)
-
- subject.execute(timeout: 0.0)
- end
- end
-
- context "when the archive pid file already exists" do
- it "doesn't queue the RepositoryArchiveWorker" do
- expect(RepositoryArchiveWorker).not_to receive(:perform_async)
-
- subject.execute(timeout: 0.0)
- end
- end
-
- context "when the archive file exists after a little while" do
- before do
- Thread.new do
- sleep 0.1
- allow(File).to receive(:exist?).with(file_path).and_return(true)
- end
- end
-
- it "returns the file path" do
- expect(subject.execute(timeout: 0.2)).to eq(file_path)
- end
- end
-
- context "when the archive file doesn't exist after the timeout" do
- it "returns nil" do
- expect(subject.execute(timeout: 0.0)).to eq(nil)
- end
- end
- end
- end
end
end
diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb
index 84ab0a615dd..e3a8fe9681b 100644
--- a/spec/services/ci/create_commit_service_spec.rb
+++ b/spec/services/ci/create_commit_service_spec.rb
@@ -4,15 +4,19 @@ module Ci
describe CreateCommitService do
let(:service) { CreateCommitService.new }
let(:project) { FactoryGirl.create(:ci_project) }
+ let(:user) { nil }
+
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
describe :execute do
context 'valid params' do
let(:commit) do
- service.execute(project,
+ service.execute(project, user,
ref: 'refs/heads/master',
before: '00000000',
after: '31das312',
- ci_yaml_file: gitlab_ci_yaml,
commits: [ { message: "Message" } ]
)
end
@@ -26,11 +30,10 @@ module Ci
context "skip tag if there is no build for it" do
it "creates commit if there is appropriate job" do
- result = service.execute(project,
+ result = service.execute(project, user,
ref: 'refs/tags/0_1',
before: '00000000',
after: '31das312',
- ci_yaml_file: gitlab_ci_yaml,
commits: [ { message: "Message" } ]
)
expect(result).to be_persisted
@@ -38,12 +41,12 @@ module Ci
it "creates commit if there is no appropriate job but deploy job has right ref setting" do
config = YAML.dump({ deploy: { deploy: "ls", only: ["0_1"] } })
+ stub_ci_commit_yaml_file(config)
- result = service.execute(project,
+ result = service.execute(project, user,
ref: 'refs/heads/0_1',
before: '00000000',
after: '31das312',
- ci_yaml_file: config,
commits: [ { message: "Message" } ]
)
expect(result).to be_persisted
@@ -51,11 +54,11 @@ module Ci
end
it 'fails commits without .gitlab-ci.yml' do
- result = service.execute(project,
+ stub_ci_commit_yaml_file(nil)
+ result = service.execute(project, user,
ref: 'refs/heads/0_1',
before: '00000000',
after: '31das312',
- ci_yaml_file: config,
commits: [ { message: 'Message' } ]
)
expect(result).to be_persisted
@@ -64,41 +67,46 @@ module Ci
end
describe :ci_skip? do
+ let(:message) { "some message[ci skip]" }
+
+ before do
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { message }
+ end
+
it "skips builds creation if there is [ci skip] tag in commit message" do
- commits = [{ message: "some message[ci skip]" }]
- commit = service.execute(project,
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
ref: 'refs/tags/0_1',
before: '00000000',
after: '31das312',
- commits: commits,
- ci_yaml_file: gitlab_ci_yaml
+ commits: commits
)
expect(commit.builds.any?).to be false
expect(commit.status).to eq("skipped")
end
it "does not skips builds creation if there is no [ci skip] tag in commit message" do
- commits = [{ message: "some message" }]
+ allow_any_instance_of(Ci::Commit).to receive(:git_commit_message) { "some message" }
- commit = service.execute(project,
+ commits = [{ message: "some message" }]
+ commit = service.execute(project, user,
ref: 'refs/tags/0_1',
before: '00000000',
after: '31das312',
- commits: commits,
- ci_yaml_file: gitlab_ci_yaml
+ commits: commits
)
expect(commit.builds.first.name).to eq("staging")
end
it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do
- commits = [{ message: "some message[ci skip]" }]
- commit = service.execute(project,
+ stub_ci_commit_yaml_file('invalid: file')
+ commits = [{ message: message }]
+ commit = service.execute(project, user,
ref: 'refs/tags/0_1',
before: '00000000',
after: '31das312',
- commits: commits,
- ci_yaml_file: "invalid: file"
+ commits: commits
)
expect(commit.builds.any?).to be false
expect(commit.status).to eq("skipped")
@@ -106,35 +114,36 @@ module Ci
end
it "skips build creation if there are already builds" do
+ allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { gitlab_ci_yaml }
+
commits = [{ message: "message" }]
- commit = service.execute(project,
+ commit = service.execute(project, user,
ref: 'refs/heads/master',
before: '00000000',
after: '31das312',
- commits: commits,
- ci_yaml_file: gitlab_ci_yaml
+ commits: commits
)
expect(commit.builds.count(:all)).to eq(2)
- commit = service.execute(project,
+ commit = service.execute(project, user,
ref: 'refs/heads/master',
before: '00000000',
after: '31das312',
- commits: commits,
- ci_yaml_file: gitlab_ci_yaml
+ commits: commits
)
expect(commit.builds.count(:all)).to eq(2)
end
it "creates commit with failed status if yaml is invalid" do
+ stub_ci_commit_yaml_file('invalid: file')
+
commits = [{ message: "some message" }]
- commit = service.execute(project,
+ commit = service.execute(project, user,
ref: 'refs/tags/0_1',
before: '00000000',
after: '31das312',
- commits: commits,
- ci_yaml_file: "invalid: file"
+ commits: commits
)
expect(commit.status).to eq("failed")
diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb
index 525a24cc200..fcafae38644 100644
--- a/spec/services/ci/create_trigger_request_service_spec.rb
+++ b/spec/services/ci/create_trigger_request_service_spec.rb
@@ -2,20 +2,20 @@ require 'spec_helper'
describe Ci::CreateTriggerRequestService do
let(:service) { Ci::CreateTriggerRequestService.new }
- let(:project) { FactoryGirl.create :ci_project }
- let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
- let(:trigger) { FactoryGirl.create :ci_trigger, project: project }
+ let(:gl_project) { create(:project) }
+ let(:project) { create(:ci_project, gl_project: gl_project) }
+ let(:trigger) { create(:ci_trigger, project: project) }
+
+ before do
+ stub_ci_commit_to_return_yaml_file
+ end
describe :execute do
context 'valid params' do
subject { service.execute(project, trigger, 'master') }
- before do
- @commit = FactoryGirl.create :ci_commit, gl_project: gl_project
- end
-
it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
- it { expect(subject.commit).to eq(@commit) }
+ it { expect(subject.builds.first).to be_kind_of(Ci::Build) }
end
context 'no commit for ref' do
@@ -28,26 +28,11 @@ describe Ci::CreateTriggerRequestService do
subject { service.execute(project, trigger, 'master') }
before do
- FactoryGirl.create :ci_commit_without_jobs, gl_project: gl_project
+ stub_ci_commit_yaml_file('{}')
+ FactoryGirl.create :ci_commit, gl_project: gl_project
end
it { expect(subject).to be_nil }
end
-
- context 'for multiple commits' do
- subject { service.execute(project, trigger, 'master') }
-
- before do
- @commit1 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: gl_project
- @commit2 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
- @commit3 = FactoryGirl.create :ci_commit, committed_at: 3.hour.ago, gl_project: gl_project
- end
-
- context 'retries latest one' do
- it { expect(subject).to be_kind_of(Ci::TriggerRequest) }
- it { expect(subject).to be_persisted }
- it { expect(subject.commit).to eq(@commit2) }
- end
- end
end
end
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index c483060fd73..17015d29e51 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -112,6 +112,14 @@ describe GitPushService do
it { expect(@event.project).to eq(project) }
it { expect(@event.action).to eq(Event::PUSHED) }
it { expect(@event.data).to eq(service.push_data) }
+
+ context "Updates merge requests" do
+ it "when pushing a new branch for the first time" do
+ expect(project).to receive(:update_merge_requests).
+ with(@blankrev, 'newrev', 'refs/heads/master', user)
+ service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master')
+ end
+ end
end
describe "Web Hooks" do
@@ -155,7 +163,7 @@ describe GitPushService do
before do
allow(commit).to receive_messages(
- safe_message: "this commit \n mentions ##{issue.id}",
+ safe_message: "this commit \n mentions #{issue.to_reference}",
references: [issue],
author_name: commit_author.name,
author_email: commit_author.email
diff --git a/spec/services/merge_requests/refresh_service_spec.rb b/spec/services/merge_requests/refresh_service_spec.rb
index 9516e7936d8..227ac995ec2 100644
--- a/spec/services/merge_requests/refresh_service_spec.rb
+++ b/spec/services/merge_requests/refresh_service_spec.rb
@@ -106,6 +106,27 @@ describe MergeRequests::RefreshService do
it { expect(@fork_merge_request.notes).to be_empty }
end
+ context 'push new branch that exists in a merge request' do
+ let(:refresh_service) { service.new(@fork_project, @user) }
+
+ it 'refreshes the merge request' do
+ expect(refresh_service).to receive(:execute_hooks).
+ with(@fork_merge_request, 'update')
+ allow_any_instance_of(Repository).to receive(:merge_base).and_return(@oldrev)
+
+ refresh_service.execute(Gitlab::Git::BLANK_SHA, @newrev, 'refs/heads/master')
+ reload_mrs
+
+ expect(@merge_request.notes).to be_empty
+ expect(@merge_request).to be_open
+
+ notes = @fork_merge_request.notes.reorder(:created_at).map(&:note)
+ expect(notes[0]).to include('Restored source branch `master`')
+ expect(notes[1]).to include('Added 4 commits')
+ expect(@fork_merge_request).to be_open
+ end
+ end
+
def reload_mrs
@merge_request.reload
@fork_merge_request.reload
diff --git a/spec/services/projects/download_service_spec.rb b/spec/services/projects/download_service_spec.rb
index f12e09c58c3..ddee2e62dfc 100644
--- a/spec/services/projects/download_service_spec.rb
+++ b/spec/services/projects/download_service_spec.rb
@@ -37,7 +37,6 @@ describe Projects::DownloadService do
it { expect(@link_to_file).to have_key('url') }
it { expect(@link_to_file).to have_key('is_image') }
it { expect(@link_to_file['is_image']).to be true }
- it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
it { expect(@link_to_file['url']).to match('rails_sample.jpg') }
it { expect(@link_to_file['alt']).to eq('rails_sample') }
end
@@ -52,7 +51,6 @@ describe Projects::DownloadService do
it { expect(@link_to_file).to have_key('url') }
it { expect(@link_to_file).to have_key('is_image') }
it { expect(@link_to_file['is_image']).to be false }
- it { expect(@link_to_file['url']).to match("/#{@project.path_with_namespace}") }
it { expect(@link_to_file['url']).to match('doc_sample.txt') }
it { expect(@link_to_file['alt']).to eq('doc_sample.txt') }
end
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index bb7da33b12e..47755bfc990 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -7,6 +7,8 @@ describe Projects::TransferService do
context 'namespace -> namespace' do
before do
+ allow_any_instance_of(Gitlab::UploadsTransfer).
+ to receive(:move_project).and_return(true)
group.add_owner(user)
@result = transfer_project(project, user, group)
end
diff --git a/spec/services/projects/upload_service_spec.rb b/spec/services/projects/upload_service_spec.rb
index fa4ff6b01ad..1b1a80d1fe7 100644
--- a/spec/services/projects/upload_service_spec.rb
+++ b/spec/services/projects/upload_service_spec.rb
@@ -18,7 +18,6 @@ describe Projects::UploadService do
it { expect(@link_to_file).to have_key(:is_image) }
it { expect(@link_to_file).to have_value('banana_sample') }
it { expect(@link_to_file[:is_image]).to equal(true) }
- it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
it { expect(@link_to_file[:url]).to match('banana_sample.gif') }
end
@@ -34,7 +33,6 @@ describe Projects::UploadService do
it { expect(@link_to_file).to have_value('dk') }
it { expect(@link_to_file).to have_key(:is_image) }
it { expect(@link_to_file[:is_image]).to equal(true) }
- it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
it { expect(@link_to_file[:url]).to match('dk.png') }
end
@@ -49,7 +47,6 @@ describe Projects::UploadService do
it { expect(@link_to_file).to have_key(:is_image) }
it { expect(@link_to_file).to have_value('rails_sample') }
it { expect(@link_to_file[:is_image]).to equal(true) }
- it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
it { expect(@link_to_file[:url]).to match('rails_sample.jpg') }
end
@@ -64,7 +61,6 @@ describe Projects::UploadService do
it { expect(@link_to_file).to have_key(:is_image) }
it { expect(@link_to_file).to have_value('doc_sample.txt') }
it { expect(@link_to_file[:is_image]).to equal(false) }
- it { expect(@link_to_file[:url]).to match("/#{@project.path_with_namespace}") }
it { expect(@link_to_file[:url]).to match('doc_sample.txt') }
end
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index 48c49e2f717..a31fc1e4b07 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -13,8 +13,8 @@ describe SystemHooksService do
it { expect(event_data(user, :destroy)).to include(:event_name, :name, :created_at, :email, :user_id) }
it { expect(event_data(project, :create)).to include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
it { expect(event_data(project, :destroy)).to include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
- it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
- it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
+ it { expect(event_data(project_member, :create)).to include(:event_name, :created_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
+ it { expect(event_data(project_member, :destroy)).to include(:event_name, :created_at, :project_name, :project_path, :project_path_with_namespace, :project_id, :user_name, :user_email, :access_level, :project_visibility) }
it { expect(event_data(key, :create)).to include(:username, :key, :id) }
it { expect(event_data(key, :destroy)).to include(:username, :key, :id) }
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 2658576640c..a45130bd473 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -242,6 +242,18 @@ describe SystemNoteService do
end
end
+ describe '.change_branch_presence' do
+ subject { described_class.change_branch_presence(noteable, project, author, :source, 'feature', :delete) }
+
+ it_behaves_like 'a system note'
+
+ context 'when source branch deleted' do
+ it 'sets the note text' do
+ expect(subject.note).to eq "Deleted source branch `feature`"
+ end
+ end
+ end
+
describe '.cross_reference' do
subject { described_class.cross_reference(noteable, mentioner, author) }
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index dfe855926c6..2be13bb3e6a 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -14,6 +14,7 @@ require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'shoulda/matchers'
require 'sidekiq/testing/inline'
+require 'benchmark/ips'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
@@ -32,7 +33,7 @@ RSpec.configure do |config|
config.include TestEnv
config.include StubGitlabCalls
config.include StubGitlabData
-
+ config.include BenchmarkMatchers, benchmark: true
config.infer_spec_type_from_file_location!
config.raise_errors_for_deprecations!
@@ -42,4 +43,8 @@ RSpec.configure do |config|
end
end
+FactoryGirl::SyntaxRunner.class_eval do
+ include RSpec::Mocks::ExampleMethods
+end
+
ActiveRecord::Migration.maintain_test_schema!
diff --git a/spec/support/filter_spec_helper.rb b/spec/support/filter_spec_helper.rb
index 203117aee70..97e5c270a59 100644
--- a/spec/support/filter_spec_helper.rb
+++ b/spec/support/filter_spec_helper.rb
@@ -29,12 +29,19 @@ module FilterSpecHelper
#
# Returns the Hash
def pipeline_result(body, contexts = {})
- contexts.reverse_merge!(project: project)
+ contexts.reverse_merge!(project: project) if defined?(project)
pipeline = HTML::Pipeline.new([described_class], contexts)
pipeline.call(body)
end
+ def reference_pipeline_result(body, contexts = {})
+ contexts.reverse_merge!(project: project) if defined?(project)
+
+ pipeline = HTML::Pipeline.new([described_class, Gitlab::Markdown::ReferenceGathererFilter], contexts)
+ pipeline.call(body)
+ end
+
# Modify a String reference to make it invalid
#
# Commit SHAs get reversed, IDs get incremented by 1, all other Strings get
@@ -55,20 +62,6 @@ module FilterSpecHelper
end
end
- # Stub CrossProjectReference#user_can_reference_project? to return true for
- # the current test
- def allow_cross_reference!
- allow_any_instance_of(described_class).
- to receive(:user_can_reference_project?).and_return(true)
- end
-
- # Stub CrossProjectReference#user_can_reference_project? to return false for
- # the current test
- def disallow_cross_reference!
- allow_any_instance_of(described_class).
- to receive(:user_can_reference_project?).and_return(false)
- end
-
# Shortcut to Rails' auto-generated routes helpers, to avoid including the
# module
def urls
diff --git a/spec/support/markdown_feature.rb b/spec/support/markdown_feature.rb
index 39a64391460..bedc1a7f1db 100644
--- a/spec/support/markdown_feature.rb
+++ b/spec/support/markdown_feature.rb
@@ -15,18 +15,17 @@ class MarkdownFeature
end
def group
- unless @group
- @group = create(:group)
- @group.add_developer(user)
+ @group ||= create(:group).tap do |group|
+ group.add_developer(user)
end
-
- @group
end
# Direct references ----------------------------------------------------------
def project
- @project ||= create(:project)
+ @project ||= create(:project).tap do |project|
+ project.team << [user, :master]
+ end
end
def issue
@@ -46,12 +45,10 @@ class MarkdownFeature
end
def commit_range
- unless @commit_range
+ @commit_range ||= begin
commit2 = project.commit('HEAD~3')
- @commit_range = CommitRange.new("#{commit.id}...#{commit2.id}", project)
+ CommitRange.new("#{commit.id}...#{commit2.id}", project)
end
-
- @commit_range
end
def simple_label
@@ -65,13 +62,12 @@ class MarkdownFeature
# Cross-references -----------------------------------------------------------
def xproject
- unless @xproject
+ @xproject ||= begin
namespace = create(:namespace, name: 'cross-reference')
- @xproject = create(:project, namespace: namespace)
- @xproject.team << [user, :developer]
+ create(:project, namespace: namespace) do |project|
+ project.team << [user, :developer]
+ end
end
-
- @xproject
end
def xissue
@@ -91,12 +87,10 @@ class MarkdownFeature
end
def xcommit_range
- unless @xcommit_range
+ @xcommit_range ||= begin
xcommit2 = xproject.commit('HEAD~2')
- @xcommit_range = CommitRange.new("#{xcommit.id}...#{xcommit2.id}", xproject)
+ CommitRange.new("#{xcommit.id}...#{xcommit2.id}", xproject)
end
-
- @xcommit_range
end
def raw_markdown
diff --git a/spec/support/matchers/benchmark_matchers.rb b/spec/support/matchers/benchmark_matchers.rb
new file mode 100644
index 00000000000..84f655c2119
--- /dev/null
+++ b/spec/support/matchers/benchmark_matchers.rb
@@ -0,0 +1,61 @@
+module BenchmarkMatchers
+ extend RSpec::Matchers::DSL
+
+ def self.included(into)
+ into.extend(ClassMethods)
+ end
+
+ matcher :iterate_per_second do |min_iterations|
+ supports_block_expectations
+
+ match do |block|
+ @max_stddev ||= 30
+
+ @entry = benchmark(&block)
+
+ expect(@entry.ips).to be >= min_iterations
+ expect(@entry.stddev_percentage).to be <= @max_stddev
+ end
+
+ chain :with_maximum_stddev do |value|
+ @max_stddev = value
+ end
+
+ description do
+ "run at least #{min_iterations} iterations per second"
+ end
+
+ failure_message do
+ ips = @entry.ips.round(2)
+ stddev = @entry.stddev_percentage.round(2)
+
+ "expected at least #{min_iterations} iterations per second " \
+ "with a maximum stddev of #{@max_stddev}%, instead of " \
+ "#{ips} iterations per second with a stddev of #{stddev}%"
+ end
+ end
+
+ # Benchmarks the given block and returns a Benchmark::IPS::Report::Entry.
+ def benchmark(&block)
+ report = Benchmark.ips(quiet: true) do |bench|
+ bench.report do
+ instance_eval(&block)
+ end
+ end
+
+ report.entries[0]
+ end
+
+ module ClassMethods
+ # Wraps around rspec's subject method so you can write:
+ #
+ # benchmark_subject { SomeClass.some_method }
+ #
+ # instead of:
+ #
+ # subject { -> { SomeClass.some_method } }
+ def benchmark_subject(&block)
+ subject { block }
+ end
+ end
+end
diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb
index e3de0afb448..3bb568f4d49 100644
--- a/spec/support/mentionable_shared_examples.rb
+++ b/spec/support/mentionable_shared_examples.rb
@@ -5,7 +5,7 @@
# - let(:set_mentionable_text) { lambda { |txt| "block that assigns txt to the subject's mentionable_text" } }
def common_mentionable_setup
- let(:project) { create :project }
+ let(:project) { subject.project }
let(:author) { subject.author }
let(:mentioned_issue) { create(:issue, project: project) }
@@ -50,6 +50,8 @@ def common_mentionable_setup
}
extra_commits.each { |c| commitmap[c.short_id] = c }
+ allow(Project).to receive(:find).and_call_original
+ allow(Project).to receive(:find).with(project.id.to_s).and_return(project)
allow(project.repository).to receive(:commit) { |sha| commitmap[sha] }
set_mentionable_text.call(ref_string)
@@ -65,7 +67,7 @@ shared_examples 'a mentionable' do
it "extracts references from its reference property" do
# De-duplicate and omit itself
- refs = subject.references(project)
+ refs = subject.referenced_mentionables
expect(refs.size).to eq(6)
expect(refs).to include(mentioned_issue)
expect(refs).to include(mentioned_mr)
@@ -84,14 +86,7 @@ shared_examples 'a mentionable' do
with(referenced, subject.local_reference, author)
end
- subject.create_cross_references!(project, author)
- end
-
- it 'detects existing cross-references' do
- SystemNoteService.cross_reference(mentioned_issue, subject.local_reference, author)
-
- expect(subject).to have_mentioned(mentioned_issue)
- expect(subject).not_to have_mentioned(mentioned_mr)
+ subject.create_cross_references!
end
end
@@ -143,6 +138,6 @@ shared_examples 'an editable mentionable' do
end
set_mentionable_text.call(new_text)
- subject.create_new_cross_references!(project, author)
+ subject.create_new_cross_references!(author)
end
end
diff --git a/spec/support/services_shared_context.rb b/spec/support/services_shared_context.rb
index 4d007ae55ee..d1c999cad4d 100644
--- a/spec/support/services_shared_context.rb
+++ b/spec/support/services_shared_context.rb
@@ -3,7 +3,13 @@ Service.available_services_names.each do |service|
let(:dashed_service) { service.dasherize }
let(:service_method) { "#{service}_service".to_sym }
let(:service_klass) { "#{service}_service".classify.constantize }
- let(:service_attrs_list) { service_klass.new.fields.inject([]) {|arr, hash| arr << hash[:name].to_sym } }
+ let(:service_fields) { service_klass.new.fields }
+ let(:service_attrs_list) { service_fields.inject([]) {|arr, hash| arr << hash[:name].to_sym } }
+ let(:service_attrs_list_without_passwords) do
+ service_fields.
+ select { |field| field[:type] != 'password' }.
+ map { |field| field[:name].to_sym}
+ end
let(:service_attrs) do
service_attrs_list.inject({}) do |hash, k|
if k =~ /^(token*|.*_token|.*_key)/
diff --git a/spec/support/setup_builds_storage.rb b/spec/support/setup_builds_storage.rb
index a3e59646187..a4f21e95338 100644
--- a/spec/support/setup_builds_storage.rb
+++ b/spec/support/setup_builds_storage.rb
@@ -10,8 +10,10 @@ RSpec.configure do |config|
end
config.after(:suite) do
- Dir.chdir(builds_path) do
- `ls | grep -v .gitkeep | xargs rm -r`
+ Dir[File.join(builds_path, '*')].each do |path|
+ next if File.basename(path) == '.gitkeep'
+
+ FileUtils.rm_rf(path)
end
end
end
diff --git a/spec/support/stub_gitlab_calls.rb b/spec/support/stub_gitlab_calls.rb
index 5e6744afda1..5b3eb1bfc5f 100644
--- a/spec/support/stub_gitlab_calls.rb
+++ b/spec/support/stub_gitlab_calls.rb
@@ -13,6 +13,14 @@ module StubGitlabCalls
allow_any_instance_of(Network).to receive(:projects) { project_hash_array }
end
+ def stub_ci_commit_to_return_yaml_file
+ stub_ci_commit_yaml_file(gitlab_ci_yaml)
+ end
+
+ def stub_ci_commit_yaml_file(ci_yaml)
+ allow_any_instance_of(Ci::Commit).to receive(:ci_yaml_file) { ci_yaml }
+ end
+
private
def gitlab_url
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 3eab74ba986..d12ba25b71b 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -9,7 +9,7 @@ module TestEnv
'flatten-dir' => 'e56497b',
'feature' => '0b4bc9a',
'feature_conflict' => 'bb5206f',
- 'fix' => '12d65c8',
+ 'fix' => '48f0be4',
'improve/awesome' => '5937ac0',
'markdown' => '0ed8c6c',
'master' => '5937ac0',
diff --git a/spec/workers/repository_archive_worker_spec.rb b/spec/workers/repository_archive_worker_spec.rb
deleted file mode 100644
index a914d0ac8dc..00000000000
--- a/spec/workers/repository_archive_worker_spec.rb
+++ /dev/null
@@ -1,79 +0,0 @@
-require 'spec_helper'
-
-describe RepositoryArchiveWorker do
- let(:project) { create(:project) }
- subject { RepositoryArchiveWorker.new }
-
- before do
- allow(Project).to receive(:find).and_return(project)
- end
-
- describe "#perform" do
- it "cleans old archives" do
- expect(project.repository).to receive(:clean_old_archives)
-
- subject.perform(project.id, "master", "zip")
- end
-
- context "when the repository doesn't have an archive file path" do
- before do
- allow(project.repository).to receive(:archive_file_path).and_return(nil)
- end
-
- it "doesn't archive the repo" do
- expect(project.repository).not_to receive(:archive_repo)
-
- subject.perform(project.id, "master", "zip")
- end
- end
-
- context "when the repository has an archive file path" do
- let(:file_path) { "/archive.zip" }
- let(:pid_file_path) { "/archive.zip.pid" }
-
- before do
- allow(project.repository).to receive(:archive_file_path).and_return(file_path)
- allow(project.repository).to receive(:archive_pid_file_path).and_return(pid_file_path)
- end
-
- context "when the archive file already exists" do
- before do
- allow(File).to receive(:exist?).with(file_path).and_return(true)
- end
-
- it "doesn't archive the repo" do
- expect(project.repository).not_to receive(:archive_repo)
-
- subject.perform(project.id, "master", "zip")
- end
- end
-
- context "when the archive file doesn't exist yet" do
- before do
- allow(File).to receive(:exist?).with(file_path).and_return(false)
- allow(File).to receive(:exist?).with(pid_file_path).and_return(true)
- end
-
- context "when the archive pid file doesn't exist yet" do
- before do
- allow(File).to receive(:exist?).with(pid_file_path).and_return(false)
- end
-
- it "archives the repo" do
- expect(project.repository).to receive(:archive_repo)
-
- subject.perform(project.id, "master", "zip")
- end
- end
-
- context "when the archive pid file already exists" do
- it "doesn't archive the repo" do
- expect(project.repository).not_to receive(:archive_repo)
-
- subject.perform(project.id, "master", "zip")
- end
- end
- end
- end
- end
-end