namespace_spec.rb 15.7 KB
Newer Older
1 2
require 'spec_helper'

3
describe Namespace do
4 5
  let!(:namespace) { create(:namespace) }

6
  it { is_expected.to have_one(:namespace_statistics) }
7
  it { is_expected.to belong_to(:plan) }
8 9

  it { is_expected.to delegate_method(:shared_runners_minutes).to(:namespace_statistics) }
10 11
  it { is_expected.to delegate_method(:shared_runners_seconds).to(:namespace_statistics) }
  it { is_expected.to delegate_method(:shared_runners_seconds_last_reset).to(:namespace_statistics) }
12

13 14 15 16 17
  context 'scopes' do
    describe '.with_plan' do
      let!(:namespace) { create :namespace, plan: namespace_plan }

      context 'plan is set' do
18
        let(:namespace_plan) { :bronze_plan }
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44

        it 'returns namespaces with plan' do
          expect(described_class.with_plan).to eq([namespace])
        end
      end

      context 'plan is not set' do
        context 'plan is empty string' do
          let(:namespace_plan) { '' }

          it 'returns no namespace' do
            expect(described_class.with_plan).to be_empty
          end
        end

        context 'plan is nil' do
          let(:namespace_plan) { nil }

          it 'returns no namespace' do
            expect(described_class.with_plan).to be_empty
          end
        end
      end
    end
  end

45 46 47 48 49 50
  describe 'custom validations' do
    describe '#validate_plan_name' do
      let(:group) { build(:group) }

      context 'with a valid plan name' do
        it 'is valid' do
51
          group.plan = create(:bronze_plan)
52 53 54 55 56 57 58 59 60 61 62 63 64 65

          expect(group).to be_valid
        end
      end

      context 'with an invalid plan name' do
        it 'is invalid' do
          group.plan = 'unknown'

          expect(group).not_to be_valid
          expect(group.errors[:plan]).to include('is not included in the list')
        end
      end
    end
ayufanpl's avatar
ayufanpl committed
66 67 68

    describe '#validate_shared_runner_minutes_support' do
      before do
69
        stub_feature_flags(shared_runner_minutes_on_root_namespace: true)
ayufanpl's avatar
ayufanpl committed
70 71 72 73 74 75
      end

      context 'when changing :shared_runners_minutes_limit' do
        before do
          namespace.shared_runners_minutes_limit = 100
        end
ayufanpl's avatar
ayufanpl committed
76

ayufanpl's avatar
ayufanpl committed
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
        context 'when group is subgroup' do
          set(:root_ancestor) { create(:group) }
          let(:namespace) { create(:namespace, parent: root_ancestor) }

          it 'is invalid' do
            expect(namespace).not_to be_valid
            expect(namespace.errors[:shared_runners_minutes_limit]).to include('is not supported for this namespace')
          end
        end

        context 'when group is root' do
          it 'is valid' do
            expect(namespace).to be_valid
          end
        end
      end
    end
94 95
  end

96 97
  describe '#move_dir' do
    context 'when running on a primary node' do
98 99
      set(:primary) { create(:geo_node, :primary) }
      set(:secondary) { create(:geo_node) }
100 101 102 103 104
      let(:gitlab_shell) { Gitlab::Shell.new }

      it 'logs the Geo::RepositoryRenamedEvent for each project inside namespace' do
        parent = create(:namespace)
        child = create(:group, name: 'child', path: 'child', parent: parent)
105 106 107
        project_legacy_storage = create(:project_empty_repo, :legacy_storage, namespace: parent)
        create(:project, namespace: child)
        create(:project_empty_repo, :legacy_storage, namespace: child)
108 109 110 111 112 113 114 115 116
        full_path_was = "#{parent.full_path}_old"
        new_path = parent.full_path

        allow(parent).to receive(:gitlab_shell).and_return(gitlab_shell)
        allow(parent).to receive(:path_changed?).and_return(true)
        allow(parent).to receive(:full_path_was).and_return(full_path_was)
        allow(parent).to receive(:full_path).and_return(new_path)

        allow(gitlab_shell).to receive(:mv_namespace)
117
          .with(project_legacy_storage.repository_storage_path, full_path_was, new_path)
118 119
          .and_return(true)

120
        expect { parent.move_dir }.to change(Geo::RepositoryRenamedEvent, :count).by(3)
121 122 123 124
      end
    end
  end

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
  describe '#features' do
    let(:plan_license) { :free_plan }
    let(:group) { create(:group, plan: plan_license) }
    let(:global_license) { create(:license) }

    before do
      allow(License).to receive(:current).and_return(global_license)
      allow(global_license).to receive(:features).and_return([
        :epics, # Gold only
        :service_desk, # Silver and up
        :audit_events, # Bronze and up
        :geo, # Global feature, should not be checked at namespace level
      ])
    end

    subject { group.features }

    context 'when the namespace should be checked' do
      before do
        enable_namespace_license_check!
      end

      context 'when bronze' do
        let(:plan_license) { :bronze_plan }

        it 'filters for bronze features' do
          is_expected.to contain_exactly(:audit_events, :geo)
        end
      end

      context 'when silver' do
        let(:plan_license) { :silver_plan }

        it 'filters for silver features' do
          is_expected.to contain_exactly(:service_desk, :audit_events, :geo)
        end
      end

      context 'when gold' do
        let(:plan_license) { :gold_plan }

        it 'filters for gold features' do
          is_expected.to contain_exactly(:epics, :service_desk, :audit_events, :geo)
        end
      end

      context 'when free plan' do
        let(:plan_license) { :free_plan }

        it 'filters out paid features' do
          is_expected.to contain_exactly(:geo)
        end
      end
    end

    context 'when namespace should not be checked' do
      it 'includes all features in global license' do
        is_expected.to contain_exactly(:epics, :service_desk, :audit_events, :geo)
      end
    end

    context 'when there is no license' do
      before do
        allow(License).to receive(:current).and_return(nil)
      end

      it { is_expected.to be_empty }
    end
  end

195
  describe '#feature_available?' do
196
    let(:plan_license) { :bronze_plan }
197
    let(:group) { create(:group, plan: plan_license) }
198
    let(:feature) { :service_desk }
199 200 201

    subject { group.feature_available?(feature) }

202 203 204
    before do
      stub_licensed_features(feature => true)
    end
205

206 207 208 209 210 211
    it 'uses the global setting when running on premise' do
      stub_application_setting_on_object(group, should_check_namespace_plan: false)

      is_expected.to be_truthy
    end

212 213 214 215 216 217
    it 'only checks the plan once' do
      expect(group).to receive(:load_feature_available).once.and_call_original

      2.times { group.feature_available?(:service_desk) }
    end

218 219 220 221 222 223 224
    context 'when checking namespace plan' do
      before do
        stub_application_setting_on_object(group, should_check_namespace_plan: true)
      end

      it 'combines the global setting with the group setting when not running on premise' do
        is_expected.to be_falsy
225 226
      end

227
      context 'when feature available on the plan' do
228
        let(:plan_license) { :gold_plan }
229

230 231 232 233 234 235 236 237 238 239 240 241 242
        context 'when feature available for current group' do
          it 'returns true' do
            is_expected.to be_truthy
          end
        end

        if Group.supports_nested_groups?
          context 'when license is applied to parent group' do
            let(:child_group) { create :group, parent: group }

            it 'child group has feature available' do
              expect(child_group.feature_available?(feature)).to be_truthy
            end
243
          end
244 245 246
        end
      end

247 248
      context 'when feature not available in the plan' do
        let(:feature) { :deploy_board }
249
        let(:plan_license) { :bronze_plan }
250

251 252 253
        it 'returns false' do
          is_expected.to be_falsy
        end
254 255 256
      end
    end
  end
257

258
  describe '#max_active_pipelines' do
259
    context 'when there is no limit defined' do
260 261 262 263 264
      it 'returns zero' do
        expect(namespace.max_active_pipelines).to be_zero
      end
    end

265 266
    context 'when free plan has limit defined' do
      before do
267
        create(:free_plan, active_pipelines_limit: 40)
268 269 270 271 272 273 274 275
      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
276
      before do
277
        namespace.plan = create(:gold_plan)
278 279 280 281 282 283 284 285 286
      end

      it 'returns zero' do
        expect(namespace.max_active_pipelines).to be_zero
      end
    end

    context 'when limit is defined' do
      before do
287
        namespace.plan = create(:gold_plan)
288 289 290 291 292 293 294 295 296 297
        namespace.plan.update_column(:active_pipelines_limit, 10)
      end

      it 'returns a number of maximum active pipelines' do
        expect(namespace.max_active_pipelines).to eq 10
      end
    end
  end

  describe '#max_pipeline_size' do
298
    context 'when there are no limits defined' do
299
      it 'returns zero' do
300 301 302 303 304 305
        expect(namespace.max_pipeline_size).to be_zero
      end
    end

    context 'when free plan has limit defined' do
      before do
306
        create(:free_plan, pipeline_size_limit: 40)
307 308 309 310
      end

      it 'returns a free plan limits' do
        expect(namespace.max_pipeline_size).to be 40
311 312 313
      end
    end

314
    context 'when associated plan has no limits defined' do
315
      before do
316
        namespace.plan = create(:gold_plan)
317 318 319 320 321 322 323 324 325
      end

      it 'returns zero' do
        expect(namespace.max_pipeline_size).to be_zero
      end
    end

    context 'when limit is defined' do
      before do
326
        namespace.plan = create(:gold_plan)
327 328 329 330 331 332 333 334 335
        namespace.plan.update_column(:pipeline_size_limit, 15)
      end

      it 'returns a number of maximum pipeline size' do
        expect(namespace.max_pipeline_size).to eq 15
      end
    end
  end

336 337 338 339 340 341 342 343 344 345
  describe '#shared_runners_enabled?' do
    subject { namespace.shared_runners_enabled? }

    context 'without projects' do
      it { is_expected.to be_falsey }
    end

    context 'with project' do
      context 'and disabled shared runners' do
        let!(:project) do
346
          create(:project,
347 348 349 350 351 352 353 354 355
            namespace: namespace,
            shared_runners_enabled: false)
        end

        it { is_expected.to be_falsey }
      end

      context 'and enabled shared runners' do
        let!(:project) do
356
          create(:project,
357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
            namespace: namespace,
            shared_runners_enabled: true)
        end

        it { is_expected.to be_truthy }
      end
    end
  end

  describe '#actual_shared_runners_minutes_limit' do
    subject { namespace.actual_shared_runners_minutes_limit }

    context 'when no limit defined' do
      it { is_expected.to be_zero }
    end

    context 'when application settings limit is set' do
      before do
        stub_application_setting(shared_runners_minutes: 1000)
      end

      it 'returns global limit' do
        is_expected.to eq(1000)
      end

      context 'when namespace limit is set' do
        before do
          namespace.shared_runners_minutes_limit = 500
        end

        it 'returns namespace limit' do
          is_expected.to eq(500)
        end
      end
    end
  end

ayufanpl's avatar
ayufanpl committed
394 395 396 397 398 399 400 401
  describe '#shared_runner_minutes_supported?' do
    subject { namespace.shared_runner_minutes_supported? }

    context 'when is subgroup' do
      before do
        namespace.parent = build(:group)
      end

402
      context 'when shared_runner_minutes_on_root_namespace is disabled' do
ayufanpl's avatar
ayufanpl committed
403
        before do
404
          stub_feature_flags(shared_runner_minutes_on_root_namespace: false)
ayufanpl's avatar
ayufanpl committed
405 406 407 408 409 410 411
        end

        it 'returns true' do
          is_expected.to eq(true)
        end
      end

412
      context 'when shared_runner_minutes_on_root_namespace is enabled', :nested_groups do
ayufanpl's avatar
ayufanpl committed
413
        before do
414
          stub_feature_flags(shared_runner_minutes_on_root_namespace: true)
ayufanpl's avatar
ayufanpl committed
415 416 417 418 419 420 421 422 423 424 425 426 427 428 429
        end

        it 'returns false' do
          is_expected.to eq(false)
        end
      end
    end

    context 'when is root' do
      it 'returns true' do
        is_expected.to eq(true)
      end
    end
  end

430 431 432 433 434
  describe '#shared_runners_minutes_limit_enabled?' do
    subject { namespace.shared_runners_minutes_limit_enabled? }

    context 'with project' do
      let!(:project) do
435
        create(:project,
436 437 438 439 440 441 442 443 444 445 446 447 448 449
          namespace: namespace,
          shared_runners_enabled: true)
      end

      context 'when no limit defined' do
        it { is_expected.to be_falsey }
      end

      context 'when limit is defined' do
        before do
          namespace.shared_runners_minutes_limit = 500
        end

        it { is_expected.to be_truthy }
ayufanpl's avatar
ayufanpl committed
450

451
        context 'when is subgroup', :nested_groups do
ayufanpl's avatar
ayufanpl committed
452
          before do
453
            stub_feature_flags(shared_runner_minutes_on_root_namespace: true)
ayufanpl's avatar
ayufanpl committed
454 455 456 457 458
            namespace.parent = build(:group)
          end

          it { is_expected.to be_falsey }
        end
459 460 461 462 463 464 465 466
      end
    end

    context 'without project' do
      it { is_expected.to be_falsey }
    end
  end

ayufanpl's avatar
ayufanpl committed
467 468 469 470 471 472 473
  describe '#shared_runners_enabled?' do
    subject { namespace.shared_runners_enabled? }

    context 'subgroup with shared runners enabled project' do
      let(:subgroup) { create(:group, parent: namespace) }
      let!(:subproject) { create(:project, namespace: subgroup, shared_runners_enabled: true) }

474
      context 'when shared_runner_minutes_on_root_namespace is disabled' do
ayufanpl's avatar
ayufanpl committed
475
        before do
476
          stub_feature_flags(shared_runner_minutes_on_root_namespace: false)
ayufanpl's avatar
ayufanpl committed
477 478 479 480 481 482 483
        end

        it "returns false" do
          is_expected.to eq(false)
        end
      end

484
      context 'when shared_runner_minutes_on_root_namespace is enabled', :nested_groups do
ayufanpl's avatar
ayufanpl committed
485
        before do
486
          stub_feature_flags(shared_runner_minutes_on_root_namespace: true)
ayufanpl's avatar
ayufanpl committed
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
        end

        it "returns true" do
          is_expected.to eq(true)
        end
      end
    end

    context 'group with shared runners enabled project' do
      let!(:project) { create(:project, namespace: namespace, shared_runners_enabled: true) }

      it "returns true" do
        is_expected.to eq(true)
      end
    end
ayufanpl's avatar
ayufanpl committed
502

ayufanpl's avatar
ayufanpl committed
503 504 505 506 507 508 509
    context 'group without projects' do
      it "returns false" do
        is_expected.to eq(false)
      end
    end
  end

510 511 512 513 514
  describe '#shared_runners_minutes_used?' do
    subject { namespace.shared_runners_minutes_used? }

    context 'with project' do
      let!(:project) do
515
        create(:project,
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547
          namespace: namespace,
          shared_runners_enabled: true)
      end

      context 'when limit is defined' do
        context 'when limit is used' do
          let(:namespace) { create(:namespace, :with_used_build_minutes_limit) }

          it { is_expected.to be_truthy }
        end

        context 'when limit not yet used' do
          let(:namespace) { create(:namespace, :with_not_used_build_minutes_limit) }

          it { is_expected.to be_falsey }
        end

        context 'when minutes are not yet set' do
          it { is_expected.to be_falsey }
        end
      end

      context 'without limit' do
        let(:namespace) { create(:namespace, :with_build_minutes_limit) }

        it { is_expected.to be_falsey }
      end
    end

    context 'without project' do
      it { is_expected.to be_falsey }
    end
548
  end
549 550 551 552

  describe '#actual_plan' do
    context 'when namespace has a plan associated' do
      before do
553
        namespace.plan = create(:gold_plan)
554 555 556 557 558 559 560 561 562
      end

      it 'returns an associated plan' do
        expect(namespace.plan).not_to be_nil
        expect(namespace.actual_plan.name).to eq 'gold'
      end
    end

    context 'when namespace does not have plan associated' do
563 564 565 566
      before do
        create(:free_plan)
      end

567 568 569 570 571 572 573 574 575 576
      it 'returns a free plan object' do
        expect(namespace.plan).to be_nil
        expect(namespace.actual_plan.name).to eq 'free'
      end
    end
  end

  describe '#actual_plan_name' do
    context 'when namespace has a plan associated' do
      before do
577
        namespace.plan = create(:gold_plan)
578 579 580 581 582 583 584 585 586 587 588 589 590
      end

      it 'returns an associated plan name' do
        expect(namespace.actual_plan_name).to eq 'gold'
      end
    end

    context 'when namespace does not have plan associated' do
      it 'returns a free plan name' do
        expect(namespace.actual_plan_name).to eq 'free'
      end
    end
  end
591
end