spec_helper.rb 9.05 KB
Newer Older
1 2
require './spec/simplecov_env'
SimpleCovEnv.start!
3

4
ENV["RAILS_ENV"] = 'test'
5
ENV["IN_MEMORY_APPLICATION_SETTINGS"] = 'true'
6

Lin Jen-Shin's avatar
Lin Jen-Shin committed
7
require File.expand_path('../config/environment', __dir__)
Robert Speicher's avatar
Robert Speicher committed
8
require 'rspec/rails'
9
require 'shoulda/matchers'
Kamil Trzcinski's avatar
Kamil Trzcinski committed
10
require 'rspec/retry'
11
require 'rspec-parameterized'
Kamil Trzcinski's avatar
Kamil Trzcinski committed
12

13
rspec_profiling_is_configured =
14
  ENV['RSPEC_PROFILING_POSTGRES_URL'].present? ||
15 16
  ENV['RSPEC_PROFILING']
branch_can_be_profiled =
17 18 19
  ENV['GITLAB_DATABASE'] == 'postgresql' &&
  (ENV['CI_COMMIT_REF_NAME'] == 'master' ||
    ENV['CI_COMMIT_REF_NAME'] =~ /rspec-profile/)
20 21

if rspec_profiling_is_configured && (!ENV.key?('CI') || branch_can_be_profiled)
22 23 24
  require 'rspec_profiling/rspec'
end

25
if ENV['CI'] && ENV['KNAPSACK_GENERATE_REPORT'] && !ENV['NO_KNAPSACK']
26 27 28
  require 'knapsack'
  Knapsack::Adapters::RSpecAdapter.bind
end
Robert Speicher's avatar
Robert Speicher committed
29

30 31
# require rainbow gem String monkeypatch, so we can test SystemChecks
require 'rainbow/ext/string'
32
Rainbow.enabled = false
33

Robert Speicher's avatar
Robert Speicher committed
34 35
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
36
# Requires helpers, and shared contexts/examples first since they're used in other support files
37 38 39 40 41

# Load these first since they may be required by other helpers
require Rails.root.join("spec/support/helpers/git_helpers.rb")

# Then the rest
42 43 44
Dir[Rails.root.join("spec/support/helpers/*.rb")].each { |f| require f }
Dir[Rails.root.join("spec/support/shared_contexts/*.rb")].each { |f| require f }
Dir[Rails.root.join("spec/support/shared_examples/*.rb")].each { |f| require f }
45
Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f }
Robert Speicher's avatar
Robert Speicher committed
46 47

RSpec.configure do |config|
Jeroen van Baarsen's avatar
Jeroen van Baarsen committed
48 49
  config.use_transactional_fixtures = false
  config.use_instantiated_fixtures  = false
50
  config.fixture_path = Rails.root
Robert Speicher's avatar
Robert Speicher committed
51

Kamil Trzcinski's avatar
Kamil Trzcinski committed
52 53 54
  config.verbose_retry = true
  config.display_try_failure_messages = true

55
  config.infer_spec_type_from_file_location!
56

57 58 59 60 61 62 63 64 65 66
  config.define_derived_metadata(file_path: %r{/spec/}) do |metadata|
    location = metadata[:location]

    metadata[:api] = true if location =~ %r{/spec/requests/api/}

    # do not overwrite type if it's already set
    next if metadata.key?(:type)

    match = location.match(%r{/spec/([^/]+)/})
    metadata[:type] = match[1].singularize.to_sym if match
67 68
  end

69 70 71 72 73 74 75 76 77 78
  config.include ActiveJob::TestHelper
  config.include ActiveSupport::Testing::TimeHelpers
  config.include CycleAnalyticsHelpers
  config.include ExpectOffense
  config.include FactoryBot::Syntax::Methods
  config.include FixtureHelpers
  config.include GitlabRoutingHelper
  config.include StubFeatureFlags
  config.include StubGitlabCalls
  config.include StubGitlabData
79
  config.include ExpectNextInstanceOf
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
  config.include TestEnv
  config.include Devise::Test::ControllerHelpers, type: :controller
  config.include Devise::Test::IntegrationHelpers, type: :feature
  config.include LoginHelpers, type: :feature
  config.include SearchHelpers, type: :feature
  config.include EmailHelpers, :mailer, type: :mailer
  config.include Warden::Test::Helpers, type: :request
  config.include Gitlab::Routing, type: :routing
  config.include Devise::Test::ControllerHelpers, type: :view
  config.include ApiHelpers, :api
  config.include CookieHelper, :js
  config.include InputHelper, :js
  config.include SelectionHelper, :js
  config.include InspectRequests, :js
  config.include WaitForRequests, :js
  config.include LiveDebugger, :js
  config.include MigrationsHelpers, :migration
97
  config.include RedisHelpers
98
  config.include Rails.application.routes.url_helpers, type: :routing
Robert Speicher's avatar
Robert Speicher committed
99

100 101 102
  if ENV['CI']
    # This includes the first try, i.e. tests will be run 4 times before failing.
    config.default_retry_count = 4
103 104 105 106
    config.reporter.register_listener(
      RspecFlaky::Listener.new,
      :example_passed,
      :dump_summary)
107 108
  end

Robert Speicher's avatar
Robert Speicher committed
109
  config.before(:suite) do
Rémy Coutable's avatar
Rémy Coutable committed
110
    Timecop.safe_mode = true
111
    TestEnv.init
Robert Speicher's avatar
Robert Speicher committed
112
  end
113

114 115 116 117
  config.after(:all) do
    TestEnv.clean_test_path
  end

118
  config.before do
119 120
    # Enable all features by default for testing
    allow(Feature).to receive(:enabled?) { true }
121 122 123 124 125 126 127

    # The following can be removed when we remove the staged rollout strategy
    # and we can just enable it using instance wide settings
    # (ie. ApplicationSetting#auto_devops_enabled)
    allow(Feature).to receive(:enabled?)
      .with(:force_autodevops_on_by_default, anything)
      .and_return(false)
128 129
  end

Rémy Coutable's avatar
Rémy Coutable committed
130 131 132 133 134
  config.before(:example, :quarantine) do
    # Skip tests in quarantine unless we explicitly focus on them.
    skip('In quarantine') unless config.inclusion_filter[:quarantine]
  end

135 136 137 138 139 140 141 142 143
  config.before(:example, :request_store) do
    RequestStore.begin!
  end

  config.after(:example, :request_store) do
    RequestStore.end!
    RequestStore.clear!
  end

144
  config.after do
Kamil Trzciński's avatar
Kamil Trzciński committed
145 146 147
    Fog.unmock! if Fog.mock?
  end

148
  config.after do
149 150 151
    Gitlab::CurrentSettings.clear_in_memory_application_settings!
  end

152 153 154 155
  config.before(:example, :mailer) do
    reset_delivered_emails!
  end

156 157 158 159 160 161 162
  config.before(:example, :prometheus) do
    matching_files = File.join(::Prometheus::Client.configuration.multiprocess_files_dir, "*.db")
    Dir[matching_files].map { |filename| File.delete(filename) if File.file?(filename) }

    Gitlab::Metrics.reset_registry!
  end

163
  config.around(:each, :use_clean_rails_memory_store_caching) do |example|
164
    caching_store = Rails.cache
165 166
    Rails.cache = ActiveSupport::Cache::MemoryStore.new

167
    example.run
168

169 170
    Rails.cache = caching_store
  end
171

172
  config.around(:each, :clean_gitlab_redis_cache) do |example|
173
    redis_cache_cleanup!
174 175 176

    example.run

177
    redis_cache_cleanup!
178 179 180
  end

  config.around(:each, :clean_gitlab_redis_shared_state) do |example|
181
    redis_shared_state_cleanup!
182

183
    example.run
184

185 186 187 188 189 190 191 192 193
    redis_shared_state_cleanup!
  end

  config.around(:each, :clean_gitlab_redis_queues) do |example|
    redis_queues_cleanup!

    example.run

    redis_queues_cleanup!
194
  end
195

196 197 198 199 200 201 202 203 204 205 206
  config.around(:each, :use_clean_rails_memory_store_fragment_caching) do |example|
    caching_store = ActionController::Base.cache_store
    ActionController::Base.cache_store = ActiveSupport::Cache::MemoryStore.new
    ActionController::Base.perform_caching = true

    example.run

    ActionController::Base.perform_caching = false
    ActionController::Base.cache_store = caching_store
  end

207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
  # The :each scope runs "inside" the example, so this hook ensures the DB is in the
  # correct state before any examples' before hooks are called. This prevents a
  # problem where `ScheduleIssuesClosedAtTypeChange` (or any migration that depends
  # on background migrations being run inline during test setup) can be broken by
  # altering Sidekiq behavior in an unrelated spec like so:
  #
  # around do |example|
  #   Sidekiq::Testing.fake! do
  #     example.run
  #   end
  # end
  config.before(:context, :migration) do
    schema_migrate_down!
  end

  # Each example may call `migrate!`, so we must ensure we are migrated down every time
223
  config.before(:each, :migration) do
224 225
    use_fake_application_settings

226
    schema_migrate_down!
227 228
  end

229
  config.after(:context, :migration) do
230
    schema_migrate_up!
231 232

    Gitlab::CurrentSettings.clear_in_memory_application_settings!
233
  end
234

235
  config.around(:each, :nested_groups) do |example|
236
    example.run if Group.supports_nested_objects?
237 238 239 240 241
  end

  config.around(:each, :postgresql) do |example|
    example.run if Gitlab::Database.postgresql?
  end
242

243 244 245 246
  config.around(:each, :mysql) do |example|
    example.run if Gitlab::Database.mysql?
  end

247 248 249 250 251 252 253
  # This makes sure the `ApplicationController#can?` method is stubbed with the
  # original implementation for all view specs.
  config.before(:each, type: :view) do
    allow(view).to receive(:can?) do |*args|
      Ability.allowed?(*args)
    end
  end
Rob Watson's avatar
Rob Watson committed
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269

  config.before(:each, :http_pages_enabled) do |_|
    allow(Gitlab.config.pages).to receive(:external_http).and_return(['1.1.1.1:80'])
  end

  config.before(:each, :https_pages_enabled) do |_|
    allow(Gitlab.config.pages).to receive(:external_https).and_return(['1.1.1.1:443'])
  end

  config.before(:each, :http_pages_disabled) do |_|
    allow(Gitlab.config.pages).to receive(:external_http).and_return(false)
  end

  config.before(:each, :https_pages_disabled) do |_|
    allow(Gitlab.config.pages).to receive(:external_https).and_return(false)
  end
Andrew8xx8's avatar
Andrew8xx8 committed
270
end
271

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
# add simpler way to match asset paths containing digest strings
RSpec::Matchers.define :match_asset_path do |expected|
  match do |actual|
    path = Regexp.escape(expected)
    extname = Regexp.escape(File.extname(expected))
    digest_regex = Regexp.new(path.sub(extname, "(?:-\\h+)?#{extname}") << '$')
    digest_regex =~ actual
  end

  failure_message do |actual|
    "expected that #{actual} would include an asset path for #{expected}"
  end

  failure_message_when_negated do |actual|
    "expected that #{actual} would not include an asset path for  #{expected}"
  end
end

290
FactoryBot::SyntaxRunner.class_eval do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
291 292 293
  include RSpec::Mocks::ExampleMethods
end

294
ActiveRecord::Migration.maintain_test_schema!
295 296 297 298 299 300 301

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
302 303 304

# Prevent Rugged from picking up local developer gitconfig.
Rugged::Settings['search_path_global'] = Rails.root.join('tmp/tests').to_s