spec_helper.rb 9.38 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
  config.include LicenseHelpers
70 71 72 73 74 75 76 77 78 79
  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
80
  config.include ExpectNextInstanceOf
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  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
98
  config.include RedisHelpers
99
  config.include Rails.application.routes.url_helpers, type: :routing
100
  config.include PolicyHelpers, type: :policy
Robert Speicher's avatar
Robert Speicher committed
101

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

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

116 117 118 119
  config.after(:all) do
    TestEnv.clean_test_path
  end

120
  config.before do |example|
121 122
    # Enable all features by default for testing
    allow(Feature).to receive(:enabled?) { true }
123

124 125 126 127 128 129 130
    enabled = example.metadata[:enable_rugged].present?

    # Disable Rugged features by default
    Gitlab::Git::RuggedImpl::Repository::FEATURE_FLAGS.each do |flag|
      allow(Feature).to receive(:enabled?).with(flag).and_return(enabled)
    end

131 132 133 134 135 136
    # 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)
137 138
  end

Rémy Coutable's avatar
Rémy Coutable committed
139 140 141 142 143
  config.before(:example, :quarantine) do
    # Skip tests in quarantine unless we explicitly focus on them.
    skip('In quarantine') unless config.inclusion_filter[:quarantine]
  end

144 145 146 147 148 149 150 151 152
  config.before(:example, :request_store) do
    RequestStore.begin!
  end

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

153
  config.after do
Kamil Trzciński's avatar
Kamil Trzciński committed
154 155 156
    Fog.unmock! if Fog.mock?
  end

157
  config.after do
158 159 160
    Gitlab::CurrentSettings.clear_in_memory_application_settings!
  end

161 162 163 164
  config.before(:example, :mailer) do
    reset_delivered_emails!
  end

165 166 167 168 169 170 171
  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

172
  config.around(:each, :use_clean_rails_memory_store_caching) do |example|
173
    caching_store = Rails.cache
174 175
    Rails.cache = ActiveSupport::Cache::MemoryStore.new

176
    example.run
177

178 179
    Rails.cache = caching_store
  end
180

181
  config.around(:each, :clean_gitlab_redis_cache) do |example|
182
    redis_cache_cleanup!
183 184 185

    example.run

186
    redis_cache_cleanup!
187 188 189
  end

  config.around(:each, :clean_gitlab_redis_shared_state) do |example|
190
    redis_shared_state_cleanup!
191

192
    example.run
193

194 195 196 197 198 199 200 201 202
    redis_shared_state_cleanup!
  end

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

    example.run

    redis_queues_cleanup!
203
  end
204

205 206 207 208 209 210 211 212 213 214 215
  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

216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231
  # 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
232
  config.before(:each, :migration) do
233 234
    use_fake_application_settings

235
    schema_migrate_down!
236 237
  end

238
  config.after(:context, :migration) do
239
    schema_migrate_up!
240 241

    Gitlab::CurrentSettings.clear_in_memory_application_settings!
242
  end
243

244
  config.around(:each, :nested_groups) do |example|
245
    example.run if Group.supports_nested_objects?
246 247 248 249 250
  end

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

252 253 254 255
  config.around(:each, :mysql) do |example|
    example.run if Gitlab::Database.mysql?
  end

256 257 258 259 260 261 262
  # 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
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278

  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
279
end
280

281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
# 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

299
FactoryBot::SyntaxRunner.class_eval do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
300 301 302
  include RSpec::Mocks::ExampleMethods
end

303
ActiveRecord::Migration.maintain_test_schema!
304 305 306 307 308 309 310

Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end
311 312 313

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