spec/support/shared_examples/environment_state_shared_examples.rb (146 lines of code) (raw):
# frozen_string_literal: true
require 'spec_helper'
RSpec.shared_examples 'staging and production' do
subject(:perform_event) { service.perform_event(event) }
let!(:service) { described_class.new }
let(:deployments) { [build(:deployment, :success, sha: 'abcd1234')] }
let(:gprd_version) do
build(:product_version, auto_deploy_ref: '16.10.202402100400-abdf1234567.abcdef12345')
end
before do
allow(ReleaseTools::GitlabOpsClient)
.to receive(:deployments)
.and_return(deployments)
allow(ReleaseTools::ProductVersion)
.to receive(:each)
.and_yield(ReleaseTools::ProductVersion.new('16.10.202402101000'))
.and_yield(ReleaseTools::ProductVersion.new('16.10.202402100800'))
.and_yield(ReleaseTools::ProductVersion.new('16.10.202402100400'))
allow(ReleaseTools::GitlabOpsClient)
.to receive(:pipelines)
.with(ReleaseTools::Project::ReleaseTools, name: 'Coordinator pipeline', ref: '16.10.202402101000')
.and_return([build(:pipeline, id: 10, ref: '16.10.202402101000')])
allow(ReleaseTools::GitlabOpsClient)
.to receive(:pipelines)
.with(ReleaseTools::Project::ReleaseTools, name: 'Coordinator pipeline', ref: '16.10.202402100800')
.and_return([build(:pipeline, id: 8, ref: '16.10.202402100800')])
allow(ReleaseTools::GitlabOpsClient)
.to receive(:pipelines)
.with(ReleaseTools::Project::ReleaseTools, name: 'Coordinator pipeline', ref: '16.10.202402100400')
.and_return([build(:pipeline, id: 6, ref: '16.10.202402100400')])
allow(ReleaseTools::ProductVersion)
.to receive(:from_metadata_sha)
.with('abcd1234')
.and_return(gprd_version)
allow(ReleaseTools::GitlabOpsClient)
.to receive(:pipeline_jobs)
.with(ReleaseTools::Project::ReleaseTools, 10, scope: described_class::PROMOTE_JOB_VALID_STATES)
.and_return(Gitlab::PaginatedResponse.new([]))
allow(ReleaseTools::GitlabOpsClient)
.to receive(:pipeline_jobs)
.with(ReleaseTools::Project::ReleaseTools, 8, scope: described_class::PROMOTE_JOB_VALID_STATES)
.and_return(Gitlab::PaginatedResponse.new([build(:job, name: 'promote')]))
allow(ReleaseTools::GitlabOpsClient)
.to receive(:pipeline_jobs)
.with(ReleaseTools::Project::ReleaseTools, 6, scope: described_class::PROMOTE_JOB_VALID_STATES)
.and_return(Gitlab::PaginatedResponse.new([build(:job, name: 'promote')]))
end
where(:locked_state_metric_value, :ready_state_metric_value, :baking_time_metric_value, :awaiting_promotion, :event, :validity, :new_state) do
[
['0', '0', '0', '0', 'success', true, 'awaiting_promotion'],
['0', '0', '0', '0', 'start', true, 'locked'],
['1', '0', '0', '0', 'success', true, 'awaiting_promotion'],
['1', '0', '0', '0', 'start', true, 'locked'],
['0', '1', '0', '0', 'start', true, 'locked'],
['0', '1', '0', '0', 'success', false, 'ready'],
['0', '1', '0', '0', 'baking_complete', true, 'awaiting_promotion'],
['1', '0', '0', '0', 'baking_complete', false, 'locked']
]
end
with_them do
it "returns validity" do
expect(perform_event).to eq(validity)
expect(service.current_state).to eq(new_state)
end
end
context 'when there are no new packages available for promotion' do
before do
allow(ReleaseTools::GitlabOpsClient)
.to receive(:pipeline_jobs)
.with(ReleaseTools::Project::ReleaseTools, 8, scope: described_class::PROMOTE_JOB_VALID_STATES)
.and_return(Gitlab::PaginatedResponse.new([]))
end
where(:locked_state_metric_value, :ready_state_metric_value, :baking_time_metric_value, :awaiting_promotion, :event, :validity, :new_state) do
[
['0', '0', '0', '0', 'success', true, 'ready'],
['1', '0', '0', '0', 'success', true, 'ready'],
['0', '1', '0', '0', 'baking_complete', false, 'ready']
]
end
with_them do
it "returns validity and moves state" do
expect(perform_event).to eq(validity)
expect(service.current_state).to eq(new_state)
end
end
end
end
# Stub query to Prometheus for `auto_deploy_environment_state` metric
RSpec.shared_context 'environment state transition context' do |environment, stage|
let(:query_string) { "auto_deploy_environment_state{target_env=\"#{environment}\",target_stage=\"#{stage}\"}" }
let(:query_spy) { instance_spy(ReleaseTools::Prometheus::Query) }
let(:results) do
[
{
"metric" => {
"__name__" => "auto_deploy_environment_state",
"target_env" => "gstg",
"target_stage" => "cny",
"env_state" => 'ready'
},
"value" => [1_435_781_451.781, ready_state_metric_value]
},
{
"metric" => {
"__name__" => "auto_deploy_environment_state",
"target_env" => "gstg",
"target_stage" => "cny",
"env_state" => 'locked'
},
"value" => [1_435_781_451.781, locked_state_metric_value]
}
]
end
let(:response) do
{
"status" => "success",
"data" => {
"resultType" => "vector",
"result" => results
}
}
end
before do
allow(ReleaseTools::Prometheus::Query).to receive(:new).and_return(query_spy)
allow(query_spy).to receive(:run).with(query_string).and_return(response)
end
end
RSpec.shared_examples 'environment state transition' do |environment, stage|
include_context 'metric registry'
include_context 'environment state transition context', environment, stage
let(:new_state) { 'ready' }
let(:ready_state_metric_value) { '0' }
let(:locked_state_metric_value) { '1' }
describe '#current_state' do
subject(:current_state) { described_class.new.current_state }
context 'with non nil current state' do
it 'returns current_state' do
expect(current_state).to eq('locked')
end
end
context 'with nil state' do
let(:locked_state_metric_value) { '0' }
it 'returns initial state' do
expect(current_state).to eq('initial')
end
end
end
end