Module: Webhookdb::SpecHelpers::Postgres

Extended by:
MethodUtilities
Defined in:
lib/webhookdb/spec_helpers/postgres.rb

Overview

Some helper functions for testing. Usage:

# in spec/spec_helper.rb
RSpec.configure do |c|
  c.include( Webhookdb::SpecHelpers::Postgres )
end

# in my_class_spec.rb; mark an example as needing database setup
describe MyClass, db: true do
end

Defined Under Namespace

Modules: Models Classes: HaveRowMatcher

Constant Summary collapse

BASEDIR =

Pathname constants

Pathname(__FILE__).dirname.parent
SPECDIR =
BASEDIR + "spec"
DATADIR =
SPECDIR + "data"
SNIFF_LEAKY_TESTS =
false

Class Method Summary collapse

Methods included from MethodUtilities

attr_predicate, attr_predicate_accessor, singleton_attr_accessor, singleton_attr_reader, singleton_attr_writer, singleton_method_alias, singleton_predicate_accessor, singleton_predicate_reader

Class Method Details

._truncate(example) ⇒ Object



54
55
56
57
58
59
# File 'lib/webhookdb/spec_helpers/postgres.rb', line 54

module_function def _truncate(example)
  tr = example.[:truncate]
  return unless tr
  tr = [tr] unless tr.respond_to?(:to_ary)
  tr.each(&:truncate)
end

.create_model(name) ⇒ Object

Create an anonymous model with the given table name. Can be a symbol, string, or [:schema, :table] array.



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/webhookdb/spec_helpers/postgres.rb', line 93

module_function def create_model(name, &)
  Webhookdb::SpecHelpers::Postgres.current_test_model_uid += 1

  qualifier = Sequel
  prefix = name
  if name.is_a?(Array)
    qualifier = Sequel[name[0]]
    Webhookdb::Postgres::Model.create_schema!(qualifier)
    prefix = name[1]
  end
  table_name = :"testtable_#{prefix}_#{Webhookdb::SpecHelpers::Postgres.current_test_model_uid}"
  qualified_name = qualifier[table_name]

  Webhookdb::Postgres.logger.info "Creating table: %p" % [qualified_name]
  Webhookdb::Postgres::Model.db.create_table!(qualified_name, &)
  clsname = table_name.to_s.classify
  clsfqn = "#{Webhookdb::SpecHelpers::Postgres::Models}::#{clsname}"
  cls = Class.new(Webhookdb::Postgres::Model(qualified_name)) do
    define_singleton_method(:name) { clsfqn }
  end
  Webhookdb::SpecHelpers::Postgres::Models.const_set(clsname, cls)
  # Object.const_get(clsfqn)
  return cls
end

.have_row(criteria) ⇒ Object



181
182
183
# File 'lib/webhookdb/spec_helpers/postgres.rb', line 181

module_function def have_row(criteria)
  return HaveRowMatcher.new(criteria)
end

.included(context) ⇒ Object

Inclusion callback – install some hooks



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/webhookdb/spec_helpers/postgres.rb', line 30

def self.included(context)
  context.around(:each) do |example|
    Webhookdb::Postgres.unsafe_skip_transaction_check = true if example.[:no_transaction_check]

    _truncate(example)
    setting = example.[:db]
    if setting && setting != :no_transaction
      Webhookdb::SpecHelpers::Postgres.wrap_example_in_transactions(example)
    else
      Webhookdb::Postgres.logger.debug "Running spec without a transaction"
      example.run
    end
  end

  context.after(:each) do |example|
    Webhookdb::Postgres.unsafe_skip_transaction_check = false if example.[:no_transaction_check]

    truncate_all if example.[:db] == :no_transaction
    _truncate(example)
  end

  super
end

.truncate_allObject



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/webhookdb/spec_helpers/postgres.rb', line 118

module_function def truncate_all
  # We can delete items from 'leaf' to 'trunk' in association terms
  # by using the TSort API (so Address and Customer, for example, are very early,
  # while 'StripeAttributes', which nothing has an FK into, is very late).
  # This is much faster than truncating with cascade.
  # Though in some cases, it doesn't work, so we need to cascade.
  Webhookdb::Postgres.each_model_superclass do |sc|
    sc.tsort.reverse_each do |m|
      m.dataset.delete
    rescue Sequel::ForeignKeyConstraintViolation
      m.truncate(cascade: true)
    rescue Sequel::DatabaseError
      # The table may not exist, maybe because the type was created in a test
      # and now no longer exists but it still a subclass.
      nil
    end
  end
end

.wrap_example_in_transactions(example) ⇒ Object

Run the specified example in the context of a transaction for each loaded model superclass. Raises if any of the loaded superclasses aren’t configured.



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/webhookdb/spec_helpers/postgres.rb', line 64

def self.wrap_example_in_transactions(example)
  txn_classes = Webhookdb::Postgres.model_superclasses
  Webhookdb::Postgres.logger.debug "Wrapping example for model superclasses: %p" %
    [txn_classes]

  wrapped_proc = txn_classes.inject(example.method(:run)) do |callback, txn_class|
    if (db = txn_class.db)
      Webhookdb::Postgres.logger.debug "DB: Running with an outer transaction"
      proc { db.transaction(auto_savepoint: :only, rollback: :always, &callback) }
    else
      raise "No database connection for %p configured! Add a %s section to the test config." %
        [txn_class, txn_class.config_key]
    end
  end

  wrapped_proc.call
  return if !SNIFF_LEAKY_TESTS || (Webhookdb::Customer.empty? && Webhookdb::Organization.empty?)
  puts "Customer is not cleaned up, failing for diagnosis."
  puts "Check the spec that ran before: #{example.[:full_description]}"
  exit
end