summaryrefslogtreecommitdiff
path: root/spec/models/preloaders/environments/deployment_preloader_spec.rb
blob: 3f2f28a069e6c3cfe65db9dd9e753b7401c883a4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Preloaders::Environments::DeploymentPreloader do
  let_it_be(:user) { create(:user) }
  let_it_be(:project, reload: true) { create(:project, :repository) }

  let_it_be(:pipeline) { create(:ci_pipeline, user: user, project: project, sha: project.commit.sha) }
  let_it_be(:ci_build_a) { create(:ci_build, user: user, project: project, pipeline: pipeline) }
  let_it_be(:ci_build_b) { create(:ci_build, user: user, project: project, pipeline: pipeline) }
  let_it_be(:ci_build_c) { create(:ci_build, user: user, project: project, pipeline: pipeline) }

  let_it_be(:environment_a) { create(:environment, project: project, state: :available) }
  let_it_be(:environment_b) { create(:environment, project: project, state: :available) }

  before do
    create(:deployment, :success, project: project, environment: environment_a, deployable: ci_build_a)
    create(:deployment, :success, project: project, environment: environment_a, deployable: ci_build_b)
    create(:deployment, :success, project: project, environment: environment_b, deployable: ci_build_c)
  end

  def preload_association(association_name)
    described_class.new(project.environments)
      .execute_with_union(association_name, deployment_associations)
  end

  def deployment_associations
    {
      user: [],
      deployable: {
        pipeline: {
          manual_actions: []
        }
      }
    }
  end

  it 'does not trigger N+1 queries' do
    control = ActiveRecord::QueryRecorder.new { preload_association(:last_deployment) }

    ci_build_d = create(:ci_build, user: user, project: project, pipeline: pipeline)
    create(:deployment, :success, project: project, environment: environment_b, deployable: ci_build_d)

    expect { preload_association(:last_deployment) }.not_to exceed_query_limit(control)
  end

  it 'batch loads the dependent associations' do
    preload_association(:last_deployment)

    expect do
      project.environments.first.last_deployment.deployable.pipeline.manual_actions
    end.not_to exceed_query_limit(0)
  end

  # Example query scoped with IN clause for `last_deployment` association preload:
  # SELECT DISTINCT ON (environment_id) deployments.* FROM "deployments" WHERE "deployments"."status" IN (1, 2, 3, 4, 6) AND "deployments"."environment_id" IN (35, 34, 33) ORDER BY environment_id, deployments.id DESC
  it 'avoids scoping with IN clause during preload' do
    control = ActiveRecord::QueryRecorder.new { preload_association(:last_deployment) }

    default_preload_query = control.occurrences_by_line_method.first[1][:occurrences].any? { |i| i.include?('"deployments"."environment_id" IN') }

    expect(default_preload_query).to be(false)
  end

  it 'sets environment on the associated deployment', :aggregate_failures do
    preload_association(:last_deployment)

    expect do
      project.environments.each { |environment| environment.last_deployment.environment }
    end.not_to exceed_query_limit(0)

    project.environments.each do |environment|
      expect(environment.last_deployment.environment).to eq(environment)
    end
  end

  it 'does not attempt to set environment on a nil deployment' do
    create(:environment, project: project, state: :available)

    expect { preload_association(:last_deployment) }.not_to raise_error
  end
end