Commit 8921946c authored by Jason Goodman's avatar Jason Goodman

Add spec for existing deploy boards behavior

Small refactor to existing implementation
parent d4628f0c
...@@ -28,7 +28,7 @@ module EE ...@@ -28,7 +28,7 @@ module EE
pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug) pods = filter_by_project_environment(data[:pods], project.full_path_slug, environment.slug)
legacy_deployments = filter_by_legacy_label(data[:deployments], project.full_path_slug, environment.slug) legacy_deployments = filter_by_legacy_label(data[:deployments], project.full_path_slug, environment.slug)
::Gitlab::Kubernetes::RolloutStatus.from_deployments(*deployments, pods: pods, legacy_deployments: legacy_deployments) ::Gitlab::Kubernetes::RolloutStatus.from_deployments(*deployments, pods_attrs: pods, legacy_deployments: legacy_deployments)
end end
private private
......
...@@ -7,7 +7,7 @@ module Gitlab ...@@ -7,7 +7,7 @@ module Gitlab
STABLE_TRACK_VALUE = 'stable'.freeze STABLE_TRACK_VALUE = 'stable'.freeze
def initialize(attributes = {}, pods: {}) def initialize(attributes = {}, pods: [])
@attributes = attributes @attributes = attributes
@pods = pods @pods = pods
end end
......
...@@ -30,10 +30,10 @@ module Gitlab ...@@ -30,10 +30,10 @@ module Gitlab
@status == :found @status == :found
end end
def self.from_deployments(*deployments, pods: {}, legacy_deployments: []) def self.from_deployments(*deployments, pods_attrs: [], legacy_deployments: [])
return new([], status: :not_found, legacy_deployments: legacy_deployments) if deployments.empty? return new([], status: :not_found, legacy_deployments: legacy_deployments) if deployments.empty?
deployments = deployments.map { |deploy| ::Gitlab::Kubernetes::Deployment.new(deploy, pods: pods) } deployments = deployments.map { |deploy| ::Gitlab::Kubernetes::Deployment.new(deploy, pods: pods_attrs) }
deployments.sort_by!(&:order) deployments.sort_by!(&:order)
new(deployments, legacy_deployments: legacy_deployments) new(deployments, legacy_deployments: legacy_deployments)
end end
......
...@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do ...@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do
] ]
end end
subject(:rollout_status) { described_class.from_deployments(*specs, pods: pods, legacy_deployments: legacy_deployments) } subject(:rollout_status) { described_class.from_deployments(*specs, pods_attrs: pods, legacy_deployments: legacy_deployments) }
describe '#has_legacy_app_label?' do describe '#has_legacy_app_label?' do
let(:specs) { [] } let(:specs) { [] }
...@@ -85,7 +85,7 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do ...@@ -85,7 +85,7 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do
create_pods(name: "one", count: 3, track: 'stable') + create_pods(name: "two", count: 3, track: track) create_pods(name: "one", count: 3, track: 'stable') + create_pods(name: "two", count: 3, track: track)
end end
it 'stores the union of deployment instances' do it 'sorts stable instances last' do
expected = [ expected = [
{ status: 'running', pod_name: "two", tooltip: 'two (Running)', track: 'canary', stable: false }, { status: 'running', pod_name: "two", tooltip: 'two (Running)', track: 'canary', stable: false },
{ status: 'running', pod_name: "two", tooltip: 'two (Running)', track: 'canary', stable: false }, { status: 'running', pod_name: "two", tooltip: 'two (Running)', track: 'canary', stable: false },
...@@ -104,6 +104,8 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do ...@@ -104,6 +104,8 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do
subject { rollout_status.completion } subject { rollout_status.completion }
context 'when all instances are finished' do context 'when all instances are finished' do
let(:track) { 'canary' }
it { is_expected.to eq(100) } it { is_expected.to eq(100) }
end end
...@@ -118,12 +120,83 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do ...@@ -118,12 +120,83 @@ RSpec.describe Gitlab::Kubernetes::RolloutStatus do
it { is_expected.to eq(50) } it { is_expected.to eq(50) }
end end
context 'with one deployment' do
it 'sets the completion percentage when a deployment has more running pods than desired' do
deployments = [kube_deployment(name: 'one', track: 'one', replicas: 2)]
pods = create_pods(name: 'one', track: 'one', count: 3)
rollout_status = described_class.from_deployments(*deployments, pods_attrs: pods)
expect(rollout_status.completion).to eq(100)
end
end
context 'with two deployments on different tracks' do
it 'sets the completion percentage when all pods are complete' do
deployments = [
kube_deployment(name: 'one', track: 'one', replicas: 2),
kube_deployment(name: 'two', track: 'two', replicas: 2)
]
pods = create_pods(name: 'one', track: 'one', count: 2) + create_pods(name: 'two', track: 'two', count: 2)
rollout_status = described_class.from_deployments(*deployments, pods_attrs: pods)
expect(rollout_status.completion).to eq(100)
end
end
context 'with two deployments that both have track set to "stable"' do
it 'sets the completion percentage when all pods are complete' do
deployments = [
kube_deployment(name: 'one', track: 'stable', replicas: 2),
kube_deployment(name: 'two', track: 'stable', replicas: 2)
]
pods = create_pods(name: 'one', track: 'stable', count: 2) + create_pods(name: 'two', track: 'stable', count: 2)
rollout_status = described_class.from_deployments(*deployments, pods_attrs: pods)
expect(rollout_status.completion).to eq(100)
end
it 'sets the completion percentage when no pods are complete' do
deployments = [
kube_deployment(name: 'one', track: 'stable', replicas: 3),
kube_deployment(name: 'two', track: 'stable', replicas: 7)
]
rollout_status = described_class.from_deployments(*deployments, pods_attrs: [])
expect(rollout_status.completion).to eq(0)
end
end
context 'with two deployments, one with track set to "stable" and one with no track label' do
it 'sets the completion percentage when all pods are complete' do
deployments = [
kube_deployment(name: 'one', track: 'stable', replicas: 3),
kube_deployment(name: 'two', track: nil, replicas: 3)
]
pods = create_pods(name: 'one', track: 'stable', count: 3) + create_pods(name: 'two', track: nil, count: 3)
rollout_status = described_class.from_deployments(*deployments, pods_attrs: pods)
expect(rollout_status.completion).to eq(100)
end
it 'sets the completion percentage when no pods are complete' do
deployments = [
kube_deployment(name: 'one', track: 'stable', replicas: 1),
kube_deployment(name: 'two', track: nil, replicas: 1)
]
rollout_status = described_class.from_deployments(*deployments, pods_attrs: [])
expect(rollout_status.completion).to eq(0)
end
end
end end
describe '#complete?' do describe '#complete?' do
subject { rollout_status.complete? } subject { rollout_status.complete? }
context 'when all instances are finished' do context 'when all instances are finished' do
let(:track) { 'canary' }
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
......
...@@ -121,11 +121,28 @@ RSpec.describe Clusters::Platforms::Kubernetes do ...@@ -121,11 +121,28 @@ RSpec.describe Clusters::Platforms::Kubernetes do
end end
end end
context 'with no deployments but there are pods' do
let(:deployments) do
[]
end
let(:pods) do
[
kube_pod(name: 'pod-1', environment_slug: environment.slug, project_slug: project.full_path_slug),
kube_pod(name: 'pod-2', environment_slug: environment.slug, project_slug: project.full_path_slug)
]
end
it 'returns an empty array' do
expect(rollout_status.instances).to eq([])
end
end
context 'with valid deployments' do context 'with valid deployments' do
let(:matched_deployment) { kube_deployment(environment_slug: environment.slug, project_slug: project.full_path_slug) } let(:matched_deployment) { kube_deployment(environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 2) }
let(:unmatched_deployment) { kube_deployment } let(:unmatched_deployment) { kube_deployment }
let(:matched_pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug) } let(:matched_pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: 'Pending') }
let(:unmatched_pod) { kube_pod(environment_slug: environment.slug, project_slug: project.full_path_slug, status: 'Pending') } let(:unmatched_pod) { kube_pod(environment_slug: environment.slug + '-test', project_slug: project.full_path_slug) }
let(:deployments) { [matched_deployment, unmatched_deployment] } let(:deployments) { [matched_deployment, unmatched_deployment] }
let(:pods) { [matched_pod, unmatched_pod] } let(:pods) { [matched_pod, unmatched_pod] }
...@@ -134,6 +151,16 @@ RSpec.describe Clusters::Platforms::Kubernetes do ...@@ -134,6 +151,16 @@ RSpec.describe Clusters::Platforms::Kubernetes do
expect(rollout_status.deployments.map(&:annotations)).to eq([ expect(rollout_status.deployments.map(&:annotations)).to eq([
{ 'app.gitlab.com/app' => project.full_path_slug, 'app.gitlab.com/env' => 'env-000000' } { 'app.gitlab.com/app' => project.full_path_slug, 'app.gitlab.com/env' => 'env-000000' }
]) ])
expect(rollout_status.instances).to eq([{ pod_name: "kube-pod",
stable: true,
status: "pending",
tooltip: "kube-pod (Pending)",
track: "stable" },
{ pod_name: "Not provided",
stable: true,
status: "pending",
tooltip: "Not provided (Pending)",
track: "stable" }])
end end
end end
...@@ -143,6 +170,145 @@ RSpec.describe Clusters::Platforms::Kubernetes do ...@@ -143,6 +170,145 @@ RSpec.describe Clusters::Platforms::Kubernetes do
expect(rollout_status).to be_not_found expect(rollout_status).to be_not_found
end end
end end
context 'when the pod track does not match the deployment track' do
let(:deployments) do
[
kube_deployment(name: 'deployment-a', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 1, track: 'weekly')
]
end
let(:pods) do
[
kube_pod(name: 'pod-a-1', environment_slug: environment.slug, project_slug: project.full_path_slug, track: 'weekly'),
kube_pod(name: 'pod-a-2', environment_slug: environment.slug, project_slug: project.full_path_slug, track: 'daily')
]
end
it 'does not return the pod' do
expect(rollout_status.instances.map { |p| p[:pod_name] }).to eq(['pod-a-1'])
end
end
context 'when the pod track is not stable' do
let(:deployments) do
[
kube_deployment(name: 'deployment-a', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 1, track: 'something')
]
end
let(:pods) do
[
kube_pod(name: 'pod-a-1', environment_slug: environment.slug, project_slug: project.full_path_slug, track: 'something')
]
end
it 'the pod is not stable' do
expect(rollout_status.instances.map { |p| p.slice(:stable, :track) }).to eq([{ stable: false, track: 'something' }])
end
end
context 'when the pod track is stable' do
let(:deployments) do
[
kube_deployment(name: 'deployment-a', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 1, track: 'stable')
]
end
let(:pods) do
[
kube_pod(name: 'pod-a-1', environment_slug: environment.slug, project_slug: project.full_path_slug, track: 'stable')
]
end
it 'the pod is stable' do
expect(rollout_status.instances.map { |p| p.slice(:stable, :track) }).to eq([{ stable: true, track: 'stable' }])
end
end
context 'when the pod track is not provided' do
let(:deployments) do
[
kube_deployment(name: 'deployment-a', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 1)
]
end
let(:pods) do
[
kube_pod(name: 'pod-a-1', environment_slug: environment.slug, project_slug: project.full_path_slug)
]
end
it 'the pod is stable' do
expect(rollout_status.instances.map { |p| p.slice(:stable, :track) }).to eq([{ stable: true, track: 'stable' }])
end
end
context 'when the number of matching pods does not match the number of replicas' do
let(:deployments) do
[
kube_deployment(name: 'deployment-a', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 3)
]
end
let(:pods) do
[
kube_pod(name: 'pod-a-1', environment_slug: environment.slug, project_slug: project.full_path_slug)
]
end
it 'returns a pending pod for each missing replica' do
expect(rollout_status.instances.map { |p| p.slice(:pod_name, :status) }).to eq([
{ pod_name: 'pod-a-1', status: 'running' },
{ pod_name: 'Not provided', status: 'pending' },
{ pod_name: 'Not provided', status: 'pending' }
])
end
end
context 'when pending pods are returned for missing replicas' do
let(:deployments) do
[
kube_deployment(name: 'deployment-a', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 2, track: 'canary'),
kube_deployment(name: 'deployment-b', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 2, track: 'stable')
]
end
let(:pods) do
[
kube_pod(name: 'pod-a-1', environment_slug: environment.slug, project_slug: project.full_path_slug, track: 'canary')
]
end
it 'returns the correct track for the pending pods' do
expect(rollout_status.instances.map { |p| p.slice(:pod_name, :status, :track) }).to eq([
{ pod_name: 'pod-a-1', status: 'running', track: 'canary' },
{ pod_name: 'Not provided', status: 'pending', track: 'canary' },
{ pod_name: 'Not provided', status: 'pending', track: 'stable' },
{ pod_name: 'Not provided', status: 'pending', track: 'stable' }
])
end
end
context 'when two deployments with the same track are missing instances' do
let(:deployments) do
[
kube_deployment(name: 'deployment-a', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 1, track: 'mytrack'),
kube_deployment(name: 'deployment-b', environment_slug: environment.slug, project_slug: project.full_path_slug, replicas: 1, track: 'mytrack')
]
end
let(:pods) do
[]
end
it 'returns the correct number of pending pods' do
expect(rollout_status.instances.map { |p| p.slice(:pod_name, :status, :track) }).to eq([
{ pod_name: 'Not provided', status: 'pending', track: 'mytrack' },
{ pod_name: 'Not provided', status: 'pending', track: 'mytrack' }
])
end
end
end end
describe '#calculate_reactive_cache_for' do describe '#calculate_reactive_cache_for' do
......
...@@ -604,7 +604,7 @@ module KubernetesHelpers ...@@ -604,7 +604,7 @@ module KubernetesHelpers
} }
end end
def kube_deployment(name: "kube-deployment", environment_slug: "production", project_slug: "project-path-slug", track: nil) def kube_deployment(name: "kube-deployment", environment_slug: "production", project_slug: "project-path-slug", track: nil, replicas: 3)
{ {
"metadata" => { "metadata" => {
"name" => name, "name" => name,
...@@ -617,7 +617,7 @@ module KubernetesHelpers ...@@ -617,7 +617,7 @@ module KubernetesHelpers
"track" => track "track" => track
}.compact }.compact
}, },
"spec" => { "replicas" => 3 }, "spec" => { "replicas" => replicas },
"status" => { "status" => {
"observedGeneration" => 4 "observedGeneration" => 4
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment