Commit ee0b11f5 authored by Sean McGivern's avatar Sean McGivern

Merge branch 'move-limits-out-of-plans' into 'master'

Move limits from Plan to new PlanLimits model

See merge request gitlab-org/gitlab!19438
parents 1d8f7f5c 724bafee
# frozen_string_literal: true
class CreatePlanLimits < ActiveRecord::Migration[5.2]
DOWNTIME = false
def change
create_table :plan_limits, id: false do |t|
t.references :plan, foreign_key: { on_delete: :cascade }, null: false, index: { unique: true }
t.integer :ci_active_pipelines, null: false, default: 0
t.integer :ci_pipeline_size, null: false, default: 0
t.integer :ci_active_jobs, null: false, default: 0
end
end
end
# frozen_string_literal: true
class MoveLimitsFromPlans < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
execute <<~SQL
INSERT INTO plan_limits (plan_id, ci_active_pipelines, ci_pipeline_size, ci_active_jobs)
SELECT id, COALESCE(active_pipelines_limit, 0), COALESCE(pipeline_size_limit, 0), COALESCE(active_jobs_limit, 0)
FROM plans
SQL
end
def down
execute 'DELETE FROM plan_limits'
end
end
# frozen_string_literal: true
class RemoveLimitsFromPlans < ActiveRecord::Migration[5.2]
DOWNTIME = false
def up
remove_column :plans, :active_pipelines_limit
remove_column :plans, :pipeline_size_limit
remove_column :plans, :active_jobs_limit
end
def down
add_column :plans, :active_pipelines_limit, :integer
add_column :plans, :pipeline_size_limit, :integer
add_column :plans, :active_jobs_limit, :integer
end
end
...@@ -2802,14 +2802,19 @@ ActiveRecord::Schema.define(version: 2019_11_12_115317) do ...@@ -2802,14 +2802,19 @@ ActiveRecord::Schema.define(version: 2019_11_12_115317) do
t.index ["user_id"], name: "index_personal_access_tokens_on_user_id" t.index ["user_id"], name: "index_personal_access_tokens_on_user_id"
end end
create_table "plan_limits", force: :cascade do |t|
t.bigint "plan_id", null: false
t.integer "ci_active_pipelines", default: 0, null: false
t.integer "ci_pipeline_size", default: 0, null: false
t.integer "ci_active_jobs", default: 0, null: false
t.index ["plan_id"], name: "index_plan_limits_on_plan_id", unique: true
end
create_table "plans", id: :serial, force: :cascade do |t| create_table "plans", id: :serial, force: :cascade do |t|
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.string "name" t.string "name"
t.string "title" t.string "title"
t.integer "active_pipelines_limit"
t.integer "pipeline_size_limit"
t.integer "active_jobs_limit", default: 0
t.index ["name"], name: "index_plans_on_name" t.index ["name"], name: "index_plans_on_name"
end end
...@@ -4389,6 +4394,7 @@ ActiveRecord::Schema.define(version: 2019_11_12_115317) do ...@@ -4389,6 +4394,7 @@ ActiveRecord::Schema.define(version: 2019_11_12_115317) do
add_foreign_key "path_locks", "projects", name: "fk_5265c98f24", on_delete: :cascade add_foreign_key "path_locks", "projects", name: "fk_5265c98f24", on_delete: :cascade
add_foreign_key "path_locks", "users" add_foreign_key "path_locks", "users"
add_foreign_key "personal_access_tokens", "users" add_foreign_key "personal_access_tokens", "users"
add_foreign_key "plan_limits", "plans", on_delete: :cascade
add_foreign_key "pool_repositories", "projects", column: "source_project_id", on_delete: :nullify add_foreign_key "pool_repositories", "projects", column: "source_project_id", on_delete: :nullify
add_foreign_key "pool_repositories", "shards", on_delete: :restrict add_foreign_key "pool_repositories", "shards", on_delete: :restrict
add_foreign_key "project_alerting_settings", "projects", on_delete: :cascade add_foreign_key "project_alerting_settings", "projects", on_delete: :cascade
......
...@@ -148,6 +148,13 @@ module EE ...@@ -148,6 +148,13 @@ module EE
end end
end end
def actual_limits
# We default to PlanLimits.new otherwise a lot of specs would fail
# On production each plan should already have associated limits record
# https://gitlab.com/gitlab-org/gitlab/issues/36037
actual_plan&.limits || PlanLimits.new
end
def actual_plan_name def actual_plan_name
actual_plan&.name || Plan::FREE actual_plan&.name || Plan::FREE
end end
...@@ -208,20 +215,6 @@ module EE ...@@ -208,20 +215,6 @@ module EE
end end
end end
# TODO, CI/CD Quotas feature check
#
def max_active_pipelines
actual_plan&.active_pipelines_limit.to_i
end
def max_pipeline_size
actual_plan&.pipeline_size_limit.to_i
end
def max_active_jobs
actual_plan&.active_jobs_limit.to_i
end
def memoized_plans=(plans) def memoized_plans=(plans)
@plans = plans # rubocop: disable Gitlab/ModuleWithInstanceVariables @plans = plans # rubocop: disable Gitlab/ModuleWithInstanceVariables
end end
......
# frozen_string_literal: true # frozen_string_literal: true
class Plan < ApplicationRecord class Plan < ApplicationRecord
# Remove these in version >= 12.6
self.ignored_columns += %i[active_pipelines_limit pipeline_size_limit active_jobs_limit]
DEFAULT = 'default'.freeze DEFAULT = 'default'.freeze
FREE = 'free'.freeze FREE = 'free'.freeze
BRONZE = 'bronze'.freeze BRONZE = 'bronze'.freeze
...@@ -15,6 +18,7 @@ class Plan < ApplicationRecord ...@@ -15,6 +18,7 @@ class Plan < ApplicationRecord
has_many :namespaces has_many :namespaces
has_many :hosted_subscriptions, class_name: 'GitlabSubscription', foreign_key: 'hosted_plan_id' has_many :hosted_subscriptions, class_name: 'GitlabSubscription', foreign_key: 'hosted_plan_id'
has_one :limits, class_name: 'PlanLimits'
def self.default def self.default
Gitlab::SafeRequestStore[:plan_default] ||= find_by(name: DEFAULT) Gitlab::SafeRequestStore[:plan_default] ||= find_by(name: DEFAULT)
......
# frozen_string_literal: true
class PlanLimits < ApplicationRecord
self.primary_key = :plan_id
belongs_to :plan
end
...@@ -6,6 +6,7 @@ module EE ...@@ -6,6 +6,7 @@ module EE
module Pipeline module Pipeline
module Quota module Quota
class Activity < Ci::Limit class Activity < Ci::Limit
include ::Gitlab::Utils::StrongMemoize
include ActionView::Helpers::TextHelper include ActionView::Helpers::TextHelper
def initialize(namespace, project) def initialize(namespace, project)
...@@ -14,7 +15,7 @@ module EE ...@@ -14,7 +15,7 @@ module EE
end end
def enabled? def enabled?
@namespace.max_active_pipelines > 0 ci_active_pipelines_limit > 0
end end
def exceeded? def exceeded?
...@@ -33,15 +34,17 @@ module EE ...@@ -33,15 +34,17 @@ module EE
private private
def excessive_pipelines_count def excessive_pipelines_count
@excessive ||= alive_pipelines_count - max_active_pipelines_count @excessive ||= alive_pipelines_count - ci_active_pipelines_limit
end end
def alive_pipelines_count def alive_pipelines_count
@project.ci_pipelines.alive.count @project.ci_pipelines.alive.count
end end
def max_active_pipelines_count def ci_active_pipelines_limit
@namespace.max_active_pipelines strong_memoize(:ci_active_pipelines_limit) do
@namespace.actual_limits.ci_active_pipelines
end
end end
end end
end end
......
...@@ -15,9 +15,7 @@ module EE ...@@ -15,9 +15,7 @@ module EE
end end
def enabled? def enabled?
strong_memoize(:enabled) do ci_active_jobs_limit > 0
@namespace.max_active_jobs > 0
end
end end
def exceeded? def exceeded?
...@@ -36,7 +34,7 @@ module EE ...@@ -36,7 +34,7 @@ module EE
private private
def excessive_jobs_count def excessive_jobs_count
@excessive ||= jobs_in_alive_pipelines_count - max_active_jobs_count @excessive ||= jobs_in_alive_pipelines_count - ci_active_jobs_limit
end end
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
...@@ -45,8 +43,10 @@ module EE ...@@ -45,8 +43,10 @@ module EE
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def max_active_jobs_count def ci_active_jobs_limit
@namespace.max_active_jobs strong_memoize(:ci_active_jobs_limit) do
@namespace.actual_limits.ci_active_jobs
end
end end
end end
end end
......
...@@ -6,6 +6,7 @@ module EE ...@@ -6,6 +6,7 @@ module EE
module Pipeline module Pipeline
module Quota module Quota
class Size < Ci::Limit class Size < Ci::Limit
include ::Gitlab::Utils::StrongMemoize
include ActionView::Helpers::TextHelper include ActionView::Helpers::TextHelper
def initialize(namespace, pipeline) def initialize(namespace, pipeline)
...@@ -14,7 +15,7 @@ module EE ...@@ -14,7 +15,7 @@ module EE
end end
def enabled? def enabled?
@namespace.max_pipeline_size > 0 ci_pipeline_size_limit > 0
end end
def exceeded? def exceeded?
...@@ -33,7 +34,13 @@ module EE ...@@ -33,7 +34,13 @@ module EE
private private
def excessive_seeds_count def excessive_seeds_count
@excessive ||= @pipeline.seeds_size - @namespace.max_pipeline_size @excessive ||= @pipeline.seeds_size - ci_pipeline_size_limit
end
def ci_pipeline_size_limit
strong_memoize(:ci_pipeline_size_limit) do
@namespace.actual_limits.ci_pipeline_size
end
end end
end end
end end
......
# frozen_string_literal: true
# EE-only
FactoryBot.define do
factory :plan_limits do
plan
end
end
...@@ -4,14 +4,12 @@ require 'spec_helper' ...@@ -4,14 +4,12 @@ require 'spec_helper'
describe EE::Gitlab::Ci::Pipeline::Quota::Activity do describe EE::Gitlab::Ci::Pipeline::Quota::Activity do
set(:namespace) { create(:namespace) } set(:namespace) { create(:namespace) }
set(:gold_plan) { create(:gold_plan) }
set(:project) { create(:project, namespace: namespace) } set(:project) { create(:project, namespace: namespace) }
set(:gold_plan) { create(:gold_plan) }
let(:plan_limits) { create(:plan_limits, plan: gold_plan) }
let!(:subscription) { create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) }
let(:limit) { described_class.new(namespace, project) } subject { described_class.new(namespace, project) }
before do
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
shared_context 'pipeline activity limit exceeded' do shared_context 'pipeline activity limit exceeded' do
before do before do
...@@ -19,34 +17,44 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do ...@@ -19,34 +17,44 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do
create(:ci_pipeline, project: project, status: 'pending') create(:ci_pipeline, project: project, status: 'pending')
create(:ci_pipeline, project: project, status: 'running') create(:ci_pipeline, project: project, status: 'running')
gold_plan.update_column(:active_pipelines_limit, 1) plan_limits.update(ci_active_pipelines: 1)
end end
end end
shared_context 'pipeline activity limit not exceeded' do shared_context 'pipeline activity limit not exceeded' do
before do before do
gold_plan.update_column(:active_pipelines_limit, 2) plan_limits.update!(ci_active_pipelines: 2)
end end
end end
describe '#enabled?' do describe '#enabled?' do
context 'when limit is enabled in plan' do context 'when limit is enabled in plan' do
before do before do
gold_plan.update_column(:active_pipelines_limit, 10) plan_limits.update!(ci_active_pipelines: 10)
end end
it 'is enabled' do it 'is enabled' do
expect(limit).to be_enabled expect(subject).to be_enabled
end end
end end
context 'when limit is not enabled' do context 'when limit is not enabled' do
before do before do
gold_plan.update_column(:active_pipelines_limit, 0) plan_limits.update!(ci_active_pipelines: 0)
end
it 'is not enabled' do
expect(subject).not_to be_enabled
end
end
context 'when limit does not exist' do
before do
allow(namespace).to receive(:actual_plan) { create(:default_plan) }
end end
it 'is not enabled' do it 'is not enabled' do
expect(limit).not_to be_enabled expect(subject).not_to be_enabled
end end
end end
end end
...@@ -56,7 +64,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do ...@@ -56,7 +64,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do
include_context 'pipeline activity limit exceeded' include_context 'pipeline activity limit exceeded'
it 'is exceeded' do it 'is exceeded' do
expect(limit).to be_exceeded expect(subject).to be_exceeded
end end
end end
...@@ -64,7 +72,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do ...@@ -64,7 +72,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do
include_context 'pipeline activity limit not exceeded' include_context 'pipeline activity limit not exceeded'
it 'is not exceeded' do it 'is not exceeded' do
expect(limit).not_to be_exceeded expect(subject).not_to be_exceeded
end end
end end
end end
...@@ -74,7 +82,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do ...@@ -74,7 +82,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Activity do
include_context 'pipeline activity limit exceeded' include_context 'pipeline activity limit exceeded'
it 'returns info about pipeline activity limit exceeded' do it 'returns info about pipeline activity limit exceeded' do
expect(limit.message) expect(subject.message)
.to eq "Active pipelines limit exceeded by 2 pipelines!" .to eq "Active pipelines limit exceeded by 2 pipelines!"
end end
end end
......
...@@ -5,34 +5,48 @@ require 'spec_helper' ...@@ -5,34 +5,48 @@ require 'spec_helper'
describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do
let_it_be(:namespace, refind: true) { create(:namespace) } let_it_be(:namespace, refind: true) { create(:namespace) }
let_it_be(:project, refind: true) { create(:project, namespace: namespace) } let_it_be(:project, refind: true) { create(:project, namespace: namespace) }
let(:gold_plan) { create(:gold_plan, active_jobs_limit: active_jobs_limit) } set(:gold_plan) { create(:gold_plan) }
set(:plan_limits) { create(:plan_limits, plan: gold_plan) }
let!(:subscription) { create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) }
let(:limit) { described_class.new(namespace, project) } subject { described_class.new(namespace, project) }
before do
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
describe '#enabled?' do describe '#enabled?' do
context 'when limit is enabled in plan' do context 'when limit is enabled in plan' do
let(:active_jobs_limit) { 10 } before do
plan_limits.update!(ci_active_jobs: 10)
end
it 'is enabled' do it 'is enabled' do
expect(limit).to be_enabled expect(subject).to be_enabled
end end
end end
context 'when limit is not enabled' do context 'when limit is not enabled' do
let(:active_jobs_limit) { 0 } before do
plan_limits.update!(ci_active_jobs: 0)
end
it 'is not enabled' do
expect(subject).not_to be_enabled
end
end
context 'when limit does not exist' do
before do
allow(namespace).to receive(:actual_plan) { create(:default_plan) }
end
it 'is not enabled' do it 'is not enabled' do
expect(limit).not_to be_enabled expect(subject).not_to be_enabled
end end
end end
end end
describe '#exceeded?' do describe '#exceeded?' do
let(:active_jobs_limit) { 2 } before do
plan_limits.update!(ci_active_jobs: 2)
end
context 'when pipelines created recently' do context 'when pipelines created recently' do
context 'and pipelines are running' do context 'and pipelines are running' do
...@@ -46,7 +60,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do ...@@ -46,7 +60,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do
context 'when count of jobs in alive pipelines is below the limit' do context 'when count of jobs in alive pipelines is below the limit' do
it 'is not exceeded' do it 'is not exceeded' do
expect(limit).not_to be_exceeded expect(subject).not_to be_exceeded
end end
end end
...@@ -56,7 +70,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do ...@@ -56,7 +70,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do
end end
it 'is exceeded' do it 'is exceeded' do
expect(limit).to be_exceeded expect(subject).to be_exceeded
end end
end end
end end
...@@ -71,7 +85,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do ...@@ -71,7 +85,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do
end end
it 'is not exceeded' do it 'is not exceeded' do
expect(limit).not_to be_exceeded expect(subject).not_to be_exceeded
end end
end end
end end
...@@ -86,16 +100,16 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do ...@@ -86,16 +100,16 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do
end end
it 'is not exceeded' do it 'is not exceeded' do
expect(limit).not_to be_exceeded expect(subject).not_to be_exceeded
end end
end end
end end
describe '#message' do describe '#message' do
context 'when limit is exceeded' do context 'when limit is exceeded' do
let(:active_jobs_limit) { 1 }
before do before do
plan_limits.update!(ci_active_jobs: 1)
create(:ci_pipeline, project: project, status: 'created', created_at: Time.now).tap do |pipeline| create(:ci_pipeline, project: project, status: 'created', created_at: Time.now).tap do |pipeline|
create(:ci_build, pipeline: pipeline) create(:ci_build, pipeline: pipeline)
create(:ci_build, pipeline: pipeline) create(:ci_build, pipeline: pipeline)
...@@ -104,7 +118,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do ...@@ -104,7 +118,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::JobActivity do
end end
it 'returns info about pipeline activity limit exceeded' do it 'returns info about pipeline activity limit exceeded' do
expect(limit.message) expect(subject.message)
.to eq "Active jobs limit exceeded by 2 jobs in the past 24 hours!" .to eq "Active jobs limit exceeded by 2 jobs in the past 24 hours!"
end end
end end
......
...@@ -6,13 +6,12 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do ...@@ -6,13 +6,12 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do
set(:namespace) { create(:namespace) } set(:namespace) { create(:namespace) }
set(:gold_plan) { create(:gold_plan) } set(:gold_plan) { create(:gold_plan) }
set(:project) { create(:project, :repository, namespace: namespace) } set(:project) { create(:project, :repository, namespace: namespace) }
set(:plan_limits) { create(:plan_limits, plan: gold_plan) }
let!(:subscription) { create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) }
let(:pipeline) { build_stubbed(:ci_pipeline, project: project) } let(:pipeline) { build_stubbed(:ci_pipeline, project: project) }
let(:limit) { described_class.new(namespace, pipeline) }
before do subject { described_class.new(namespace, pipeline) }
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
shared_context 'pipeline size limit exceeded' do shared_context 'pipeline size limit exceeded' do
let(:pipeline) do let(:pipeline) do
...@@ -23,7 +22,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do ...@@ -23,7 +22,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do
end end
before do before do
gold_plan.update_column(:pipeline_size_limit, 1) plan_limits.update!(ci_pipeline_size: 1)
end end
end end
...@@ -31,28 +30,38 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do ...@@ -31,28 +30,38 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do
let(:pipeline) { build(:ci_pipeline_with_one_job, project: project) } let(:pipeline) { build(:ci_pipeline_with_one_job, project: project) }
before do before do
gold_plan.update_column(:pipeline_size_limit, 2) plan_limits.update!(ci_pipeline_size: 2)
end end
end end
describe '#enabled?' do describe '#enabled?' do
context 'when limit is enabled in plan' do context 'when limit is enabled in plan' do
before do before do
gold_plan.update_column(:pipeline_size_limit, 10) plan_limits.update!(ci_pipeline_size: 10)
end end
it 'is enabled' do it 'is enabled' do
expect(limit).to be_enabled expect(subject).to be_enabled
end end
end end
context 'when limit is not enabled' do context 'when limit is not enabled' do
before do before do
gold_plan.update_column(:pipeline_size_limit, 0) plan_limits.update!(ci_pipeline_size: 0)
end
it 'is not enabled' do
expect(subject).not_to be_enabled
end
end
context 'when limit does not exist' do
before do
allow(namespace).to receive(:actual_plan) { create(:default_plan) }
end end
it 'is not enabled' do it 'is not enabled' do
expect(limit).not_to be_enabled expect(subject).not_to be_enabled
end end
end end
end end
...@@ -62,7 +71,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do ...@@ -62,7 +71,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do
include_context 'pipeline size limit exceeded' include_context 'pipeline size limit exceeded'
it 'is exceeded' do it 'is exceeded' do
expect(limit).to be_exceeded expect(subject).to be_exceeded
end end
end end
...@@ -70,7 +79,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do ...@@ -70,7 +79,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do
include_context 'pipeline size limit not exceeded' include_context 'pipeline size limit not exceeded'
it 'is not exceeded' do it 'is not exceeded' do
expect(limit).not_to be_exceeded expect(subject).not_to be_exceeded
end end
end end
end end
...@@ -80,7 +89,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do ...@@ -80,7 +89,7 @@ describe EE::Gitlab::Ci::Pipeline::Quota::Size do
include_context 'pipeline size limit exceeded' include_context 'pipeline size limit exceeded'
it 'returns infor about pipeline size limit exceeded' do it 'returns infor about pipeline size limit exceeded' do
expect(limit.message) expect(subject.message)
.to eq "Pipeline size limit exceeded by 1 job!" .to eq "Pipeline size limit exceeded by 1 job!"
end end
end end
......
...@@ -21,7 +21,8 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Activity do ...@@ -21,7 +21,8 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Activity do
context 'when active pipelines limit is exceeded' do context 'when active pipelines limit is exceeded' do
before do before do
gold_plan = create(:gold_plan, active_pipelines_limit: 1) gold_plan = create(:gold_plan)
create(:plan_limits, plan: gold_plan, ci_active_pipelines: 1)
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
create(:ci_pipeline, project: project, status: 'pending') create(:ci_pipeline, project: project, status: 'pending')
...@@ -63,6 +64,12 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Activity do ...@@ -63,6 +64,12 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Activity do
end end
context 'when pipeline activity limit is not exceeded' do context 'when pipeline activity limit is not exceeded' do
before do
gold_plan = create(:gold_plan)
create(:plan_limits, plan: gold_plan, ci_active_pipelines: 100)
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
it 'does not break the chain' do it 'does not break the chain' do
subject subject
......
...@@ -21,7 +21,8 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::JobActivity do ...@@ -21,7 +21,8 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::JobActivity do
context 'when active jobs limit is exceeded' do context 'when active jobs limit is exceeded' do
before do before do
gold_plan = create(:gold_plan, active_jobs_limit: 2) gold_plan = create(:gold_plan)
create(:plan_limits, plan: gold_plan, ci_active_jobs: 2)
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
pipeline = create(:ci_pipeline, project: project, status: 'running', created_at: Time.now) pipeline = create(:ci_pipeline, project: project, status: 'running', created_at: Time.now)
...@@ -65,6 +66,12 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::JobActivity do ...@@ -65,6 +66,12 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::JobActivity do
end end
context 'when job activity limit is not exceeded' do context 'when job activity limit is not exceeded' do
before do
gold_plan = create(:gold_plan)
create(:plan_limits, plan: gold_plan, ci_active_jobs: 100)
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
it 'does not break the chain' do it 'does not break the chain' do
subject subject
......
...@@ -23,7 +23,8 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Size do ...@@ -23,7 +23,8 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Size do
context 'when pipeline size limit is exceeded' do context 'when pipeline size limit is exceeded' do
before do before do
gold_plan = create(:gold_plan, pipeline_size_limit: 1) gold_plan = create(:gold_plan)
create(:plan_limits, plan: gold_plan, ci_pipeline_size: 1)
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end end
...@@ -104,6 +105,12 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Size do ...@@ -104,6 +105,12 @@ describe ::Gitlab::Ci::Pipeline::Chain::Limit::Size do
end end
context 'when pipeline size limit is not exceeded' do context 'when pipeline size limit is not exceeded' do
before do
gold_plan = create(:gold_plan)
create(:plan_limits, plan: gold_plan, ci_pipeline_size: 100)
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
it 'does not break the chain' do it 'does not break the chain' do
subject subject
......
...@@ -270,119 +270,84 @@ describe Namespace do ...@@ -270,119 +270,84 @@ describe Namespace do
end end
end end
describe '#max_active_pipelines' do describe '#actual_limits' do
context 'when there is no limit defined' do subject { namespace.actual_limits }
it 'returns zero' do
expect(namespace.max_active_pipelines).to be_zero
end
end
context 'when free plan has limit defined' do
before do
free_plan.update_column(:active_pipelines_limit, 40)
end
it 'returns a free plan limits' do
expect(namespace.max_active_pipelines).to be 40
end
end
context 'when associated plan has no limit defined' do
before do
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
it 'returns zero' do
expect(namespace.max_active_pipelines).to be_zero
end
end
context 'when limit is defined' do shared_examples 'uses an implied configuration' do
before do it 'is a non persisted PlanLimits' do
gold_plan.update_column(:active_pipelines_limit, 10) expect(subject.id).to be_nil
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) expect(subject).to be_kind_of(PlanLimits)
end end
it 'returns a number of maximum active pipelines' do it 'has all limits disabled' do
expect(namespace.max_active_pipelines).to eq 10 limits = subject.attributes.except('id', 'plan_id')
limits.each do |_attribute, limit|
expect(limit).to be_zero
end
end end
end end
end
describe '#max_pipeline_size' do context 'when no limits are defined in the system' do
context 'when there are no limits defined' do it_behaves_like 'uses an implied configuration'
it 'returns zero' do
expect(namespace.max_pipeline_size).to be_zero
end
end end
context 'when free plan has limit defined' do context 'when "default" plan is defined in the system' do
before do let!(:default_plan) { create(:default_plan) }
free_plan.update_column(:pipeline_size_limit, 40)
end
it 'returns a free plan limits' do
expect(namespace.max_pipeline_size).to be 40
end
end
context 'when associated plan has no limits defined' do context 'when no limits are set' do
before do it_behaves_like 'uses an implied configuration'
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end end
it 'returns zero' do context 'when limits are set for the default plan' do
expect(namespace.max_pipeline_size).to be_zero let!(:default_limits) do
end create(:plan_limits,
end plan: default_plan,
ci_active_pipelines: 1,
ci_pipeline_size: 2,
ci_active_jobs: 3)
end
context 'when limit is defined' do it { is_expected.to eq(default_limits) }
before do
gold_plan.update_column(:pipeline_size_limit, 15)
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end end
it 'returns a number of maximum pipeline size' do context 'when "free" plan is defined in the system' do
expect(namespace.max_pipeline_size).to eq 15 let!(:free_plan) { create(:free_plan) }
end
end
end
describe '#max_active_jobs' do context 'when no limits are set' do
context 'when there is no limit defined' do it_behaves_like 'uses an implied configuration'
it 'returns zero' do end
expect(namespace.max_active_jobs).to be_zero
end
end
context 'when free plan has limit defined' do context 'when limits are set for the free plan' do
before do let!(:free_limits) do
free_plan.update_column(:active_jobs_limit, 100) create(:plan_limits,
end plan: free_plan,
ci_active_pipelines: 3,
ci_pipeline_size: 4,
ci_active_jobs: 5)
end
it 'returns a free plan limits' do it { is_expected.to eq(free_limits) }
expect(namespace.max_active_jobs).to be 100 end
end
end
context 'when associated plan has no limit defined' do context 'when subscription plan is defined in the system' do
before do let!(:subscription) { create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) }
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan)
end
it 'returns zero' do context 'when limits are not set for the plan' do
expect(namespace.max_active_jobs).to be_zero it_behaves_like 'uses an implied configuration'
end end
end
context 'when limit is defined' do context 'when limits are set for the plan' do
before do let!(:subscription_limits) do
gold_plan.update_column(:active_jobs_limit, 10) create(:plan_limits,
create(:gitlab_subscription, namespace: namespace, hosted_plan: gold_plan) plan: gold_plan,
end ci_active_pipelines: 5,
ci_pipeline_size: 6,
ci_active_jobs: 7)
end
it 'returns a number of maximum active jobs' do it { is_expected.to eq(subscription_limits) }
expect(namespace.max_active_jobs).to eq 10 end
end
end end
end end
end end
......
...@@ -5,6 +5,7 @@ require 'spec_helper' ...@@ -5,6 +5,7 @@ require 'spec_helper'
describe Ci::CreatePipelineService, '#execute' do describe Ci::CreatePipelineService, '#execute' do
set(:namespace) { create(:namespace) } set(:namespace) { create(:namespace) }
set(:gold_plan) { create(:gold_plan) } set(:gold_plan) { create(:gold_plan) }
set(:plan_limits) { create(:plan_limits, plan: gold_plan) }
set(:project) { create(:project, :repository, namespace: namespace) } set(:project) { create(:project, :repository, namespace: namespace) }
set(:user) { create(:user) } set(:user) { create(:user) }
...@@ -36,7 +37,7 @@ describe Ci::CreatePipelineService, '#execute' do ...@@ -36,7 +37,7 @@ describe Ci::CreatePipelineService, '#execute' do
context 'when pipeline activity limit is exceeded' do context 'when pipeline activity limit is exceeded' do
before do before do
gold_plan.update_column(:active_pipelines_limit, 2) plan_limits.update_column(:ci_active_pipelines, 2)
create(:ci_pipeline, project: project, status: 'pending') create(:ci_pipeline, project: project, status: 'pending')
create(:ci_pipeline, project: project, status: 'running') create(:ci_pipeline, project: project, status: 'running')
...@@ -55,7 +56,7 @@ describe Ci::CreatePipelineService, '#execute' do ...@@ -55,7 +56,7 @@ describe Ci::CreatePipelineService, '#execute' do
context 'when pipeline size limit is exceeded' do context 'when pipeline size limit is exceeded' do
before do before do
gold_plan.update_column(:pipeline_size_limit, 2) plan_limits.update_column(:ci_pipeline_size, 2)
end end
it 'drops pipeline without creating jobs' do it 'drops pipeline without creating jobs' do
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20191030152934_move_limits_from_plans.rb')
describe MoveLimitsFromPlans, :migration do
let(:plans) { table(:plans) }
let(:plan_limits) { table(:plan_limits) }
let!(:early_adopter_plan) { plans.create(name: 'early_adopter', title: 'Early adopter', active_pipelines_limit: 10, pipeline_size_limit: 11, active_jobs_limit: 12) }
let!(:gold_plan) { plans.create(name: 'gold', title: 'Gold', active_pipelines_limit: 20, pipeline_size_limit: 21, active_jobs_limit: 22) }
let!(:silver_plan) { plans.create(name: 'silver', title: 'Silver', active_pipelines_limit: 30, pipeline_size_limit: 31, active_jobs_limit: 32) }
let!(:bronze_plan) { plans.create(name: 'bronze', title: 'Bronze', active_pipelines_limit: 40, pipeline_size_limit: 41, active_jobs_limit: 42) }
let!(:free_plan) { plans.create(name: 'free', title: 'Free', active_pipelines_limit: 50, pipeline_size_limit: 51, active_jobs_limit: 52) }
let!(:other_plan) { plans.create(name: 'other', title: 'Other', active_pipelines_limit: nil, pipeline_size_limit: nil, active_jobs_limit: 0) }
describe 'migrate' do
it 'populates plan_limits from all the records in plans' do
expect { migrate! }.to change { plan_limits.count }.by 6
end
it 'copies plan limits and plan.id into to plan_limits table' do
migrate!
new_data = plan_limits.pluck(:plan_id, :ci_active_pipelines, :ci_pipeline_size, :ci_active_jobs)
expected_data = [
[early_adopter_plan.id, 10, 11, 12],
[gold_plan.id, 20, 21, 22],
[silver_plan.id, 30, 31, 32],
[bronze_plan.id, 40, 41, 42],
[free_plan.id, 50, 51, 52],
[other_plan.id, 0, 0, 0]
]
expect(new_data).to contain_exactly(*expected_data)
end
end
end
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