Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-01-07 00:07:43 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-01-07 00:07:43 +0300
commit015663b70f1bcdae4483e38c2beac884f92da5b8 (patch)
tree6dd5a59c7f9a27c3cca22801ca30bf3dd8f9b401
parent5eb11b697d7ee280b0b5c2ff9a1850a3b5e9b7e3 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--Gemfile4
-rw-r--r--Gemfile.lock3
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue3
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue6
-rw-r--r--app/assets/javascripts/performance_bar/components/request_selector.vue4
-rw-r--r--app/controllers/projects/error_tracking/stack_traces_controller.rb37
-rw-r--r--app/controllers/projects/error_tracking_controller.rb29
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--changelogs/unreleased/ff-toggle-backend.yml5
-rw-r--r--changelogs/unreleased/fix-skip-snippet-raw-buttons-for-external-caching.yml5
-rw-r--r--config/routes/project.rb2
-rw-r--r--db/migrate/20191213184609_backfill_operations_feature_flags_active.rb20
-rw-r--r--doc/user/project/operations/feature_flags.md5
-rw-r--r--doc/user/project/operations/img/feature_flags_list.pngbin22548 -> 0 bytes
-rw-r--r--doc/user/project/operations/img/feature_flags_list_v12_7.pngbin0 -> 7124 bytes
-rw-r--r--lib/gitlab/database/migration_helpers.rb12
-rw-r--r--lib/sentry/client.rb15
-rw-r--r--lib/sentry/client/issue.rb4
-rw-r--r--lib/tasks/pngquant.rake97
-rw-r--r--qa/qa/page/layout/performance_bar.rb16
-rw-r--r--spec/controllers/projects/error_tracking/stack_traces_controller_spec.rb87
-rw-r--r--spec/controllers/projects/error_tracking_controller_spec.rb96
-rw-r--r--spec/helpers/application_helper_spec.rb9
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb19
-rw-r--r--spec/migrations/backfill_operations_feature_flags_active_spec.rb54
-rw-r--r--spec/support/shared_examples/migration_helpers_examples.rb23
26 files changed, 417 insertions, 140 deletions
diff --git a/Gemfile b/Gemfile
index 0c5fffe73ea..428d7413a32 100644
--- a/Gemfile
+++ b/Gemfile
@@ -386,6 +386,10 @@ group :development, :test do
gem 'simple_po_parser', '~> 1.1.2', require: false
gem 'timecop', '~> 0.8.0'
+
+ gem 'png_quantizator', '~> 0.2.1', require: false
+
+ gem 'parallel', '~> 1.17.0', require: false
end
# Gems required in omnibus-gitlab pipeline
diff --git a/Gemfile.lock b/Gemfile.lock
index 24d321cccb1..35aa419e2e2 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -734,6 +734,7 @@ GEM
peek (1.1.0)
railties (>= 4.0.0)
pg (1.1.4)
+ png_quantizator (0.2.1)
po_to_json (1.0.1)
json (>= 1.6.0)
premailer (1.11.1)
@@ -1286,8 +1287,10 @@ DEPENDENCIES
omniauth_crowd (~> 2.2.0)
omniauth_openid_connect (~> 0.3.3)
org-ruby (~> 0.9.12)
+ parallel (~> 1.17.0)
peek (~> 1.1)
pg (~> 1.1)
+ png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.9.10)
pry-byebug (~> 3.5.1)
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index 7ce32032ed3..24ae900b445 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -59,7 +59,8 @@ export default {
<div
v-if="currentRequest.details && metricDetails"
:id="`peek-view-${metric}`"
- class="view qa-performance-bar-detailed-metric"
+ class="view"
+ data-qa-selector="detailed_metric_content"
>
<button
:data-target="`#modal-peek-${metric}-details`"
diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
index d17c2f33adc..1df5562e1b6 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -107,7 +107,11 @@ export default {
</script>
<template>
<div id="js-peek" :class="env">
- <div v-if="currentRequest" class="d-flex container-fluid container-limited qa-performance-bar">
+ <div
+ v-if="currentRequest"
+ class="d-flex container-fluid container-limited"
+ data-qa-selector="performance_bar"
+ >
<div id="peek-view-host" class="view">
<span
v-if="hasHost"
diff --git a/app/assets/javascripts/performance_bar/components/request_selector.vue b/app/assets/javascripts/performance_bar/components/request_selector.vue
index 1610534ae0d..115b2ff08ac 100644
--- a/app/assets/javascripts/performance_bar/components/request_selector.vue
+++ b/app/assets/javascripts/performance_bar/components/request_selector.vue
@@ -45,13 +45,13 @@ export default {
};
</script>
<template>
- <div id="peek-request-selector">
+ <div id="peek-request-selector" data-qa-selector="request_dropdown">
<select v-model="currentRequestId">
<option
v-for="request in requests"
:key="request.id"
:value="request.id"
- class="qa-performance-bar-request"
+ data-qa-selector="request_dropdown_option"
>
{{ request.truncatedUrl }}
<span v-if="request.hasWarnings">(!)</span>
diff --git a/app/controllers/projects/error_tracking/stack_traces_controller.rb b/app/controllers/projects/error_tracking/stack_traces_controller.rb
new file mode 100644
index 00000000000..3b553752d26
--- /dev/null
+++ b/app/controllers/projects/error_tracking/stack_traces_controller.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+module Projects
+ module ErrorTracking
+ class StackTracesController < Projects::ApplicationController
+ respond_to :json
+
+ before_action :authorize_read_sentry_issue!
+
+ def index
+ result = fetch_latest_event_issue
+
+ if result[:status] == :success
+ result_with_syntax_highlight = Gitlab::ErrorTracking::StackTraceHighlightDecorator.decorate(result[:latest_event])
+
+ render json: { error: serialize_error_event(result_with_syntax_highlight) }
+ else
+ render json: { message: result[:message] }, status: result.fetch(:http_status, :bad_request)
+ end
+ end
+
+ private
+
+ def fetch_latest_event_issue
+ ::ErrorTracking::IssueLatestEventService
+ .new(project, current_user, issue_id: params[:issue_id])
+ .execute
+ end
+
+ def serialize_error_event(event)
+ ::ErrorTracking::ErrorEventSerializer
+ .new(project: project, user: current_user)
+ .represent(event)
+ end
+ end
+ end
+end
diff --git a/app/controllers/projects/error_tracking_controller.rb b/app/controllers/projects/error_tracking_controller.rb
index d1253d85758..35e12c37056 100644
--- a/app/controllers/projects/error_tracking_controller.rb
+++ b/app/controllers/projects/error_tracking_controller.rb
@@ -2,7 +2,7 @@
class Projects::ErrorTrackingController < Projects::ApplicationController
before_action :authorize_read_sentry_issue!
- before_action :set_issue_id, only: [:details, :stack_trace]
+ before_action :set_issue_id, only: :details
POLLING_INTERVAL = 10_000
@@ -25,14 +25,6 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
end
end
- def stack_trace
- respond_to do |format|
- format.json do
- render_issue_stack_trace_json
- end
- end
- end
-
private
def render_index_json
@@ -63,19 +55,6 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
}
end
- def render_issue_stack_trace_json
- service = ErrorTracking::IssueLatestEventService.new(project, current_user, issue_details_params)
- result = service.execute
-
- return if handle_errors(result)
-
- result_with_syntax_highlight = Gitlab::ErrorTracking::StackTraceHighlightDecorator.decorate(result[:latest_event])
-
- render json: {
- error: serialize_error_event(result_with_syntax_highlight)
- }
- end
-
def handle_errors(result)
unless result[:status] == :success
render json: { message: result[:message] },
@@ -110,10 +89,4 @@ class Projects::ErrorTrackingController < Projects::ApplicationController
.new(project: project, user: current_user)
.represent(error)
end
-
- def serialize_error_event(event)
- ErrorTracking::ErrorEventSerializer
- .new(project: project, user: current_user)
- .represent(event)
- end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 8389272fd35..8833b36c42d 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -198,7 +198,7 @@ module ApplicationHelper
end
def external_storage_url_or_path(path, project = @project)
- return path unless static_objects_external_storage_enabled?
+ return path if @snippet || !static_objects_external_storage_enabled?
uri = URI(Gitlab::CurrentSettings.static_objects_external_storage_url)
path = URI(path) # `path` could have query parameters, so we need to split query and path apart
diff --git a/changelogs/unreleased/ff-toggle-backend.yml b/changelogs/unreleased/ff-toggle-backend.yml
new file mode 100644
index 00000000000..cff969efda8
--- /dev/null
+++ b/changelogs/unreleased/ff-toggle-backend.yml
@@ -0,0 +1,5 @@
+---
+title: Add feature flag override toggle
+merge_request: 21598
+author:
+type: added
diff --git a/changelogs/unreleased/fix-skip-snippet-raw-buttons-for-external-caching.yml b/changelogs/unreleased/fix-skip-snippet-raw-buttons-for-external-caching.yml
new file mode 100644
index 00000000000..4116d0fb9f9
--- /dev/null
+++ b/changelogs/unreleased/fix-skip-snippet-raw-buttons-for-external-caching.yml
@@ -0,0 +1,5 @@
+---
+title: Exclude snippets from external caching handling
+merge_request:
+author:
+type: fixed
diff --git a/config/routes/project.rb b/config/routes/project.rb
index ddd1693ef02..df1b6cd5032 100644
--- a/config/routes/project.rb
+++ b/config/routes/project.rb
@@ -269,7 +269,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
to: 'error_tracking#details',
as: 'details'
get ':issue_id/stack_trace',
- to: 'error_tracking#stack_trace',
+ to: 'error_tracking/stack_traces#index',
as: 'stack_trace'
end
end
diff --git a/db/migrate/20191213184609_backfill_operations_feature_flags_active.rb b/db/migrate/20191213184609_backfill_operations_feature_flags_active.rb
new file mode 100644
index 00000000000..cc61b30acae
--- /dev/null
+++ b/db/migrate/20191213184609_backfill_operations_feature_flags_active.rb
@@ -0,0 +1,20 @@
+# frozen_string_literal: true
+
+class BackfillOperationsFeatureFlagsActive < ActiveRecord::Migration[5.2]
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ class OperationsFeatureFlag < ActiveRecord::Base
+ self.table_name = 'operations_feature_flags'
+ self.inheritance_column = :_type_disabled
+ end
+
+ def up
+ OperationsFeatureFlag.where(active: false).update_all(active: true)
+ end
+
+ def down
+ # no-op
+ end
+end
diff --git a/doc/user/project/operations/feature_flags.md b/doc/user/project/operations/feature_flags.md
index 665c0e856f1..4d372721d72 100644
--- a/doc/user/project/operations/feature_flags.md
+++ b/doc/user/project/operations/feature_flags.md
@@ -51,7 +51,10 @@ with ability to edit or remove them.
To make a feature flag active or inactive, click the pencil icon to edit it,
and toggle the status for each [spec](#define-environment-specs).
-![Feature flags list](img/feature_flags_list.png)
+The toggles next to each feature flag on the list page function as global shutoff switches.
+If a toggle is off, that feature flag is disabled for every environment.
+
+![Feature flags list](img/feature_flags_list_v12_7.png)
## Define environment specs
diff --git a/doc/user/project/operations/img/feature_flags_list.png b/doc/user/project/operations/img/feature_flags_list.png
deleted file mode 100644
index f3e85b9ce44..00000000000
--- a/doc/user/project/operations/img/feature_flags_list.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/project/operations/img/feature_flags_list_v12_7.png b/doc/user/project/operations/img/feature_flags_list_v12_7.png
new file mode 100644
index 00000000000..a28a844b46d
--- /dev/null
+++ b/doc/user/project/operations/img/feature_flags_list_v12_7.png
Binary files differ
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index f9340b262e5..1f246620a9c 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -158,7 +158,7 @@ module Gitlab
# name - The name of the foreign key.
#
# rubocop:disable Gitlab/RailsLogger
- def add_concurrent_foreign_key(source, target, column:, on_delete: :cascade, name: nil)
+ def add_concurrent_foreign_key(source, target, column:, on_delete: :cascade, name: nil, validate: true)
# Transactions would result in ALTER TABLE locks being held for the
# duration of the transaction, defeating the purpose of this method.
if transaction_open?
@@ -197,10 +197,16 @@ module Gitlab
# Validate the existing constraint. This can potentially take a very
# long time to complete, but fortunately does not lock the source table
# while running.
+ # Disable this check by passing `validate: false` to the method call
+ # The check will be enforced for new data (inserts) coming in,
+ # but validating existing data is delayed.
#
# Note this is a no-op in case the constraint is VALID already
- disable_statement_timeout do
- execute("ALTER TABLE #{source} VALIDATE CONSTRAINT #{options[:name]};")
+
+ if validate
+ disable_statement_timeout do
+ execute("ALTER TABLE #{source} VALIDATE CONSTRAINT #{options[:name]};")
+ end
end
end
# rubocop:enable Gitlab/RailsLogger
diff --git a/lib/sentry/client.rb b/lib/sentry/client.rb
index 65bedbf9e0f..211c828ccc3 100644
--- a/lib/sentry/client.rb
+++ b/lib/sentry/client.rb
@@ -71,9 +71,22 @@ module Sentry
end
def http_get(url, params = {})
- response = handle_request_exceptions do
+ http_request do
Gitlab::HTTP.get(url, **request_params.merge(params))
end
+ end
+
+ def http_put(url, params = {})
+ http_request do
+ Gitlab::HTTP.put(url, **request_params.merge({ body: params }))
+ end
+ end
+
+ def http_request
+ response = handle_request_exceptions do
+ yield
+ end
+
handle_response(response)
end
diff --git a/lib/sentry/client/issue.rb b/lib/sentry/client/issue.rb
index 28e87ab18a1..4a11c87faa4 100644
--- a/lib/sentry/client/issue.rb
+++ b/lib/sentry/client/issue.rb
@@ -15,6 +15,10 @@ module Sentry
http_get(issue_api_url(issue_id))[:body]
end
+ def update_issue(issue_id:, params:)
+ http_put(issue_api_url(issue_id), params)[:body]
+ end
+
def issue_api_url(issue_id)
issue_url = URI(url)
issue_url.path = "/api/0/issues/#{CGI.escape(issue_id.to_s)}/"
diff --git a/lib/tasks/pngquant.rake b/lib/tasks/pngquant.rake
new file mode 100644
index 00000000000..0197cc9dbcf
--- /dev/null
+++ b/lib/tasks/pngquant.rake
@@ -0,0 +1,97 @@
+return if Rails.env.production?
+
+require 'png_quantizator'
+require 'parallel'
+
+# The amount of variance (in bytes) allowed in
+# file size when testing for compression size
+TOLERANCE = 10
+
+namespace :pngquant do
+ # Returns an array of all images eligible for compression
+ def doc_images
+ Dir.glob('doc/**/*.png', File::FNM_CASEFOLD)
+ end
+
+ # Runs pngquant on an image and optionally
+ # writes the result to disk
+ def compress_image(file, overwrite_original)
+ compressed_file = "#{file}.compressed"
+ FileUtils.copy(file, compressed_file)
+
+ pngquant_file = PngQuantizator::Image.new(compressed_file)
+
+ # Run the image repeatedly through pngquant until
+ # the change in file size is within TOLERANCE
+ loop do
+ before = File.size(compressed_file)
+ pngquant_file.quantize!
+ after = File.size(compressed_file)
+ break if before - after <= TOLERANCE
+ end
+
+ savings = File.size(file) - File.size(compressed_file)
+ is_uncompressed = savings > TOLERANCE
+
+ if is_uncompressed && overwrite_original
+ FileUtils.copy(compressed_file, file)
+ end
+
+ FileUtils.remove(compressed_file)
+
+ [is_uncompressed, savings]
+ end
+
+ # Ensures pngquant is available and prints an error if not
+ def check_executable
+ unless system('pngquant --version', out: File::NULL)
+ warn(
+ 'Error: pngquant executable was not detected in the system.'.color(:red),
+ 'Download pngquant at https://pngquant.org/ and place the executable in /usr/local/bin'.color(:green)
+ )
+ abort
+ end
+ end
+
+ desc 'GitLab | pngquant | Compress all documentation PNG images using pngquant'
+ task :compress do
+ check_executable
+
+ files = doc_images
+ puts "Compressing #{files.size} PNG files in doc/**"
+
+ Parallel.each(files) do |file|
+ was_uncompressed, savings = compress_image(file, true)
+
+ if was_uncompressed
+ puts "#{file} was reduced by #{savings} bytes"
+ end
+ end
+ end
+
+ desc 'GitLab | pngquant | Checks that all documentation PNG images have been compressed with pngquant'
+ task :lint do
+ check_executable
+
+ files = doc_images
+ puts "Checking #{files.size} PNG files in doc/**"
+
+ uncompressed_files = Parallel.map(files) do |file|
+ is_uncompressed, _ = compress_image(file, false)
+ if is_uncompressed
+ puts "Uncompressed file detected: ".color(:red) + file
+ file
+ end
+ end.compact
+
+ if uncompressed_files.empty?
+ puts "All documentation images are optimally compressed!".color(:green)
+ else
+ warn(
+ "The #{uncompressed_files.size} image(s) above have not been optimally compressed using pngquant.".color(:red),
+ 'Please run "bin/rake pngquant:compress" and commit the result.'
+ )
+ abort
+ end
+ end
+end
diff --git a/qa/qa/page/layout/performance_bar.rb b/qa/qa/page/layout/performance_bar.rb
index 79e4d3edce0..dbfcf908610 100644
--- a/qa/qa/page/layout/performance_bar.rb
+++ b/qa/qa/page/layout/performance_bar.rb
@@ -9,11 +9,12 @@ module QA
end
view 'app/assets/javascripts/performance_bar/components/detailed_metric.vue' do
- element :performance_bar_detailed_metric
+ element :detailed_metric_content
end
view 'app/assets/javascripts/performance_bar/components/request_selector.vue' do
- element :performance_bar_request
+ element :request_dropdown_option
+ element :request_dropdown
end
def has_performance_bar?
@@ -21,13 +22,18 @@ module QA
end
def has_detailed_metrics?
- all_elements(:performance_bar_detailed_metric).all? do |metric|
- metric.has_text?(%r{\d+})
+ retry_until(sleep_interval: 1) do
+ all_elements(:detailed_metric_content).all? do |metric|
+ metric.has_text?(%r{\d+})
+ end
end
end
def has_request_for?(path)
- has_element?(:performance_bar_request, text: path)
+ click_element(:request_dropdown)
+ retry_until(sleep_interval: 1) do
+ has_element?(:request_dropdown_option, text: path)
+ end
end
end
end
diff --git a/spec/controllers/projects/error_tracking/stack_traces_controller_spec.rb b/spec/controllers/projects/error_tracking/stack_traces_controller_spec.rb
new file mode 100644
index 00000000000..a836253f9e1
--- /dev/null
+++ b/spec/controllers/projects/error_tracking/stack_traces_controller_spec.rb
@@ -0,0 +1,87 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::ErrorTracking::StackTracesController do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { create(:user) }
+
+ before do
+ sign_in(user)
+ project.add_maintainer(user)
+ end
+
+ describe 'GET #index' do
+ let(:issue_id) { 1234 }
+ let(:issue_stack_trace_service) { spy(:issue_stack_trace_service) }
+
+ subject(:get_stack_trace) do
+ get :index, params: { namespace_id: project.namespace, project_id: project, issue_id: issue_id, format: :json }
+ end
+
+ before do
+ expect(ErrorTracking::IssueLatestEventService)
+ .to receive(:new).with(project, user, issue_id: issue_id.to_s)
+ .and_return(issue_stack_trace_service)
+ expect(issue_stack_trace_service).to receive(:execute).and_return(service_response)
+
+ get_stack_trace
+ end
+
+ context 'awaiting data' do
+ let(:service_response) { { status: :error, http_status: :no_content }}
+
+ it 'responds with no data' do
+ expect(response).to have_gitlab_http_status(:no_content)
+ end
+ end
+
+ context 'service result is successful' do
+ let(:service_response) { { status: :success, latest_event: error_event } }
+ let(:error_event) { build(:error_tracking_error_event) }
+
+ it 'responds with success' do
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'responds with error' do
+ expect(response).to match_response_schema('error_tracking/issue_stack_trace')
+ end
+
+ it 'highlights stack trace source code' do
+ expect(json_response['error']).to eq(
+ Gitlab::ErrorTracking::StackTraceHighlightDecorator.decorate(error_event).as_json
+ )
+ end
+ end
+
+ context 'service result is erroneous' do
+ let(:error_message) { 'error message' }
+
+ context 'without http_status' do
+ let(:service_response) { { status: :error, message: error_message } }
+
+ it 'responds with bad request' do
+ expect(response).to have_gitlab_http_status(:bad_request)
+ end
+
+ it 'responds with error message' do
+ expect(json_response['message']).to eq(error_message)
+ end
+ end
+
+ context 'with explicit http_status' do
+ let(:http_status) { :no_content }
+ let(:service_response) { { status: :error, message: error_message, http_status: http_status } }
+
+ it 'responds with custom http status' do
+ expect(response).to have_gitlab_http_status(http_status)
+ end
+
+ it 'responds with error message' do
+ expect(json_response['message']).to eq(error_message)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/controllers/projects/error_tracking_controller_spec.rb b/spec/controllers/projects/error_tracking_controller_spec.rb
index b1f7c7178c1..d0f248437b4 100644
--- a/spec/controllers/projects/error_tracking_controller_spec.rb
+++ b/spec/controllers/projects/error_tracking_controller_spec.rb
@@ -266,102 +266,6 @@ describe Projects::ErrorTrackingController do
end
end
- describe 'GET #stack_trace' do
- let_it_be(:issue_id) { 1234 }
-
- let(:issue_stack_trace_service) { spy(:issue_stack_trace_service) }
-
- let(:permitted_params) do
- ActionController::Parameters.new(
- { issue_id: issue_id.to_s }
- ).permit!
- end
-
- subject(:get_stack_trace) do
- get :stack_trace, params: issue_params(issue_id: issue_id, format: :json)
- end
-
- before do
- expect(ErrorTracking::IssueLatestEventService)
- .to receive(:new).with(project, user, permitted_params)
- .and_return(issue_stack_trace_service)
- end
-
- describe 'format json' do
- context 'awaiting data' do
- before do
- expect(issue_stack_trace_service).to receive(:execute)
- .and_return(status: :error, http_status: :no_content)
- end
-
- it 'returns no data' do
- get_stack_trace
-
- expect(response).to have_gitlab_http_status(:no_content)
- end
- end
-
- context 'service result is successful' do
- before do
- expect(issue_stack_trace_service).to receive(:execute)
- .and_return(status: :success, latest_event: error_event)
-
- get_stack_trace
- end
-
- let(:error_event) { build(:error_tracking_error_event) }
-
- it 'returns an error' do
- expect(response).to have_gitlab_http_status(:ok)
- expect(response).to match_response_schema('error_tracking/issue_stack_trace')
- end
-
- it 'highlights stack trace source code' do
- expect(json_response['error']).to eq(
- Gitlab::ErrorTracking::StackTraceHighlightDecorator.decorate(error_event).as_json
- )
- end
- end
-
- context 'service result is erroneous' do
- let(:error_message) { 'error message' }
-
- context 'without http_status' do
- before do
- expect(issue_stack_trace_service).to receive(:execute)
- .and_return(status: :error, message: error_message)
- end
-
- it 'returns 400 with message' do
- get_stack_trace
-
- expect(response).to have_gitlab_http_status(:bad_request)
- expect(json_response['message']).to eq(error_message)
- end
- end
-
- context 'with explicit http_status' do
- let(:http_status) { :no_content }
-
- before do
- expect(issue_stack_trace_service).to receive(:execute).and_return(
- status: :error,
- message: error_message,
- http_status: http_status
- )
- end
-
- it 'returns http_status with message' do
- get_stack_trace
-
- expect(response).to have_gitlab_http_status(http_status)
- expect(json_response['message']).to eq(error_message)
- end
- end
- end
- end
- end
-
private
def issue_params(opts = {})
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index a0c85863150..a67475e47a3 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -206,6 +206,15 @@ describe ApplicationHelper do
end
end
+ context 'when @snippet is set' do
+ it 'returns the passed path' do
+ snippet = create(:snippet)
+ assign(:snippet, snippet)
+
+ expect(helper.external_storage_url_or_path('/foo/bar', project)).to eq('/foo/bar')
+ end
+ end
+
context 'when external storage is enabled' do
let(:user) { create(:user, static_object_token: 'hunter1') }
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index cac6908f4b4..9c8d53b0ed7 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -325,6 +325,25 @@ describe Gitlab::Database::MigrationHelpers do
end
end
end
+
+ describe 'validate option' do
+ let(:args) { [:projects, :users] }
+ let(:options) { { column: :user_id, on_delete: nil } }
+
+ context 'when validate is supplied with a falsey value' do
+ it_behaves_like 'skips validation', validate: false
+ it_behaves_like 'skips validation', validate: nil
+ end
+
+ context 'when validate is supplied with a truthy value' do
+ it_behaves_like 'performs validation', validate: true
+ it_behaves_like 'performs validation', validate: :whatever
+ end
+
+ context 'when validate is not supplied' do
+ it_behaves_like 'performs validation', {}
+ end
+ end
end
end
diff --git a/spec/migrations/backfill_operations_feature_flags_active_spec.rb b/spec/migrations/backfill_operations_feature_flags_active_spec.rb
new file mode 100644
index 00000000000..ad69b776052
--- /dev/null
+++ b/spec/migrations/backfill_operations_feature_flags_active_spec.rb
@@ -0,0 +1,54 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+require Rails.root.join('db', 'migrate', '20191213184609_backfill_operations_feature_flags_active.rb')
+
+describe BackfillOperationsFeatureFlagsActive, :migration do
+ let(:namespaces) { table(:namespaces) }
+ let(:projects) { table(:projects) }
+ let(:flags) { table(:operations_feature_flags) }
+
+ def setup
+ namespace = namespaces.create!(name: 'foo', path: 'foo')
+ project = projects.create!(namespace_id: namespace.id)
+
+ project
+ end
+
+ it 'executes successfully when there are no flags in the table' do
+ setup
+
+ disable_migrations_output { migrate! }
+
+ expect(flags.count).to eq(0)
+ end
+
+ it 'updates active to true' do
+ project = setup
+ flag = flags.create!(project_id: project.id, name: 'test_flag', active: false)
+
+ disable_migrations_output { migrate! }
+
+ expect(flag.reload.active).to eq(true)
+ end
+
+ it 'updates active to true for multiple flags' do
+ project = setup
+ flag_a = flags.create!(project_id: project.id, name: 'test_flag', active: false)
+ flag_b = flags.create!(project_id: project.id, name: 'other_flag', active: false)
+
+ disable_migrations_output { migrate! }
+
+ expect(flag_a.reload.active).to eq(true)
+ expect(flag_b.reload.active).to eq(true)
+ end
+
+ it 'leaves active true if it is already true' do
+ project = setup
+ flag = flags.create!(project_id: project.id, name: 'test_flag', active: true)
+
+ disable_migrations_output { migrate! }
+
+ expect(flag.reload.active).to eq(true)
+ end
+end
diff --git a/spec/support/shared_examples/migration_helpers_examples.rb b/spec/support/shared_examples/migration_helpers_examples.rb
new file mode 100644
index 00000000000..3587297a2d7
--- /dev/null
+++ b/spec/support/shared_examples/migration_helpers_examples.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+shared_examples 'skips validation' do |validation_option|
+ it 'skips validation' do
+ expect(model).not_to receive(:disable_statement_timeout)
+ expect(model).to receive(:execute).with(/ADD CONSTRAINT/)
+ expect(model).not_to receive(:execute).with(/VALIDATE CONSTRAINT/)
+
+ model.add_concurrent_foreign_key(*args, **options.merge(validation_option))
+ end
+end
+
+shared_examples 'performs validation' do |validation_option|
+ it 'performs validation' do
+ expect(model).to receive(:disable_statement_timeout).and_call_original
+ expect(model).to receive(:execute).with(/statement_timeout/)
+ expect(model).to receive(:execute).ordered.with(/NOT VALID/)
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+ expect(model).to receive(:execute).with(/RESET ALL/)
+
+ model.add_concurrent_foreign_key(*args, **options.merge(validation_option))
+ end
+end