Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
25521def84
commit
1da3754b25
|
|
@ -1,19 +1,21 @@
|
|||
import { secondsIn, timeWindowsKeyNames } from './constants';
|
||||
|
||||
const secondsToMilliseconds = seconds => seconds * 1000;
|
||||
|
||||
export const getTimeDiff = timeWindow => {
|
||||
const end = Math.floor(Date.now() / 1000); // convert milliseconds to seconds
|
||||
const difference = secondsIn[timeWindow] || secondsIn.eightHours;
|
||||
const start = end - difference;
|
||||
|
||||
return {
|
||||
start: new Date(start * 1000).toISOString(),
|
||||
end: new Date(end * 1000).toISOString(),
|
||||
start: new Date(secondsToMilliseconds(start)).toISOString(),
|
||||
end: new Date(secondsToMilliseconds(end)).toISOString(),
|
||||
};
|
||||
};
|
||||
|
||||
export const getTimeWindow = ({ start, end }) =>
|
||||
Object.entries(secondsIn).reduce((acc, [timeRange, value]) => {
|
||||
if (end - start === value) {
|
||||
if (new Date(end) - new Date(start) === secondsToMilliseconds(value)) {
|
||||
return timeRange;
|
||||
}
|
||||
return acc;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const textBuilder = results => {
|
|||
const { failed, resolved, total } = results;
|
||||
|
||||
const failedString = failed
|
||||
? n__('%d failed test result', '%d failed test results', failed)
|
||||
? n__('%d failed/error test result', '%d failed/error test results', failed)
|
||||
: null;
|
||||
const resolvedString = resolved
|
||||
? n__('%d fixed test result', '%d fixed test results', resolved)
|
||||
|
|
|
|||
|
|
@ -4,19 +4,15 @@ class HealthController < ActionController::Base
|
|||
protect_from_forgery with: :exception, prepend: true
|
||||
include RequiresWhitelistedMonitoringClient
|
||||
|
||||
CHECKS = [
|
||||
Gitlab::HealthChecks::DbCheck,
|
||||
Gitlab::HealthChecks::Redis::RedisCheck,
|
||||
Gitlab::HealthChecks::Redis::CacheCheck,
|
||||
Gitlab::HealthChecks::Redis::QueuesCheck,
|
||||
Gitlab::HealthChecks::Redis::SharedStateCheck,
|
||||
Gitlab::HealthChecks::GitalyCheck
|
||||
].freeze
|
||||
|
||||
def readiness
|
||||
results = CHECKS.map { |check| [check.name, check.readiness] }
|
||||
results = checks.flat_map(&:readiness)
|
||||
success = results.all?(&:success)
|
||||
|
||||
render_check_results(results)
|
||||
# disable static error pages at the gitlab-workhorse level, we want to see this error response even in production
|
||||
headers["X-GitLab-Custom-Error"] = 1 unless success
|
||||
|
||||
response = results.map { |result| [result.name, result.payload] }.to_h
|
||||
render json: response, status: success ? :ok : :service_unavailable
|
||||
end
|
||||
|
||||
def liveness
|
||||
|
|
@ -25,26 +21,7 @@ class HealthController < ActionController::Base
|
|||
|
||||
private
|
||||
|
||||
def render_check_results(results)
|
||||
flattened = results.flat_map do |name, result|
|
||||
if result.is_a?(Gitlab::HealthChecks::Result)
|
||||
[[name, result]]
|
||||
else
|
||||
result.map { |r| [name, r] }
|
||||
end
|
||||
end
|
||||
success = flattened.all? { |name, r| r.success }
|
||||
|
||||
response = flattened.map do |name, r|
|
||||
info = { status: r.success ? 'ok' : 'failed' }
|
||||
info['message'] = r.message if r.message
|
||||
info[:labels] = r.labels if r.labels
|
||||
[name, info]
|
||||
end
|
||||
|
||||
# disable static error pages at the gitlab-workhorse level, we want to see this error response even in production
|
||||
headers["X-GitLab-Custom-Error"] = 1 unless success
|
||||
|
||||
render json: response.to_h, status: success ? :ok : :service_unavailable
|
||||
def checks
|
||||
::Gitlab::HealthChecks::CHECKS
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -63,7 +63,9 @@ module Projects
|
|||
:api_host,
|
||||
:token,
|
||||
project: [:slug, :name, :organization_slug, :organization_name]
|
||||
]
|
||||
],
|
||||
|
||||
grafana_integration_attributes: [:token, :grafana_url]
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ module GroupsHelper
|
|||
end
|
||||
|
||||
def can_disable_group_emails?(group)
|
||||
Feature.enabled?(:emails_disabled, group, default_enabled: true) &&
|
||||
can?(current_user, :set_emails_disabled, group) && !group.parent&.emails_disabled?
|
||||
can?(current_user, :set_emails_disabled, group) && !group.parent&.emails_disabled?
|
||||
end
|
||||
|
||||
def group_issues_count(state:)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ module ProjectsHelper
|
|||
def can_disable_emails?(project, current_user)
|
||||
return false if project.group&.emails_disabled?
|
||||
|
||||
can?(current_user, :set_emails_disabled, project) && Feature.enabled?(:emails_disabled, project, default_enabled: true)
|
||||
can?(current_user, :set_emails_disabled, project)
|
||||
end
|
||||
|
||||
def last_push_event
|
||||
|
|
@ -354,6 +354,14 @@ module ProjectsHelper
|
|||
@project.metrics_setting_external_dashboard_url
|
||||
end
|
||||
|
||||
def grafana_integration_url
|
||||
@project.grafana_integration&.grafana_url
|
||||
end
|
||||
|
||||
def grafana_integration_token
|
||||
@project.grafana_integration&.token
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_project_nav_tabs(project, current_user)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class GrafanaIntegration < ApplicationRecord
|
||||
belongs_to :project
|
||||
|
||||
attr_encrypted :token,
|
||||
mode: :per_attribute_iv,
|
||||
algorithm: 'aes-256-gcm',
|
||||
key: Settings.attr_encrypted_db_key_base_32
|
||||
|
||||
validates :grafana_url,
|
||||
length: { maximum: 1024 },
|
||||
addressable_url: { enforce_sanitization: true, ascii_only: true }
|
||||
|
||||
validates :token, :project, presence: true
|
||||
end
|
||||
|
|
@ -182,7 +182,7 @@ class Namespace < ApplicationRecord
|
|||
# any ancestor can disable emails for all descendants
|
||||
def emails_disabled?
|
||||
strong_memoize(:emails_disabled) do
|
||||
Feature.enabled?(:emails_disabled, self, default_enabled: true) && self_and_ancestors.where(emails_disabled: true).exists?
|
||||
self_and_ancestors.where(emails_disabled: true).exists?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ class Project < ApplicationRecord
|
|||
has_one :project_repository, inverse_of: :project
|
||||
has_one :error_tracking_setting, inverse_of: :project, class_name: 'ErrorTracking::ProjectErrorTrackingSetting'
|
||||
has_one :metrics_setting, inverse_of: :project, class_name: 'ProjectMetricsSetting'
|
||||
has_one :grafana_integration, inverse_of: :project
|
||||
|
||||
# Merge Requests for target project should be removed with it
|
||||
has_many :merge_requests, foreign_key: 'target_project_id', inverse_of: :target_project
|
||||
|
|
@ -311,6 +312,7 @@ class Project < ApplicationRecord
|
|||
|
||||
accepts_nested_attributes_for :error_tracking_setting, update_only: true
|
||||
accepts_nested_attributes_for :metrics_setting, update_only: true, allow_destroy: true
|
||||
accepts_nested_attributes_for :grafana_integration, update_only: true, allow_destroy: true
|
||||
|
||||
delegate :name, to: :owner, allow_nil: true, prefix: true
|
||||
delegate :members, to: :team, prefix: true
|
||||
|
|
@ -664,7 +666,7 @@ class Project < ApplicationRecord
|
|||
def emails_disabled?
|
||||
strong_memoize(:emails_disabled) do
|
||||
# disabling in the namespace overrides the project setting
|
||||
Feature.enabled?(:emails_disabled, self, default_enabled: true) && (super || namespace.emails_disabled?)
|
||||
super || namespace.emails_disabled?
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -27,8 +27,12 @@ module Storage
|
|||
"#{base_dir}/#{disk_hash}" if disk_hash
|
||||
end
|
||||
|
||||
# TODO: remove this method entirely after 12.4 https://gitlab.com/gitlab-org/gitlab/issues/33244
|
||||
# we no longer need ensure_storage_path_exists to call add_namespace since both creating and moving
|
||||
# repositories will be preceded by a mkdir -p in gitaly to ensure the parent of the destination directory
|
||||
# exists.
|
||||
def ensure_storage_path_exists
|
||||
gitlab_shell.add_namespace(repository_storage, base_dir)
|
||||
true
|
||||
end
|
||||
|
||||
def rename_repo(old_full_path: nil, new_full_path: nil)
|
||||
|
|
|
|||
|
|
@ -23,10 +23,14 @@ module Storage
|
|||
project.full_path
|
||||
end
|
||||
|
||||
# TODO: remove this method entirely after 12.4 https://gitlab.com/gitlab-org/gitlab/issues/33244
|
||||
# we no longer need ensure_storage_path_exists to call add_namespace since both creating and moving
|
||||
# repositories will be preceded by a mkdir -p in gitaly to ensure the parent of the destination directory
|
||||
# exists.
|
||||
def ensure_storage_path_exists
|
||||
return unless namespace
|
||||
|
||||
gitlab_shell.add_namespace(repository_storage, base_dir)
|
||||
true
|
||||
end
|
||||
|
||||
def rename_repo(old_full_path: nil, new_full_path: nil)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,9 @@ module Projects
|
|||
private
|
||||
|
||||
def project_update_params
|
||||
error_tracking_params.merge(metrics_setting_params)
|
||||
error_tracking_params
|
||||
.merge(metrics_setting_params)
|
||||
.merge(grafana_integration_params)
|
||||
end
|
||||
|
||||
def metrics_setting_params
|
||||
|
|
@ -44,6 +46,14 @@ module Projects
|
|||
}
|
||||
}
|
||||
end
|
||||
|
||||
def grafana_integration_params
|
||||
return {} unless attrs = params[:grafana_integration_attributes]
|
||||
|
||||
destroy = attrs[:grafana_url].blank? && attrs[:token].blank?
|
||||
|
||||
{ grafana_integration_attributes: attrs.merge(_destroy: destroy) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Do not start mirroring via API when paused
|
||||
merge_request: 17930
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Time window filter in monitor dashboard gets reset
|
||||
merge_request: 17972
|
||||
author:
|
||||
type: fixed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: MR Test Summary now shows errors as failures.
|
||||
merge_request: 17039
|
||||
author:
|
||||
type: changed
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Create table for grafana api token for metrics embeds
|
||||
merge_request: 17234
|
||||
author:
|
||||
type: added
|
||||
|
|
@ -22,7 +22,7 @@ class LightSettings
|
|||
end
|
||||
|
||||
def host
|
||||
config['gitlab']['host']
|
||||
config.dig('gitlab', 'host') || ENV['GITLAB_HOST'] || 'localhost'
|
||||
end
|
||||
|
||||
def gl_subdomain?
|
||||
|
|
|
|||
|
|
@ -16,6 +16,9 @@ en:
|
|||
api_url: "Sentry API URL"
|
||||
project/metrics_setting:
|
||||
external_dashboard_url: "External dashboard URL"
|
||||
project/grafana_integration:
|
||||
token: "Grafana HTTP API Token"
|
||||
grafana_url: "Grafana API URL"
|
||||
views:
|
||||
pagination:
|
||||
previous: "Prev"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateGrafanaIntegrations < ActiveRecord::Migration[5.2]
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
create_table :grafana_integrations do |t|
|
||||
t.references :project, index: true, foreign_key: { on_delete: :cascade }, unique: true, null: false
|
||||
t.timestamps_with_timezone null: false
|
||||
t.string :encrypted_token, limit: 255, null: false
|
||||
t.string :encrypted_token_iv, limit: 255, null: false
|
||||
t.string :grafana_url, null: false, limit: 1024
|
||||
end
|
||||
end
|
||||
end
|
||||
11
db/schema.rb
11
db/schema.rb
|
|
@ -1704,6 +1704,16 @@ ActiveRecord::Schema.define(version: 2019_09_27_074328) do
|
|||
t.index ["project_id"], name: "index_gpg_signatures_on_project_id"
|
||||
end
|
||||
|
||||
create_table "grafana_integrations", force: :cascade do |t|
|
||||
t.bigint "project_id", null: false
|
||||
t.datetime_with_timezone "created_at", null: false
|
||||
t.datetime_with_timezone "updated_at", null: false
|
||||
t.string "encrypted_token", limit: 255, null: false
|
||||
t.string "encrypted_token_iv", limit: 255, null: false
|
||||
t.string "grafana_url", limit: 1024, null: false
|
||||
t.index ["project_id"], name: "index_grafana_integrations_on_project_id"
|
||||
end
|
||||
|
||||
create_table "group_custom_attributes", id: :serial, force: :cascade do |t|
|
||||
t.datetime_with_timezone "created_at", null: false
|
||||
t.datetime_with_timezone "updated_at", null: false
|
||||
|
|
@ -3997,6 +4007,7 @@ ActiveRecord::Schema.define(version: 2019_09_27_074328) do
|
|||
add_foreign_key "gpg_signatures", "gpg_key_subkeys", on_delete: :nullify
|
||||
add_foreign_key "gpg_signatures", "gpg_keys", on_delete: :nullify
|
||||
add_foreign_key "gpg_signatures", "projects", on_delete: :cascade
|
||||
add_foreign_key "grafana_integrations", "projects", on_delete: :cascade
|
||||
add_foreign_key "group_custom_attributes", "namespaces", column: "group_id", on_delete: :cascade
|
||||
add_foreign_key "identities", "saml_providers", name: "fk_aade90f0fc", on_delete: :cascade
|
||||
add_foreign_key "import_export_uploads", "projects", on_delete: :cascade
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ module Gitlab
|
|||
if data['failure']
|
||||
status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED
|
||||
system_output = data['failure']
|
||||
elsif data['error']
|
||||
# For now, as an MVC, we are grouping error test cases together
|
||||
# with failed ones. But we will improve this further on
|
||||
# https://gitlab.com/gitlab-org/gitlab/issues/32046.
|
||||
status = ::Gitlab::Ci::Reports::TestCase::STATUS_FAILED
|
||||
system_output = data['error']
|
||||
else
|
||||
status = ::Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS
|
||||
system_output = nil
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module HealthChecks
|
||||
CHECKS = [
|
||||
Gitlab::HealthChecks::DbCheck,
|
||||
Gitlab::HealthChecks::Redis::RedisCheck,
|
||||
Gitlab::HealthChecks::Redis::CacheCheck,
|
||||
Gitlab::HealthChecks::Redis::QueuesCheck,
|
||||
Gitlab::HealthChecks::Redis::SharedStateCheck,
|
||||
Gitlab::HealthChecks::GitalyCheck
|
||||
].freeze
|
||||
end
|
||||
end
|
||||
|
|
@ -29,7 +29,13 @@ module Gitlab
|
|||
def check(storage_name)
|
||||
serv = Gitlab::GitalyClient::HealthCheckService.new(storage_name)
|
||||
result = serv.check
|
||||
HealthChecks::Result.new(result[:success], result[:message], shard: storage_name)
|
||||
|
||||
HealthChecks::Result.new(
|
||||
name,
|
||||
result[:success],
|
||||
result[:message],
|
||||
shard: storage_name
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab::HealthChecks
|
||||
Metric = Struct.new(:name, :value, :labels)
|
||||
module Gitlab
|
||||
module HealthChecks
|
||||
Metric = Struct.new(:name, :value, :labels)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module HealthChecks
|
||||
class PrometheusTextFormat
|
||||
def marshal(metrics)
|
||||
"#{metrics_with_type_declarations(metrics).join("\n")}\n"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def metrics_with_type_declarations(metrics)
|
||||
type_declaration_added = {}
|
||||
|
||||
metrics.flat_map do |metric|
|
||||
metric_lines = []
|
||||
|
||||
unless type_declaration_added.key?(metric.name)
|
||||
type_declaration_added[metric.name] = true
|
||||
metric_lines << metric_type_declaration(metric)
|
||||
end
|
||||
|
||||
metric_lines << metric_text(metric)
|
||||
end
|
||||
end
|
||||
|
||||
def metric_type_declaration(metric)
|
||||
"# TYPE #{metric.name} gauge"
|
||||
end
|
||||
|
||||
def metric_text(metric)
|
||||
labels = metric.labels&.map { |key, value| "#{key}=\"#{value}\"" }&.join(',') || ''
|
||||
|
||||
if labels.empty?
|
||||
"#{metric.name} #{metric.value}"
|
||||
else
|
||||
"#{metric.name}{#{labels}} #{metric.value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,5 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab::HealthChecks
|
||||
Result = Struct.new(:success, :message, :labels)
|
||||
module Gitlab
|
||||
module HealthChecks
|
||||
Result = Struct.new(:name, :success, :message, :labels) do
|
||||
def payload
|
||||
{
|
||||
status: success ? 'ok' : 'failed',
|
||||
message: message,
|
||||
labels: labels
|
||||
}.compact
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,14 +8,14 @@ module Gitlab
|
|||
def readiness
|
||||
check_result = check
|
||||
if successful?(check_result)
|
||||
HealthChecks::Result.new(true)
|
||||
HealthChecks::Result.new(name, true)
|
||||
elsif check_result.is_a?(Timeout::Error)
|
||||
HealthChecks::Result.new(false, "#{human_name} check timed out")
|
||||
HealthChecks::Result.new(name, false, "#{human_name} check timed out")
|
||||
else
|
||||
HealthChecks::Result.new(false, "unexpected #{human_name} check result: #{check_result}")
|
||||
HealthChecks::Result.new(name, false, "unexpected #{human_name} check result: #{check_result}")
|
||||
end
|
||||
rescue => e
|
||||
HealthChecks::Result.new(false, "unexpected #{human_name} check result: #{e}")
|
||||
HealthChecks::Result.new(name, false, "unexpected #{human_name} check result: #{e}")
|
||||
end
|
||||
|
||||
def metrics
|
||||
|
|
|
|||
|
|
@ -113,10 +113,6 @@ module Gitlab
|
|||
success
|
||||
end
|
||||
|
||||
# Move repository reroutes to mv_directory which is an alias for
|
||||
# mv_namespace. Given the underlying implementation is a move action,
|
||||
# indescriminate of what the folders might be.
|
||||
#
|
||||
# storage - project's storage path
|
||||
# path - project disk path
|
||||
# new_path - new project disk path
|
||||
|
|
@ -275,7 +271,6 @@ module Gitlab
|
|||
|
||||
false
|
||||
end
|
||||
alias_method :mv_directory, :mv_namespace # Note: ShellWorker uses this alias
|
||||
|
||||
def url_to_repo(path)
|
||||
Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git"
|
||||
|
|
|
|||
|
|
@ -125,6 +125,11 @@ module Gitlab
|
|||
# If the addr can't be resolved or the url is invalid (i.e http://1.1.1.1.1)
|
||||
# we block the url
|
||||
raise BlockedUrlError, "Host cannot be resolved or invalid"
|
||||
rescue ArgumentError => error
|
||||
# Addrinfo.getaddrinfo errors if the domain exceeds 1024 characters.
|
||||
raise unless error.message.include?('hostname too long')
|
||||
|
||||
raise BlockedUrlError, "Host is too long (maximum is 1024 characters)"
|
||||
end
|
||||
|
||||
def validate_local_request(
|
||||
|
|
|
|||
|
|
@ -95,8 +95,8 @@ msgid_plural "%d exporters"
|
|||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
msgid "%d failed test result"
|
||||
msgid_plural "%d failed test results"
|
||||
msgid "%d failed/error test result"
|
||||
msgid_plural "%d failed/error test results"
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,8 @@ describe HealthController do
|
|||
end
|
||||
|
||||
it 'responds with readiness checks data when a failure happens' do
|
||||
allow(Gitlab::HealthChecks::Redis::RedisCheck).to receive(:readiness).and_return(Gitlab::HealthChecks::Result.new(false, "check error"))
|
||||
allow(Gitlab::HealthChecks::Redis::RedisCheck).to receive(:readiness).and_return(
|
||||
Gitlab::HealthChecks::Result.new('redis_check', false, "check error"))
|
||||
|
||||
subject
|
||||
|
||||
|
|
|
|||
|
|
@ -180,6 +180,21 @@ describe Projects::Settings::OperationsController do
|
|||
end
|
||||
end
|
||||
|
||||
context 'grafana integration' do
|
||||
describe 'PATCH #update' do
|
||||
let(:params) do
|
||||
{
|
||||
grafana_integration_attributes: {
|
||||
grafana_url: 'https://grafana.gitlab.com',
|
||||
token: 'eyJrIjoicDRlRTREdjhhOEZ5WjZPWXUzazJOSW0zZHJUejVOd3IiLCJuIjoiVGVzdCBLZXkiLCJpZCI6MX0='
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it_behaves_like 'PATCHable'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project_params(project, params = {})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :grafana_integration, class: GrafanaIntegration do
|
||||
project
|
||||
grafana_url { 'https://grafana.com' }
|
||||
token { SecureRandom.hex(10) }
|
||||
end
|
||||
end
|
||||
|
|
@ -536,10 +536,10 @@ describe 'Merge request > User sees merge widget', :js do
|
|||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 failed test result out of 2 total tests')
|
||||
expect(page).to have_content('Test summary contained 1 failed/error test result out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
expect(page).to have_content('rspec found no changed test results out of 1 total test')
|
||||
expect(page).to have_content('junit found 1 failed test result out of 1 total test')
|
||||
expect(page).to have_content('junit found 1 failed/error test result out of 1 total test')
|
||||
expect(page).to have_content('New')
|
||||
expect(page).to have_content('addTest')
|
||||
end
|
||||
|
|
@ -581,9 +581,9 @@ describe 'Merge request > User sees merge widget', :js do
|
|||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
|
||||
expect(page).to have_content('Test summary contained 1 failed test result out of 2 total tests')
|
||||
expect(page).to have_content('Test summary contained 1 failed/error test result out of 2 total tests')
|
||||
within(".js-report-section-container") do
|
||||
expect(page).to have_content('rspec found 1 failed test result out of 1 total test')
|
||||
expect(page).to have_content('rspec found 1 failed/error test result out of 1 total test')
|
||||
expect(page).to have_content('junit found no changed test results out of 1 total test')
|
||||
expect(page).not_to have_content('New')
|
||||
expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary')
|
||||
|
|
@ -677,10 +677,10 @@ describe 'Merge request > User sees merge widget', :js do
|
|||
within(".js-reports-container") do
|
||||
click_button 'Expand'
|
||||
|
||||
expect(page).to have_content('Test summary contained 20 failed test results out of 20 total tests')
|
||||
expect(page).to have_content('Test summary contained 20 failed/error test results out of 20 total tests')
|
||||
within(".js-report-section-container") do
|
||||
expect(page).to have_content('rspec found 10 failed test results out of 10 total tests')
|
||||
expect(page).to have_content('junit found 10 failed test results out of 10 total tests')
|
||||
expect(page).to have_content('rspec found 10 failed/error test results out of 10 total tests')
|
||||
expect(page).to have_content('junit found 10 failed/error test results out of 10 total tests')
|
||||
|
||||
expect(page).to have_content('Test#sum when a is 1 and b is 3 returns summary', count: 2)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,7 +30,9 @@ describe('Reports store utils', () => {
|
|||
const data = { failed: 3, total: 10 };
|
||||
const result = utils.summaryTextBuilder(name, data);
|
||||
|
||||
expect(result).toBe('Test summary contained 3 failed test results out of 10 total tests');
|
||||
expect(result).toBe(
|
||||
'Test summary contained 3 failed/error test results out of 10 total tests',
|
||||
);
|
||||
});
|
||||
|
||||
it('should render text for multiple fixed results', () => {
|
||||
|
|
@ -47,7 +49,7 @@ describe('Reports store utils', () => {
|
|||
const result = utils.summaryTextBuilder(name, data);
|
||||
|
||||
expect(result).toBe(
|
||||
'Test summary contained 3 failed test results and 4 fixed test results out of 10 total tests',
|
||||
'Test summary contained 3 failed/error test results and 4 fixed test results out of 10 total tests',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -57,7 +59,7 @@ describe('Reports store utils', () => {
|
|||
const result = utils.summaryTextBuilder(name, data);
|
||||
|
||||
expect(result).toBe(
|
||||
'Test summary contained 1 failed test result and 1 fixed test result out of 10 total tests',
|
||||
'Test summary contained 1 failed/error test result and 1 fixed test result out of 10 total tests',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -84,7 +86,7 @@ describe('Reports store utils', () => {
|
|||
const data = { failed: 3, total: 10 };
|
||||
const result = utils.reportTextBuilder(name, data);
|
||||
|
||||
expect(result).toBe('Rspec found 3 failed test results out of 10 total tests');
|
||||
expect(result).toBe('Rspec found 3 failed/error test results out of 10 total tests');
|
||||
});
|
||||
|
||||
it('should render text for multiple fixed results', () => {
|
||||
|
|
@ -101,7 +103,7 @@ describe('Reports store utils', () => {
|
|||
const result = utils.reportTextBuilder(name, data);
|
||||
|
||||
expect(result).toBe(
|
||||
'Rspec found 3 failed test results and 4 fixed test results out of 10 total tests',
|
||||
'Rspec found 3 failed/error test results and 4 fixed test results out of 10 total tests',
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -111,7 +113,7 @@ describe('Reports store utils', () => {
|
|||
const result = utils.reportTextBuilder(name, data);
|
||||
|
||||
expect(result).toBe(
|
||||
'Rspec found 1 failed test result and 1 fixed test result out of 10 total tests',
|
||||
'Rspec found 1 failed/error test result and 1 fixed test result out of 10 total tests',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -902,4 +902,40 @@ describe ProjectsHelper do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#grafana_integration_url' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
before do
|
||||
helper.instance_variable_set(:@project, project)
|
||||
end
|
||||
|
||||
subject { helper.grafana_integration_url }
|
||||
|
||||
it { is_expected.to eq(nil) }
|
||||
|
||||
context 'grafana integration exists' do
|
||||
let!(:grafana_integration) { create(:grafana_integration, project: project) }
|
||||
|
||||
it { is_expected.to eq(grafana_integration.grafana_url) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#grafana_integration_token' do
|
||||
let(:project) { create(:project) }
|
||||
|
||||
before do
|
||||
helper.instance_variable_set(:@project, project)
|
||||
end
|
||||
|
||||
subject { helper.grafana_integration_token }
|
||||
|
||||
it { is_expected.to eq(nil) }
|
||||
|
||||
context 'grafana integration exists' do
|
||||
let!(:grafana_integration) { create(:grafana_integration, project: project) }
|
||||
|
||||
it { is_expected.to eq(grafana_integration.token) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -333,8 +333,8 @@ describe('Dashboard', () => {
|
|||
});
|
||||
|
||||
it('shows a specific time window selected from the url params', done => {
|
||||
const start = 1564439536;
|
||||
const end = 1564441336;
|
||||
const start = '2019-10-01T18:27:47.000Z';
|
||||
const end = '2019-10-01T18:57:47.000Z';
|
||||
spyOnDependency(Dashboard, 'getTimeDiff').and.returnValue({
|
||||
start,
|
||||
end,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { getTimeDiff, graphDataValidatorForValues } from '~/monitoring/utils';
|
||||
import { timeWindows } from '~/monitoring/constants';
|
||||
import { getTimeDiff, getTimeWindow, graphDataValidatorForValues } from '~/monitoring/utils';
|
||||
import { timeWindows, timeWindowsKeyNames } from '~/monitoring/constants';
|
||||
import { graphDataPrometheusQuery, graphDataPrometheusQueryRange } from './mock_data';
|
||||
|
||||
describe('getTimeDiff', () => {
|
||||
|
|
@ -39,6 +39,55 @@ describe('getTimeDiff', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('getTimeWindow', () => {
|
||||
[
|
||||
{
|
||||
args: [
|
||||
{
|
||||
start: '2019-10-01T18:27:47.000Z',
|
||||
end: '2019-10-01T21:27:47.000Z',
|
||||
},
|
||||
],
|
||||
expected: timeWindowsKeyNames.threeHours,
|
||||
},
|
||||
{
|
||||
args: [
|
||||
{
|
||||
start: '2019-10-01T28:27:47.000Z',
|
||||
end: '2019-10-01T21:27:47.000Z',
|
||||
},
|
||||
],
|
||||
expected: timeWindowsKeyNames.eightHours,
|
||||
},
|
||||
{
|
||||
args: [
|
||||
{
|
||||
start: '',
|
||||
end: '',
|
||||
},
|
||||
],
|
||||
expected: timeWindowsKeyNames.eightHours,
|
||||
},
|
||||
{
|
||||
args: [
|
||||
{
|
||||
start: null,
|
||||
end: null,
|
||||
},
|
||||
],
|
||||
expected: timeWindowsKeyNames.eightHours,
|
||||
},
|
||||
{
|
||||
args: [{}],
|
||||
expected: timeWindowsKeyNames.eightHours,
|
||||
},
|
||||
].forEach(({ args, expected }) => {
|
||||
it(`returns "${expected}" with args=${JSON.stringify(args)}`, () => {
|
||||
expect(getTimeWindow(...args)).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('graphDataValidatorForValues', () => {
|
||||
/*
|
||||
* When dealing with a metric using the query format, e.g.
|
||||
|
|
|
|||
|
|
@ -83,11 +83,11 @@ describe('Grouped Test Reports App', () => {
|
|||
setTimeout(() => {
|
||||
expect(vm.$el.querySelector('.gl-spinner')).toBeNull();
|
||||
expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
|
||||
'Test summary contained 2 failed test results out of 11 total tests',
|
||||
'Test summary contained 2 failed/error test results out of 11 total tests',
|
||||
);
|
||||
|
||||
expect(vm.$el.textContent).toContain(
|
||||
'rspec:pg found 2 failed test results out of 8 total tests',
|
||||
'rspec:pg found 2 failed/error test results out of 8 total tests',
|
||||
);
|
||||
|
||||
expect(vm.$el.textContent).toContain('New');
|
||||
|
|
@ -111,16 +111,16 @@ describe('Grouped Test Reports App', () => {
|
|||
setTimeout(() => {
|
||||
expect(vm.$el.querySelector('.gl-spinner')).toBeNull();
|
||||
expect(vm.$el.querySelector('.js-code-text').textContent.trim()).toEqual(
|
||||
'Test summary contained 2 failed test results and 2 fixed test results out of 11 total tests',
|
||||
'Test summary contained 2 failed/error test results and 2 fixed test results out of 11 total tests',
|
||||
);
|
||||
|
||||
expect(vm.$el.textContent).toContain(
|
||||
'rspec:pg found 1 failed test result and 2 fixed test results out of 8 total tests',
|
||||
'rspec:pg found 1 failed/error test result and 2 fixed test results out of 8 total tests',
|
||||
);
|
||||
|
||||
expect(vm.$el.textContent).toContain('New');
|
||||
expect(vm.$el.textContent).toContain(
|
||||
' java ant found 1 failed test result out of 3 total tests',
|
||||
' java ant found 1 failed/error test result out of 3 total tests',
|
||||
);
|
||||
done();
|
||||
}, 0);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ describe Backup::Repository do
|
|||
before do
|
||||
allow(progress).to receive(:puts)
|
||||
allow(progress).to receive(:print)
|
||||
allow(FileUtils).to receive(:mkdir_p).and_return(true)
|
||||
allow(FileUtils).to receive(:mv).and_return(true)
|
||||
|
||||
allow_any_instance_of(described_class).to receive(:progress).and_return(progress)
|
||||
|
|
|
|||
|
|
@ -38,24 +38,6 @@ describe Gitlab::Ci::Parsers::Test::Junit do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when there is only one <testcase> in <testsuite>' do
|
||||
let(:junit) do
|
||||
<<-EOF.strip_heredoc
|
||||
<testsuite>
|
||||
<testcase classname='Calculator' name='sumTest1' time='0.01'></testcase>
|
||||
</testsuite>
|
||||
EOF
|
||||
end
|
||||
|
||||
it 'parses XML and adds a test case to a suite' do
|
||||
expect { subject }.not_to raise_error
|
||||
|
||||
expect(test_cases[0].classname).to eq('Calculator')
|
||||
expect(test_cases[0].name).to eq('sumTest1')
|
||||
expect(test_cases[0].execution_time).to eq(0.01)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there is only one <testsuite> in <testsuites>' do
|
||||
let(:junit) do
|
||||
<<-EOF.strip_heredoc
|
||||
|
|
@ -76,6 +58,68 @@ describe Gitlab::Ci::Parsers::Test::Junit do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when there is <testcase>' do
|
||||
let(:junit) do
|
||||
<<-EOF.strip_heredoc
|
||||
<testsuite>
|
||||
<testcase classname='Calculator' name='sumTest1' time='0.01'>
|
||||
#{testcase_content}
|
||||
</testcase>
|
||||
</testsuite>
|
||||
EOF
|
||||
end
|
||||
|
||||
let(:test_case) { test_cases[0] }
|
||||
|
||||
before do
|
||||
expect { subject }.not_to raise_error
|
||||
end
|
||||
|
||||
shared_examples_for '<testcase> XML parser' do |status, output|
|
||||
it 'parses XML and adds a test case to the suite' do
|
||||
aggregate_failures do
|
||||
expect(test_case.classname).to eq('Calculator')
|
||||
expect(test_case.name).to eq('sumTest1')
|
||||
expect(test_case.execution_time).to eq(0.01)
|
||||
expect(test_case.status).to eq(status)
|
||||
expect(test_case.system_output).to eq(output)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'and has failure' do
|
||||
let(:testcase_content) { '<failure>Some failure</failure>' }
|
||||
|
||||
it_behaves_like '<testcase> XML parser',
|
||||
::Gitlab::Ci::Reports::TestCase::STATUS_FAILED,
|
||||
'Some failure'
|
||||
end
|
||||
|
||||
context 'and has error' do
|
||||
let(:testcase_content) { '<error>Some error</error>' }
|
||||
|
||||
it_behaves_like '<testcase> XML parser',
|
||||
::Gitlab::Ci::Reports::TestCase::STATUS_FAILED,
|
||||
'Some error'
|
||||
end
|
||||
|
||||
context 'and has an unknown type' do
|
||||
let(:testcase_content) { '<foo>Some foo</foo>' }
|
||||
|
||||
it_behaves_like '<testcase> XML parser',
|
||||
::Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS,
|
||||
nil
|
||||
end
|
||||
|
||||
context 'and has no content' do
|
||||
let(:testcase_content) { '' }
|
||||
|
||||
it_behaves_like '<testcase> XML parser',
|
||||
::Gitlab::Ci::Reports::TestCase::STATUS_SUCCESS,
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
context 'PHPUnit' do
|
||||
let(:junit) do
|
||||
<<-EOF.strip_heredoc
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ describe Gitlab::HealthChecks::GitalyCheck do
|
|||
context 'Gitaly server is up' do
|
||||
let(:gitaly_check) { double(check: { success: true }) }
|
||||
|
||||
it { is_expected.to eq([result_class.new(true, nil, shard: 'default')]) }
|
||||
it { is_expected.to eq([result_class.new('gitaly_check', true, nil, shard: 'default')]) }
|
||||
end
|
||||
|
||||
context 'Gitaly server is down' do
|
||||
let(:gitaly_check) { double(check: { success: false, message: 'Connection refused' }) }
|
||||
|
||||
it { is_expected.to eq([result_class.new(false, 'Connection refused', shard: 'default')]) }
|
||||
it { is_expected.to eq([result_class.new('gitaly_check', false, 'Connection refused', shard: 'default')]) }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
describe Gitlab::HealthChecks::PrometheusTextFormat do
|
||||
let(:metric_class) { Gitlab::HealthChecks::Metric }
|
||||
subject { described_class.new }
|
||||
|
||||
describe '#marshal' do
|
||||
let(:sample_metrics) do
|
||||
[metric_class.new('metric1', 1),
|
||||
metric_class.new('metric2', 2)]
|
||||
end
|
||||
|
||||
it 'marshal to text with non repeating type definition' do
|
||||
expected = <<-EXPECTED.strip_heredoc
|
||||
# TYPE metric1 gauge
|
||||
metric1 1
|
||||
# TYPE metric2 gauge
|
||||
metric2 2
|
||||
EXPECTED
|
||||
|
||||
expect(subject.marshal(sample_metrics)).to eq(expected)
|
||||
end
|
||||
|
||||
context 'metrics where name repeats' do
|
||||
let(:sample_metrics) do
|
||||
[metric_class.new('metric1', 1),
|
||||
metric_class.new('metric1', 2),
|
||||
metric_class.new('metric2', 3)]
|
||||
end
|
||||
|
||||
it 'marshal to text with non repeating type definition' do
|
||||
expected = <<-EXPECTED.strip_heredoc
|
||||
# TYPE metric1 gauge
|
||||
metric1 1
|
||||
metric1 2
|
||||
# TYPE metric2 gauge
|
||||
metric2 3
|
||||
EXPECTED
|
||||
expect(subject.marshal(sample_metrics)).to eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -411,6 +411,7 @@ project:
|
|||
- external_pull_requests
|
||||
- pages_metadatum
|
||||
- alerts_service
|
||||
- grafana_integration
|
||||
award_emoji:
|
||||
- awardable
|
||||
- user
|
||||
|
|
|
|||
|
|
@ -62,6 +62,14 @@ describe Gitlab::UrlBlocker do
|
|||
expect { subject }.to raise_error(described_class::BlockedUrlError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when domain is too long' do
|
||||
let(:import_url) { 'https://example' + 'a' * 1024 + '.com' }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(described_class::BlockedUrlError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the URL hostname is an IP address' do
|
||||
|
|
|
|||
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe GrafanaIntegration do
|
||||
describe 'associations' do
|
||||
it { is_expected.to belong_to(:project) }
|
||||
end
|
||||
|
||||
describe 'validations' do
|
||||
it { is_expected.to validate_presence_of(:project) }
|
||||
it { is_expected.to validate_presence_of(:token) }
|
||||
|
||||
it 'disallows invalid urls for grafana_url' do
|
||||
unsafe_url = %{https://replaceme.com/'><script>alert(document.cookie)</script>}
|
||||
non_ascii_url = 'http://gitlab.com/api/0/projects/project1/something€'
|
||||
blank_url = ''
|
||||
excessively_long_url = 'https://grafan' + 'a' * 1024 + '.com'
|
||||
|
||||
is_expected.not_to allow_values(
|
||||
unsafe_url,
|
||||
non_ascii_url,
|
||||
blank_url,
|
||||
excessively_long_url
|
||||
).for(:grafana_url)
|
||||
end
|
||||
|
||||
it 'allows valid urls for grafana_url' do
|
||||
external_url = 'http://grafana.com/'
|
||||
internal_url = 'http://192.168.1.1'
|
||||
|
||||
is_expected.to allow_value(
|
||||
external_url,
|
||||
internal_url
|
||||
).for(:grafana_url)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -896,32 +896,6 @@ describe Namespace do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :emails_disabled feature flag is off' do
|
||||
before do
|
||||
stub_feature_flags(emails_disabled: false)
|
||||
end
|
||||
|
||||
context 'when not a subgroup' do
|
||||
it 'returns false' do
|
||||
group = create(:group, emails_disabled: true)
|
||||
|
||||
expect(group.emails_disabled?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a subgroup and ancestor emails are disabled' do
|
||||
let(:grandparent) { create(:group) }
|
||||
let(:parent) { create(:group, parent: grandparent) }
|
||||
let(:group) { create(:group, parent: parent) }
|
||||
|
||||
it 'returns false' do
|
||||
grandparent.update_attribute(:emails_disabled, true)
|
||||
|
||||
expect(group.emails_disabled?).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#pages_virtual_domain' do
|
||||
|
|
|
|||
|
|
@ -2387,29 +2387,6 @@ describe Project do
|
|||
expect(project.emails_disabled?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context 'when :emails_disabled feature flag is off' do
|
||||
before do
|
||||
stub_feature_flags(emails_disabled: false)
|
||||
end
|
||||
|
||||
context 'emails disabled in group' do
|
||||
it 'returns false' do
|
||||
allow(project.namespace).to receive(:emails_disabled?) { true }
|
||||
|
||||
expect(project.emails_disabled?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
context 'emails enabled in group' do
|
||||
it 'returns false' do
|
||||
allow(project.namespace).to receive(:emails_disabled?) { false }
|
||||
project.update_attribute(:emails_disabled, true)
|
||||
|
||||
expect(project.emails_disabled?).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#lfs_enabled?' do
|
||||
|
|
@ -3671,14 +3648,6 @@ describe Project do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#ensure_storage_path_exists' do
|
||||
it 'delegates to gitlab_shell to ensure namespace is created' do
|
||||
expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage, project.base_dir)
|
||||
|
||||
project.ensure_storage_path_exists
|
||||
end
|
||||
end
|
||||
|
||||
describe '#legacy_storage?' do
|
||||
it 'returns true when storage_version is nil' do
|
||||
project = build(:project, storage_version: nil)
|
||||
|
|
@ -3793,16 +3762,6 @@ describe Project do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#ensure_storage_path_exists' do
|
||||
it 'delegates to gitlab_shell to ensure namespace is created' do
|
||||
allow(project).to receive(:gitlab_shell).and_return(gitlab_shell)
|
||||
|
||||
expect(gitlab_shell).to receive(:add_namespace).with(project.repository_storage, hashed_prefix)
|
||||
|
||||
project.ensure_storage_path_exists
|
||||
end
|
||||
end
|
||||
|
||||
describe '#pages_path' do
|
||||
it 'returns a path where pages are stored' do
|
||||
expect(project.pages_path).to eq(File.join(Settings.pages.path, project.namespace.full_path, project.path))
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ describe Groups::DestroyService do
|
|||
let!(:user) { create(:user) }
|
||||
let!(:group) { create(:group) }
|
||||
let!(:nested_group) { create(:group, parent: group) }
|
||||
let!(:project) { create(:project, :legacy_storage, namespace: group) }
|
||||
let!(:project) { create(:project, :repository, :legacy_storage, namespace: group) }
|
||||
let!(:notification_setting) { create(:notification_setting, source: group)}
|
||||
let(:gitlab_shell) { Gitlab::Shell.new }
|
||||
let(:remove_path) { group.path + "+#{group.id}+deleted" }
|
||||
|
|
|
|||
|
|
@ -170,5 +170,61 @@ describe Projects::Operations::UpdateService do
|
|||
expect(project.reload.name).to eq(original_name)
|
||||
end
|
||||
end
|
||||
|
||||
context 'grafana integration' do
|
||||
let(:params) do
|
||||
{
|
||||
grafana_integration_attributes: {
|
||||
grafana_url: 'http://new.grafana.com',
|
||||
token: 'VerySecureToken='
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
context 'without existing grafana integration' do
|
||||
it 'creates an integration' do
|
||||
expect(result[:status]).to eq(:success)
|
||||
|
||||
expected_attrs = params[:grafana_integration_attributes]
|
||||
integration = project.reload.grafana_integration
|
||||
|
||||
expect(integration.grafana_url).to eq(expected_attrs[:grafana_url])
|
||||
expect(integration.token).to eq(expected_attrs[:token])
|
||||
end
|
||||
end
|
||||
|
||||
context 'with an existing grafana integration' do
|
||||
before do
|
||||
create(:grafana_integration, project: project)
|
||||
end
|
||||
|
||||
it 'updates the settings' do
|
||||
expect(result[:status]).to eq(:success)
|
||||
|
||||
expected_attrs = params[:grafana_integration_attributes]
|
||||
integration = project.reload.grafana_integration
|
||||
|
||||
expect(integration.grafana_url).to eq(expected_attrs[:grafana_url])
|
||||
expect(integration.token).to eq(expected_attrs[:token])
|
||||
end
|
||||
|
||||
context 'with all grafana attributes blank in params' do
|
||||
let(:params) do
|
||||
{
|
||||
grafana_integration_attributes: {
|
||||
grafana_url: '',
|
||||
token: ''
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'destroys the metrics_setting entry in DB' do
|
||||
expect(result[:status]).to eq(:success)
|
||||
|
||||
expect(project.reload.grafana_integration).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ describe RepositoryCheck::DispatchWorker do
|
|||
context 'with unhealthy shard' do
|
||||
let(:default_shard_name) { 'default' }
|
||||
let(:unhealthy_shard_name) { 'unhealthy' }
|
||||
let(:default_shard) { Gitlab::HealthChecks::Result.new(true, nil, shard: default_shard_name) }
|
||||
let(:unhealthy_shard) { Gitlab::HealthChecks::Result.new(false, '14:Connect Failed', shard: unhealthy_shard_name) }
|
||||
let(:default_shard) { Gitlab::HealthChecks::Result.new('gitaly_check', true, nil, shard: default_shard_name) }
|
||||
let(:unhealthy_shard) { Gitlab::HealthChecks::Result.new('gitaly_check', false, '14:Connect Failed', shard: unhealthy_shard_name) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::HealthChecks::GitalyCheck).to receive(:readiness).and_return([default_shard, unhealthy_shard])
|
||||
|
|
|
|||
Loading…
Reference in New Issue