summaryrefslogtreecommitdiff
path: root/spec/support/database_cleaner.rb
blob: 01bf390d9e92d652c868cd9594a391ab1ed91ec1 (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
# frozen_string_literal: true

require_relative 'db_cleaner'

RSpec.configure do |config|
  include DbCleaner

  # Ensure the database is empty at the start of the suite run with :deletion strategy
  # neither the sequence is reset nor the tables are vacuum, but this provides
  # better I/O performance on machines with slower storage
  config.before(:suite) do
    setup_database_cleaner
    DatabaseCleaner.clean_with(:deletion)
  end

  config.append_after(:context, :migration) do
    delete_from_all_tables!

    # Postgres maximum number of columns in a table is 1600 (https://github.com/postgres/postgres/blob/de41869b64d57160f58852eab20a27f248188135/src/include/access/htup_details.h#L23-L47).
    # And since:
    # "The DROP COLUMN form does not physically remove the column, but simply makes
    # it invisible to SQL operations. Subsequent insert and update operations in the
    # table will store a null value for the column. Thus, dropping a column is quick
    # but it will not immediately reduce the on-disk size of your table, as the space
    # occupied by the dropped column is not reclaimed.
    # The space will be reclaimed over time as existing rows are updated."
    # according to https://www.postgresql.org/docs/current/sql-altertable.html.
    # We drop and recreate the database if any table has more than 1200 columns, just to be safe.
    max_allowed_columns = 1200
    tables_with_more_than_allowed_columns =
      ApplicationRecord.connection.execute("SELECT attrelid::regclass::text AS table, COUNT(*) AS column_count FROM pg_attribute GROUP BY attrelid HAVING COUNT(*) > #{max_allowed_columns}")

    if tables_with_more_than_allowed_columns.any?
      tables_with_more_than_allowed_columns.each do |result|
        puts "The #{result['table']} table has #{result['column_count']} columns."
      end
      puts "Recreating the database"
      start = Gitlab::Metrics::System.monotonic_time

      ActiveRecord::Tasks::DatabaseTasks.drop_current
      ActiveRecord::Tasks::DatabaseTasks.create_current
      ActiveRecord::Tasks::DatabaseTasks.load_schema_current
      ActiveRecord::Tasks::DatabaseTasks.migrate

      puts "Database re-creation done in #{Gitlab::Metrics::System.monotonic_time - start}"
    end
  end

  config.around(:each, :delete) do |example|
    self.class.use_transactional_tests = false

    example.run

    delete_from_all_tables!(except: deletion_except_tables)

    self.class.use_transactional_tests = true
  end

  config.around(:each, :migration) do |example|
    self.class.use_transactional_tests = false

    example.run

    delete_from_all_tables!

    self.class.use_transactional_tests = true
  end
end