From f83b8bd42c2a82b3ef9a8d93621b3955f0a8d0ca Mon Sep 17 00:00:00 2001
From: Nick Thomas <nick@gitlab.com>
Date: Thu, 26 Jan 2017 21:31:43 +0000
Subject: [PATCH] Add the rspec_profiling gem and documentation to the GitLab
 development environment

---
 Gemfile                                |  1 +
 Gemfile.lock                           |  7 ++++++
 config/initializers/rspec_profiling.rb | 14 +++++++++++
 doc/development/performance.md         | 35 ++++++++++++++++++++++++++
 spec/spec_helper.rb                    |  4 +++
 5 files changed, 61 insertions(+)
 create mode 100644 config/initializers/rspec_profiling.rb

diff --git a/Gemfile b/Gemfile
index dc8f23d07c6..37a7666602f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -280,6 +280,7 @@ group :development, :test do
   gem 'rspec-retry',        '~> 0.4.5'
   gem 'spinach-rails',      '~> 0.2.1'
   gem 'spinach-rerun-reporter', '~> 0.0.2'
+  gem 'rspec_profiling'
 
   # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
   gem 'minitest', '~> 5.7.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index 133e47e1ea4..671d7788a86 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -642,6 +642,11 @@ GEM
     rspec-retry (0.4.5)
       rspec-core
     rspec-support (3.5.0)
+    rspec_profiling (0.0.4)
+      activerecord
+      pg
+      rails
+      sqlite3
     rubocop (0.46.0)
       parser (>= 2.3.1.1, < 3.0)
       powerpack (~> 0.1)
@@ -743,6 +748,7 @@ GEM
       actionpack (>= 4.0)
       activesupport (>= 4.0)
       sprockets (>= 3.0.0)
+    sqlite3 (1.3.11)
     stackprof (0.2.10)
     state_machines (0.4.0)
     state_machines-activemodel (0.4.0)
@@ -965,6 +971,7 @@ DEPENDENCIES
   rqrcode-rails3 (~> 0.1.7)
   rspec-rails (~> 3.5.0)
   rspec-retry (~> 0.4.5)
+  rspec_profiling
   rubocop (~> 0.46.0)
   rubocop-rspec (~> 1.9.1)
   ruby-fogbugz (~> 0.2.1)
diff --git a/config/initializers/rspec_profiling.rb b/config/initializers/rspec_profiling.rb
new file mode 100644
index 00000000000..f462e654b2c
--- /dev/null
+++ b/config/initializers/rspec_profiling.rb
@@ -0,0 +1,14 @@
+module RspecProfilingConnection
+  def establish_connection
+    ::RspecProfiling::Collectors::PSQL::Result.establish_connection(ENV['RSPEC_PROFILING_POSTGRES_URL'])
+  end
+end
+
+if Rails.env.test?
+  RspecProfiling.configure do |config|
+    if ENV['RSPEC_PROFILING_POSTGRES_URL']
+      RspecProfiling::Collectors::PSQL.prepend(RspecProfilingConnection)
+      config.collector = RspecProfiling::Collectors::PSQL
+    end
+  end
+end
diff --git a/doc/development/performance.md b/doc/development/performance.md
index f936a49a2aa..c1f129e576c 100644
--- a/doc/development/performance.md
+++ b/doc/development/performance.md
@@ -211,6 +211,41 @@ suite first. See the
 [StackProf documentation](https://github.com/tmm1/stackprof/blob/master/README.md)
 for details.
 
+## RSpec profiling
+
+GitLab's development environment also includes the
+[rspec_profiling](https://github.com/foraker/rspec_profiling) gem, which is used
+to collect data on spec execution times. This is useful for analyzing the
+performance of the test suite itself, or seeing how the performance of a spec
+may have changed over time.
+
+To activate profiling in your local environment, run the following:
+
+```
+$ export RSPEC_PROFILING=yes
+$ rake rspec_profiling:install
+```
+
+This creates an SQLite3 database in `tmp/rspec_profiling`, into which statistics
+are saved every time you run specs with the `RSPEC_PROFILING` environment
+variable set.
+
+Ad-hoc investigation of the collected results can be performed in an interactive
+shell:
+
+```
+$ rake rspec_profiling:console
+irb(main):001:0> results.count
+=> 231
+irb(main):002:0> results.last.attributes.keys
+=> ["id", "commit", "date", "file", "line_number", "description", "time", "status", "exception", "query_count", "query_time", "request_count", "request_time", "created_at", "updated_at"]
+irb(main):003:0> results.where(status: "passed").average(:time).to_s
+=> "0.211340155844156"
+```
+These results can also be placed into a PostgreSQL database by setting the
+`RSPEC_PROFILING_POSTGRES_URL` variable. This is used to profile the test suite
+when running in the CI environment.
+
 ## Importance of Changes
 
 When working on performance improvements, it's important to always ask yourself
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index e160c11111b..ab38dac65c5 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -9,6 +9,10 @@ require 'rspec/rails'
 require 'shoulda/matchers'
 require 'rspec/retry'
 
+if ENV['RSPEC_PROFILING_POSTGRES_URL'] || ENV['RSPEC_PROFILING']
+  require 'rspec_profiling/rspec'
+end
+
 if ENV['CI'] && !ENV['NO_KNAPSACK']
   require 'knapsack'
   Knapsack::Adapters::RSpecAdapter.bind
-- 
GitLab