0103d5be96
These are data columns that store runtime configuration of build needed to execute it on runner and within pipeline. The definition of this data is that once used, and when no longer needed (due to retry capability) they can be freely removed. They use `jsonb` on PostgreSQL, and `text` on MySQL (due to lacking support for json datatype on old enough version).
441 lines
14 KiB
Ruby
441 lines
14 KiB
Ruby
require 'spec_helper'
|
|
|
|
describe 'Environments page', :js do
|
|
let(:project) { create(:project) }
|
|
let(:user) { create(:user) }
|
|
let(:role) { :developer }
|
|
|
|
before do
|
|
project.add_role(user, role)
|
|
sign_in(user)
|
|
end
|
|
|
|
def stop_button_selector
|
|
%q{button[data-original-title="Stop environment"]}
|
|
end
|
|
|
|
describe 'page tabs' do
|
|
it 'shows "Available" and "Stopped" tab with links' do
|
|
visit_environments(project)
|
|
|
|
expect(page).to have_selector('.js-environments-tab-available')
|
|
expect(page).to have_content('Available')
|
|
expect(page).to have_selector('.js-environments-tab-stopped')
|
|
expect(page).to have_content('Stopped')
|
|
end
|
|
|
|
describe 'with one available environment' do
|
|
before do
|
|
create(:environment, project: project, state: :available)
|
|
end
|
|
|
|
describe 'in available tab page' do
|
|
it 'should show one environment' do
|
|
visit_environments(project, scope: 'available')
|
|
|
|
expect(page).to have_css('.environments-container')
|
|
expect(page.all('.environment-name').length).to eq(1)
|
|
end
|
|
end
|
|
|
|
describe 'in stopped tab page' do
|
|
it 'should show no environments' do
|
|
visit_environments(project, scope: 'stopped')
|
|
|
|
expect(page).to have_css('.environments-container')
|
|
expect(page).to have_content('You don\'t have any environments right now')
|
|
end
|
|
end
|
|
|
|
context 'when cluster is not reachable' do
|
|
let!(:cluster) { create(:cluster, :provided_by_gcp, projects: [project]) }
|
|
let!(:application_prometheus) { create(:clusters_applications_prometheus, :installed, cluster: cluster) }
|
|
|
|
before do
|
|
allow_any_instance_of(Kubeclient::Client).to receive(:proxy_url).and_raise(Kubeclient::HttpError.new(401, 'Unauthorized', nil))
|
|
end
|
|
|
|
it 'should show one environment without error' do
|
|
visit_environments(project, scope: 'available')
|
|
|
|
expect(page).to have_css('.environments-container')
|
|
expect(page.all('.environment-name').length).to eq(1)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'with one stopped environment' do
|
|
before do
|
|
create(:environment, project: project, state: :stopped)
|
|
end
|
|
|
|
describe 'in available tab page' do
|
|
it 'should show no environments' do
|
|
visit_environments(project, scope: 'available')
|
|
|
|
expect(page).to have_css('.environments-container')
|
|
expect(page).to have_content('You don\'t have any environments right now')
|
|
end
|
|
end
|
|
|
|
describe 'in stopped tab page' do
|
|
it 'should show one environment' do
|
|
visit_environments(project, scope: 'stopped')
|
|
|
|
expect(page).to have_css('.environments-container')
|
|
expect(page.all('.environment-name').length).to eq(1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'without environments' do
|
|
before do
|
|
visit_environments(project)
|
|
end
|
|
|
|
it 'does not show environments and counters are set to zero' do
|
|
expect(page).to have_content('You don\'t have any environments right now')
|
|
|
|
expect(page.find('.js-environments-tab-available .badge').text).to eq('0')
|
|
expect(page.find('.js-environments-tab-stopped .badge').text).to eq('0')
|
|
end
|
|
end
|
|
|
|
describe 'environments table' do
|
|
let!(:environment) do
|
|
create(:environment, project: project, state: :available)
|
|
end
|
|
|
|
context 'when there are no deployments' do
|
|
before do
|
|
visit_environments(project)
|
|
end
|
|
|
|
it 'shows environments names and counters' do
|
|
expect(page).to have_link(environment.name)
|
|
|
|
expect(page.find('.js-environments-tab-available .badge').text).to eq('1')
|
|
expect(page.find('.js-environments-tab-stopped .badge').text).to eq('0')
|
|
end
|
|
|
|
it 'does not show deployments' do
|
|
expect(page).to have_content('No deployments yet')
|
|
end
|
|
|
|
it 'does not show stip button when environment is not stoppable' do
|
|
expect(page).not_to have_selector(stop_button_selector)
|
|
end
|
|
end
|
|
|
|
context 'when there are successful deployments' do
|
|
let(:project) { create(:project, :repository) }
|
|
|
|
let!(:deployment) do
|
|
create(:deployment, :success,
|
|
environment: environment,
|
|
sha: project.commit.id)
|
|
end
|
|
|
|
it 'shows deployment SHA and internal ID' do
|
|
visit_environments(project)
|
|
|
|
expect(page).to have_link(deployment.short_sha)
|
|
expect(page).to have_content(deployment.iid)
|
|
end
|
|
|
|
context 'when builds and manual actions are present' do
|
|
let!(:pipeline) { create(:ci_pipeline, project: project) }
|
|
let!(:build) { create(:ci_build, pipeline: pipeline) }
|
|
|
|
let!(:action) do
|
|
create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production')
|
|
end
|
|
|
|
let!(:deployment) do
|
|
create(:deployment, :success,
|
|
environment: environment,
|
|
deployable: build,
|
|
sha: project.commit.id)
|
|
end
|
|
|
|
before do
|
|
visit_environments(project)
|
|
end
|
|
|
|
it 'shows a play button' do
|
|
find('.js-environment-actions-dropdown').click
|
|
|
|
expect(page).to have_content(action.name.humanize)
|
|
end
|
|
|
|
it 'allows to play a manual action', :js do
|
|
expect(action).to be_manual
|
|
|
|
find('.js-environment-actions-dropdown').click
|
|
expect(page).to have_content(action.name.humanize)
|
|
|
|
expect { find('.js-manual-action-link').click }
|
|
.not_to change { Ci::Pipeline.count }
|
|
end
|
|
|
|
it 'shows build name and id' do
|
|
expect(page).to have_link("#{build.name} ##{build.id}")
|
|
end
|
|
|
|
it 'shows a stop button' do
|
|
expect(page).not_to have_selector(stop_button_selector)
|
|
end
|
|
|
|
it 'does not show external link button' do
|
|
expect(page).not_to have_css('external-url')
|
|
end
|
|
|
|
it 'does not show terminal button' do
|
|
expect(page).not_to have_terminal_button
|
|
end
|
|
|
|
context 'with external_url' do
|
|
let(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') }
|
|
let(:build) { create(:ci_build, pipeline: pipeline) }
|
|
let(:deployment) { create(:deployment, :success, environment: environment, deployable: build) }
|
|
|
|
it 'shows an external link button' do
|
|
expect(page).to have_link(nil, href: environment.external_url)
|
|
end
|
|
end
|
|
|
|
context 'with stop action' do
|
|
let(:action) do
|
|
create(:ci_build, :manual, pipeline: pipeline, name: 'close_app')
|
|
end
|
|
|
|
let(:deployment) do
|
|
create(:deployment, :success,
|
|
environment: environment,
|
|
deployable: build,
|
|
on_stop: 'close_app')
|
|
end
|
|
|
|
it 'shows a stop button' do
|
|
expect(page).to have_selector(stop_button_selector)
|
|
end
|
|
|
|
context 'when user is a reporter' do
|
|
let(:role) { :reporter }
|
|
|
|
it 'does not show stop button' do
|
|
expect(page).not_to have_selector(stop_button_selector)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when kubernetes terminal is available' do
|
|
shared_examples 'same behavior between KubernetesService and Platform::Kubernetes' do
|
|
context 'for project maintainer' do
|
|
let(:role) { :maintainer }
|
|
|
|
it 'shows the terminal button' do
|
|
expect(page).to have_terminal_button
|
|
end
|
|
end
|
|
|
|
context 'when user is a developer' do
|
|
let(:role) { :developer }
|
|
|
|
it 'does not show terminal button' do
|
|
expect(page).not_to have_terminal_button
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when user configured kubernetes from Integration > Kubernetes' do
|
|
let(:project) { create(:kubernetes_project, :test_repo) }
|
|
|
|
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
|
|
end
|
|
|
|
context 'when user configured kubernetes from CI/CD > Clusters' do
|
|
let(:cluster) { create(:cluster, :provided_by_gcp, projects: [create(:project, :repository)]) }
|
|
let(:project) { cluster.project }
|
|
|
|
it_behaves_like 'same behavior between KubernetesService and Platform::Kubernetes'
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when there is a delayed job' do
|
|
let!(:pipeline) { create(:ci_pipeline, project: project) }
|
|
let!(:build) { create(:ci_build, pipeline: pipeline) }
|
|
|
|
let!(:delayed_job) do
|
|
create(:ci_build, :scheduled,
|
|
pipeline: pipeline,
|
|
name: 'delayed job',
|
|
stage: 'test')
|
|
end
|
|
|
|
let!(:deployment) do
|
|
create(:deployment,
|
|
:success,
|
|
environment: environment,
|
|
deployable: build,
|
|
sha: project.commit.id)
|
|
end
|
|
|
|
before do
|
|
visit_environments(project)
|
|
end
|
|
|
|
it 'has a dropdown for actionable jobs' do
|
|
expect(page).to have_selector('.dropdown-new.btn.btn-default .ic-play')
|
|
end
|
|
|
|
it "has link to the delayed job's action" do
|
|
find('.js-environment-actions-dropdown').click
|
|
|
|
expect(page).to have_button('Delayed job')
|
|
expect(page).to have_content(/\d{2}:\d{2}:\d{2}/)
|
|
end
|
|
|
|
context 'when delayed job is expired already' do
|
|
let!(:delayed_job) do
|
|
create(:ci_build, :expired_scheduled,
|
|
pipeline: pipeline,
|
|
name: 'delayed job',
|
|
stage: 'test')
|
|
end
|
|
|
|
it "shows 00:00:00 as the remaining time" do
|
|
find('.js-environment-actions-dropdown').click
|
|
|
|
expect(page).to have_content("00:00:00")
|
|
end
|
|
end
|
|
|
|
context 'when user played a delayed job immediately' do
|
|
before do
|
|
find('.js-environment-actions-dropdown').click
|
|
page.accept_confirm { click_button('Delayed job') }
|
|
wait_for_requests
|
|
end
|
|
|
|
it 'enqueues the delayed job', :js do
|
|
expect(delayed_job.reload).to be_pending
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'when there is a failed deployment' do
|
|
let(:project) { create(:project, :repository) }
|
|
|
|
let!(:deployment) do
|
|
create(:deployment, :failed,
|
|
environment: environment,
|
|
sha: project.commit.id)
|
|
end
|
|
|
|
it 'does not show deployments' do
|
|
visit_environments(project)
|
|
|
|
expect(page).to have_content('No deployments yet')
|
|
end
|
|
end
|
|
end
|
|
|
|
it 'does have a new environment button' do
|
|
visit_environments(project)
|
|
|
|
expect(page).to have_link('New environment')
|
|
end
|
|
|
|
describe 'creating a new environment' do
|
|
before do
|
|
visit_environments(project)
|
|
end
|
|
|
|
context 'user is a developer' do
|
|
let(:role) { :developer }
|
|
|
|
it 'developer creates a new environment with a valid name' do
|
|
within(".top-area") { click_link 'New environment' }
|
|
fill_in('Name', with: 'production')
|
|
click_on 'Save'
|
|
|
|
expect(page).to have_content('production')
|
|
end
|
|
|
|
it 'developer creates a new environmetn with invalid name' do
|
|
within(".top-area") { click_link 'New environment' }
|
|
fill_in('Name', with: 'name,with,commas')
|
|
click_on 'Save'
|
|
|
|
expect(page).to have_content('Name can contain only letters')
|
|
end
|
|
end
|
|
|
|
context 'user is a reporter' do
|
|
let(:role) { :reporter }
|
|
|
|
it 'reporters tries to create a new environment' do
|
|
expect(page).not_to have_link('New environment')
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'environments folders' do
|
|
before do
|
|
create(:environment, project: project,
|
|
name: 'staging/review-1',
|
|
state: :available)
|
|
create(:environment, project: project,
|
|
name: 'staging/review-2',
|
|
state: :available)
|
|
end
|
|
|
|
it 'users unfurls an environment folder' do
|
|
visit_environments(project)
|
|
|
|
expect(page).not_to have_content 'review-1'
|
|
expect(page).not_to have_content 'review-2'
|
|
expect(page).to have_content 'staging 2'
|
|
|
|
within('.folder-row') do
|
|
find('.folder-name', text: 'staging').click
|
|
end
|
|
|
|
expect(page).to have_content 'review-1'
|
|
expect(page).to have_content 'review-2'
|
|
end
|
|
end
|
|
|
|
describe 'environments folders view' do
|
|
before do
|
|
create(:environment, project: project,
|
|
name: 'staging.review/review-1',
|
|
state: :available)
|
|
create(:environment, project: project,
|
|
name: 'staging.review/review-2',
|
|
state: :available)
|
|
end
|
|
|
|
it 'user opens folder view' do
|
|
visit folder_project_environments_path(project, 'staging.review')
|
|
wait_for_requests
|
|
|
|
expect(page).to have_content('Environments / staging.review')
|
|
expect(page).to have_content('review-1')
|
|
expect(page).to have_content('review-2')
|
|
end
|
|
end
|
|
|
|
def have_terminal_button
|
|
have_link(nil, href: terminal_project_environment_path(project, environment))
|
|
end
|
|
|
|
def visit_environments(project, **opts)
|
|
visit project_environments_path(project, **opts)
|
|
wait_for_requests
|
|
end
|
|
end
|