summaryrefslogtreecommitdiff
path: root/spec/models/factories_spec.rb
blob: 2993b2aee5856d3db2de355f1dd2e1e01ad13a25 (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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'factories' do
  include Database::DatabaseHelpers

  # https://gitlab.com/groups/gitlab-org/-/epics/5464 tracks the remaining
  # skipped traits.
  #
  # Consider adding a code comment if a trait cannot produce a valid object.
  def skipped_traits
    [
      [:audit_event, :unauthenticated],
      [:ci_build_trace_chunk, :fog_with_data],
      [:ci_job_artifact, :remote_store],
      [:ci_job_artifact, :raw],
      [:ci_job_artifact, :gzip],
      [:ci_job_artifact, :correct_checksum],
      [:environment, :non_playable],
      [:composer_cache_file, :object_storage],
      [:debian_project_component_file, :object_storage],
      [:debian_project_distribution, :object_storage],
      [:debian_file_metadatum, :unknown],
      [:issue_customer_relations_contact, :for_contact],
      [:issue_customer_relations_contact, :for_issue],
      [:package_file, :object_storage],
      [:pages_domain, :without_certificate],
      [:pages_domain, :without_key],
      [:pages_domain, :with_missing_chain],
      [:pages_domain, :with_trusted_chain],
      [:pages_domain, :with_trusted_expired_chain],
      [:pages_domain, :explicit_ecdsa],
      [:project_member, :blocked],
      [:remote_mirror, :ssh],
      [:user_preference, :only_comments],
      [:ci_pipeline_artifact, :remote_store]
    ]
  end

  shared_examples 'factory' do |factory|
    describe "#{factory.name} factory" do
      it 'does not raise error when built' do
        expect { build(factory.name) }.not_to raise_error
      end

      it 'does not raise error when created' do
        expect { create(factory.name) }.not_to raise_error # rubocop:disable Rails/SaveBang
      end

      factory.definition.defined_traits.map(&:name).each do |trait_name|
        describe "linting :#{trait_name} trait" do
          it 'does not raise error when created' do
            if skipped_traits.include?([factory.name, trait_name.to_sym])
              pending("Trait skipped linting due to legacy error")
            end

            expect { create(factory.name, trait_name) }.not_to raise_error
          end
        end
      end
    end
  end

  # FactoryDefault speed up specs by creating associations only once
  # and reuse them in other factories.
  #
  # However, for some factories we cannot use FactoryDefault because the
  # associations must be unique and cannot be reused, or the factory default
  # is being mutated.
  skip_factory_defaults = %i[
    ci_job_token_project_scope_link
    evidence
    exported_protected_branch
    fork_network_member
    group_member
    import_state
    issue_customer_relations_contact
    member_task
    milestone_release
    namespace
    project_broken_repo
    project_namespace
    project_repository
    prometheus_alert
    prometheus_alert_event
    prometheus_metric
    protected_branch
    protected_branch_merge_access_level
    protected_branch_push_access_level
    protected_tag
    release
    release_link
    self_managed_prometheus_alert_event
    shard
    users_star_project
    wiki_page
    wiki_page_meta
  ].to_set.freeze

  # Some factories and their corresponding models are based on
  # database views. In order to use those, we have to swap the
  # view out with a table of the same structure.
  factories_based_on_view = %i[
    postgres_index
    postgres_index_bloat_estimate
    postgres_autovacuum_activity
  ].to_set.freeze

  without_fd, with_fd = FactoryBot.factories
    .partition { |factory| skip_factory_defaults.include?(factory.name) }

  context 'with factory defaults', factory_default: :keep do
    let_it_be(:namespace) { create_default(:namespace).freeze }
    let_it_be(:project) { create_default(:project, :repository).freeze }
    let_it_be(:user) { create_default(:user).freeze }

    before do
      factories_based_on_view.each do |factory|
        view = build(factory).class.table_name
        swapout_view_for_table(view)
      end
    end

    with_fd.each do |factory|
      it_behaves_like 'factory', factory
    end
  end

  context 'without factory defaults' do
    without_fd.each do |factory|
      it_behaves_like 'factory', factory
    end
  end
end