summaryrefslogtreecommitdiff
path: root/spec/models
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models')
-rw-r--r--spec/models/abuse_report_spec.rb12
-rw-r--r--spec/models/application_setting_spec.rb48
-rw-r--r--spec/models/broadcast_message_spec.rb19
-rw-r--r--spec/models/build_spec.rb (renamed from spec/models/ci/build_spec.rb)316
-rw-r--r--spec/models/ci/commit_spec.rb396
-rw-r--r--spec/models/ci/project_services/hip_chat_message_spec.rb85
-rw-r--r--spec/models/ci/project_services/hip_chat_service_spec.rb7
-rw-r--r--spec/models/ci/project_services/mail_service_spec.rb (renamed from spec/models/ci/mail_service_spec.rb)93
-rw-r--r--spec/models/ci/project_services/slack_message_spec.rb99
-rw-r--r--spec/models/ci/project_services/slack_service_spec.rb7
-rw-r--r--spec/models/ci/project_spec.rb143
-rw-r--r--spec/models/ci/runner_project_spec.rb2
-rw-r--r--spec/models/ci/runner_spec.rb69
-rw-r--r--spec/models/ci/service_spec.rb7
-rw-r--r--spec/models/ci/trigger_spec.rb12
-rw-r--r--spec/models/ci/variable_spec.rb2
-rw-r--r--spec/models/ci/web_hook_spec.rb2
-rw-r--r--spec/models/commit_range_spec.rb127
-rw-r--r--spec/models/commit_spec.rb36
-rw-r--r--spec/models/commit_status_spec.rb197
-rw-r--r--spec/models/concerns/case_sensitivity_spec.rb189
-rw-r--r--spec/models/concerns/issuable_spec.rb1
-rw-r--r--spec/models/concerns/mentionable_spec.rb2
-rw-r--r--spec/models/concerns/strip_attribute_spec.rb20
-rw-r--r--spec/models/event_spec.rb38
-rw-r--r--spec/models/generic_commit_status_spec.rb72
-rw-r--r--spec/models/global_milestone_spec.rb65
-rw-r--r--spec/models/group_spec.rb47
-rw-r--r--spec/models/hooks/project_hook_spec.rb4
-rw-r--r--spec/models/hooks/service_hook_spec.rb2
-rw-r--r--spec/models/hooks/web_hook_spec.rb8
-rw-r--r--spec/models/issue_spec.rb39
-rw-r--r--spec/models/label_spec.rb1
-rw-r--r--spec/models/merge_request_spec.rb43
-rw-r--r--spec/models/milestone_spec.rb34
-rw-r--r--spec/models/namespace_spec.rb1
-rw-r--r--spec/models/note_spec.rb92
-rw-r--r--spec/models/project_services/bamboo_service_spec.rb94
-rw-r--r--spec/models/project_services/gitlab_ci_service_spec.rb29
-rw-r--r--spec/models/project_services/hipchat_service_spec.rb4
-rw-r--r--spec/models/project_services/jira_service_spec.rb6
-rw-r--r--spec/models/project_services/teamcity_service_spec.rb93
-rw-r--r--spec/models/project_spec.rb91
-rw-r--r--spec/models/project_team_spec.rb12
-rw-r--r--spec/models/project_wiki_spec.rb22
-rw-r--r--spec/models/release_spec.rb28
-rw-r--r--spec/models/repository_spec.rb109
-rw-r--r--spec/models/service_spec.rb121
-rw-r--r--spec/models/user_spec.rb87
-rw-r--r--spec/models/wiki_page_spec.rb2
50 files changed, 2311 insertions, 724 deletions
diff --git a/spec/models/abuse_report_spec.rb b/spec/models/abuse_report_spec.rb
index 635a6e2518c..d45319b25d4 100644
--- a/spec/models/abuse_report_spec.rb
+++ b/spec/models/abuse_report_spec.rb
@@ -16,4 +16,16 @@ RSpec.describe AbuseReport, type: :model do
subject { create(:abuse_report) }
it { expect(subject).to be_valid }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:reporter).class_name('User') }
+ it { is_expected.to belong_to(:user) }
+ end
+
+ describe 'validations' do
+ it { is_expected.to validate_presence_of(:reporter) }
+ it { is_expected.to validate_presence_of(:user) }
+ it { is_expected.to validate_presence_of(:message) }
+ it { is_expected.to validate_uniqueness_of(:user_id) }
+ end
end
diff --git a/spec/models/application_setting_spec.rb b/spec/models/application_setting_spec.rb
index de0b2ef4cda..b67b84959d9 100644
--- a/spec/models/application_setting_spec.rb
+++ b/spec/models/application_setting_spec.rb
@@ -23,16 +23,36 @@
# after_sign_out_path :string(255)
# session_expire_delay :integer default(10080), not null
# import_sources :text
+# help_page_text :text
+# admin_notification_email :string(255)
+# shared_runners_enabled :boolean default(TRUE), not null
+# max_artifacts_size :integer default(100), not null
#
require 'spec_helper'
describe ApplicationSetting, models: true do
- it { expect(ApplicationSetting.create_from_defaults).to be_valid }
+ let(:setting) { ApplicationSetting.create_from_defaults }
- context 'restricted signup domains' do
- let(:setting) { ApplicationSetting.create_from_defaults }
+ it { expect(setting).to be_valid }
+
+ describe 'validations' do
+ let(:http) { 'http://example.com' }
+ let(:https) { 'https://example.com' }
+ let(:ftp) { 'ftp://example.com' }
+
+ it { is_expected.to allow_value(nil).for(:home_page_url) }
+ it { is_expected.to allow_value(http).for(:home_page_url) }
+ it { is_expected.to allow_value(https).for(:home_page_url) }
+ it { is_expected.not_to allow_value(ftp).for(:home_page_url) }
+
+ it { is_expected.to allow_value(nil).for(:after_sign_out_path) }
+ it { is_expected.to allow_value(http).for(:after_sign_out_path) }
+ it { is_expected.to allow_value(https).for(:after_sign_out_path) }
+ it { is_expected.not_to allow_value(ftp).for(:after_sign_out_path) }
+ end
+ context 'restricted signup domains' do
it 'set single domain' do
setting.restricted_signup_domains_raw = 'example.com'
expect(setting.restricted_signup_domains).to eq(['example.com'])
@@ -53,4 +73,26 @@ describe ApplicationSetting, models: true do
expect(setting.restricted_signup_domains).to eq(['example.com', '*.example.com'])
end
end
+
+ context 'shared runners' do
+ let(:gl_project) { create(:empty_project) }
+
+ before do
+ allow_any_instance_of(Project).to receive(:current_application_settings).and_return(setting)
+ end
+
+ subject { gl_project.ensure_gitlab_ci_project.shared_runners_enabled }
+
+ context 'enabled' do
+ before { setting.update_attributes(shared_runners_enabled: true) }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'disabled' do
+ before { setting.update_attributes(shared_runners_enabled: false) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb
index 8ab72151a69..2b325f44f64 100644
--- a/spec/models/broadcast_message_spec.rb
+++ b/spec/models/broadcast_message_spec.rb
@@ -20,6 +20,21 @@ describe BroadcastMessage do
it { is_expected.to be_valid }
+ describe 'validations' do
+ let(:triplet) { '#000' }
+ let(:hex) { '#AABBCC' }
+
+ it { is_expected.to allow_value(nil).for(:color) }
+ it { is_expected.to allow_value(triplet).for(:color) }
+ it { is_expected.to allow_value(hex).for(:color) }
+ it { is_expected.not_to allow_value('000').for(:color) }
+
+ it { is_expected.to allow_value(nil).for(:font) }
+ it { is_expected.to allow_value(triplet).for(:font) }
+ it { is_expected.to allow_value(hex).for(:font) }
+ it { is_expected.not_to allow_value('000').for(:font) }
+ end
+
describe :current do
it "should return last message if time match" do
broadcast_message = create(:broadcast_message, starts_at: Time.now.yesterday, ends_at: Time.now.tomorrow)
@@ -27,12 +42,12 @@ describe BroadcastMessage do
end
it "should return nil if time not come" do
- broadcast_message = create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days)
+ create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days)
expect(BroadcastMessage.current).to be_nil
end
it "should return nil if time has passed" do
- broadcast_message = create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday)
+ create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday)
expect(BroadcastMessage.current).to be_nil
end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/build_spec.rb
index ce801152042..839b4c6b16e 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -27,16 +27,12 @@ require 'spec_helper'
describe Ci::Build do
let(:project) { FactoryGirl.create :ci_project }
- let(:commit) { FactoryGirl.create :ci_commit, project: project }
+ 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, 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
@@ -63,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? }
@@ -177,37 +107,23 @@ describe Ci::Build do
it { is_expected.to include(text) }
it { expect(subject.length).to be >= text.length }
end
- end
-
- describe :timeout do
- subject { build.timeout }
-
- it { is_expected.to eq(commit.project.timeout) }
- end
-
- describe :duration do
- subject { build.duration }
- it { is_expected.to eq(120.0) }
+ context 'if build.trace hides token' do
+ let(:token) { 'my_secret_token' }
- context 'if the building process has not started yet' do
before do
- build.started_at = nil
- build.finished_at = nil
+ build.project.update_attributes(token: token)
+ build.update_attributes(trace: token)
end
- it { is_expected.to be_nil }
+ it { is_expected.to_not include(token) }
end
+ end
- context 'if the building process has started' do
- before do
- build.started_at = Time.now - 1.minute
- build.finished_at = nil
- end
+ describe :timeout do
+ subject { build.timeout }
- it { is_expected.to be_a(Float) }
- it { is_expected.to be > 0.0 }
- end
+ it { is_expected.to eq(commit.project.timeout) }
end
describe :options do
@@ -224,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 }
@@ -308,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
@@ -327,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 }
@@ -337,14 +250,169 @@ 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
+
+ describe :download_url do
+ subject { build.download_url }
+
+ it "should be nil if artifact doesn't exist" do
+ build.update_attributes(artifacts_file: nil)
+ is_expected.to be_nil
+ end
+
+ it 'should be nil if artifact exist' do
+ gif = fixture_file_upload(Rails.root + 'spec/fixtures/banana_sample.gif', 'image/gif')
+ build.update_attributes(artifacts_file: gif)
+ is_expected.to_not be_nil
+ end
end
end
diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb
index 586c9dc23a7..a13f6458cac 100644
--- a/spec/models/ci/commit_spec.rb
+++ b/spec/models/ci/commit_spec.rb
@@ -1,39 +1,56 @@
# == Schema Information
#
-# Table name: commits
+# Table name: ci_commits
#
-# id :integer not null, primary key
-# project_id :integer
-# ref :string(255)
-# sha :string(255)
-# before_sha :string(255)
-# push_data :text
-# created_at :datetime
-# updated_at :datetime
-# tag :boolean default(FALSE)
-# yaml_errors :text
-# committed_at :datetime
+# id :integer not null, primary key
+# project_id :integer
+# ref :string(255)
+# sha :string(255)
+# before_sha :string(255)
+# push_data :text
+# created_at :datetime
+# updated_at :datetime
+# tag :boolean default(FALSE)
+# yaml_errors :text
+# committed_at :datetime
+# gl_project_id :integer
#
require 'spec_helper'
describe Ci::Commit do
let(:project) { FactoryGirl.create :ci_project }
- let(:commit) { FactoryGirl.create :ci_commit, project: project }
- let(:commit_with_project) { FactoryGirl.create :ci_commit, project: project }
- let(:config_processor) { Ci::GitlabCiYamlProcessor.new(gitlab_ci_yaml) }
+ let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
+ let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
- it { is_expected.to belong_to(:project) }
+ 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
@@ -51,53 +68,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: ''
- commit = FactoryGirl.create :ci_commit, project: 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'
- commit = FactoryGirl.create :ci_commit, project: 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'
- commit = FactoryGirl.create :ci_commit, project: 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'
- commit = FactoryGirl.create :ci_commit, project: 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
@@ -112,63 +88,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
@@ -176,61 +211,179 @@ 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
- let(:project) { FactoryGirl.create :ci_project }
- let(:commit) { FactoryGirl.create :ci_commit, project: project }
+ let(:commit) { FactoryGirl.create :ci_commit }
it "returns finished_at of latest build" do
build = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 60
- build1 = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 120
+ FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 120
expect(commit.finished_at.to_i).to eq(build.finished_at.to_i)
end
it "returns nil if there is no finished build" do
- build = FactoryGirl.create :ci_not_started_build, commit: commit
+ FactoryGirl.create :ci_not_started_build, commit: commit
expect(commit.finished_at).to be_nil
end
@@ -238,7 +391,8 @@ describe Ci::Commit do
describe "coverage" do
let(:project) { FactoryGirl.create :ci_project, coverage_regex: "/.*/" }
- let(:commit) { FactoryGirl.create :ci_commit, project: project }
+ let(:gl_project) { FactoryGirl.create :empty_project, gitlab_ci_project: project }
+ let(:commit) { FactoryGirl.create :ci_commit, gl_project: gl_project }
it "calculates average when there are two builds with coverage" do
FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit
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 49ac0860259..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,72 +3,37 @@ require 'spec_helper'
describe Ci::HipChatMessage do
subject { Ci::HipChatMessage.new(build) }
- let(:project) { FactoryGirl.create(:ci_project) }
+ let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
- context "One build" do
- let(:commit) { FactoryGirl.create(:ci_commit_with_one_job, project: project) }
-
- 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, project: project) }
-
- 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/project_services/hip_chat_service_spec.rb b/spec/models/ci/project_services/hip_chat_service_spec.rb
index 063d46b84d4..d9ccc855edf 100644
--- a/spec/models/ci/project_services/hip_chat_service_spec.rb
+++ b/spec/models/ci/project_services/hip_chat_service_spec.rb
@@ -33,15 +33,14 @@ describe Ci::HipChatService do
describe "Execute" do
let(:service) { Ci::HipChatService.new }
- let(:project) { FactoryGirl.create :ci_project }
- let(:commit) { FactoryGirl.create :ci_commit, project: project }
+ let(:commit) { FactoryGirl.create :ci_commit }
let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' }
before do
allow(service).to receive_messages(
- project: project,
- project_id: project.id,
+ project: commit.project,
+ project_id: commit.project_id,
notify_only_broken_builds: false,
hipchat_room: 123,
hipchat_token: 'a1b2c3d4e5f6'
diff --git a/spec/models/ci/mail_service_spec.rb b/spec/models/ci/project_services/mail_service_spec.rb
index b5f37b349db..c03be3ef75f 100644
--- a/spec/models/ci/mail_service_spec.rb
+++ b/spec/models/ci/project_services/mail_service_spec.rb
@@ -29,11 +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(:commit) { FactoryGirl.create(:ci_commit, project: project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
+ 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, user: user) }
before do
allow(mail).to receive_messages(
@@ -42,20 +44,18 @@ describe Ci::MailService do
end
it do
- should_email("git@example.com")
- mail.execute(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).to receive(:build_fail_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_success_email).with(build.id, email)
+ perform_enqueued_jobs do
+ expect{ mail.execute(build) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
+ expect(ActionMailer::Base.deliveries.last.to).to eq(["git@example.com"])
+ end
end
end
describe 'successfull build' do
let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) }
- let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ 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, user: user) }
before do
allow(mail).to receive_messages(
@@ -64,13 +64,10 @@ describe Ci::MailService do
end
it do
- should_email("git@example.com")
- mail.execute(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
+ perform_enqueued_jobs do
+ expect{ mail.execute(build) }.to change{ ActionMailer::Base.deliveries.size }.by(1)
+ expect(ActionMailer::Base.deliveries.last.to).to eq(["git@example.com"])
+ end
end
end
@@ -81,8 +78,9 @@ describe Ci::MailService do
email_only_broken_builds: false,
email_recipients: "jeroen@example.com")
end
- let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ 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, user: user) }
before do
allow(mail).to receive_messages(
@@ -91,14 +89,12 @@ describe Ci::MailService do
end
it do
- should_email("git@example.com")
- should_email("jeroen@example.com")
- mail.execute(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
+ perform_enqueued_jobs do
+ expect{ mail.execute(build) }.to change{ ActionMailer::Base.deliveries.size }.by(2)
+ expect(
+ ActionMailer::Base.deliveries.map(&:to).flatten
+ ).to include("git@example.com", "jeroen@example.com")
+ end
end
end
@@ -109,8 +105,9 @@ describe Ci::MailService do
email_only_broken_builds: true,
email_recipients: "jeroen@example.com")
end
- let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ 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, user: user) }
before do
allow(mail).to receive_messages(
@@ -119,14 +116,11 @@ describe Ci::MailService do
end
it do
- should_email(commit.git_author_email)
- should_email("jeroen@example.com")
- mail.execute(build) if mail.can_execute?(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).not_to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
+ perform_enqueued_jobs do
+ expect do
+ mail.execute(build) if mail.can_execute?(build)
+ end.to_not change{ ActionMailer::Base.deliveries.size }
+ end
end
end
@@ -137,8 +131,9 @@ describe Ci::MailService do
email_only_broken_builds: false,
email_recipients: "jeroen@example.com")
end
- let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) }
+ 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, user: user) }
before do
allow(mail).to receive_messages(
@@ -159,8 +154,9 @@ describe Ci::MailService do
email_only_broken_builds: true,
email_recipients: "jeroen@example.com")
end
- let(:commit) { FactoryGirl.create(:ci_commit, project: project) }
- let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) }
+ 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, user: user) }
before do
allow(mail).to receive_messages(
@@ -170,14 +166,11 @@ describe Ci::MailService do
it do
Ci::Build.retry(build)
- should_email(commit.git_author_email)
- should_email("jeroen@example.com")
- mail.execute(build) if mail.can_execute?(build)
- end
-
- def should_email(email)
- expect(Ci::Notify).not_to receive(:build_success_email).with(build.id, email)
- expect(Ci::Notify).not_to receive(:build_fail_email).with(build.id, email)
+ perform_enqueued_jobs do
+ expect do
+ mail.execute(build) if mail.can_execute?(build)
+ end.to_not change{ ActionMailer::Base.deliveries.size }
+ end
end
end
end
diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb
index f5335903728..8adda6c86cc 100644
--- a/spec/models/ci/project_services/slack_message_spec.rb
+++ b/spec/models/ci/project_services/slack_message_spec.rb
@@ -3,82 +3,41 @@ require 'spec_helper'
describe Ci::SlackMessage do
subject { Ci::SlackMessage.new(commit) }
- let(:project) { FactoryGirl.create :ci_project }
+ let(:commit) { FactoryGirl.create(:ci_commit_with_two_jobs) }
- context "One build" do
- let(:commit) { FactoryGirl.create(:ci_commit_with_one_job, project: project) }
+ context 'when all matrix builds succeeded' do
+ let(:color) { 'good' }
- let(:build) do
- commit.create_builds
- commit.builds.first
- end
-
- context 'when build succeeded' do
- let(:color) { 'good' }
-
- it 'returns a message with succeeded build' do
- build.update(status: "success")
-
- 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")
+ 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('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, project: project) }
-
- 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_services/slack_service_spec.rb b/spec/models/ci/project_services/slack_service_spec.rb
index 0524f472432..1ac7dfe568d 100644
--- a/spec/models/ci/project_services/slack_service_spec.rb
+++ b/spec/models/ci/project_services/slack_service_spec.rb
@@ -31,16 +31,15 @@ describe Ci::SlackService do
describe "Execute" do
let(:slack) { Ci::SlackService.new }
- let(:project) { FactoryGirl.create :ci_project }
- let(:commit) { FactoryGirl.create :ci_commit, project: project }
+ let(:commit) { FactoryGirl.create :ci_commit }
let(:build) { FactoryGirl.create :ci_build, commit: commit, status: 'failed' }
let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' }
let(:notify_only_broken_builds) { false }
before do
allow(slack).to receive_messages(
- project: project,
- project_id: project.id,
+ project: commit.project,
+ project_id: commit.project_id,
webhook: webhook_url,
notify_only_broken_builds: notify_only_broken_builds
)
diff --git a/spec/models/ci/project_spec.rb b/spec/models/ci/project_spec.rb
index 261ea69f5b4..ac7e38bbcb0 100644
--- a/spec/models/ci/project_spec.rb
+++ b/spec/models/ci/project_spec.rb
@@ -1,9 +1,9 @@
# == Schema Information
#
-# Table name: projects
+# Table name: ci_projects
#
# id :integer not null, primary key
-# name :string(255) not null
+# name :string(255)
# timeout :integer default(3600), not null
# created_at :datetime
# updated_at :datetime
@@ -28,13 +28,20 @@
require 'spec_helper'
describe Ci::Project do
- subject { FactoryGirl.build :ci_project }
+ let(:project) { FactoryGirl.create :ci_project }
+ let(:gl_project) { project.gl_project }
+ subject { project }
+
+ it { is_expected.to have_many(:runner_projects) }
+ it { is_expected.to have_many(:runners) }
+ it { is_expected.to have_many(:web_hooks) }
+ it { is_expected.to have_many(:events) }
+ it { is_expected.to have_many(:variables) }
+ it { is_expected.to have_many(:triggers) }
+ it { is_expected.to have_many(:services) }
- it { is_expected.to have_many(:commits) }
-
- it { is_expected.to validate_presence_of :name }
it { is_expected.to validate_presence_of :timeout }
- it { is_expected.to validate_presence_of :default_ref }
+ it { is_expected.to validate_presence_of :gitlab_id }
describe 'before_validation' do
it 'should set an random token if none provided' do
@@ -48,43 +55,89 @@ describe Ci::Project do
end
end
- describe "ordered_by_last_commit_date" do
- it "returns ordered projects" do
- newest_project = FactoryGirl.create :ci_project
- oldest_project = FactoryGirl.create :ci_project
- project_without_commits = FactoryGirl.create :ci_project
+ describe :name_with_namespace do
+ subject { project.name_with_namespace }
+
+ it { is_expected.to eq(project.name) }
+ it { is_expected.to eq(gl_project.name_with_namespace) }
+ end
+
+ describe :path_with_namespace do
+ subject { project.path_with_namespace }
+
+ it { is_expected.to eq(project.path) }
+ it { is_expected.to eq(gl_project.path_with_namespace) }
+ end
+
+ describe :path_with_namespace do
+ subject { project.web_url }
+
+ it { is_expected.to eq(gl_project.web_url) }
+ end
- FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: newest_project
- FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: oldest_project
+ describe :web_url do
+ subject { project.web_url }
- expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_project, oldest_project, project_without_commits])
+ it { is_expected.to eq(project.gitlab_url) }
+ it { is_expected.to eq(gl_project.web_url) }
+ end
+
+ describe :http_url_to_repo do
+ subject { project.http_url_to_repo }
+
+ it { is_expected.to eq(gl_project.http_url_to_repo) }
+ end
+
+ describe :ssh_url_to_repo do
+ subject { project.ssh_url_to_repo }
+
+ it { is_expected.to eq(gl_project.ssh_url_to_repo) }
+ end
+
+ describe :commits do
+ subject { project.commits }
+
+ before do
+ FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
end
+
+ it { is_expected.to eq(gl_project.ci_commits) }
end
- describe 'ordered commits' do
- let(:project) { FactoryGirl.create :ci_project }
+ describe :builds do
+ subject { project.builds }
- it 'returns ordered list of commits' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
- expect(project.commits).to eq([commit2, commit1])
+ before do
+ commit = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: gl_project
+ FactoryGirl.create :ci_build, commit: commit
end
- it 'returns commits ordered by committed_at and id, with nulls last' do
- commit1 = FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, project: project
- commit2 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
- commit3 = FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, project: project
- commit4 = FactoryGirl.create :ci_commit, committed_at: nil, project: project
- expect(project.commits).to eq([commit2, commit4, commit3, commit1])
+ it { is_expected.to eq(gl_project.ci_builds) }
+ end
+
+ describe "ordered_by_last_commit_date" do
+ it "returns ordered projects" do
+ newest_project = FactoryGirl.create :empty_project
+ newest_ci_project = newest_project.ensure_gitlab_ci_project
+ oldest_project = FactoryGirl.create :empty_project
+ oldest_ci_project = oldest_project.ensure_gitlab_ci_project
+ project_without_commits = FactoryGirl.create :empty_project
+ ci_project_without_commits = project_without_commits.ensure_gitlab_ci_project
+
+ FactoryGirl.create :ci_commit, committed_at: 1.hour.ago, gl_project: newest_project
+ FactoryGirl.create :ci_commit, committed_at: 2.hour.ago, gl_project: oldest_project
+
+ expect(Ci::Project.ordered_by_last_commit_date).to eq([newest_ci_project, oldest_ci_project, ci_project_without_commits])
end
end
context :valid_project do
- let(:project) { FactoryGirl.create :ci_project }
+ let(:commit) { FactoryGirl.create(:ci_commit) }
context :project_with_commit_and_builds do
+ let(:project) { commit.project }
+
before do
- commit = FactoryGirl.create(:ci_commit, project: project)
FactoryGirl.create(:ci_build, commit: commit)
end
@@ -141,18 +194,6 @@ describe Ci::Project do
end
end
- describe 'Project.parse' do
- let(:project) { FactoryGirl.create :project }
-
- subject { Ci::Project.parse(project) }
-
- it { is_expected.to be_valid }
- it { is_expected.to be_kind_of(Ci::Project) }
- it { expect(subject.name).to eq(project.name_with_namespace) }
- it { expect(subject.gitlab_id).to eq(project.id) }
- it { expect(subject.gitlab_url).to eq(project.web_url) }
- end
-
describe :repo_url_with_auth do
let(:project) { FactoryGirl.create :ci_project }
subject { project.repo_url_with_auth }
@@ -165,13 +206,6 @@ describe Ci::Project do
it { is_expected.to include(project.gitlab_url[7..-1]) }
end
- describe :search do
- let!(:project) { FactoryGirl.create(:ci_project, name: "foo") }
-
- it { expect(Ci::Project.search('fo')).to include(project) }
- it { expect(Ci::Project.search('bar')).to be_empty }
- end
-
describe :any_runners do
it "there are no runners available" do
project = FactoryGirl.create(:ci_project)
@@ -195,5 +229,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_project_spec.rb b/spec/models/ci/runner_project_spec.rb
index 0218d484130..37682c6ea0c 100644
--- a/spec/models/ci/runner_project_spec.rb
+++ b/spec/models/ci/runner_project_spec.rb
@@ -1,6 +1,6 @@
# == Schema Information
#
-# Table name: runner_projects
+# Table name: ci_runner_projects
#
# id :integer not null, primary key
# runner_id :integer not null
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 757593a7ab8..9a1233b9095 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -1,6 +1,6 @@
# == Schema Information
#
-# Table name: runners
+# Table name: ci_runners
#
# id :integer not null, primary key
# token :string(255)
@@ -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/ci/service_spec.rb b/spec/models/ci/service_spec.rb
index 2c575056b08..36cda988eb4 100644
--- a/spec/models/ci/service_spec.rb
+++ b/spec/models/ci/service_spec.rb
@@ -1,6 +1,6 @@
# == Schema Information
#
-# Table name: services
+# Table name: ci_services
#
# id :integer not null, primary key
# type :string(255)
@@ -29,13 +29,12 @@ describe Ci::Service do
end
describe "Testable" do
- let(:project) { FactoryGirl.create :ci_project }
- let(:commit) { FactoryGirl.create :ci_commit, project: project }
+ let(:commit) { FactoryGirl.create :ci_commit }
let(:build) { FactoryGirl.create :ci_build, commit: commit }
before do
allow(@service).to receive_messages(
- project: project
+ project: commit.project
)
build
@testable = @service.can_test?
diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb
index 19c14ef2da2..b8aa3c1e777 100644
--- a/spec/models/ci/trigger_spec.rb
+++ b/spec/models/ci/trigger_spec.rb
@@ -1,3 +1,15 @@
+# == Schema Information
+#
+# Table name: ci_triggers
+#
+# id :integer not null, primary key
+# token :string(255)
+# project_id :integer not null
+# deleted_at :datetime
+# created_at :datetime
+# updated_at :datetime
+#
+
require 'spec_helper'
describe Ci::Trigger do
diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb
index d034a6c7b9f..a515f5881ff 100644
--- a/spec/models/ci/variable_spec.rb
+++ b/spec/models/ci/variable_spec.rb
@@ -1,6 +1,6 @@
# == Schema Information
#
-# Table name: variables
+# Table name: ci_variables
#
# id :integer not null, primary key
# project_id :integer not null
diff --git a/spec/models/ci/web_hook_spec.rb b/spec/models/ci/web_hook_spec.rb
index bf9481ab81d..2865482a212 100644
--- a/spec/models/ci/web_hook_spec.rb
+++ b/spec/models/ci/web_hook_spec.rb
@@ -1,6 +1,6 @@
# == Schema Information
#
-# Table name: web_hooks
+# Table name: ci_web_hooks
#
# id :integer not null, primary key
# url :string(255) not null
diff --git a/spec/models/commit_range_spec.rb b/spec/models/commit_range_spec.rb
index 1031af097bd..3c1009a2eb0 100644
--- a/spec/models/commit_range_spec.rb
+++ b/spec/models/commit_range_spec.rb
@@ -7,50 +7,72 @@ describe CommitRange do
it { is_expected.to include_module(Referable) }
end
- let(:sha_from) { 'f3f85602' }
- let(:sha_to) { 'e86e1013' }
+ let!(:project) { create(:project, :public) }
+ let!(:commit1) { project.commit("HEAD~2") }
+ let!(:commit2) { project.commit }
- let(:range) { described_class.new("#{sha_from}...#{sha_to}") }
- let(:range2) { described_class.new("#{sha_from}..#{sha_to}") }
+ let(:sha_from) { commit1.short_id }
+ let(:sha_to) { commit2.short_id }
+
+ let(:full_sha_from) { commit1.id }
+ let(:full_sha_to) { commit2.id }
+
+ let(:range) { described_class.new("#{sha_from}...#{sha_to}", project) }
+ let(:range2) { described_class.new("#{sha_from}..#{sha_to}", project) }
it 'raises ArgumentError when given an invalid range string' do
- expect { described_class.new("Foo") }.to raise_error(ArgumentError)
+ expect { described_class.new("Foo", project) }.to raise_error(ArgumentError)
end
describe '#to_s' do
it 'is correct for three-dot syntax' do
- expect(range.to_s).to eq "#{sha_from[0..7]}...#{sha_to[0..7]}"
+ expect(range.to_s).to eq "#{full_sha_from}...#{full_sha_to}"
end
it 'is correct for two-dot syntax' do
- expect(range2.to_s).to eq "#{sha_from[0..7]}..#{sha_to[0..7]}"
+ expect(range2.to_s).to eq "#{full_sha_from}..#{full_sha_to}"
end
end
describe '#to_reference' do
- let(:project) { double('project', to_reference: 'namespace1/project') }
+ let(:cross) { create(:project) }
+
+ it 'returns a String reference to the object' do
+ expect(range.to_reference).to eq "#{full_sha_from}...#{full_sha_to}"
+ end
+
+ it 'returns a String reference to the object' do
+ expect(range2.to_reference).to eq "#{full_sha_from}..#{full_sha_to}"
+ end
+
+ it 'supports a cross-project reference' do
+ expect(range.to_reference(cross)).to eq "#{project.to_reference}@#{full_sha_from}...#{full_sha_to}"
+ end
+ end
- before do
- range.project = project
+ describe '#reference_link_text' do
+ let(:cross) { create(:project) }
+
+ it 'returns a String reference to the object' do
+ expect(range.reference_link_text).to eq "#{sha_from}...#{sha_to}"
end
it 'returns a String reference to the object' do
- expect(range.to_reference).to eq range.to_s
+ expect(range2.reference_link_text).to eq "#{sha_from}..#{sha_to}"
end
it 'supports a cross-project reference' do
- cross = double('project')
- expect(range.to_reference(cross)).to eq "#{project.to_reference}@#{range.to_s}"
+ expect(range.reference_link_text(cross)).to eq "#{project.to_reference}@#{sha_from}...#{sha_to}"
end
end
describe '#reference_title' do
it 'returns the correct String for three-dot ranges' do
- expect(range.reference_title).to eq "Commits #{sha_from} through #{sha_to}"
+ expect(range.reference_title).to eq "Commits #{full_sha_from} through #{full_sha_to}"
end
it 'returns the correct String for two-dot ranges' do
- expect(range2.reference_title).to eq "Commits #{sha_from}^ through #{sha_to}"
+ expect(range2.reference_title).to eq "Commits #{full_sha_from}^ through #{full_sha_to}"
end
end
@@ -60,11 +82,11 @@ describe CommitRange do
end
it 'includes the correct values for a three-dot range' do
- expect(range.to_param).to eq({ from: sha_from, to: sha_to })
+ expect(range.to_param).to eq({ from: full_sha_from, to: full_sha_to })
end
it 'includes the correct values for a two-dot range' do
- expect(range2.to_param).to eq({ from: sha_from + '^', to: sha_to })
+ expect(range2.to_param).to eq({ from: full_sha_from + '^', to: full_sha_to })
end
end
@@ -79,64 +101,37 @@ describe CommitRange do
end
describe '#valid_commits?' do
- context 'without a project' do
- it 'returns nil' do
- expect(range.valid_commits?).to be_nil
+ context 'with a valid repo' do
+ before do
+ expect(project).to receive(:valid_repo?).and_return(true)
end
- end
-
- it 'accepts an optional project argument' do
- project1 = double('project1').as_null_object
- project2 = double('project2').as_null_object
-
- # project1 gets assigned through the accessor, but ignored when not given
- # as an argument to `valid_commits?`
- expect(project1).not_to receive(:present?)
- range.project = project1
-
- # project2 gets passed to `valid_commits?`
- expect(project2).to receive(:present?).and_return(false)
- range.valid_commits?(project2)
- end
-
- context 'with a project' do
- let(:project) { double('project', repository: double('repository')) }
+ it 'is false when `sha_from` is invalid' do
+ expect(project).to receive(:commit).with(sha_from).and_return(nil)
+ expect(project).to receive(:commit).with(sha_to).and_call_original
- context 'with a valid repo' do
- before do
- expect(project).to receive(:valid_repo?).and_return(true)
- range.project = project
- end
+ expect(range).not_to be_valid_commits
+ end
- it 'is false when `sha_from` is invalid' do
- expect(project.repository).to receive(:commit).with(sha_from).and_return(false)
- expect(project.repository).not_to receive(:commit).with(sha_to)
- expect(range).not_to be_valid_commits
- end
+ it 'is false when `sha_to` is invalid' do
+ expect(project).to receive(:commit).with(sha_from).and_call_original
+ expect(project).to receive(:commit).with(sha_to).and_return(nil)
- it 'is false when `sha_to` is invalid' do
- expect(project.repository).to receive(:commit).with(sha_from).and_return(true)
- expect(project.repository).to receive(:commit).with(sha_to).and_return(false)
- expect(range).not_to be_valid_commits
- end
+ expect(range).not_to be_valid_commits
+ end
- it 'is true when both `sha_from` and `sha_to` are valid' do
- expect(project.repository).to receive(:commit).with(sha_from).and_return(true)
- expect(project.repository).to receive(:commit).with(sha_to).and_return(true)
- expect(range).to be_valid_commits
- end
+ it 'is true when both `sha_from` and `sha_to` are valid' do
+ expect(range).to be_valid_commits
end
+ end
- context 'without a valid repo' do
- before do
- expect(project).to receive(:valid_repo?).and_return(false)
- range.project = project
- end
+ context 'without a valid repo' do
+ before do
+ expect(project).to receive(:valid_repo?).and_return(false)
+ end
- it 'returns false' do
- expect(range).not_to be_valid_commits
- end
+ it 'returns false' do
+ expect(range).not_to be_valid_commits
end
end
end
diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb
index e303a97e6b5..38a3dc1f4a6 100644
--- a/spec/models/commit_spec.rb
+++ b/spec/models/commit_spec.rb
@@ -24,6 +24,17 @@ describe Commit do
end
end
+ describe '#reference_link_text' do
+ it 'returns a String reference to the object' do
+ expect(commit.reference_link_text).to eq commit.short_id
+ end
+
+ it 'supports a cross-project reference' do
+ cross = double('project')
+ expect(commit.reference_link_text(cross)).to eq "#{project.to_reference}@#{commit.short_id}"
+ end
+ end
+
describe '#title' do
it "returns no_commit_message when safe_message is blank" do
allow(commit).to receive(:safe_message).and_return('')
@@ -77,21 +88,17 @@ eos
let(:other_issue) { create :issue, project: other_project }
it 'detects issues that this commit is marked as closing' do
- allow(commit).to receive(:safe_message).and_return("Fixes ##{issue.iid}")
- expect(commit.closes_issues).to eq([issue])
- end
-
- it 'does not detect issues from other projects' do
ext_ref = "#{other_project.path_with_namespace}##{other_issue.iid}"
- allow(commit).to receive(:safe_message).and_return("Fixes #{ext_ref}")
- expect(commit.closes_issues).to be_empty
+ allow(commit).to receive(:safe_message).and_return("Fixes ##{issue.iid} and #{ext_ref}")
+ expect(commit.closes_issues).to include(issue)
+ expect(commit.closes_issues).to include(other_issue)
end
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) }
@@ -100,4 +107,15 @@ eos
# Include the subject in the repository stub.
let(:extra_commits) { [subject] }
end
+
+ describe '#hook_attrs' do
+ let(:data) { commit.hook_attrs(with_changed_files: true) }
+
+ it { expect(data).to be_a(Hash) }
+ it { expect(data[:message]).to include('Add submodule from gitlab.com') }
+ it { expect(data[:timestamp]).to eq('2014-02-27T11:01:38+02:00') }
+ it { expect(data[:added]).to eq(["gitlab-grack"]) }
+ it { expect(data[:modified]).to eq([".gitmodules"]) }
+ it { expect(data[:removed]).to eq([]) }
+ end
end
diff --git a/spec/models/commit_status_spec.rb b/spec/models/commit_status_spec.rb
new file mode 100644
index 00000000000..dca0715eed8
--- /dev/null
+++ b/spec/models/commit_status_spec.rb
@@ -0,0 +1,197 @@
+# == Schema Information
+#
+# Table name: ci_builds
+#
+# id :integer not null, primary key
+# project_id :integer
+# status :string(255)
+# finished_at :datetime
+# trace :text
+# created_at :datetime
+# updated_at :datetime
+# started_at :datetime
+# runner_id :integer
+# coverage :float
+# commit_id :integer
+# commands :text
+# job_id :integer
+# name :string(255)
+# deploy :boolean default(FALSE)
+# options :text
+# allow_failure :boolean default(FALSE), not null
+# stage :string(255)
+# trigger_request_id :integer
+# stage_idx :integer
+# tag :boolean
+# ref :string(255)
+# user_id :integer
+# type :string(255)
+# target_url :string(255)
+# description :string(255)
+# artifacts_file :text
+#
+
+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/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 8f706f8934b..0f13c4410cd 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -68,7 +68,6 @@ describe Issue, "Issuable" do
end
end
-
describe "#to_hook_data" do
let(:hook_data) { issue.to_hook_data(user) }
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/concerns/strip_attribute_spec.rb b/spec/models/concerns/strip_attribute_spec.rb
new file mode 100644
index 00000000000..6445e29c3ef
--- /dev/null
+++ b/spec/models/concerns/strip_attribute_spec.rb
@@ -0,0 +1,20 @@
+require 'spec_helper'
+
+describe Milestone, "StripAttribute" do
+ let(:milestone) { create(:milestone) }
+
+ describe ".strip_attributes" do
+ it { expect(Milestone).to respond_to(:strip_attributes) }
+ it { expect(Milestone.strip_attrs).to include(:title) }
+ end
+
+ describe "#strip_attributes" do
+ before do
+ milestone.title = ' 8.3 '
+ milestone.valid?
+ end
+
+ it { expect(milestone.title).to eq('8.3') }
+ end
+
+end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index 0f32f162a10..ae53f7a536b 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -64,4 +64,42 @@ describe Event do
it { expect(@event.branch_name).to eq("master") }
it { expect(@event.author).to eq(@user) }
end
+
+ describe '.latest_update_time' do
+ describe 'when events are present' do
+ let(:time) { Time.utc(2015, 1, 1) }
+
+ before do
+ create(:closed_issue_event, updated_at: time)
+ create(:closed_issue_event, updated_at: time + 5)
+ end
+
+ it 'returns the latest update time' do
+ expect(Event.latest_update_time).to eq(time + 5)
+ end
+ end
+
+ describe 'when no events exist' do
+ it 'returns nil' do
+ expect(Event.latest_update_time).to be_nil
+ end
+ end
+ end
+
+ describe '.limit_recent' do
+ let!(:event1) { create(:closed_issue_event) }
+ let!(:event2) { create(:closed_issue_event) }
+
+ describe 'without an explicit limit' do
+ subject { Event.limit_recent }
+
+ it { is_expected.to eq([event2, event1]) }
+ end
+
+ describe 'with an explicit limit' do
+ subject { Event.limit_recent(1) }
+
+ it { is_expected.to eq([event2]) }
+ end
+ 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..c86314c454c
--- /dev/null
+++ b/spec/models/generic_commit_status_spec.rb
@@ -0,0 +1,72 @@
+# == Schema Information
+#
+# Table name: ci_builds
+#
+# id :integer not null, primary key
+# project_id :integer
+# status :string(255)
+# finished_at :datetime
+# trace :text
+# created_at :datetime
+# updated_at :datetime
+# started_at :datetime
+# runner_id :integer
+# coverage :float
+# commit_id :integer
+# commands :text
+# job_id :integer
+# name :string(255)
+# deploy :boolean default(FALSE)
+# options :text
+# allow_failure :boolean default(FALSE), not null
+# stage :string(255)
+# trigger_request_id :integer
+# stage_idx :integer
+# tag :boolean
+# ref :string(255)
+# user_id :integer
+# type :string(255)
+# target_url :string(255)
+# description :string(255)
+# artifacts_file :text
+#
+
+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/global_milestone_spec.rb b/spec/models/global_milestone_spec.rb
new file mode 100644
index 00000000000..6eeff30b20e
--- /dev/null
+++ b/spec/models/global_milestone_spec.rb
@@ -0,0 +1,65 @@
+require 'spec_helper'
+
+describe GlobalMilestone do
+ let(:user) { create(:user) }
+ let(:user2) { create(:user) }
+ let(:group) { create(:group) }
+ let(:project1) { create(:project, group: group) }
+ let(:project2) { create(:project, path: 'gitlab-ci', group: group) }
+ let(:project3) { create(:project, path: 'cookbook-gitlab', group: group) }
+ let(:milestone1_project1) { create(:milestone, title: "Milestone v1.2", project: project1) }
+ let(:milestone1_project2) { create(:milestone, title: "Milestone v1.2", project: project2) }
+ let(:milestone1_project3) { create(:milestone, title: "Milestone v1.2", project: project3) }
+ let(:milestone2_project1) { create(:milestone, title: "VD-123", project: project1) }
+ let(:milestone2_project2) { create(:milestone, title: "VD-123", project: project2) }
+ let(:milestone2_project3) { create(:milestone, title: "VD-123", project: project3) }
+
+ describe :build_collection do
+ before do
+ milestones =
+ [
+ milestone1_project1,
+ milestone1_project2,
+ milestone1_project3,
+ milestone2_project1,
+ milestone2_project2,
+ milestone2_project3
+ ]
+
+ @global_milestones = GlobalMilestone.build_collection(milestones)
+ end
+
+ it 'should have all project milestones' do
+ expect(@global_milestones.count).to eq(2)
+ end
+
+ it 'should have all project milestones titles' do
+ expect(@global_milestones.map(&:title)).to match_array(['Milestone v1.2', 'VD-123'])
+ end
+
+ it 'should have all project milestones' do
+ expect(@global_milestones.map { |group_milestone| group_milestone.milestones.count }.sum).to eq(6)
+ end
+ end
+
+ describe :initialize do
+ before do
+ milestones =
+ [
+ milestone1_project1,
+ milestone1_project2,
+ milestone1_project3,
+ ]
+
+ @global_milestone = GlobalMilestone.new(milestone1_project1.title, milestones)
+ end
+
+ it 'should have exactly one group milestone' do
+ expect(@global_milestone.title).to eq('Milestone v1.2')
+ end
+
+ it 'should have all project milestones with the same title' do
+ expect(@global_milestone.milestones.count).to eq(3)
+ end
+ end
+end
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 80638fc8db2..6f166b5ab75 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -11,6 +11,7 @@
# type :string(255)
# description :string(255) default(""), not null
# avatar :string(255)
+# public :boolean default(FALSE)
#
require 'spec_helper'
@@ -37,6 +38,33 @@ describe Group do
it { is_expected.not_to validate_presence_of :owner }
end
+ describe '.public_and_given_groups' do
+ let!(:public_group) { create(:group, public: true) }
+
+ subject { described_class.public_and_given_groups([group.id]) }
+
+ it { is_expected.to eq([public_group, group]) }
+ end
+
+ describe '.visible_to_user' do
+ let!(:group) { create(:group) }
+ let!(:user) { create(:user) }
+
+ subject { described_class.visible_to_user(user) }
+
+ describe 'when the user has access to a group' do
+ before do
+ group.add_user(user, Gitlab::Access::MASTER)
+ end
+
+ it { is_expected.to eq([group]) }
+ end
+
+ describe 'when the user does not have access to any groups' do
+ it { is_expected.to eq([]) }
+ end
+ end
+
describe '#to_reference' do
it 'returns a String reference to the object' do
expect(group.to_reference).to eq "@#{group.name}"
@@ -84,4 +112,23 @@ describe Group do
expect(group.avatar_type).to eq(["only images allowed"])
end
end
+
+ describe "public_profile?" do
+ it "returns true for public group" do
+ group = create(:group, public: true)
+ expect(group.public_profile?).to be_truthy
+ end
+
+ it "returns true for non-public group with public project" do
+ group = create(:group)
+ create(:project, :public, group: group)
+ expect(group.public_profile?).to be_truthy
+ end
+
+ it "returns false for non-public group with no public projects" do
+ group = create(:group)
+ create(:project, group: group)
+ expect(group.public_profile?).to be_falsy
+ end
+ end
end
diff --git a/spec/models/hooks/project_hook_spec.rb b/spec/models/hooks/project_hook_spec.rb
index dae7e399cfb..a2dc66fce3e 100644
--- a/spec/models/hooks/project_hook_spec.rb
+++ b/spec/models/hooks/project_hook_spec.rb
@@ -22,7 +22,7 @@ describe ProjectHook do
describe '.push_hooks' do
it 'should return hooks for push events only' do
hook = create(:project_hook, push_events: true)
- hook2 = create(:project_hook, push_events: false)
+ create(:project_hook, push_events: false)
expect(ProjectHook.push_hooks).to eq([hook])
end
end
@@ -30,7 +30,7 @@ describe ProjectHook do
describe '.tag_push_hooks' do
it 'should return hooks for tag push events only' do
hook = create(:project_hook, tag_push_events: true)
- hook2 = create(:project_hook, tag_push_events: false)
+ create(:project_hook, tag_push_events: false)
expect(ProjectHook.tag_push_hooks).to eq([hook])
end
end
diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb
index 4c8b8910ae7..16641c12124 100644
--- a/spec/models/hooks/service_hook_spec.rb
+++ b/spec/models/hooks/service_hook_spec.rb
@@ -39,8 +39,6 @@ describe ServiceHook do
end
it "POSTs the data as JSON" do
- json = @data.to_json
-
@service_hook.execute(@data)
expect(WebMock).to have_requested(:post, @service_hook.url).with(
headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Service Hook' }
diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb
index 23f30881d99..35042788c65 100644
--- a/spec/models/hooks/web_hook_spec.rb
+++ b/spec/models/hooks/web_hook_spec.rb
@@ -60,8 +60,6 @@ describe ProjectHook do
end
it "POSTs the data as JSON" do
- json = @data.to_json
-
@project_hook.execute(@data, 'push_hooks')
expect(WebMock).to have_requested(:post, @project_hook.url).with(
headers: { 'Content-Type'=>'application/json', 'X-Gitlab-Event'=>'Push Hook' }
@@ -73,5 +71,11 @@ describe ProjectHook do
expect { @project_hook.execute(@data, 'push_hooks') }.to raise_error(RuntimeError)
end
+
+ it "handles SSL exceptions" do
+ expect(WebHook).to receive(:post).and_raise(OpenSSL::SSL::SSLError.new('SSL error'))
+
+ expect(@project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error'])
+ end
end
end
diff --git a/spec/models/issue_spec.rb b/spec/models/issue_spec.rb
index cf336d82957..c9aa1b063c6 100644
--- a/spec/models/issue_spec.rb
+++ b/spec/models/issue_spec.rb
@@ -68,8 +68,45 @@ describe Issue do
end
end
+ describe '#closed_by_merge_requests' do
+ let(:project) { create(:project) }
+ let(:issue) { create(:issue, project: project, state: "opened")}
+ let(:closed_issue) { build(:issue, project: project, state: "closed")}
+
+ let(:mr) do
+ opts = {
+ title: 'Awesome merge_request',
+ description: "Fixes #{issue.to_reference}",
+ source_branch: 'feature',
+ target_branch: 'master'
+ }
+ MergeRequests::CreateService.new(project, project.owner, opts).execute
+ end
+
+ let(:closed_mr) do
+ opts = {
+ title: 'Awesome merge_request 2',
+ description: "Fixes #{issue.to_reference}",
+ source_branch: 'feature',
+ target_branch: 'master',
+ state: 'closed'
+ }
+ MergeRequests::CreateService.new(project, project.owner, opts).execute
+ end
+
+ it 'returns the merge request to close this issue' do
+ allow(mr).to receive(:closes_issue?).with(issue).and_return(true)
+
+ expect(issue.closed_by_merge_requests).to eq([mr])
+ end
+
+ it "returns an empty array when the current issue is closed already" do
+ expect(closed_issue.closed_by_merge_requests).to eq([])
+ end
+ 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/label_spec.rb b/spec/models/label_spec.rb
index 6518213d71c..511ee8cbd96 100644
--- a/spec/models/label_spec.rb
+++ b/spec/models/label_spec.rb
@@ -8,6 +8,7 @@
# project_id :integer
# created_at :datetime
# updated_at :datetime
+# template :boolean default(FALSE)
#
require 'spec_helper'
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index 17a49013d25..567c911425c 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -20,6 +20,7 @@
# position :integer default(0)
# locked_at :datetime
# updated_by_id :integer
+# merge_error :string(255)
#
require 'spec_helper'
@@ -79,6 +80,12 @@ describe MergeRequest do
expect(merge_request.commits).not_to be_empty
expect(merge_request.mr_and_commit_notes.count).to eq(2)
end
+
+ it "should include notes for commits from target project as well" do
+ create(:note, commit_id: merge_request.commits.first.id, noteable_type: 'Commit', project: merge_request.target_project)
+ expect(merge_request.commits).not_to be_empty
+ expect(merge_request.mr_and_commit_notes.count).to eq(3)
+ end
end
describe '#is_being_reassigned?' do
@@ -165,6 +172,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) }
@@ -175,4 +193,29 @@ describe MergeRequest do
it_behaves_like 'a Taskable' do
subject { create :merge_request, :simple }
end
+
+ describe '#ci_commit' do
+ describe 'when the source project exists' do
+ it 'returns the latest commit' do
+ commit = double(:commit, id: '123abc')
+ ci_commit = double(:ci_commit)
+
+ allow(subject).to receive(:last_commit).and_return(commit)
+
+ expect(subject.source_project).to receive(:ci_commit).
+ with('123abc').
+ and_return(ci_commit)
+
+ expect(subject.ci_commit).to eq(ci_commit)
+ end
+ end
+
+ describe 'when the source project does not exist' do
+ it 'returns nil' do
+ allow(subject).to receive(:source_project).and_return(nil)
+
+ expect(subject.ci_commit).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb
index 36352e1ecce..77c58627322 100644
--- a/spec/models/milestone_spec.rb
+++ b/spec/models/milestone_spec.rb
@@ -111,8 +111,8 @@ describe Milestone do
describe :is_empty? do
before do
- issue = create :closed_issue, milestone: milestone
- merge_request = create :merge_request, milestone: milestone
+ create :closed_issue, milestone: milestone
+ create :merge_request, milestone: milestone
end
it 'Should return total count of issues and merge requests assigned to milestone' do
@@ -125,7 +125,7 @@ describe Milestone do
milestone = create :milestone
create :closed_issue, milestone: milestone
- issue = create :issue
+ create :issue
end
it 'should be true if milestone active and all nested issues closed' do
@@ -140,4 +140,32 @@ describe Milestone do
end
end
+ describe '#sort_issues' do
+ let(:milestone) { create(:milestone) }
+
+ let(:issue1) { create(:issue, milestone: milestone, position: 1) }
+ let(:issue2) { create(:issue, milestone: milestone, position: 2) }
+ let(:issue3) { create(:issue, milestone: milestone, position: 3) }
+ let(:issue4) { create(:issue, position: 42) }
+
+ it 'sorts the given issues' do
+ milestone.sort_issues([issue3.id, issue2.id, issue1.id])
+
+ issue1.reload
+ issue2.reload
+ issue3.reload
+
+ expect(issue1.position).to eq(3)
+ expect(issue2.position).to eq(2)
+ expect(issue3.position).to eq(1)
+ end
+
+ it 'ignores issues not part of the milestone' do
+ milestone.sort_issues([issue3.id, issue2.id, issue1.id, issue4.id])
+
+ issue4.reload
+
+ expect(issue4.position).to eq(42)
+ end
+ end
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index 1d72a9503ae..a98b9cb7321 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -11,6 +11,7 @@
# type :string(255)
# description :string(255) default(""), not null
# avatar :string(255)
+# public :boolean default(FALSE)
#
require 'spec_helper'
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 3a0b194ba1e..f347f537550 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -32,77 +32,6 @@ describe Note do
it { is_expected.to validate_presence_of(:project) }
end
- describe '#votable?' do
- it 'is true for issue notes' do
- note = build(:note_on_issue)
- expect(note).to be_votable
- end
-
- it 'is true for merge request notes' do
- note = build(:note_on_merge_request)
- expect(note).to be_votable
- end
-
- it 'is false for merge request diff notes' do
- note = build(:note_on_merge_request_diff)
- expect(note).not_to be_votable
- end
-
- it 'is false for commit notes' do
- note = build(:note_on_commit)
- expect(note).not_to be_votable
- end
-
- it 'is false for commit diff notes' do
- note = build(:note_on_commit_diff)
- expect(note).not_to be_votable
- end
- end
-
- describe 'voting score' do
- it 'recognizes a neutral note' do
- note = build(:votable_note, note: 'This is not a +1 note')
- expect(note).not_to be_upvote
- expect(note).not_to be_downvote
- end
-
- it 'recognizes a neutral emoji note' do
- note = build(:votable_note, note: "I would :+1: this, but I don't want to")
- expect(note).not_to be_upvote
- expect(note).not_to be_downvote
- end
-
- it 'recognizes a +1 note' do
- note = build(:votable_note, note: '+1 for this')
- expect(note).to be_upvote
- end
-
- it 'recognizes a +1 emoji as a vote' do
- note = build(:votable_note, note: ':+1: for this')
- expect(note).to be_upvote
- end
-
- it 'recognizes a thumbsup emoji as a vote' do
- note = build(:votable_note, note: ':thumbsup: for this')
- expect(note).to be_upvote
- end
-
- it 'recognizes a -1 note' do
- note = build(:votable_note, note: '-1 for this')
- expect(note).to be_downvote
- end
-
- it 'recognizes a -1 emoji as a vote' do
- note = build(:votable_note, note: ':-1: for this')
- expect(note).to be_downvote
- end
-
- it 'recognizes a thumbsdown emoji as a vote' do
- note = build(:votable_note, note: ':thumbsdown: for this')
- expect(note).to be_downvote
- end
- end
-
describe "Commit notes" do
let!(:note) { create(:note_on_commit, note: "+1 from me") }
let!(:commit) { note.noteable }
@@ -139,10 +68,6 @@ describe Note do
it "should be recognized by #for_commit_diff_line?" do
expect(note).to be_for_commit_diff_line
end
-
- it "should not be votable" do
- expect(note).not_to be_votable
- end
end
describe 'authorization' do
@@ -192,10 +117,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
@@ -205,4 +129,16 @@ describe Note do
it { expect(Note.search('wow')).to include(note) }
end
+
+ describe :grouped_awards do
+ before do
+ create :note, note: "smile", is_award: true
+ create :note, note: "smile", is_award: true
+ end
+
+ it "returns grouped array of notes" do
+ expect(Note.grouped_awards.first.first).to eq("smile")
+ expect(Note.grouped_awards.first.last).to match_array(Note.all)
+ end
+ end
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 8cdd551a0ca..b9006b693b2 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/builds")}
end
describe "execute" do
@@ -48,33 +47,11 @@ 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
- service_hook = double
- 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
end
end
-
- describe "Fork registration" do
- before do
- @old_project = create(:ci_project).gl_project
- @project = create(:empty_project)
- @user = create(:user)
-
- @service = GitlabCiService.new
- allow(@service).to receive_messages(
- service_hook: true,
- project_url: 'http://ci.gitlab.org/projects/2',
- token: 'verySecret',
- project: @old_project
- )
- end
-
- it "creates fork on CI" do
- expect_any_instance_of(Ci::CreateProjectService).to receive(:execute)
- @service.fork_registration(@project, @user)
- end
- end
end
diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb
index 65d16beef91..f67d7b30980 100644
--- a/spec/models/project_services/hipchat_service_spec.rb
+++ b/spec/models/project_services/hipchat_service_spec.rb
@@ -87,7 +87,7 @@ describe HipchatService do
it "should create a push message" do
message = hipchat.send(:create_push_message, push_sample_data)
- obj_attr = push_sample_data[:object_attributes]
+ push_sample_data[:object_attributes]
branch = push_sample_data[:ref].gsub('refs/heads/', '')
expect(message).to include("#{user.name} pushed to branch " \
"<a href=\"#{project.web_url}/commits/#{branch}\">#{branch}</a> of " \
@@ -107,7 +107,7 @@ describe HipchatService do
it "should create a tag push message" do
message = hipchat.send(:create_push_message, push_sample_data)
- obj_attr = push_sample_data[:object_attributes]
+ push_sample_data[:object_attributes]
expect(message).to eq("#{user.name} pushed new tag " \
"<a href=\"#{project.web_url}/commits/test\">test</a> to " \
"<a href=\"#{project.web_url}\">#{project_name}</a>\n")
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index ddd2cce212c..576f5fc79eb 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -94,9 +94,9 @@ describe JiraService do
end
it 'should be prepopulated with the settings' do
- expect(@service.properties[:project_url]).to eq('http://jira.sample/projects/project_a')
- expect(@service.properties[:issues_url]).to eq("http://jira.sample/issues/:id")
- expect(@service.properties[:new_issue_url]).to eq("http://jira.sample/projects/project_a/issues/new")
+ expect(@service.properties["project_url"]).to eq('http://jira.sample/projects/project_a')
+ expect(@service.properties["issues_url"]).to eq("http://jira.sample/issues/:id")
+ expect(@service.properties["new_issue_url"]).to eq("http://jira.sample/projects/project_a/issues/new")
end
end
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 9e7b6f5cb30..06a02c13bf1 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -140,7 +140,7 @@ describe Project do
describe 'last_activity_date' do
it 'returns the creation date of the project\'s last event if present' do
- last_activity_event = create(:event, project: project)
+ create(:event, project: project)
expect(project.last_activity_at.to_i).to eq(last_event.created_at.to_i)
end
@@ -220,6 +220,7 @@ describe Project do
end
it { expect(Project.find_with_namespace('gitlab/gitlabhq')).to eq(@project) }
+ it { expect(Project.find_with_namespace('GitLab/GitlabHQ')).to eq(@project) }
it { expect(Project.find_with_namespace('gitlab-ci')).to be_nil }
end
end
@@ -344,17 +345,6 @@ describe Project do
expect(project1.star_count).to eq(0)
expect(project2.star_count).to eq(0)
end
-
- it 'is decremented when an upvoter account is deleted' do
- user = create :user
- project = create :project, :public
- user.toggle_star(project)
- project.reload
- expect(project.star_count).to eq(1)
- user.destroy
- project.reload
- expect(project.star_count).to eq(0)
- end
end
describe :avatar_type do
@@ -404,21 +394,84 @@ describe Project do
describe :ci_commit do
let(:project) { create :project }
- let(:ci_project) { create :ci_project, gl_project: project }
- let(:commit) { create :ci_commit, project: ci_project }
+ let(:commit) { create :ci_commit, gl_project: project }
- before { project.create_gitlab_ci_service(active: true) }
+ before do
+ project.ensure_gitlab_ci_project
+ project.create_gitlab_ci_service(active: true)
+ end
it { expect(project.ci_commit(commit.sha)).to eq(commit) }
end
- describe :enable_ci do
+ describe :builds_enabled do
let(:project) { create :project }
- let(:user) { create :user }
- before { project.enable_ci(user) }
+ before { project.builds_enabled = true }
+
+ subject { project.builds_enabled }
- it { expect(project.gitlab_ci?).to be_truthy }
+ it { is_expected.to eq(project.gitlab_ci_service.active) }
+ it { expect(project.builds_enabled?).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
+ # Little fix for special issue related to Fractional Seconds support for MySQL.
+ # See: https://github.com/rails/rails/pull/14359/files
+ create(:note_on_commit, project: project2, created_at: date + 1)
+ end
+ end
+
+ it 'sorts Projects by the amount of notes in descending order' do
+ expect(subject).to eq([project2, project1])
+ end
+ end
+ end
+
+ describe '.visible_to_user' do
+ let!(:project) { create(:project, :private) }
+ let!(:user) { create(:user) }
+
+ subject { described_class.visible_to_user(user) }
+
+ describe 'when a user has access to a project' do
+ before do
+ project.team.add_user(user, Gitlab::Access::MASTER)
+ end
+
+ it { is_expected.to eq([project]) }
+ end
+
+ describe 'when a user does not have access to any projects' do
+ it { is_expected.to eq([]) }
+ end
+ end
end
diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb
index cc1138490a0..26e8fdae472 100644
--- a/spec/models/project_team_spec.rb
+++ b/spec/models/project_team_spec.rb
@@ -66,4 +66,16 @@ describe ProjectTeam do
it { expect(project.team.member?(guest)).to be_truthy }
end
end
+
+ describe "#human_max_access" do
+ it "return master role" do
+ user = create :user
+ group = create :group
+ group.add_users([user.id], GroupMember::MASTER)
+ project = create(:project, namespace: group)
+ project.team << [user, :guest]
+
+ expect(project.team.human_max_access(user.id)).to eq("Master")
+ end
+ end
end
diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb
index f785203af7d..3b889144447 100644
--- a/spec/models/project_wiki_spec.rb
+++ b/spec/models/project_wiki_spec.rb
@@ -184,6 +184,12 @@ describe ProjectWiki do
subject.create_page("test page", "some content", :markdown, "commit message")
expect(subject.pages.first.page.version.message).to eq("commit message")
end
+
+ it 'updates project activity' do
+ expect(subject).to receive(:update_project_activity)
+
+ subject.create_page('Test Page', 'This is content')
+ end
end
describe "#update_page" do
@@ -205,6 +211,12 @@ describe ProjectWiki do
it "sets the correct commit message" do
expect(@page.version.message).to eq("updated page")
end
+
+ it 'updates project activity' do
+ expect(subject).to receive(:update_project_activity)
+
+ subject.update_page(@gollum_page, 'Yet more content', :markdown, 'Updated page again')
+ end
end
describe "#delete_page" do
@@ -217,13 +229,19 @@ describe ProjectWiki do
subject.delete_page(@page)
expect(subject.pages.count).to eq(0)
end
+
+ it 'updates project activity' do
+ expect(subject).to receive(:update_project_activity)
+
+ subject.delete_page(@page)
+ end
end
private
def create_temp_repo(path)
FileUtils.mkdir_p path
- system(*%W(git init --quiet --bare -- #{path}))
+ system(*%W(#{Gitlab.config.git.bin_path} init --quiet --bare -- #{path}))
end
def remove_temp_repo(path)
@@ -231,7 +249,7 @@ describe ProjectWiki do
end
def commit_details
- commit = { name: user.name, email: user.email, message: "test commit" }
+ { name: user.name, email: user.email, message: "test commit" }
end
def create_page(name, content)
diff --git a/spec/models/release_spec.rb b/spec/models/release_spec.rb
new file mode 100644
index 00000000000..72ecb442a36
--- /dev/null
+++ b/spec/models/release_spec.rb
@@ -0,0 +1,28 @@
+# == Schema Information
+#
+# Table name: releases
+#
+# id :integer not null, primary key
+# tag :string(255)
+# description :text
+# project_id :integer
+# created_at :datetime
+# updated_at :datetime
+#
+
+require 'rails_helper'
+
+RSpec.describe Release, type: :model do
+ let(:release) { create(:release) }
+
+ it { expect(release).to be_valid }
+
+ describe 'associations' do
+ it { is_expected.to belong_to(:project) }
+ end
+
+ describe 'validation' do
+ it { is_expected.to validate_presence_of(:project) }
+ it { is_expected.to validate_presence_of(:description) }
+ end
+end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 05e51532eb8..fa261e64c35 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -4,6 +4,7 @@ describe Repository do
include RepoHelpers
let(:repository) { create(:project).repository }
+ let(:user) { create(:user) }
describe :branch_names_contains do
subject { repository.branch_names_contains(sample_commit.id) }
@@ -26,6 +27,15 @@ describe Repository do
it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
end
+ describe :find_commits_by_message do
+ subject { repository.find_commits_by_message('submodule').map{ |k| k.id } }
+
+ it { is_expected.to include('5937ac0a7beb003549fc5fd26fc247adbce4a52e') }
+ it { is_expected.to include('6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9') }
+ it { is_expected.to include('cfe32cf61b73a0d5e9f13e774abde7ff789b1660') }
+ it { is_expected.not_to include('913c66a37b4a45b9769037c55c2d238bd0942d2e') }
+ end
+
describe :blob_at do
context 'blank sha' do
subject { repository.blob_at(Gitlab::Git::BLANK_SHA, '.gitignore') }
@@ -90,5 +100,104 @@ describe Repository do
it { expect(subject.startline).to eq(186) }
it { expect(subject.data.lines[2]).to eq(" - Feature: Replace teams with group membership\n") }
end
+
+ end
+
+ describe :add_branch do
+ context 'when pre hooks were successful' do
+ it 'should run without errors' do
+ hook = double(trigger: true)
+ expect(Gitlab::Git::Hook).to receive(:new).exactly(3).times.and_return(hook)
+
+ expect { repository.add_branch(user, 'new_feature', 'master') }.not_to raise_error
+ end
+
+ it 'should create the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true)
+
+ branch = repository.add_branch(user, 'new_feature', 'master')
+
+ expect(branch.name).to eq('new_feature')
+ end
+ end
+
+ context 'when pre hooks failed' do
+ it 'should get an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.add_branch(user, 'new_feature', 'master')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ end
+
+ it 'should not create the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.add_branch(user, 'new_feature', 'master')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ expect(repository.find_branch('new_feature')).to be_nil
+ end
+ end
+ end
+
+ describe :rm_branch do
+ context 'when pre hooks were successful' do
+ it 'should run without errors' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true)
+
+ expect { repository.rm_branch(user, 'feature') }.not_to raise_error
+ end
+
+ it 'should delete the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(true)
+
+ expect { repository.rm_branch(user, 'feature') }.not_to raise_error
+
+ expect(repository.find_branch('feature')).to be_nil
+ end
+ end
+
+ context 'when pre hooks failed' do
+ it 'should get an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.rm_branch(user, 'new_feature')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ end
+
+ it 'should not delete the branch' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.rm_branch(user, 'feature')
+ end.to raise_error(GitHooksService::PreReceiveError)
+ expect(repository.find_branch('feature')).not_to be_nil
+ end
+ end
end
+
+ describe :commit_with_hooks do
+ context 'when pre hooks were successful' do
+ it 'should run without errors' do
+ expect_any_instance_of(GitHooksService).to receive(:execute).and_return(true)
+
+ expect do
+ repository.commit_with_hooks(user, 'feature') { sample_commit.id }
+ end.not_to raise_error
+ end
+ end
+
+ context 'when pre hooks failed' do
+ it 'should get an error' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return(false)
+
+ expect do
+ repository.commit_with_hooks(user, 'feature') { sample_commit.id }
+ end.to raise_error(GitHooksService::PreReceiveError)
+ 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/models/user_spec.rb b/spec/models/user_spec.rb
index 480950859a2..a0f78d3b336 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -54,6 +54,8 @@
# public_email :string(255) default(""), not null
# dashboard :integer default(0)
# project_view :integer default(0)
+# consumed_timestep :integer
+# layout :integer default(0)
#
require 'spec_helper'
@@ -85,10 +87,27 @@ describe User do
it { is_expected.to have_many(:merge_requests).dependent(:destroy) }
it { is_expected.to have_many(:assigned_merge_requests).dependent(:destroy) }
it { is_expected.to have_many(:identities).dependent(:destroy) }
+ it { is_expected.to have_one(:abuse_report) }
end
describe 'validations' do
- it { is_expected.to validate_presence_of(:username) }
+ describe 'username' do
+ it 'validates presence' do
+ expect(subject).to validate_presence_of(:username)
+ end
+
+ it 'rejects blacklisted names' do
+ user = build(:user, username: 'dashboard')
+
+ expect(user).not_to be_valid
+ expect(user.errors.values).to eq [['dashboard is a reserved name']]
+ end
+
+ it 'validates uniqueness' do
+ expect(subject).to validate_uniqueness_of(:username)
+ end
+ end
+
it { is_expected.to validate_presence_of(:projects_limit) }
it { is_expected.to validate_numericality_of(:projects_limit) }
it { is_expected.to allow_value(0).for(:projects_limit) }
@@ -227,6 +246,26 @@ describe User do
end
end
+ describe '#recently_sent_password_reset?' do
+ it 'is false when reset_password_sent_at is nil' do
+ user = build_stubbed(:user, reset_password_sent_at: nil)
+
+ expect(user.recently_sent_password_reset?).to eq false
+ end
+
+ it 'is false when sent more than one minute ago' do
+ user = build_stubbed(:user, reset_password_sent_at: 5.minutes.ago)
+
+ expect(user.recently_sent_password_reset?).to eq false
+ end
+
+ it 'is true when sent less than one minute ago' do
+ user = build_stubbed(:user, reset_password_sent_at: Time.now)
+
+ expect(user.recently_sent_password_reset?).to eq true
+ end
+ end
+
describe '#disable_two_factor!' do
it 'clears all 2FA-related fields' do
user = create(:user, :two_factor)
@@ -642,28 +681,28 @@ describe User do
@user1 = create :user, created_at: Date.today - 1, last_sign_in_at: Date.today - 1, name: 'Omega'
end
- it "sorts users as recently_signed_in" do
+ it "sorts users by the recent sign-in time" do
expect(User.sort('recent_sign_in').first).to eq(@user)
end
- it "sorts users as late_signed_in" do
+ it "sorts users by the oldest sign-in time" do
expect(User.sort('oldest_sign_in').first).to eq(@user1)
end
- it "sorts users as recently_created" do
+ it "sorts users in descending order by their creation time" do
expect(User.sort('created_desc').first).to eq(@user)
end
- it "sorts users as late_created" do
+ it "sorts users in ascending order by their creation time" do
expect(User.sort('created_asc').first).to eq(@user1)
end
- it "sorts users by name when nil is passed" do
- expect(User.sort(nil).first).to eq(@user)
+ it "sorts users by id in descending order when nil is passed" do
+ expect(User.sort(nil).first).to eq(@user1)
end
end
- describe "#contributed_projects_ids" do
+ describe "#contributed_projects" do
subject { create(:user) }
let!(:project1) { create(:project) }
let!(:project2) { create(:project, forked_from_project: project3) }
@@ -678,15 +717,15 @@ describe User do
end
it "includes IDs for projects the user has pushed to" do
- expect(subject.contributed_projects_ids).to include(project1.id)
+ expect(subject.contributed_projects).to include(project1)
end
it "includes IDs for projects the user has had merge requests merged into" do
- expect(subject.contributed_projects_ids).to include(project3.id)
+ expect(subject.contributed_projects).to include(project3)
end
it "doesn't include IDs for unrelated projects" do
- expect(subject.contributed_projects_ids).not_to include(project2.id)
+ expect(subject.contributed_projects).not_to include(project2)
end
end
@@ -735,4 +774,30 @@ describe User do
expect(subject.recent_push).to eq(nil)
end
end
+
+ describe '#authorized_groups' do
+ let!(:user) { create(:user) }
+ let!(:private_group) { create(:group) }
+
+ before do
+ private_group.add_user(user, Gitlab::Access::MASTER)
+ end
+
+ subject { user.authorized_groups }
+
+ it { is_expected.to eq([private_group]) }
+ end
+
+ describe '#authorized_projects' do
+ let!(:user) { create(:user) }
+ let!(:private_project) { create(:project, :private) }
+
+ before do
+ private_project.team << [user, Gitlab::Access::MASTER]
+ end
+
+ subject { user.authorized_projects }
+
+ it { is_expected.to eq([private_project]) }
+ end
end
diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb
index dc84a14bb40..d7802d1734f 100644
--- a/spec/models/wiki_page_spec.rb
+++ b/spec/models/wiki_page_spec.rb
@@ -196,7 +196,7 @@ describe WikiPage do
end
def commit_details
- commit = { name: user.name, email: user.email, message: "test commit" }
+ { name: user.name, email: user.email, message: "test commit" }
end
def create_page(name, content)