2016-06-14 07:51:12 -04:00
|
|
|
require 'spec_helper'
|
|
|
|
|
|
|
|
describe Environment, models: true do
|
2016-12-07 20:09:18 -05:00
|
|
|
subject(:environment) { create(:environment) }
|
2016-06-14 07:51:12 -04:00
|
|
|
|
|
|
|
it { is_expected.to belong_to(:project) }
|
|
|
|
it { is_expected.to have_many(:deployments) }
|
|
|
|
|
|
|
|
it { is_expected.to delegate_method(:last_deployment).to(:deployments).as(:last) }
|
|
|
|
|
2016-10-17 17:40:44 -04:00
|
|
|
it { is_expected.to delegate_method(:stop_action).to(:last_deployment) }
|
2016-11-21 11:26:35 -05:00
|
|
|
it { is_expected.to delegate_method(:manual_actions).to(:last_deployment) }
|
2016-10-17 11:10:26 -04:00
|
|
|
|
2016-06-14 07:51:12 -04:00
|
|
|
it { is_expected.to validate_presence_of(:name) }
|
|
|
|
it { is_expected.to validate_uniqueness_of(:name).scoped_to(:project_id) }
|
2016-12-02 07:54:57 -05:00
|
|
|
it { is_expected.to validate_length_of(:name).is_at_most(255) }
|
2016-07-26 03:35:47 -04:00
|
|
|
|
2016-12-07 20:09:18 -05:00
|
|
|
it { is_expected.to validate_uniqueness_of(:slug).scoped_to(:project_id) }
|
|
|
|
it { is_expected.to validate_length_of(:slug).is_at_most(24) }
|
2016-07-26 03:35:47 -04:00
|
|
|
|
2016-12-07 20:09:18 -05:00
|
|
|
it { is_expected.to validate_length_of(:external_url).is_at_most(255) }
|
|
|
|
it { is_expected.to validate_uniqueness_of(:external_url).scoped_to(:project_id) }
|
2016-07-26 08:19:37 -04:00
|
|
|
|
|
|
|
describe '#nullify_external_url' do
|
|
|
|
it 'replaces a blank url with nil' do
|
|
|
|
env = build(:environment, external_url: "")
|
|
|
|
|
|
|
|
expect(env.save).to be true
|
2016-07-29 06:14:36 -04:00
|
|
|
expect(env.external_url).to be_nil
|
2016-07-26 08:19:37 -04:00
|
|
|
end
|
|
|
|
end
|
2016-08-03 07:37:39 -04:00
|
|
|
|
2016-08-09 09:11:14 -04:00
|
|
|
describe '#includes_commit?' do
|
2016-08-03 07:37:39 -04:00
|
|
|
context 'without a last deployment' do
|
|
|
|
it "returns false" do
|
2016-08-09 09:11:14 -04:00
|
|
|
expect(environment.includes_commit?('HEAD')).to be false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'with a last deployment' do
|
|
|
|
let(:project) { create(:project) }
|
|
|
|
let(:environment) { create(:environment, project: project) }
|
|
|
|
|
|
|
|
let!(:deployment) do
|
|
|
|
create(:deployment, environment: environment, sha: project.commit('master').id)
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'in the same branch' do
|
|
|
|
it 'returns true' do
|
|
|
|
expect(environment.includes_commit?(RepoHelpers.sample_commit)).to be true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'not in the same branch' do
|
|
|
|
before do
|
|
|
|
deployment.update(sha: project.commit('feature').id)
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'returns false' do
|
|
|
|
expect(environment.includes_commit?(RepoHelpers.sample_commit)).to be false
|
|
|
|
end
|
2016-08-03 07:37:39 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-09-14 16:32:11 -04:00
|
|
|
|
2016-10-10 14:38:48 -04:00
|
|
|
describe '#first_deployment_for' do
|
2016-10-04 10:03:13 -04:00
|
|
|
let(:project) { create(:project) }
|
|
|
|
let!(:environment) { create(:environment, project: project) }
|
|
|
|
let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) }
|
|
|
|
let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) }
|
|
|
|
let(:head_commit) { project.commit }
|
|
|
|
let(:commit) { project.commit.parent }
|
|
|
|
|
|
|
|
it 'returns deployment id for the environment' do
|
2016-10-10 14:38:48 -04:00
|
|
|
expect(environment.first_deployment_for(commit)).to eq deployment1
|
2016-10-04 10:03:13 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
it 'return nil when no deployment is found' do
|
2016-10-10 14:38:48 -04:00
|
|
|
expect(environment.first_deployment_for(head_commit)).to eq nil
|
2016-10-04 10:03:13 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2016-09-14 16:32:11 -04:00
|
|
|
describe '#environment_type' do
|
|
|
|
subject { environment.environment_type }
|
|
|
|
|
|
|
|
it 'sets a environment type if name has multiple segments' do
|
2016-09-19 03:01:04 -04:00
|
|
|
environment.update!(name: 'production/worker.gitlab.com')
|
2016-09-14 16:32:11 -04:00
|
|
|
|
|
|
|
is_expected.to eq('production')
|
|
|
|
end
|
|
|
|
|
|
|
|
it 'nullifies a type if it\'s a simple name' do
|
2016-09-19 03:01:04 -04:00
|
|
|
environment.update!(name: 'production')
|
2016-09-14 16:32:11 -04:00
|
|
|
|
|
|
|
is_expected.to be_nil
|
|
|
|
end
|
|
|
|
end
|
2016-10-17 11:10:26 -04:00
|
|
|
|
|
|
|
describe '#stoppable?' do
|
|
|
|
subject { environment.stoppable? }
|
|
|
|
|
|
|
|
context 'when no other actions' do
|
|
|
|
it { is_expected.to be_falsey }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when matching action is defined' do
|
|
|
|
let(:build) { create(:ci_build) }
|
|
|
|
let!(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') }
|
|
|
|
let!(:close_action) { create(:ci_build, pipeline: build.pipeline, name: 'close_app', when: :manual) }
|
|
|
|
|
|
|
|
context 'when environment is available' do
|
|
|
|
before do
|
|
|
|
environment.start
|
|
|
|
end
|
|
|
|
|
|
|
|
it { is_expected.to be_truthy }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when environment is stopped' do
|
|
|
|
before do
|
|
|
|
environment.stop
|
|
|
|
end
|
|
|
|
|
|
|
|
it { is_expected.to be_falsey }
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-10-18 06:02:50 -04:00
|
|
|
|
|
|
|
describe '#stop!' do
|
|
|
|
let(:user) { create(:user) }
|
|
|
|
|
|
|
|
subject { environment.stop!(user) }
|
|
|
|
|
|
|
|
before do
|
|
|
|
expect(environment).to receive(:stoppable?).and_call_original
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when no other actions' do
|
|
|
|
it { is_expected.to be_nil }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when matching action is defined' do
|
|
|
|
let(:build) { create(:ci_build) }
|
|
|
|
let!(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') }
|
|
|
|
|
|
|
|
context 'when action did not yet finish' do
|
|
|
|
let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
|
|
|
|
|
|
|
|
it 'returns the same action' do
|
2016-10-18 07:51:12 -04:00
|
|
|
expect(subject).to eq(close_action)
|
|
|
|
expect(subject.user).to eq(user)
|
2016-10-18 06:02:50 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'if action did finish' do
|
|
|
|
let!(:close_action) { create(:ci_build, :manual, :success, pipeline: build.pipeline, name: 'close_app') }
|
|
|
|
|
|
|
|
it 'returns a new action of the same type' do
|
|
|
|
is_expected.to be_persisted
|
2016-10-18 07:51:12 -04:00
|
|
|
expect(subject.name).to eq(close_action.name)
|
|
|
|
expect(subject.user).to eq(user)
|
2016-10-18 06:02:50 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-11-16 05:26:36 -05:00
|
|
|
|
|
|
|
describe 'recently_updated_on_branch?' do
|
|
|
|
subject { environment.recently_updated_on_branch?('feature') }
|
|
|
|
|
|
|
|
context 'when last deployment to environment is the most recent one' do
|
|
|
|
before do
|
|
|
|
create(:deployment, environment: environment, ref: 'feature')
|
|
|
|
end
|
|
|
|
|
|
|
|
it { is_expected.to be true }
|
|
|
|
end
|
|
|
|
|
|
|
|
context 'when last deployment to environment is not the most recent' do
|
|
|
|
before do
|
|
|
|
create(:deployment, environment: environment, ref: 'feature')
|
|
|
|
create(:deployment, environment: environment, ref: 'master')
|
|
|
|
end
|
|
|
|
|
|
|
|
it { is_expected.to be false }
|
|
|
|
end
|
|
|
|
end
|
2016-11-21 11:26:35 -05:00
|
|
|
|
|
|
|
describe '#actions_for' do
|
|
|
|
let(:deployment) { create(:deployment, environment: environment) }
|
|
|
|
let(:pipeline) { deployment.deployable.pipeline }
|
|
|
|
let!(:review_action) { create(:ci_build, :manual, name: 'review-apps', pipeline: pipeline, environment: 'review/$CI_BUILD_REF_NAME' )}
|
|
|
|
let!(:production_action) { create(:ci_build, :manual, name: 'production', pipeline: pipeline, environment: 'production' )}
|
|
|
|
|
|
|
|
it 'returns a list of actions with matching environment' do
|
|
|
|
expect(environment.actions_for('review/master')).to contain_exactly(review_action)
|
|
|
|
end
|
|
|
|
end
|
2016-12-07 20:09:18 -05:00
|
|
|
|
|
|
|
describe '#slug' do
|
|
|
|
it "is automatically generated" do
|
|
|
|
expect(environment.slug).not_to be_nil
|
|
|
|
end
|
|
|
|
|
|
|
|
it "is not regenerated if name changes" do
|
|
|
|
original_slug = environment.slug
|
|
|
|
environment.update_attributes!(name: environment.name.reverse)
|
|
|
|
|
|
|
|
expect(environment.slug).to eq(original_slug)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe '#generate_slug' do
|
|
|
|
SUFFIX = "-[a-z0-9]{6}"
|
|
|
|
{
|
|
|
|
"staging-12345678901234567" => "staging-123456789" + SUFFIX,
|
|
|
|
"9-staging-123456789012345" => "env-9-staging-123" + SUFFIX,
|
|
|
|
"staging-1234567890123456" => "staging-1234567890123456",
|
|
|
|
"production" => "production",
|
|
|
|
"PRODUCTION" => "production" + SUFFIX,
|
|
|
|
"review/1-foo" => "review-1-foo" + SUFFIX,
|
|
|
|
"1-foo" => "env-1-foo" + SUFFIX,
|
|
|
|
"1/foo" => "env-1-foo" + SUFFIX,
|
|
|
|
"foo-" => "foo" + SUFFIX,
|
|
|
|
}.each do |name, matcher|
|
|
|
|
it "returns a slug matching #{matcher}, given #{name}" do
|
2016-12-08 10:37:41 -05:00
|
|
|
slug = described_class.new(name: name).generate_slug
|
2016-12-07 20:09:18 -05:00
|
|
|
|
|
|
|
expect(slug).to match(/\A#{matcher}\z/)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2016-06-14 07:51:12 -04:00
|
|
|
end
|