Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									b304a72312
								
							
						
					
					
						commit
						eb1f5a3e08
					
				|  | @ -345,6 +345,8 @@ RSpec/HaveGitlabHttpStatus: | ||||||
|     - 'ee/spec/controllers/**/*' |     - 'ee/spec/controllers/**/*' | ||||||
|     - 'spec/requests/*.rb' |     - 'spec/requests/*.rb' | ||||||
|     - 'ee/spec/requests/*.rb' |     - 'ee/spec/requests/*.rb' | ||||||
|  |     - 'spec/requests/api/*/**/*.rb' | ||||||
|  |     - 'ee/spec/requests/api/*/**/*.rb' | ||||||
| 
 | 
 | ||||||
| Style/MultilineWhenThen: | Style/MultilineWhenThen: | ||||||
|   Enabled: false |   Enabled: false | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ import AccessorUtils from '~/lib/utils/accessor'; | ||||||
| import Icon from '~/vue_shared/components/icon.vue'; | import Icon from '~/vue_shared/components/icon.vue'; | ||||||
| import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; | import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; | ||||||
| import { __ } from '~/locale'; | import { __ } from '~/locale'; | ||||||
| import _ from 'underscore'; | import { isEmpty } from 'lodash'; | ||||||
| 
 | 
 | ||||||
| export const tableDataClass = 'table-col d-flex d-sm-table-cell align-items-center'; | export const tableDataClass = 'table-col d-flex d-sm-table-cell align-items-center'; | ||||||
| 
 | 
 | ||||||
|  | @ -139,7 +139,7 @@ export default { | ||||||
|       'cursor', |       'cursor', | ||||||
|     ]), |     ]), | ||||||
|     paginationRequired() { |     paginationRequired() { | ||||||
|       return !_.isEmpty(this.pagination); |       return !isEmpty(this.pagination); | ||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   watch: { |   watch: { | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| <script> | <script> | ||||||
| import _ from 'underscore'; | import { escape as esc } from 'lodash'; | ||||||
| import { GlTooltip } from '@gitlab/ui'; | import { GlTooltip } from '@gitlab/ui'; | ||||||
| import { __, sprintf } from '~/locale'; | import { __, sprintf } from '~/locale'; | ||||||
| import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; | import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; | ||||||
|  | @ -62,7 +62,7 @@ export default { | ||||||
|         ? sprintf( |         ? sprintf( | ||||||
|             __(`%{spanStart}in%{spanEnd} %{errorFn}`), |             __(`%{spanStart}in%{spanEnd} %{errorFn}`), | ||||||
|             { |             { | ||||||
|               errorFn: `<strong>${_.escape(this.errorFn)}</strong>`, |               errorFn: `<strong>${esc(this.errorFn)}</strong>`, | ||||||
|               spanStart: `<span class="text-tertiary">`, |               spanStart: `<span class="text-tertiary">`, | ||||||
|               spanEnd: `</span>`, |               spanEnd: `</span>`, | ||||||
|             }, |             }, | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import $ from 'jquery'; | import $ from 'jquery'; | ||||||
| import _ from 'underscore'; | import { debounce } from 'lodash'; | ||||||
| import { __ } from '~/locale'; | import { __ } from '~/locale'; | ||||||
| import Flash from '~/flash'; | import Flash from '~/flash'; | ||||||
| import axios from '~/lib/utils/axios_utils'; | import axios from '~/lib/utils/axios_utils'; | ||||||
|  | @ -62,7 +62,7 @@ export default class MirrorRepos { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   registerUpdateListeners() { |   registerUpdateListeners() { | ||||||
|     this.debouncedUpdateUrl = _.debounce(() => this.updateUrl(), 200); |     this.debouncedUpdateUrl = debounce(() => this.updateUrl(), 200); | ||||||
|     this.$urlInput.on('input', () => this.debouncedUpdateUrl()); |     this.$urlInput.on('input', () => this.debouncedUpdateUrl()); | ||||||
|     this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches()); |     this.$protectedBranchesInput.on('change', () => this.updateProtectedBranches()); | ||||||
|     this.$table.on('click', '.js-delete-mirror', event => this.deleteMirror(event)); |     this.$table.on('click', '.js-delete-mirror', event => this.deleteMirror(event)); | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import $ from 'jquery'; | import $ from 'jquery'; | ||||||
| import _ from 'underscore'; | import { escape as esc } from 'lodash'; | ||||||
| import { __ } from '~/locale'; | import { __ } from '~/locale'; | ||||||
| import axios from '~/lib/utils/axios_utils'; | import axios from '~/lib/utils/axios_utils'; | ||||||
| import Flash from '~/flash'; | import Flash from '~/flash'; | ||||||
|  | @ -162,7 +162,7 @@ export default class SSHMirror { | ||||||
|     const $fingerprintsList = this.$hostKeysInformation.find('.js-fingerprints-list'); |     const $fingerprintsList = this.$hostKeysInformation.find('.js-fingerprints-list'); | ||||||
|     let fingerprints = ''; |     let fingerprints = ''; | ||||||
|     sshHostKeys.fingerprints.forEach(fingerprint => { |     sshHostKeys.fingerprints.forEach(fingerprint => { | ||||||
|       const escFingerprints = _.escape(fingerprint.fingerprint); |       const escFingerprints = esc(fingerprint.fingerprint); | ||||||
|       fingerprints += `<code>${escFingerprints}</code>`; |       fingerprints += `<code>${escFingerprints}</code>`; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| <script> | <script> | ||||||
| import { mapActions, mapState } from 'vuex'; | import { mapActions, mapState } from 'vuex'; | ||||||
| import { GlAlert } from '@gitlab/ui'; | import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui'; | ||||||
| import { sprintf, s__ } from '~/locale'; | import { s__ } from '~/locale'; | ||||||
| 
 | 
 | ||||||
| import { FETCH_SETTINGS_ERROR_MESSAGE } from '../../shared/constants'; | import { FETCH_SETTINGS_ERROR_MESSAGE } from '../../shared/constants'; | ||||||
| 
 | 
 | ||||||
|  | @ -11,22 +11,16 @@ export default { | ||||||
|   components: { |   components: { | ||||||
|     SettingsForm, |     SettingsForm, | ||||||
|     GlAlert, |     GlAlert, | ||||||
|  |     GlSprintf, | ||||||
|  |     GlLink, | ||||||
|  |   }, | ||||||
|  |   i18n: { | ||||||
|  |     unavailableFeatureText: s__( | ||||||
|  |       'ContainerRegistry|Currently, the Container Registry tag expiration feature is not available for projects created before GitLab version 12.8. For updates and more information, visit Issue %{linkStart}#196124%{linkEnd}', | ||||||
|  |     ), | ||||||
|   }, |   }, | ||||||
|   computed: { |   computed: { | ||||||
|     ...mapState(['isDisabled']), |     ...mapState(['isDisabled']), | ||||||
|     notAvailableMessage() { |  | ||||||
|       return sprintf( |  | ||||||
|         s__( |  | ||||||
|           'ContainerRegistry|Currently, the Container Registry tag expiration feature is not available for projects created before GitLab version 12.8. For updates and more information, visit Issue %{linkStart}#196124%{linkEnd}', |  | ||||||
|         ), |  | ||||||
|         { |  | ||||||
|           linkStart: |  | ||||||
|             '<a href="https://gitlab.com/gitlab-org/gitlab/issues/196124" target="_blank" rel="noopener noreferrer">', |  | ||||||
|           linkEnd: '</a>', |  | ||||||
|         }, |  | ||||||
|         false, |  | ||||||
|       ); |  | ||||||
|     }, |  | ||||||
|   }, |   }, | ||||||
|   mounted() { |   mounted() { | ||||||
|     this.fetchSettings().catch(() => |     this.fetchSettings().catch(() => | ||||||
|  | @ -56,7 +50,15 @@ export default { | ||||||
|     </ul> |     </ul> | ||||||
|     <settings-form v-if="!isDisabled" /> |     <settings-form v-if="!isDisabled" /> | ||||||
|     <gl-alert v-else :dismissible="false"> |     <gl-alert v-else :dismissible="false"> | ||||||
|       <p v-html="notAvailableMessage"></p> |       <p> | ||||||
|  |         <gl-sprintf :message="$options.i18n.unavailableFeatureText"> | ||||||
|  |           <template #link="{content}"> | ||||||
|  |             <gl-link href="https://gitlab.com/gitlab-org/gitlab/issues/196124" target="_blank"> | ||||||
|  |               {{ content }} | ||||||
|  |             </gl-link> | ||||||
|  |           </template> | ||||||
|  |         </gl-sprintf> | ||||||
|  |       </p> | ||||||
|     </gl-alert> |     </gl-alert> | ||||||
|   </div> |   </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| <script> | <script> | ||||||
| import { uniqueId } from 'lodash'; | import { uniqueId } from 'lodash'; | ||||||
| import { GlFormGroup, GlToggle, GlFormSelect, GlFormTextarea } from '@gitlab/ui'; | import { GlFormGroup, GlToggle, GlFormSelect, GlFormTextarea, GlSprintf } from '@gitlab/ui'; | ||||||
| import { s__, __, sprintf } from '~/locale'; | import { s__, __ } from '~/locale'; | ||||||
| import { NAME_REGEX_LENGTH } from '../constants'; | import { NAME_REGEX_LENGTH } from '../constants'; | ||||||
| import { mapComputedToEvent } from '../utils'; | import { mapComputedToEvent } from '../utils'; | ||||||
| 
 | 
 | ||||||
|  | @ -11,6 +11,7 @@ export default { | ||||||
|     GlToggle, |     GlToggle, | ||||||
|     GlFormSelect, |     GlFormSelect, | ||||||
|     GlFormTextarea, |     GlFormTextarea, | ||||||
|  |     GlSprintf, | ||||||
|   }, |   }, | ||||||
|   props: { |   props: { | ||||||
|     formOptions: { |     formOptions: { | ||||||
|  | @ -70,27 +71,6 @@ export default { | ||||||
|     policyEnabledText() { |     policyEnabledText() { | ||||||
|       return this.enabled ? __('enabled') : __('disabled'); |       return this.enabled ? __('enabled') : __('disabled'); | ||||||
|     }, |     }, | ||||||
|     toggleDescriptionText() { |  | ||||||
|       return sprintf( |  | ||||||
|         s__('ContainerRegistry|Docker tag expiration policy is %{toggleStatus}'), |  | ||||||
|         { |  | ||||||
|           toggleStatus: `<strong>${this.policyEnabledText}</strong>`, |  | ||||||
|         }, |  | ||||||
|         false, |  | ||||||
|       ); |  | ||||||
|     }, |  | ||||||
|     regexHelpText() { |  | ||||||
|       return sprintf( |  | ||||||
|         s__( |  | ||||||
|           'ContainerRegistry|Wildcards such as %{codeStart}.*-stable%{codeEnd} or %{codeStart}production/.*%{codeEnd} are supported.  To select all tags, use %{codeStart}.*%{codeEnd}', |  | ||||||
|         ), |  | ||||||
|         { |  | ||||||
|           codeStart: '<code>', |  | ||||||
|           codeEnd: '</code>', |  | ||||||
|         }, |  | ||||||
|         false, |  | ||||||
|       ); |  | ||||||
|     }, |  | ||||||
|     nameRegexState() { |     nameRegexState() { | ||||||
|       return this.name_regex ? this.name_regex.length <= NAME_REGEX_LENGTH : null; |       return this.name_regex ? this.name_regex.length <= NAME_REGEX_LENGTH : null; | ||||||
|     }, |     }, | ||||||
|  | @ -139,7 +119,15 @@ export default { | ||||||
|           v-model="enabled" |           v-model="enabled" | ||||||
|           :disabled="isLoading" |           :disabled="isLoading" | ||||||
|         /> |         /> | ||||||
|         <span class="mb-2 ml-1 lh-2" v-html="toggleDescriptionText"></span> |         <span class="mb-2 ml-1 lh-2"> | ||||||
|  |           <gl-sprintf | ||||||
|  |             :message="s__('ContainerRegistry|Docker tag expiration policy is %{toggleStatus}')" | ||||||
|  |           > | ||||||
|  |             <template #toggleStatus> | ||||||
|  |               <strong>{{ policyEnabledText }}</strong> | ||||||
|  |             </template> | ||||||
|  |           </gl-sprintf> | ||||||
|  |         </span> | ||||||
|       </div> |       </div> | ||||||
|     </gl-form-group> |     </gl-form-group> | ||||||
| 
 | 
 | ||||||
|  | @ -190,7 +178,19 @@ export default { | ||||||
|         trim |         trim | ||||||
|       /> |       /> | ||||||
|       <template #description> |       <template #description> | ||||||
|         <span ref="regex-description" v-html="regexHelpText"></span> |         <span ref="regex-description"> | ||||||
|  |           <gl-sprintf | ||||||
|  |             :message=" | ||||||
|  |               s__( | ||||||
|  |                 'ContainerRegistry|Wildcards such as %{codeStart}.*-stable%{codeEnd} or %{codeStart}production/.*%{codeEnd} are supported.  To select all tags, use %{codeStart}.*%{codeEnd}', | ||||||
|  |               ) | ||||||
|  |             " | ||||||
|  |           > | ||||||
|  |             <template #code="{content}"> | ||||||
|  |               <code>{{ content }}</code> | ||||||
|  |             </template> | ||||||
|  |           </gl-sprintf> | ||||||
|  |         </span> | ||||||
|       </template> |       </template> | ||||||
|     </gl-form-group> |     </gl-form-group> | ||||||
|   </div> |   </div> | ||||||
|  |  | ||||||
|  | @ -44,7 +44,6 @@ class Projects::IssuesController < Projects::ApplicationController | ||||||
| 
 | 
 | ||||||
|   before_action do |   before_action do | ||||||
|     push_frontend_feature_flag(:vue_issuable_sidebar, project.group) |     push_frontend_feature_flag(:vue_issuable_sidebar, project.group) | ||||||
|     push_frontend_feature_flag(:issue_link_types, project) |  | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   around_action :allow_gitaly_ref_name_caching, only: [:discussions] |   around_action :allow_gitaly_ref_name_caching, only: [:discussions] | ||||||
|  |  | ||||||
|  | @ -161,7 +161,7 @@ class DiffNote < Note | ||||||
|   def positions_complete |   def positions_complete | ||||||
|     return if self.original_position.complete? && self.position.complete? |     return if self.original_position.complete? && self.position.complete? | ||||||
| 
 | 
 | ||||||
|     errors.add(:position, "is invalid") |     errors.add(:position, "is incomplete") | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def keep_around_commits |   def keep_around_commits | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ module ChatMessage | ||||||
| 
 | 
 | ||||||
|     def initialize(params) |     def initialize(params) | ||||||
|       @markdown = params[:markdown] || false |       @markdown = params[:markdown] || false | ||||||
|       @project_name = params.dig(:project, :path_with_namespace) || params[:project_name] |       @project_name = params[:project_name] || params.dig(:project, :path_with_namespace) | ||||||
|       @project_url = params.dig(:project, :web_url) || params[:project_url] |       @project_url = params.dig(:project, :web_url) || params[:project_url] | ||||||
|       @user_full_name = params.dig(:user, :name) || params[:user_full_name] |       @user_full_name = params.dig(:user, :name) || params[:user_full_name] | ||||||
|       @user_name = params.dig(:user, :username) || params[:user_name] |       @user_name = params.dig(:user, :username) || params[:user_name] | ||||||
|  |  | ||||||
|  | @ -157,7 +157,7 @@ class ChatNotificationService < Service | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def project_name |   def project_name | ||||||
|     project.full_name.gsub(/\s/, '') |     project.full_name | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def project_url |   def project_url | ||||||
|  |  | ||||||
|  | @ -2,7 +2,7 @@ | ||||||
| - setting = project_incident_management_setting | - setting = project_incident_management_setting | ||||||
| - templates = setting.available_issue_templates.map { |t| [t.name, t.key] } | - templates = setting.available_issue_templates.map { |t| [t.name, t.key] } | ||||||
| 
 | 
 | ||||||
| %section.settings.no-animate.js-incident-management-settings | %section.settings.no-animate.qa-incident-management-settings | ||||||
|   .settings-header |   .settings-header | ||||||
|     %h4= _('Incidents') |     %h4= _('Incidents') | ||||||
|     %button.btn.js-settings-toggle{ type: 'button' } |     %button.btn.js-settings-toggle{ type: 'button' } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Do not remove space from project name in Slack | ||||||
|  | merge_request: 24851 | ||||||
|  | author: | ||||||
|  | type: fixed | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Parse filebeat modsec logs as JSON | ||||||
|  | merge_request: 24836 | ||||||
|  | author: | ||||||
|  | type: changed | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Fix usage ping timeouts with batch counters | ||||||
|  | merge_request: 22705 | ||||||
|  | author: | ||||||
|  | type: performance | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Replace underscore with lodash for ./app/assets/javascripts/mirrors | ||||||
|  | merge_request: 24967 | ||||||
|  | author: Jacopo Beschi @jacopo-beschi | ||||||
|  | type: changed | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Add blocking issues feature | ||||||
|  | merge_request: 24460 | ||||||
|  | author: | ||||||
|  | type: added | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Fix overriding the image pull policy from a values file for Auto Deploy | ||||||
|  | merge_request: 25271 | ||||||
|  | author: robcalcroft | ||||||
|  | type: fixed | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Fixed default-branch link under Pipeline Subscription settings | ||||||
|  | merge_request: 24834 | ||||||
|  | author: James Johnson | ||||||
|  | type: fixed | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Replace underscore with lodash for ./app/assets/javascripts/error_tracking | ||||||
|  | merge_request: 25143 | ||||||
|  | author: Tobias Spagert | ||||||
|  | type: other | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | title: Fix application settings not working with pending migrations | ||||||
|  | merge_request: | ||||||
|  | author: | ||||||
|  | type: fixed | ||||||
|  | @ -61,7 +61,7 @@ RspecProfiling.configure do |config| | ||||||
|     RspecProfiling::Run.prepend(RspecProfilingExt::Run) |     RspecProfiling::Run.prepend(RspecProfilingExt::Run) | ||||||
|     config.collector = RspecProfilingExt::Collectors::CSVWithTimestamps |     config.collector = RspecProfilingExt::Collectors::CSVWithTimestamps | ||||||
|     config.csv_path = -> do |     config.csv_path = -> do | ||||||
|       prefix = "#{ENV['CI_JOB_NAME']}-".tr(' ', '-') if ENV['CI_JOB_NAME'] |       prefix = "#{ENV['CI_JOB_NAME']}-".gsub(/[ \/]/, '-') if ENV['CI_JOB_NAME'] | ||||||
|       "rspec_profiling/#{prefix}#{Time.now.to_i}-#{SecureRandom.hex(8)}-rspec-data.csv" |       "rspec_profiling/#{prefix}#{Time.now.to_i}-#{SecureRandom.hex(8)}-rspec-data.csv" | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| .auto-deploy: | .auto-deploy: | ||||||
|   image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.9.1" |   image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.9.3" | ||||||
| 
 | 
 | ||||||
| review: | review: | ||||||
|   extends: .auto-deploy |   extends: .auto-deploy | ||||||
|  |  | ||||||
|  | @ -50,7 +50,7 @@ module Gitlab | ||||||
|         # need to be added to the application settings. To prevent Rake tasks |         # need to be added to the application settings. To prevent Rake tasks | ||||||
|         # and other callers from failing, use any loaded settings and return |         # and other callers from failing, use any loaded settings and return | ||||||
|         # defaults for missing columns. |         # defaults for missing columns. | ||||||
|         if ActiveRecord::Base.connection.migration_context.needs_migration? |         if Gitlab::Runtime.rake? && ActiveRecord::Base.connection.migration_context.needs_migration? | ||||||
|           db_attributes = current_settings&.attributes || {} |           db_attributes = current_settings&.attributes || {} | ||||||
|           fake_application_settings(db_attributes) |           fake_application_settings(db_attributes) | ||||||
|         elsif current_settings.present? |         elsif current_settings.present? | ||||||
|  |  | ||||||
|  | @ -0,0 +1,89 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | # For large tables, PostgreSQL can take a long time to count rows due to MVCC. | ||||||
|  | # Implements a distinct and ordinary batch counter | ||||||
|  | # Needs indexes on the column below to calculate max, min and range queries | ||||||
|  | # For larger tables just set use higher batch_size with index optimization | ||||||
|  | # See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22705 | ||||||
|  | # Examples: | ||||||
|  | #  extend ::Gitlab::Database::BatchCount | ||||||
|  | #  batch_count(User.active) | ||||||
|  | #  batch_count(::Clusters::Cluster.aws_installed.enabled, :cluster_id) | ||||||
|  | #  batch_distinct_count(::Project, :creator_id) | ||||||
|  | module Gitlab | ||||||
|  |   module Database | ||||||
|  |     module BatchCount | ||||||
|  |       def batch_count(relation, column = nil, batch_size: nil) | ||||||
|  |         BatchCounter.new(relation, column: column).count(batch_size: batch_size) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def batch_distinct_count(relation, column = nil, batch_size: nil) | ||||||
|  |         BatchCounter.new(relation, column: column).count(mode: :distinct, batch_size: batch_size) | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       class << self | ||||||
|  |         include BatchCount | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     class BatchCounter | ||||||
|  |       FALLBACK = -1 | ||||||
|  |       MIN_REQUIRED_BATCH_SIZE = 2_000 | ||||||
|  |       MAX_ALLOWED_LOOPS = 10_000 | ||||||
|  |       SLEEP_TIME_IN_SECONDS = 0.01 # 10 msec sleep | ||||||
|  |       # Each query should take <<500ms https://gitlab.com/gitlab-org/gitlab/-/merge_requests/22705 | ||||||
|  |       DEFAULT_DISTINCT_BATCH_SIZE = 100_000 | ||||||
|  |       DEFAULT_BATCH_SIZE = 10_000 | ||||||
|  | 
 | ||||||
|  |       def initialize(relation, column: nil) | ||||||
|  |         @relation = relation | ||||||
|  |         @column = column || relation.primary_key | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def unwanted_configuration?(finish, batch_size, start) | ||||||
|  |         batch_size <= MIN_REQUIRED_BATCH_SIZE || | ||||||
|  |           (finish - start) / batch_size >= MAX_ALLOWED_LOOPS || | ||||||
|  |           start > finish | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def count(batch_size: nil, mode: :itself) | ||||||
|  |         raise 'BatchCount can not be run inside a transaction' if ActiveRecord::Base.connection.transaction_open? | ||||||
|  |         raise "The mode #{mode.inspect} is not supported" unless [:itself, :distinct].include?(mode) | ||||||
|  | 
 | ||||||
|  |         # non-distinct have better performance | ||||||
|  |         batch_size ||= mode == :distinct ? DEFAULT_BATCH_SIZE : DEFAULT_DISTINCT_BATCH_SIZE | ||||||
|  | 
 | ||||||
|  |         start = @relation.minimum(@column) || 0 | ||||||
|  |         finish = @relation.maximum(@column) || 0 | ||||||
|  | 
 | ||||||
|  |         raise "Batch counting expects positive values only for #{@column}" if start < 0 || finish < 0 | ||||||
|  |         return FALLBACK if unwanted_configuration?(finish, batch_size, start) | ||||||
|  | 
 | ||||||
|  |         counter = 0 | ||||||
|  |         batch_start = start | ||||||
|  | 
 | ||||||
|  |         while batch_start <= finish | ||||||
|  |           begin | ||||||
|  |             counter += batch_fetch(batch_start, batch_start + batch_size, mode) | ||||||
|  |             batch_start += batch_size | ||||||
|  |           rescue ActiveRecord::QueryCanceled | ||||||
|  |             # retry with a safe batch size & warmer cache | ||||||
|  |             if batch_size >= 2 * MIN_REQUIRED_BATCH_SIZE | ||||||
|  |               batch_size /= 2 | ||||||
|  |             else | ||||||
|  |               return FALLBACK | ||||||
|  |             end | ||||||
|  |           end | ||||||
|  |           sleep(SLEEP_TIME_IN_SECONDS) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         counter | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def batch_fetch(start, finish, mode) | ||||||
|  |         # rubocop:disable GitlabSecurity/PublicSend | ||||||
|  |         @relation.select(@column).public_send(mode).where(@column => start..(finish - 1)).count | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -37,7 +37,7 @@ module Gitlab | ||||||
|       # We have `base_sha` directly available on `DiffRefs` because it's faster# |       # We have `base_sha` directly available on `DiffRefs` because it's faster# | ||||||
|       # than having to look it up in the repo every time. |       # than having to look it up in the repo every time. | ||||||
|       def complete? |       def complete? | ||||||
|         start_sha && head_sha |         start_sha.present? && head_sha.present? | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def compare_in(project) |       def compare_in(project) | ||||||
|  |  | ||||||
|  | @ -23,7 +23,7 @@ module Gitlab | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def complete? |         def complete? | ||||||
|           x && y && width && height |           [x, y, width, height].all?(&:present?) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def to_h |         def to_h | ||||||
|  |  | ||||||
|  | @ -19,7 +19,7 @@ module Gitlab | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def complete? |         def complete? | ||||||
|           old_line || new_line |           old_line.present? || new_line.present? | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         def to_h |         def to_h | ||||||
|  |  | ||||||
|  | @ -67,8 +67,8 @@ module Gitlab | ||||||
|             clusters_disabled: count(::Clusters::Cluster.disabled), |             clusters_disabled: count(::Clusters::Cluster.disabled), | ||||||
|             project_clusters_disabled: count(::Clusters::Cluster.disabled.project_type), |             project_clusters_disabled: count(::Clusters::Cluster.disabled.project_type), | ||||||
|             group_clusters_disabled: count(::Clusters::Cluster.disabled.group_type), |             group_clusters_disabled: count(::Clusters::Cluster.disabled.group_type), | ||||||
|             clusters_platforms_eks: count(::Clusters::Cluster.aws_installed.enabled), |             clusters_platforms_eks: count(::Clusters::Cluster.aws_installed.enabled, batch: false), | ||||||
|             clusters_platforms_gke: count(::Clusters::Cluster.gcp_installed.enabled), |             clusters_platforms_gke: count(::Clusters::Cluster.gcp_installed.enabled, batch: false), | ||||||
|             clusters_platforms_user: count(::Clusters::Cluster.user_provided.enabled), |             clusters_platforms_user: count(::Clusters::Cluster.user_provided.enabled), | ||||||
|             clusters_applications_helm: count(::Clusters::Applications::Helm.available), |             clusters_applications_helm: count(::Clusters::Applications::Helm.available), | ||||||
|             clusters_applications_ingress: count(::Clusters::Applications::Ingress.available), |             clusters_applications_ingress: count(::Clusters::Applications::Ingress.available), | ||||||
|  | @ -85,7 +85,7 @@ module Gitlab | ||||||
|             issues: count(Issue), |             issues: count(Issue), | ||||||
|             issues_created_from_gitlab_error_tracking_ui: count(SentryIssue), |             issues_created_from_gitlab_error_tracking_ui: count(SentryIssue), | ||||||
|             issues_with_associated_zoom_link: count(ZoomMeeting.added_to_issue), |             issues_with_associated_zoom_link: count(ZoomMeeting.added_to_issue), | ||||||
|             issues_using_zoom_quick_actions: count(ZoomMeeting.select(:issue_id).distinct), |             issues_using_zoom_quick_actions: count(ZoomMeeting.select(:issue_id).distinct, batch: false), | ||||||
|             issues_with_embedded_grafana_charts_approx: ::Gitlab::GrafanaEmbedUsageData.issue_count, |             issues_with_embedded_grafana_charts_approx: ::Gitlab::GrafanaEmbedUsageData.issue_count, | ||||||
|             incident_issues: count(::Issue.authored(::User.alert_bot)), |             incident_issues: count(::Issue.authored(::User.alert_bot)), | ||||||
|             keys: count(Key), |             keys: count(Key), | ||||||
|  | @ -99,7 +99,7 @@ module Gitlab | ||||||
|             projects_imported_from_github: count(Project.where(import_type: 'github')), |             projects_imported_from_github: count(Project.where(import_type: 'github')), | ||||||
|             projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)), |             projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)), | ||||||
|             projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)), |             projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)), | ||||||
|             projects_with_alerts_service_enabled: count(AlertsService.active), |             projects_with_alerts_service_enabled: count(AlertsService.active, batch: false), | ||||||
|             protected_branches: count(ProtectedBranch), |             protected_branches: count(ProtectedBranch), | ||||||
|             releases: count(Release), |             releases: count(Release), | ||||||
|             remote_mirrors: count(RemoteMirror), |             remote_mirrors: count(RemoteMirror), | ||||||
|  | @ -181,7 +181,7 @@ module Gitlab | ||||||
| 
 | 
 | ||||||
|       # rubocop: disable CodeReuse/ActiveRecord |       # rubocop: disable CodeReuse/ActiveRecord | ||||||
|       def services_usage |       def services_usage | ||||||
|         service_counts = count(Service.active.where(template: false).where.not(type: 'JiraService').group(:type), fallback: Hash.new(-1)) |         service_counts = count(Service.active.where(template: false).where.not(type: 'JiraService').group(:type), fallback: Hash.new(-1), batch: false) | ||||||
| 
 | 
 | ||||||
|         results = Service.available_services_names.each_with_object({}) do |service_name, response| |         results = Service.available_services_names.each_with_object({}) do |service_name, response| | ||||||
|           response["projects_#{service_name}_active".to_sym] = service_counts["#{service_name}_service".camelize] || 0 |           response["projects_#{service_name}_active".to_sym] = service_counts["#{service_name}_service".camelize] || 0 | ||||||
|  | @ -217,9 +217,9 @@ module Gitlab | ||||||
|           results[:projects_jira_server_active] += counts[:server].count if counts[:server] |           results[:projects_jira_server_active] += counts[:server].count if counts[:server] | ||||||
|           results[:projects_jira_cloud_active] += counts[:cloud].count if counts[:cloud] |           results[:projects_jira_cloud_active] += counts[:cloud].count if counts[:cloud] | ||||||
|           if results[:projects_jira_active] == -1 |           if results[:projects_jira_active] == -1 | ||||||
|             results[:projects_jira_active] = count(services) |             results[:projects_jira_active] = count(services, batch: false) | ||||||
|           else |           else | ||||||
|             results[:projects_jira_active] += count(services) |             results[:projects_jira_active] += count(services, batch: false) | ||||||
|           end |           end | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|  | @ -231,8 +231,22 @@ module Gitlab | ||||||
|         {} # augmented in EE |         {} # augmented in EE | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def count(relation, fallback: -1) |       def count(relation, column = nil, fallback: -1, batch: true) | ||||||
|         relation.count |         if batch && Feature.enabled?(:usage_ping_batch_counter) | ||||||
|  |           Gitlab::Database::BatchCount.batch_count(relation, column) | ||||||
|  |         else | ||||||
|  |           relation.count | ||||||
|  |         end | ||||||
|  |       rescue ActiveRecord::StatementInvalid | ||||||
|  |         fallback | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       def distinct_count(relation, column = nil, fallback: -1, batch: true) | ||||||
|  |         if batch && Feature.enabled?(:usage_ping_batch_counter) | ||||||
|  |           Gitlab::Database::BatchCount.batch_distinct_count(relation, column) | ||||||
|  |         else | ||||||
|  |           relation.distinct_count_by(column) | ||||||
|  |         end | ||||||
|       rescue ActiveRecord::StatementInvalid |       rescue ActiveRecord::StatementInvalid | ||||||
|         fallback |         fallback | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -15795,9 +15795,6 @@ msgstr "" | ||||||
| msgid "Related Merged Requests" | msgid "Related Merged Requests" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
| msgid "Related issues" |  | ||||||
| msgstr "" |  | ||||||
| 
 |  | ||||||
| msgid "Related merge requests" | msgid "Related merge requests" | ||||||
| msgstr "" | msgstr "" | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -16,6 +16,7 @@ describe Admin::ApplicationSettingsController do | ||||||
| 
 | 
 | ||||||
|   describe 'GET #usage_data with no access' do |   describe 'GET #usage_data with no access' do | ||||||
|     before do |     before do | ||||||
|  |       allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false) | ||||||
|       sign_in(user) |       sign_in(user) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -28,6 +29,7 @@ describe Admin::ApplicationSettingsController do | ||||||
| 
 | 
 | ||||||
|   describe 'GET #usage_data' do |   describe 'GET #usage_data' do | ||||||
|     before do |     before do | ||||||
|  |       allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false) | ||||||
|       sign_in(admin) |       sign_in(admin) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,51 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | FactoryBot.define do | ||||||
|  |   factory :diff_position, class: 'Gitlab::Diff::Position' do | ||||||
|  |     skip_create # non-model factories (i.e. without #save) | ||||||
|  | 
 | ||||||
|  |     transient do | ||||||
|  |       file { 'path/to/file' } | ||||||
|  | 
 | ||||||
|  |       # Allow diff to be passed as a single object. | ||||||
|  |       diff_refs do | ||||||
|  |         ::Gitlab::Diff::DiffRefs.new( | ||||||
|  |           base_sha: Digest::SHA1.hexdigest(SecureRandom.hex), | ||||||
|  |           head_sha: Digest::SHA1.hexdigest(SecureRandom.hex), | ||||||
|  |           start_sha: Digest::SHA1.hexdigest(SecureRandom.hex) | ||||||
|  |         ) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     old_path { file } | ||||||
|  |     new_path { file } | ||||||
|  | 
 | ||||||
|  |     base_sha  { diff_refs&.base_sha } | ||||||
|  |     head_sha  { diff_refs&.head_sha } | ||||||
|  |     start_sha { diff_refs&.start_sha } | ||||||
|  | 
 | ||||||
|  |     initialize_with { new(attributes) } | ||||||
|  | 
 | ||||||
|  |     trait :moved do | ||||||
|  |       new_path { 'path/to/new.file' } | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     factory :text_diff_position do | ||||||
|  |       position_type { 'text' } | ||||||
|  |       old_line { 10 } | ||||||
|  |       new_line { 10 } | ||||||
|  | 
 | ||||||
|  |       trait :added do | ||||||
|  |         old_line { nil } | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     factory :image_diff_position do | ||||||
|  |       position_type { 'image' } | ||||||
|  |       x { 1 } | ||||||
|  |       y { 1 } | ||||||
|  |       width { 10 } | ||||||
|  |       height { 10 } | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -58,24 +58,20 @@ FactoryBot.define do | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       position do |       position do | ||||||
|         Gitlab::Diff::Position.new( |         build(:text_diff_position, | ||||||
|           old_path: "files/ruby/popen.rb", |               file: "files/ruby/popen.rb", | ||||||
|           new_path: "files/ruby/popen.rb", |               old_line: nil, | ||||||
|           old_line: nil, |               new_line: line_number, | ||||||
|           new_line: line_number, |               diff_refs: diff_refs) | ||||||
|           diff_refs: diff_refs |  | ||||||
|         ) |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       trait :folded_position do |       trait :folded_position do | ||||||
|         position do |         position do | ||||||
|           Gitlab::Diff::Position.new( |           build(:text_diff_position, | ||||||
|             old_path: "files/ruby/popen.rb", |                 file: "files/ruby/popen.rb", | ||||||
|             new_path: "files/ruby/popen.rb", |                 old_line: 1, | ||||||
|             old_line: 1, |                 new_line: 1, | ||||||
|             new_line: 1, |                 diff_refs: diff_refs) | ||||||
|             diff_refs: diff_refs |  | ||||||
|           ) |  | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -86,16 +82,9 @@ FactoryBot.define do | ||||||
| 
 | 
 | ||||||
|       factory :image_diff_note_on_merge_request do |       factory :image_diff_note_on_merge_request do | ||||||
|         position do |         position do | ||||||
|           Gitlab::Diff::Position.new( |           build(:image_diff_position, | ||||||
|             old_path: "files/images/any_image.png", |                 file: "files/images/any_image.png", | ||||||
|             new_path: "files/images/any_image.png", |                 diff_refs: diff_refs) | ||||||
|             width: 10, |  | ||||||
|             height: 10, |  | ||||||
|             x: 1, |  | ||||||
|             y: 1, |  | ||||||
|             diff_refs: diff_refs, |  | ||||||
|             position_type: "image" |  | ||||||
|           ) |  | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -109,9 +98,8 @@ FactoryBot.define do | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       position do |       position do | ||||||
|         Gitlab::Diff::Position.new( |         build(:text_diff_position, | ||||||
|           old_path: "files/ruby/popen.rb", |           file: "files/ruby/popen.rb", | ||||||
|           new_path: "files/ruby/popen.rb", |  | ||||||
|           old_line: nil, |           old_line: nil, | ||||||
|           new_line: line_number, |           new_line: line_number, | ||||||
|           diff_refs: diff_refs |           diff_refs: diff_refs | ||||||
|  |  | ||||||
|  | @ -326,6 +326,8 @@ describe 'Admin updates settings', :clean_gitlab_redis_shared_state, :do_not_moc | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'loads usage ping payload on click', :js do |       it 'loads usage ping payload on click', :js do | ||||||
|  |         allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false) | ||||||
|  | 
 | ||||||
|         expect(page).to have_button 'Preview payload' |         expect(page).to have_button 'Preview payload' | ||||||
| 
 | 
 | ||||||
|         find('.js-usage-ping-payload-trigger').click |         find('.js-usage-ping-payload-trigger').click | ||||||
|  |  | ||||||
|  | @ -48,29 +48,11 @@ describe 'Merge request > User creates image diff notes', :js do | ||||||
|       let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') } |       let(:commit) { project.commit('2f63565e7aac07bcdadb654e253078b727143ec4') } | ||||||
| 
 | 
 | ||||||
|       let(:note1_position) do |       let(:note1_position) do | ||||||
|         Gitlab::Diff::Position.new( |         build(:image_diff_position, file: path, diff_refs: commit.diff_refs) | ||||||
|           old_path: path, |  | ||||||
|           new_path: path, |  | ||||||
|           width: 100, |  | ||||||
|           height: 100, |  | ||||||
|           x: 10, |  | ||||||
|           y: 10, |  | ||||||
|           position_type: "image", |  | ||||||
|           diff_refs: commit.diff_refs |  | ||||||
|         ) |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       let(:note2_position) do |       let(:note2_position) do | ||||||
|         Gitlab::Diff::Position.new( |         build(:image_diff_position, file: path, diff_refs: commit.diff_refs) | ||||||
|           old_path: path, |  | ||||||
|           new_path: path, |  | ||||||
|           width: 100, |  | ||||||
|           height: 100, |  | ||||||
|           x: 20, |  | ||||||
|           y: 20, |  | ||||||
|           position_type: "image", |  | ||||||
|           diff_refs: commit.diff_refs |  | ||||||
|         ) |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       let!(:note1) { create(:diff_note_on_commit, commit_id: commit.id, project: project, position: note1_position, note: 'my note 1') } |       let!(:note1) { create(:diff_note_on_commit, commit_id: commit.id, project: project, position: note1_position, note: 'my note 1') } | ||||||
|  | @ -93,16 +75,7 @@ describe 'Merge request > User creates image diff notes', :js do | ||||||
|   %w(inline parallel).each do |view| |   %w(inline parallel).each do |view| | ||||||
|     context "#{view} view" do |     context "#{view} view" do | ||||||
|       let(:position) do |       let(:position) do | ||||||
|         Gitlab::Diff::Position.new( |         build(:image_diff_position, file: path, diff_refs: merge_request.diff_refs) | ||||||
|           old_path: path, |  | ||||||
|           new_path: path, |  | ||||||
|           width: 100, |  | ||||||
|           height: 100, |  | ||||||
|           x: 1, |  | ||||||
|           y: 1, |  | ||||||
|           position_type: "image", |  | ||||||
|           diff_refs: merge_request.diff_refs |  | ||||||
|         ) |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: position) } |       let!(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: position) } | ||||||
|  | @ -167,16 +140,7 @@ describe 'Merge request > User creates image diff notes', :js do | ||||||
|     let(:path)          { "files/images/ee_repo_logo.png" } |     let(:path)          { "files/images/ee_repo_logo.png" } | ||||||
| 
 | 
 | ||||||
|     let(:position) do |     let(:position) do | ||||||
|       Gitlab::Diff::Position.new( |       build(:image_diff_position, file: path, diff_refs: merge_request.diff_refs) | ||||||
|         old_path: path, |  | ||||||
|         new_path: path, |  | ||||||
|         width: 100, |  | ||||||
|         height: 100, |  | ||||||
|         x: 50, |  | ||||||
|         y: 50, |  | ||||||
|         position_type: "image", |  | ||||||
|         diff_refs: merge_request.diff_refs |  | ||||||
|       ) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     before do |     before do | ||||||
|  |  | ||||||
|  | @ -10,13 +10,9 @@ describe 'Merge request > User resolves diff notes and threads', :js do | ||||||
|   let!(:note)         { create(:diff_note_on_merge_request, project: project, noteable: merge_request, note: "| Markdown | Table |\n|-------|---------|\n| first | second |") } |   let!(:note)         { create(:diff_note_on_merge_request, project: project, noteable: merge_request, note: "| Markdown | Table |\n|-------|---------|\n| first | second |") } | ||||||
|   let(:path)          { "files/ruby/popen.rb" } |   let(:path)          { "files/ruby/popen.rb" } | ||||||
|   let(:position) do |   let(:position) do | ||||||
|     Gitlab::Diff::Position.new( |     build(:text_diff_position, | ||||||
|       old_path: path, |           file: path, old_line: nil, new_line: 9, | ||||||
|       new_path: path, |           diff_refs: merge_request.diff_refs) | ||||||
|       old_line: nil, |  | ||||||
|       new_line: 9, |  | ||||||
|       diff_refs: merge_request.diff_refs |  | ||||||
|     ) |  | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   before do |   before do | ||||||
|  |  | ||||||
|  | @ -13,20 +13,16 @@ describe 'Merge request > User resolves outdated diff discussions', :js do | ||||||
|   let(:current_diff_refs) { merge_request.diff_refs } |   let(:current_diff_refs) { merge_request.diff_refs } | ||||||
| 
 | 
 | ||||||
|   let(:outdated_position) do |   let(:outdated_position) do | ||||||
|     Gitlab::Diff::Position.new( |     build(:text_diff_position, :added, | ||||||
|       old_path: 'files/csv/Book1.csv', |       file: 'files/csv/Book1.csv', | ||||||
|       new_path: 'files/csv/Book1.csv', |  | ||||||
|       old_line: nil, |  | ||||||
|       new_line: 9, |       new_line: 9, | ||||||
|       diff_refs: outdated_diff_refs |       diff_refs: outdated_diff_refs | ||||||
|     ) |     ) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   let(:current_position) do |   let(:current_position) do | ||||||
|     Gitlab::Diff::Position.new( |     build(:text_diff_position, :added, | ||||||
|       old_path: 'files/csv/Book1.csv', |       file: 'files/csv/Book1.csv', | ||||||
|       new_path: 'files/csv/Book1.csv', |  | ||||||
|       old_line: nil, |  | ||||||
|       new_line: 1, |       new_line: 1, | ||||||
|       diff_refs: current_diff_refs |       diff_refs: current_diff_refs | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  | @ -10,10 +10,8 @@ describe 'Merge request > User sees avatars on diff notes', :js do | ||||||
|   let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: 'Bug NS-04') } |   let(:merge_request) { create(:merge_request_with_diffs, source_project: project, author: user, title: 'Bug NS-04') } | ||||||
|   let(:path)          { 'files/ruby/popen.rb' } |   let(:path)          { 'files/ruby/popen.rb' } | ||||||
|   let(:position) do |   let(:position) do | ||||||
|     Gitlab::Diff::Position.new( |     build(:text_diff_position, :added, | ||||||
|       old_path: path, |       file: path, | ||||||
|       new_path: path, |  | ||||||
|       old_line: nil, |  | ||||||
|       new_line: 9, |       new_line: 9, | ||||||
|       diff_refs: merge_request.diff_refs |       diff_refs: merge_request.diff_refs | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  | @ -18,10 +18,8 @@ describe 'Merge request > User sees threads', :js do | ||||||
|     let!(:outdated_discussion) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: outdated_position).to_discussion } |     let!(:outdated_discussion) { create(:diff_note_on_merge_request, project: project, noteable: merge_request, position: outdated_position).to_discussion } | ||||||
|     let!(:active_discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } |     let!(:active_discussion) { create(:diff_note_on_merge_request, noteable: merge_request, project: project).to_discussion } | ||||||
|     let(:outdated_position) do |     let(:outdated_position) do | ||||||
|       Gitlab::Diff::Position.new( |       build(:text_diff_position, :added, | ||||||
|         old_path: "files/ruby/popen.rb", |         file: "files/ruby/popen.rb", | ||||||
|         new_path: "files/ruby/popen.rb", |  | ||||||
|         old_line: nil, |  | ||||||
|         new_line: 9, |         new_line: 9, | ||||||
|         diff_refs: outdated_diff_refs |         diff_refs: outdated_diff_refs | ||||||
|       ) |       ) | ||||||
|  |  | ||||||
|  | @ -86,10 +86,8 @@ describe 'Merge request > User sees versions', :js do | ||||||
|     it 'shows comments that were last relevant at that version' do |     it 'shows comments that were last relevant at that version' do | ||||||
|       expect(page).to have_content '5 files' |       expect(page).to have_content '5 files' | ||||||
| 
 | 
 | ||||||
|       position = Gitlab::Diff::Position.new( |       position = build(:text_diff_position, :added, | ||||||
|         old_path: ".gitmodules", |         file: ".gitmodules", | ||||||
|         new_path: ".gitmodules", |  | ||||||
|         old_line: nil, |  | ||||||
|         new_line: 4, |         new_line: 4, | ||||||
|         diff_refs: merge_request_diff1.diff_refs |         diff_refs: merge_request_diff1.diff_refs | ||||||
|       ) |       ) | ||||||
|  | @ -136,9 +134,8 @@ describe 'Merge request > User sees versions', :js do | ||||||
|       expect(additions_content).to eq '15' |       expect(additions_content).to eq '15' | ||||||
|       expect(deletions_content).to eq '6' |       expect(deletions_content).to eq '6' | ||||||
| 
 | 
 | ||||||
|       position = Gitlab::Diff::Position.new( |       position = build(:text_diff_position, | ||||||
|         old_path: ".gitmodules", |         file: ".gitmodules", | ||||||
|         new_path: ".gitmodules", |  | ||||||
|         old_line: 4, |         old_line: 4, | ||||||
|         new_line: 4, |         new_line: 4, | ||||||
|         diff_refs: merge_request_diff3.compare_with(merge_request_diff1.head_commit_sha).diff_refs |         diff_refs: merge_request_diff3.compare_with(merge_request_diff1.head_commit_sha).diff_refs | ||||||
|  |  | ||||||
|  | @ -58,7 +58,7 @@ describe 'Projects > Settings > For a forked project', :js do | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       def click_expand_incident_management_button |       def click_expand_incident_management_button | ||||||
|         within '.js-incident-management-settings' do |         within '.qa-incident-management-settings' do | ||||||
|           click_button('Expand') |           click_button('Expand') | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -36,10 +36,8 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont | ||||||
|   end |   end | ||||||
|   let(:path) { "files/ruby/popen.rb" } |   let(:path) { "files/ruby/popen.rb" } | ||||||
|   let(:position) do |   let(:position) do | ||||||
|     Gitlab::Diff::Position.new( |     build(:text_diff_position, :added, | ||||||
|       old_path: path, |       file: path, | ||||||
|       new_path: path, |  | ||||||
|       old_line: nil, |  | ||||||
|       new_line: 14, |       new_line: 14, | ||||||
|       diff_refs: merge_request.diff_refs |       diff_refs: merge_request.diff_refs | ||||||
|     ) |     ) | ||||||
|  | @ -112,14 +110,8 @@ describe Projects::MergeRequestsController, '(JavaScript fixtures)', type: :cont | ||||||
|     let(:merge_request2) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, title: "Added images") } |     let(:merge_request2) { create(:merge_request_with_diffs, :with_image_diffs, source_project: project, title: "Added images") } | ||||||
|     let(:image_path) { "files/images/ee_repo_logo.png" } |     let(:image_path) { "files/images/ee_repo_logo.png" } | ||||||
|     let(:image_position) do |     let(:image_position) do | ||||||
|       Gitlab::Diff::Position.new( |       build(:image_diff_position, | ||||||
|         old_path: image_path, |         file: image_path, | ||||||
|         new_path: image_path, |  | ||||||
|         width: 100, |  | ||||||
|         height: 100, |  | ||||||
|         x: 1, |  | ||||||
|         y: 1, |  | ||||||
|         position_type: "image", |  | ||||||
|         diff_refs: merge_request2.diff_refs |         diff_refs: merge_request2.diff_refs | ||||||
|       ) |       ) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -12,10 +12,8 @@ describe Projects::MergeRequests::DiffsController, '(JavaScript fixtures)', type | ||||||
|   let(:path) { "files/ruby/popen.rb" } |   let(:path) { "files/ruby/popen.rb" } | ||||||
|   let(:selected_commit) { merge_request.all_commits[0] } |   let(:selected_commit) { merge_request.all_commits[0] } | ||||||
|   let(:position) do |   let(:position) do | ||||||
|     Gitlab::Diff::Position.new( |     build(:text_diff_position, :added, | ||||||
|       old_path: path, |       file: path, | ||||||
|       new_path: path, |  | ||||||
|       old_line: nil, |  | ||||||
|       new_line: 14, |       new_line: 14, | ||||||
|       diff_refs: merge_request.diff_refs |       diff_refs: merge_request.diff_refs | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ exports[`Expiration Policy Form renders 1`] = ` | ||||||
| <div | <div | ||||||
|   class="lh-2" |   class="lh-2" | ||||||
| > | > | ||||||
|   <glformgroup-stub |   <gl-form-group-stub | ||||||
|     id="expiration-policy-toggle-group" |     id="expiration-policy-toggle-group" | ||||||
|     label="Expiration policy:" |     label="Expiration policy:" | ||||||
|     label-align="right" |     label-align="right" | ||||||
|  | @ -14,7 +14,7 @@ exports[`Expiration Policy Form renders 1`] = ` | ||||||
|     <div |     <div | ||||||
|       class="d-flex align-items-start" |       class="d-flex align-items-start" | ||||||
|     > |     > | ||||||
|       <gltoggle-stub |       <gl-toggle-stub | ||||||
|         id="expiration-policy-toggle" |         id="expiration-policy-toggle" | ||||||
|         labeloff="Toggle Status: OFF" |         labeloff="Toggle Status: OFF" | ||||||
|         labelon="Toggle Status: ON" |         labelon="Toggle Status: ON" | ||||||
|  | @ -30,16 +30,16 @@ exports[`Expiration Policy Form renders 1`] = ` | ||||||
|         </strong> |         </strong> | ||||||
|       </span> |       </span> | ||||||
|     </div> |     </div> | ||||||
|   </glformgroup-stub> |   </gl-form-group-stub> | ||||||
|     |     | ||||||
|   <glformgroup-stub |   <gl-form-group-stub | ||||||
|     id="expiration-policy-interval-group" |     id="expiration-policy-interval-group" | ||||||
|     label="Expiration interval:" |     label="Expiration interval:" | ||||||
|     label-align="right" |     label-align="right" | ||||||
|     label-cols="3" |     label-cols="3" | ||||||
|     label-for="expiration-policy-interval" |     label-for="expiration-policy-interval" | ||||||
|   > |   > | ||||||
|     <glformselect-stub |     <gl-form-select-stub | ||||||
|       disabled="true" |       disabled="true" | ||||||
|       id="expiration-policy-interval" |       id="expiration-policy-interval" | ||||||
|     > |     > | ||||||
|  | @ -57,16 +57,16 @@ exports[`Expiration Policy Form renders 1`] = ` | ||||||
|         Bar |         Bar | ||||||
|        |        | ||||||
|       </option> |       </option> | ||||||
|     </glformselect-stub> |     </gl-form-select-stub> | ||||||
|   </glformgroup-stub> |   </gl-form-group-stub> | ||||||
|   <glformgroup-stub |   <gl-form-group-stub | ||||||
|     id="expiration-policy-schedule-group" |     id="expiration-policy-schedule-group" | ||||||
|     label="Expiration schedule:" |     label="Expiration schedule:" | ||||||
|     label-align="right" |     label-align="right" | ||||||
|     label-cols="3" |     label-cols="3" | ||||||
|     label-for="expiration-policy-schedule" |     label-for="expiration-policy-schedule" | ||||||
|   > |   > | ||||||
|     <glformselect-stub |     <gl-form-select-stub | ||||||
|       disabled="true" |       disabled="true" | ||||||
|       id="expiration-policy-schedule" |       id="expiration-policy-schedule" | ||||||
|     > |     > | ||||||
|  | @ -84,16 +84,16 @@ exports[`Expiration Policy Form renders 1`] = ` | ||||||
|         Bar |         Bar | ||||||
|        |        | ||||||
|       </option> |       </option> | ||||||
|     </glformselect-stub> |     </gl-form-select-stub> | ||||||
|   </glformgroup-stub> |   </gl-form-group-stub> | ||||||
|   <glformgroup-stub |   <gl-form-group-stub | ||||||
|     id="expiration-policy-latest-group" |     id="expiration-policy-latest-group" | ||||||
|     label="Number of tags to retain:" |     label="Number of tags to retain:" | ||||||
|     label-align="right" |     label-align="right" | ||||||
|     label-cols="3" |     label-cols="3" | ||||||
|     label-for="expiration-policy-latest" |     label-for="expiration-policy-latest" | ||||||
|   > |   > | ||||||
|     <glformselect-stub |     <gl-form-select-stub | ||||||
|       disabled="true" |       disabled="true" | ||||||
|       id="expiration-policy-latest" |       id="expiration-policy-latest" | ||||||
|     > |     > | ||||||
|  | @ -111,10 +111,10 @@ exports[`Expiration Policy Form renders 1`] = ` | ||||||
|         Bar |         Bar | ||||||
|        |        | ||||||
|       </option> |       </option> | ||||||
|     </glformselect-stub> |     </gl-form-select-stub> | ||||||
|   </glformgroup-stub> |   </gl-form-group-stub> | ||||||
|     |     | ||||||
|   <glformgroup-stub |   <gl-form-group-stub | ||||||
|     id="expiration-policy-name-matching-group" |     id="expiration-policy-name-matching-group" | ||||||
|     invalid-feedback="The value of this input should be less than 255 characters" |     invalid-feedback="The value of this input should be less than 255 characters" | ||||||
|     label="Docker tags with names matching this regex pattern will expire:" |     label="Docker tags with names matching this regex pattern will expire:" | ||||||
|  | @ -122,13 +122,13 @@ exports[`Expiration Policy Form renders 1`] = ` | ||||||
|     label-cols="3" |     label-cols="3" | ||||||
|     label-for="expiration-policy-name-matching" |     label-for="expiration-policy-name-matching" | ||||||
|   > |   > | ||||||
|     <glformtextarea-stub |     <gl-form-textarea-stub | ||||||
|       disabled="true" |       disabled="true" | ||||||
|       id="expiration-policy-name-matching" |       id="expiration-policy-name-matching" | ||||||
|       placeholder=".*" |       placeholder=".*" | ||||||
|       trim="" |       trim="" | ||||||
|       value="" |       value="" | ||||||
|     /> |     /> | ||||||
|   </glformgroup-stub> |   </gl-form-group-stub> | ||||||
| </div> | </div> | ||||||
| `; | `; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import { mount } from '@vue/test-utils'; | import { shallowMount } from '@vue/test-utils'; | ||||||
| import stubChildren from 'helpers/stub_children'; | import { GlSprintf } from '@gitlab/ui'; | ||||||
| import component from '~/registry/shared/components/expiration_policy_fields.vue'; | import component from '~/registry/shared/components/expiration_policy_fields.vue'; | ||||||
| 
 | 
 | ||||||
| import { NAME_REGEX_LENGTH } from '~/registry/shared/constants'; | import { NAME_REGEX_LENGTH } from '~/registry/shared/constants'; | ||||||
|  | @ -15,9 +15,9 @@ describe('Expiration Policy Form', () => { | ||||||
|     parent.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}`); |     parent.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}`); | ||||||
| 
 | 
 | ||||||
|   const mountComponent = props => { |   const mountComponent = props => { | ||||||
|     wrapper = mount(component, { |     wrapper = shallowMount(component, { | ||||||
|       stubs: { |       stubs: { | ||||||
|         ...stubChildren(component), |         GlSprintf, | ||||||
|       }, |       }, | ||||||
|       propsData: { |       propsData: { | ||||||
|         formOptions, |         formOptions, | ||||||
|  |  | ||||||
|  | @ -62,10 +62,8 @@ describe NotesHelper do | ||||||
| 
 | 
 | ||||||
|         context 'when the discussion is on an older merge request version' do |         context 'when the discussion is on an older merge request version' do | ||||||
|           let(:position) do |           let(:position) do | ||||||
|             Gitlab::Diff::Position.new( |             build(:text_diff_position, :added, | ||||||
|               old_path: ".gitmodules", |               file: ".gitmodules", | ||||||
|               new_path: ".gitmodules", |  | ||||||
|               old_line: nil, |  | ||||||
|               new_line: 4, |               new_line: 4, | ||||||
|               diff_refs: merge_request_diff1.diff_refs |               diff_refs: merge_request_diff1.diff_refs | ||||||
|             ) |             ) | ||||||
|  | @ -86,9 +84,8 @@ describe NotesHelper do | ||||||
| 
 | 
 | ||||||
|         context 'when the discussion is on a comparison between merge request versions' do |         context 'when the discussion is on a comparison between merge request versions' do | ||||||
|           let(:position) do |           let(:position) do | ||||||
|             Gitlab::Diff::Position.new( |             build(:text_diff_position, | ||||||
|               old_path: ".gitmodules", |               file: ".gitmodules", | ||||||
|               new_path: ".gitmodules", |  | ||||||
|               old_line: 4, |               old_line: 4, | ||||||
|               new_line: 4, |               new_line: 4, | ||||||
|               diff_refs: merge_request_diff3.compare_with(merge_request_diff1.head_commit_sha).diff_refs |               diff_refs: merge_request_diff3.compare_with(merge_request_diff1.head_commit_sha).diff_refs | ||||||
|  |  | ||||||
|  | @ -120,17 +120,13 @@ describe Gitlab::CurrentSettings do | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         context 'with pending migrations' do |         context 'with pending migrations' do | ||||||
|  |           let(:current_settings) { described_class.current_application_settings } | ||||||
|  | 
 | ||||||
|           before do |           before do | ||||||
|             expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:needs_migration?).and_return(true) |             allow(Gitlab::Runtime).to receive(:rake?).and_return(false) | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           shared_examples 'a non-persisted ApplicationSetting object' do |           shared_examples 'a non-persisted ApplicationSetting object' do | ||||||
|             let(:current_settings) { described_class.current_application_settings } |  | ||||||
| 
 |  | ||||||
|             it 'returns a FakeApplicationSettings object' do |  | ||||||
|               expect(current_settings).to be_a(Gitlab::FakeApplicationSettings) |  | ||||||
|             end |  | ||||||
| 
 |  | ||||||
|             it 'uses the default value from ApplicationSetting.defaults' do |             it 'uses the default value from ApplicationSetting.defaults' do | ||||||
|               expect(current_settings.signup_enabled).to eq(ApplicationSetting.defaults[:signup_enabled]) |               expect(current_settings.signup_enabled).to eq(ApplicationSetting.defaults[:signup_enabled]) | ||||||
|             end |             end | ||||||
|  | @ -144,18 +140,16 @@ describe Gitlab::CurrentSettings do | ||||||
|             end |             end | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|           context 'with no ApplicationSetting DB record' do |           context 'in a Rake task' do | ||||||
|             it_behaves_like 'a non-persisted ApplicationSetting object' |             before do | ||||||
|           end |               allow(Gitlab::Runtime).to receive(:rake?).and_return(true) | ||||||
| 
 |               expect_any_instance_of(ActiveRecord::MigrationContext).to receive(:needs_migration?).and_return(true) | ||||||
|           context 'with an existing ApplicationSetting DB record' do |             end | ||||||
|             let!(:db_settings) { ApplicationSetting.build_from_defaults(home_page_url: 'http://mydomain.com').save! && ApplicationSetting.last } |  | ||||||
|             let(:current_settings) { described_class.current_application_settings } |  | ||||||
| 
 | 
 | ||||||
|             it_behaves_like 'a non-persisted ApplicationSetting object' |             it_behaves_like 'a non-persisted ApplicationSetting object' | ||||||
| 
 | 
 | ||||||
|             it 'uses the value from the DB attribute if present and not overridden by an accessor' do |             it 'returns a FakeApplicationSettings object' do | ||||||
|               expect(current_settings.home_page_url).to eq(db_settings.home_page_url) |               expect(current_settings).to be_a(Gitlab::FakeApplicationSettings) | ||||||
|             end |             end | ||||||
| 
 | 
 | ||||||
|             context 'when a new column is used before being migrated' do |             context 'when a new column is used before being migrated' do | ||||||
|  | @ -168,6 +162,20 @@ describe Gitlab::CurrentSettings do | ||||||
|               end |               end | ||||||
|             end |             end | ||||||
|           end |           end | ||||||
|  | 
 | ||||||
|  |           context 'with no ApplicationSetting DB record' do | ||||||
|  |             it_behaves_like 'a non-persisted ApplicationSetting object' | ||||||
|  |           end | ||||||
|  | 
 | ||||||
|  |           context 'with an existing ApplicationSetting DB record' do | ||||||
|  |             let!(:db_settings) { ApplicationSetting.build_from_defaults(home_page_url: 'http://mydomain.com').save! && ApplicationSetting.last } | ||||||
|  | 
 | ||||||
|  |             it_behaves_like 'a non-persisted ApplicationSetting object' | ||||||
|  | 
 | ||||||
|  |             it 'uses the value from the DB attribute if present and not overridden by an accessor' do | ||||||
|  |               expect(current_settings.home_page_url).to eq(db_settings.home_page_url) | ||||||
|  |             end | ||||||
|  |           end | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         context 'when ApplicationSettings.current is present' do |         context 'when ApplicationSettings.current is present' do | ||||||
|  |  | ||||||
|  | @ -0,0 +1,94 @@ | ||||||
|  | # frozen_string_literal: true | ||||||
|  | 
 | ||||||
|  | require 'spec_helper' | ||||||
|  | 
 | ||||||
|  | describe Gitlab::Database::BatchCount do | ||||||
|  |   let(:model) { Issue } | ||||||
|  |   let(:column) { :author_id } | ||||||
|  | 
 | ||||||
|  |   let(:in_transaction) { false } | ||||||
|  |   let(:user) { create(:user) } | ||||||
|  |   let(:another_user) { create(:user) } | ||||||
|  | 
 | ||||||
|  |   before do | ||||||
|  |     create_list(:issue, 3, author: user ) | ||||||
|  |     create_list(:issue, 2, author: another_user ) | ||||||
|  |     allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(in_transaction) | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe '#batch_count' do | ||||||
|  |     it 'counts table' do | ||||||
|  |       expect(described_class.batch_count(model)).to eq(5) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with :id field' do | ||||||
|  |       expect(described_class.batch_count(model, :id)).to eq(5) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with "id" field' do | ||||||
|  |       expect(described_class.batch_count(model, 'id')).to eq(5) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with table.id field' do | ||||||
|  |       expect(described_class.batch_count(model, "#{model.table_name}.id")).to eq(5) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts table with batch_size 50K' do | ||||||
|  |       expect(described_class.batch_count(model, batch_size: 50_000)).to eq(5) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'will not count table with batch_size 1K' do | ||||||
|  |       fallback = ::Gitlab::Database::BatchCounter::FALLBACK | ||||||
|  |       expect(described_class.batch_count(model, batch_size: fallback / 2)).to eq(fallback) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with a small edge case batch_sizes than result' do | ||||||
|  |       stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 0) | ||||||
|  | 
 | ||||||
|  |       [1, 2, 4, 5, 6].each { |i| expect(described_class.batch_count(model, batch_size: i)).to eq(5) } | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     context 'in a transaction' do | ||||||
|  |       let(:in_transaction) { true } | ||||||
|  | 
 | ||||||
|  |       it 'cannot count' do | ||||||
|  |         expect do | ||||||
|  |           described_class.batch_count(model) | ||||||
|  |         end.to raise_error 'BatchCount can not be run inside a transaction' | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   describe '#batch_distinct_count' do | ||||||
|  |     it 'counts with :id field' do | ||||||
|  |       expect(described_class.batch_distinct_count(model, :id)).to eq(5) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with column field' do | ||||||
|  |       expect(described_class.batch_distinct_count(model, column)).to eq(2) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with "id" field' do | ||||||
|  |       expect(described_class.batch_distinct_count(model, "#{column}")).to eq(2) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with table.column field' do | ||||||
|  |       expect(described_class.batch_distinct_count(model, "#{model.table_name}.#{column}")).to eq(2) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with :column field with batch_size of 50K' do | ||||||
|  |       expect(described_class.batch_distinct_count(model, column, batch_size: 50_000)).to eq(2) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'will not count table with batch_size 1K' do | ||||||
|  |       fallback = ::Gitlab::Database::BatchCounter::FALLBACK | ||||||
|  |       expect(described_class.batch_distinct_count(model, column, batch_size: fallback / 2)).to eq(fallback) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'counts with a small edge case batch_sizes than result' do | ||||||
|  |       stub_const('Gitlab::Database::BatchCounter::MIN_REQUIRED_BATCH_SIZE', 0) | ||||||
|  | 
 | ||||||
|  |       [1, 2, 4, 5, 6].each { |i| expect(described_class.batch_distinct_count(model, column, batch_size: i)).to eq(2) } | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  | @ -212,14 +212,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
| 
 | 
 | ||||||
|   context 'position requires a middle expansion and new match lines' do |   context 'position requires a middle expansion and new match lines' do | ||||||
|     let(:position) do |     let(:position) do | ||||||
|       Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |       build(:text_diff_position, old_line: 43, new_line: 40) | ||||||
|                                  start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |  | ||||||
|                                  head_sha: "1487062132228de836236c522fe52fed4980a46c", |  | ||||||
|                                  old_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  new_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  position_type:  "text", |  | ||||||
|                                  old_line: 43, |  | ||||||
|                                  new_line: 40) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'blob lines' do |     context 'blob lines' do | ||||||
|  | @ -321,14 +314,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
| 
 | 
 | ||||||
|   context 'position requires a middle expansion and no top match line' do |   context 'position requires a middle expansion and no top match line' do | ||||||
|     let(:position) do |     let(:position) do | ||||||
|       Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |       build(:text_diff_position, old_line: 16, new_line: 17) | ||||||
|                                  start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |  | ||||||
|                                  head_sha: "1487062132228de836236c522fe52fed4980a46c", |  | ||||||
|                                  old_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  new_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  position_type:  "text", |  | ||||||
|                                  old_line: 16, |  | ||||||
|                                  new_line: 17) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'blob lines' do |     context 'blob lines' do | ||||||
|  | @ -422,14 +408,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
| 
 | 
 | ||||||
|   context 'position requires a middle expansion and no bottom match line' do |   context 'position requires a middle expansion and no bottom match line' do | ||||||
|     let(:position) do |     let(:position) do | ||||||
|       Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |       build(:text_diff_position, old_line: 82, new_line: 79) | ||||||
|                                  start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |  | ||||||
|                                  head_sha: "1487062132228de836236c522fe52fed4980a46c", |  | ||||||
|                                  old_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  new_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  position_type:  "text", |  | ||||||
|                                  old_line: 82, |  | ||||||
|                                  new_line: 79) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'blob lines' do |     context 'blob lines' do | ||||||
|  | @ -523,14 +502,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
| 
 | 
 | ||||||
|   context 'position requires a short top expansion' do |   context 'position requires a short top expansion' do | ||||||
|     let(:position) do |     let(:position) do | ||||||
|       Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |       build(:text_diff_position, old_line: 6, new_line: 6) | ||||||
|                                  start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |  | ||||||
|                                  head_sha: "1487062132228de836236c522fe52fed4980a46c", |  | ||||||
|                                  old_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  new_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  position_type: "text", |  | ||||||
|                                  old_line: 6, |  | ||||||
|                                  new_line: 6) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'blob lines' do |     context 'blob lines' do | ||||||
|  | @ -621,14 +593,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
| 
 | 
 | ||||||
|   context 'position sits between two match lines (no expasion needed)' do |   context 'position sits between two match lines (no expasion needed)' do | ||||||
|     let(:position) do |     let(:position) do | ||||||
|       Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |       build(:text_diff_position, old_line: 64, new_line: 61) | ||||||
|                                  start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |  | ||||||
|                                  head_sha: "1487062132228de836236c522fe52fed4980a46c", |  | ||||||
|                                  old_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  new_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  position_type: "text", |  | ||||||
|                                  old_line: 64, |  | ||||||
|                                  new_line: 61) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'diff lines' do |     context 'diff lines' do | ||||||
|  | @ -640,14 +605,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
| 
 | 
 | ||||||
|   context 'position requires bottom expansion and new match lines' do |   context 'position requires bottom expansion and new match lines' do | ||||||
|     let(:position) do |     let(:position) do | ||||||
|       Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |       build(:text_diff_position, old_line: 107, new_line: 99) | ||||||
|                                  start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |  | ||||||
|                                  head_sha: "1487062132228de836236c522fe52fed4980a46c", |  | ||||||
|                                  old_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  new_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                  position_type: "text", |  | ||||||
|                                  old_line: 107, |  | ||||||
|                                  new_line: 99) |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'blob lines' do |     context 'blob lines' do | ||||||
|  | @ -744,14 +702,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
| 
 | 
 | ||||||
|     context 'position requires bottom expansion and no new match line' do |     context 'position requires bottom expansion and no new match line' do | ||||||
|       let(:position) do |       let(:position) do | ||||||
|         Gitlab::Diff::Position.new(base_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |         build(:text_diff_position, old_line: 95, new_line: 87) | ||||||
|                                    start_sha: "1c59dfa64afbea8c721bb09a06a9d326c952ea19", |  | ||||||
|                                    head_sha: "1487062132228de836236c522fe52fed4980a46c", |  | ||||||
|                                    old_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                    new_path: "build-aux/flatpak/org.gnome.Nautilus.json", |  | ||||||
|                                    position_type: "text", |  | ||||||
|                                    old_line: 95, |  | ||||||
|                                    new_line: 87) |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       context 'blob lines' do |       context 'blob lines' do | ||||||
|  | @ -844,16 +795,7 @@ describe Gitlab::Diff::LinesUnfolder do | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   context 'positioned on an image' do |   context 'positioned on an image' do | ||||||
|     let(:position) do |     let(:position) { build(:image_diff_position) } | ||||||
|       Gitlab::Diff::Position.new( |  | ||||||
|         base_sha: '1c59dfa64afbea8c721bb09a06a9d326c952ea19', |  | ||||||
|         start_sha: '1c59dfa64afbea8c721bb09a06a9d326c952ea19', |  | ||||||
|         head_sha: '1487062132228de836236c522fe52fed4980a46c', |  | ||||||
|         old_path: 'image.jpg', |  | ||||||
|         new_path: 'image.jpg', |  | ||||||
|         position_type: 'image' |  | ||||||
|       ) |  | ||||||
|     end |  | ||||||
| 
 | 
 | ||||||
|     before do |     before do | ||||||
|       allow(old_blob).to receive(:binary?).and_return(binary?) |       allow(old_blob).to receive(:binary?).and_return(binary?) | ||||||
|  |  | ||||||
|  | @ -5,36 +5,17 @@ require 'spec_helper' | ||||||
| describe Gitlab::Diff::PositionCollection do | describe Gitlab::Diff::PositionCollection do | ||||||
|   let(:merge_request) { build(:merge_request) } |   let(:merge_request) { build(:merge_request) } | ||||||
| 
 | 
 | ||||||
|   def build_text_position(attrs = {}) |   let(:text_position) do | ||||||
|     attributes = { |     build(:text_diff_position, :added, diff_refs: diff_refs) | ||||||
|       old_path: "files/ruby/popen.rb", |   end | ||||||
|       new_path: "files/ruby/popen.rb", |   let(:folded_text_position) do | ||||||
|       old_line: nil, |     build(:text_diff_position, diff_refs: diff_refs, old_line: 1, new_line: 1) | ||||||
|       new_line: 14, |   end | ||||||
|       diff_refs: merge_request.diff_refs |   let(:image_position) do | ||||||
|     }.merge(attrs) |     build(:image_diff_position, diff_refs: diff_refs) | ||||||
| 
 |  | ||||||
|     Gitlab::Diff::Position.new(attributes) |  | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def build_image_position(attrs = {}) |   let(:diff_refs) { merge_request.diff_refs } | ||||||
|     attributes = { |  | ||||||
|       old_path: "files/images/any_image.png", |  | ||||||
|       new_path: "files/images/any_image.png", |  | ||||||
|       width: 10, |  | ||||||
|       height: 10, |  | ||||||
|       x: 1, |  | ||||||
|       y: 1, |  | ||||||
|       diff_refs: merge_request.diff_refs, |  | ||||||
|       position_type: "image" |  | ||||||
|     }.merge(attrs) |  | ||||||
| 
 |  | ||||||
|     Gitlab::Diff::Position.new(attributes) |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   let(:text_position) { build_text_position } |  | ||||||
|   let(:folded_text_position) { build_text_position(old_line: 1, new_line: 1) } |  | ||||||
|   let(:image_position) { build_image_position } |  | ||||||
|   let(:invalid_position) { 'a position' } |   let(:invalid_position) { 'a position' } | ||||||
|   let(:head_sha) { merge_request.diff_head_sha } |   let(:head_sha) { merge_request.diff_head_sha } | ||||||
| 
 | 
 | ||||||
|  | @ -71,7 +52,9 @@ describe Gitlab::Diff::PositionCollection do | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   describe '#concat' do |   describe '#concat' do | ||||||
|     let(:new_text_position) { build_text_position(old_line: 1, new_line: 1) } |     let(:new_text_position) do | ||||||
|  |       build(:text_diff_position, diff_refs: diff_refs, old_line: 1, new_line: 1) | ||||||
|  |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns a Gitlab::Diff::Position' do |     it 'returns a Gitlab::Diff::Position' do | ||||||
|       expect(collection.concat([new_text_position])).to be_a(described_class) |       expect(collection.concat([new_text_position])).to be_a(described_class) | ||||||
|  |  | ||||||
|  | @ -35,6 +35,32 @@ describe Gitlab::Diff::Position do | ||||||
|     } |     } | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |   describe 'factory' do | ||||||
|  |     it 'produces a complete text position' do | ||||||
|  |       position = build(:text_diff_position) | ||||||
|  | 
 | ||||||
|  |       expect(position).to be_complete | ||||||
|  |       expect(position).to have_attributes(position_type: 'text') | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'produces a complete image position' do | ||||||
|  |       position = build(:image_diff_position) | ||||||
|  | 
 | ||||||
|  |       expect(position).to be_complete | ||||||
|  |       expect(position).to have_attributes(position_type: 'image') | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     it 'allows the diff_refs to be passed as a single object' do | ||||||
|  |       head_sha  = Digest::SHA1.hexdigest(SecureRandom.hex) | ||||||
|  |       base_sha  = Digest::SHA1.hexdigest(SecureRandom.hex) | ||||||
|  |       start_sha = Digest::SHA1.hexdigest(SecureRandom.hex) | ||||||
|  | 
 | ||||||
|  |       refs = ::Gitlab::Diff::DiffRefs.new(base_sha: base_sha, start_sha: start_sha, head_sha: head_sha) | ||||||
|  | 
 | ||||||
|  |       expect(build(:diff_position, diff_refs: refs).diff_refs).to eq(refs) | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|   describe "position for an added text file" do |   describe "position for an added text file" do | ||||||
|     let(:commit) { project.commit("2ea1f3dec713d940208fb5ce4a38765ecb5d3f73") } |     let(:commit) { project.commit("2ea1f3dec713d940208fb5ce4a38765ecb5d3f73") } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,381 +6,392 @@ describe Gitlab::UsageData do | ||||||
|   let(:projects) { create_list(:project, 4) } |   let(:projects) { create_list(:project, 4) } | ||||||
|   let!(:board) { create(:board, project: projects[0]) } |   let!(:board) { create(:board, project: projects[0]) } | ||||||
| 
 | 
 | ||||||
|   describe '#data' do |   before do | ||||||
|     before do |     allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false) | ||||||
|       create(:jira_service, project: projects[0]) |  | ||||||
|       create(:jira_service, :without_properties_callback, project: projects[1]) |  | ||||||
|       create(:jira_service, :jira_cloud_service, project: projects[2]) |  | ||||||
|       create(:jira_service, :without_properties_callback, project: projects[3], |  | ||||||
|              properties: { url: 'https://mysite.atlassian.net' }) |  | ||||||
|       create(:prometheus_service, project: projects[1]) |  | ||||||
|       create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true) |  | ||||||
|       create(:service, project: projects[1], type: 'SlackService', active: true) |  | ||||||
|       create(:service, project: projects[2], type: 'SlackService', active: true) |  | ||||||
|       create(:service, project: projects[2], type: 'MattermostService', active: false) |  | ||||||
|       create(:service, project: projects[2], type: 'MattermostService', active: true, template: true) |  | ||||||
|       create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true) |  | ||||||
|       create(:project_error_tracking_setting, project: projects[0]) |  | ||||||
|       create(:project_error_tracking_setting, project: projects[1], enabled: false) |  | ||||||
|       create(:alerts_service, project: projects[0]) |  | ||||||
|       create(:alerts_service, :inactive, project: projects[1]) |  | ||||||
|       create_list(:issue, 2, project: projects[0], author: User.alert_bot) |  | ||||||
|       create_list(:issue, 2, project: projects[1], author: User.alert_bot) |  | ||||||
|       create_list(:issue, 4, project: projects[0]) |  | ||||||
|       create(:zoom_meeting, project: projects[0], issue: projects[0].issues[0], issue_status: :added) |  | ||||||
|       create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[1], issue_status: :removed) |  | ||||||
|       create(:zoom_meeting, project: projects[0], issue: projects[0].issues[2], issue_status: :added) |  | ||||||
|       create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[2], issue_status: :removed) |  | ||||||
|       create(:sentry_issue, issue: projects[0].issues[0]) |  | ||||||
| 
 |  | ||||||
|       # Enabled clusters |  | ||||||
|       gcp_cluster = create(:cluster_provider_gcp, :created).cluster |  | ||||||
|       create(:cluster_provider_aws, :created) |  | ||||||
|       create(:cluster_platform_kubernetes) |  | ||||||
|       create(:cluster, :group) |  | ||||||
| 
 |  | ||||||
|       # Disabled clusters |  | ||||||
|       create(:cluster, :disabled) |  | ||||||
|       create(:cluster, :group, :disabled) |  | ||||||
|       create(:cluster, :group, :disabled) |  | ||||||
| 
 |  | ||||||
|       # Applications |  | ||||||
|       create(:clusters_applications_helm, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_ingress, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_cert_manager, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_prometheus, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_crossplane, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_runner, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_knative, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster) |  | ||||||
|       create(:clusters_applications_jupyter, :installed, cluster: gcp_cluster) |  | ||||||
| 
 |  | ||||||
|       create(:grafana_integration, project: projects[0], enabled: true) |  | ||||||
|       create(:grafana_integration, project: projects[1], enabled: true) |  | ||||||
|       create(:grafana_integration, project: projects[2], enabled: false) |  | ||||||
| 
 |  | ||||||
|       allow(Gitlab::GrafanaEmbedUsageData).to receive(:issue_count).and_return(2) |  | ||||||
| 
 |  | ||||||
|       ProjectFeature.first.update_attribute('repository_access_level', 0) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     subject { described_class.data } |  | ||||||
| 
 |  | ||||||
|     it 'gathers usage data', :aggregate_failures do |  | ||||||
|       expect(subject.keys).to include(*%i( |  | ||||||
|         active_user_count |  | ||||||
|         counts |  | ||||||
|         recorded_at |  | ||||||
|         edition |  | ||||||
|         version |  | ||||||
|         installation_type |  | ||||||
|         uuid |  | ||||||
|         hostname |  | ||||||
|         mattermost_enabled |  | ||||||
|         signup_enabled |  | ||||||
|         ldap_enabled |  | ||||||
|         gravatar_enabled |  | ||||||
|         omniauth_enabled |  | ||||||
|         reply_by_email_enabled |  | ||||||
|         container_registry_enabled |  | ||||||
|         dependency_proxy_enabled |  | ||||||
|         gitlab_shared_runners_enabled |  | ||||||
|         gitlab_pages |  | ||||||
|         git |  | ||||||
|         gitaly |  | ||||||
|         database |  | ||||||
|         avg_cycle_analytics |  | ||||||
|         influxdb_metrics_enabled |  | ||||||
|         prometheus_metrics_enabled |  | ||||||
|         web_ide_clientside_preview_enabled |  | ||||||
|         ingress_modsecurity_enabled |  | ||||||
|       )) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'gathers usage counts' do |  | ||||||
|       smau_keys = %i( |  | ||||||
|         snippet_create |  | ||||||
|         snippet_update |  | ||||||
|         snippet_comment |  | ||||||
|         merge_request_comment |  | ||||||
|         merge_request_create |  | ||||||
|         commit_comment |  | ||||||
|         wiki_pages_create |  | ||||||
|         wiki_pages_update |  | ||||||
|         wiki_pages_delete |  | ||||||
|         web_ide_views |  | ||||||
|         web_ide_commits |  | ||||||
|         web_ide_merge_requests |  | ||||||
|         web_ide_previews |  | ||||||
|         navbar_searches |  | ||||||
|         cycle_analytics_views |  | ||||||
|         productivity_analytics_views |  | ||||||
|         source_code_pushes |  | ||||||
|       ) |  | ||||||
| 
 |  | ||||||
|       expected_keys = %i( |  | ||||||
|         assignee_lists |  | ||||||
|         boards |  | ||||||
|         ci_builds |  | ||||||
|         ci_internal_pipelines |  | ||||||
|         ci_external_pipelines |  | ||||||
|         ci_pipeline_config_auto_devops |  | ||||||
|         ci_pipeline_config_repository |  | ||||||
|         ci_runners |  | ||||||
|         ci_triggers |  | ||||||
|         ci_pipeline_schedules |  | ||||||
|         auto_devops_enabled |  | ||||||
|         auto_devops_disabled |  | ||||||
|         deploy_keys |  | ||||||
|         deployments |  | ||||||
|         successful_deployments |  | ||||||
|         failed_deployments |  | ||||||
|         environments |  | ||||||
|         clusters |  | ||||||
|         clusters_enabled |  | ||||||
|         project_clusters_enabled |  | ||||||
|         group_clusters_enabled |  | ||||||
|         clusters_disabled |  | ||||||
|         project_clusters_disabled |  | ||||||
|         group_clusters_disabled |  | ||||||
|         clusters_platforms_eks |  | ||||||
|         clusters_platforms_gke |  | ||||||
|         clusters_platforms_user |  | ||||||
|         clusters_applications_helm |  | ||||||
|         clusters_applications_ingress |  | ||||||
|         clusters_applications_cert_managers |  | ||||||
|         clusters_applications_prometheus |  | ||||||
|         clusters_applications_crossplane |  | ||||||
|         clusters_applications_runner |  | ||||||
|         clusters_applications_knative |  | ||||||
|         clusters_applications_elastic_stack |  | ||||||
|         clusters_applications_jupyter |  | ||||||
|         in_review_folder |  | ||||||
|         grafana_integrated_projects |  | ||||||
|         groups |  | ||||||
|         issues |  | ||||||
|         issues_created_from_gitlab_error_tracking_ui |  | ||||||
|         issues_with_associated_zoom_link |  | ||||||
|         issues_using_zoom_quick_actions |  | ||||||
|         issues_with_embedded_grafana_charts_approx |  | ||||||
|         incident_issues |  | ||||||
|         keys |  | ||||||
|         label_lists |  | ||||||
|         labels |  | ||||||
|         lfs_objects |  | ||||||
|         merge_requests |  | ||||||
|         milestone_lists |  | ||||||
|         milestones |  | ||||||
|         notes |  | ||||||
|         pool_repositories |  | ||||||
|         projects |  | ||||||
|         projects_imported_from_github |  | ||||||
|         projects_asana_active |  | ||||||
|         projects_jira_active |  | ||||||
|         projects_jira_server_active |  | ||||||
|         projects_jira_cloud_active |  | ||||||
|         projects_slack_notifications_active |  | ||||||
|         projects_slack_slash_active |  | ||||||
|         projects_slack_active |  | ||||||
|         projects_slack_slash_commands_active |  | ||||||
|         projects_custom_issue_tracker_active |  | ||||||
|         projects_mattermost_active |  | ||||||
|         projects_prometheus_active |  | ||||||
|         projects_with_repositories_enabled |  | ||||||
|         projects_with_error_tracking_enabled |  | ||||||
|         projects_with_alerts_service_enabled |  | ||||||
|         pages_domains |  | ||||||
|         protected_branches |  | ||||||
|         releases |  | ||||||
|         remote_mirrors |  | ||||||
|         snippets |  | ||||||
|         suggestions |  | ||||||
|         todos |  | ||||||
|         uploads |  | ||||||
|         web_hooks |  | ||||||
|       ).push(*smau_keys) |  | ||||||
| 
 |  | ||||||
|       count_data = subject[:counts] |  | ||||||
| 
 |  | ||||||
|       expect(count_data[:boards]).to eq(1) |  | ||||||
|       expect(count_data[:projects]).to eq(4) |  | ||||||
|       expect(count_data.values_at(*smau_keys)).to all(be_an(Integer)) |  | ||||||
|       expect(count_data.keys).to include(*expected_keys) |  | ||||||
|       expect(expected_keys - count_data.keys).to be_empty |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'gathers projects data correctly', :aggregate_failures do |  | ||||||
|       count_data = subject[:counts] |  | ||||||
| 
 |  | ||||||
|       expect(count_data[:projects]).to eq(4) |  | ||||||
|       expect(count_data[:projects_asana_active]).to eq(0) |  | ||||||
|       expect(count_data[:projects_prometheus_active]).to eq(1) |  | ||||||
|       expect(count_data[:projects_jira_active]).to eq(4) |  | ||||||
|       expect(count_data[:projects_jira_server_active]).to eq(2) |  | ||||||
|       expect(count_data[:projects_jira_cloud_active]).to eq(2) |  | ||||||
|       expect(count_data[:projects_slack_notifications_active]).to eq(2) |  | ||||||
|       expect(count_data[:projects_slack_slash_active]).to eq(1) |  | ||||||
|       expect(count_data[:projects_slack_active]).to eq(2) |  | ||||||
|       expect(count_data[:projects_slack_slash_commands_active]).to eq(1) |  | ||||||
|       expect(count_data[:projects_custom_issue_tracker_active]).to eq(1) |  | ||||||
|       expect(count_data[:projects_mattermost_active]).to eq(0) |  | ||||||
|       expect(count_data[:projects_with_repositories_enabled]).to eq(3) |  | ||||||
|       expect(count_data[:projects_with_error_tracking_enabled]).to eq(1) |  | ||||||
|       expect(count_data[:projects_with_alerts_service_enabled]).to eq(1) |  | ||||||
|       expect(count_data[:issues_created_from_gitlab_error_tracking_ui]).to eq(1) |  | ||||||
|       expect(count_data[:issues_with_associated_zoom_link]).to eq(2) |  | ||||||
|       expect(count_data[:issues_using_zoom_quick_actions]).to eq(3) |  | ||||||
|       expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2) |  | ||||||
|       expect(count_data[:incident_issues]).to eq(4) |  | ||||||
| 
 |  | ||||||
|       expect(count_data[:clusters_enabled]).to eq(4) |  | ||||||
|       expect(count_data[:project_clusters_enabled]).to eq(3) |  | ||||||
|       expect(count_data[:group_clusters_enabled]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_disabled]).to eq(3) |  | ||||||
|       expect(count_data[:project_clusters_disabled]).to eq(1) |  | ||||||
|       expect(count_data[:group_clusters_disabled]).to eq(2) |  | ||||||
|       expect(count_data[:group_clusters_enabled]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_platforms_eks]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_platforms_gke]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_platforms_user]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_helm]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_ingress]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_cert_managers]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_crossplane]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_prometheus]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_runner]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_knative]).to eq(1) |  | ||||||
|       expect(count_data[:clusters_applications_elastic_stack]).to eq(1) |  | ||||||
|       expect(count_data[:grafana_integrated_projects]).to eq(2) |  | ||||||
|       expect(count_data[:clusters_applications_jupyter]).to eq(1) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'works when queries time out' do |  | ||||||
|       allow_any_instance_of(ActiveRecord::Relation) |  | ||||||
|         .to receive(:count).and_raise(ActiveRecord::StatementInvalid.new('')) |  | ||||||
| 
 |  | ||||||
|       expect { subject }.not_to raise_error |  | ||||||
|     end |  | ||||||
|   end |   end | ||||||
| 
 |   [true, false].each do |usage_ping_batch_counter_on| | ||||||
|   describe '#usage_data_counters' do |     describe "when the feature flag usage_ping_batch_counter is set to #{usage_ping_batch_counter_on}" do | ||||||
|     subject { described_class.usage_data_counters } |       before do | ||||||
| 
 |         stub_feature_flags(usage_ping_batch_counter: usage_ping_batch_counter_on) | ||||||
|     it { is_expected.to all(respond_to :totals) } |  | ||||||
| 
 |  | ||||||
|     describe 'the results of calling #totals on all objects in the array' do |  | ||||||
|       subject { described_class.usage_data_counters.map(&:totals) } |  | ||||||
| 
 |  | ||||||
|       it { is_expected.to all(be_a Hash) } |  | ||||||
|       it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) } |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'does not have any conflicts' do |  | ||||||
|       all_keys = subject.flat_map { |counter| counter.totals.keys } |  | ||||||
| 
 |  | ||||||
|       expect(all_keys.size).to eq all_keys.to_set.size |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#features_usage_data_ce' do |  | ||||||
|     subject { described_class.features_usage_data_ce } |  | ||||||
| 
 |  | ||||||
|     it 'gathers feature usage data', :aggregate_failures do |  | ||||||
|       expect(subject[:mattermost_enabled]).to eq(Gitlab.config.mattermost.enabled) |  | ||||||
|       expect(subject[:signup_enabled]).to eq(Gitlab::CurrentSettings.allow_signup?) |  | ||||||
|       expect(subject[:ldap_enabled]).to eq(Gitlab.config.ldap.enabled) |  | ||||||
|       expect(subject[:gravatar_enabled]).to eq(Gitlab::CurrentSettings.gravatar_enabled?) |  | ||||||
|       expect(subject[:omniauth_enabled]).to eq(Gitlab::Auth.omniauth_enabled?) |  | ||||||
|       expect(subject[:reply_by_email_enabled]).to eq(Gitlab::IncomingEmail.enabled?) |  | ||||||
|       expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled) |  | ||||||
|       expect(subject[:dependency_proxy_enabled]).to eq(Gitlab.config.dependency_proxy.enabled) |  | ||||||
|       expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled) |  | ||||||
|       expect(subject[:web_ide_clientside_preview_enabled]).to eq(Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#components_usage_data' do |  | ||||||
|     subject { described_class.components_usage_data } |  | ||||||
| 
 |  | ||||||
|     it 'gathers components usage data', :aggregate_failures do |  | ||||||
|       expect(subject[:gitlab_pages][:enabled]).to eq(Gitlab.config.pages.enabled) |  | ||||||
|       expect(subject[:gitlab_pages][:version]).to eq(Gitlab::Pages::VERSION) |  | ||||||
|       expect(subject[:git][:version]).to eq(Gitlab::Git.version) |  | ||||||
|       expect(subject[:database][:adapter]).to eq(Gitlab::Database.adapter_name) |  | ||||||
|       expect(subject[:database][:version]).to eq(Gitlab::Database.version) |  | ||||||
|       expect(subject[:gitaly][:version]).to be_present |  | ||||||
|       expect(subject[:gitaly][:servers]).to be >= 1 |  | ||||||
|       expect(subject[:gitaly][:filesystems]).to be_an(Array) |  | ||||||
|       expect(subject[:gitaly][:filesystems].first).to be_a(String) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#ingress_modsecurity_usage' do |  | ||||||
|     subject { described_class.ingress_modsecurity_usage } |  | ||||||
| 
 |  | ||||||
|     it 'gathers variable data' do |  | ||||||
|       allow_any_instance_of( |  | ||||||
|         ::Clusters::Applications::IngressModsecurityUsageService |  | ||||||
|       ).to receive(:execute).and_return( |  | ||||||
|         { |  | ||||||
|           ingress_modsecurity_blocking: 1, |  | ||||||
|           ingress_modsecurity_disabled: 2 |  | ||||||
|         } |  | ||||||
|       ) |  | ||||||
| 
 |  | ||||||
|       expect(subject[:ingress_modsecurity_blocking]).to eq(1) |  | ||||||
|       expect(subject[:ingress_modsecurity_disabled]).to eq(2) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#license_usage_data' do |  | ||||||
|     subject { described_class.license_usage_data } |  | ||||||
| 
 |  | ||||||
|     it 'gathers license data', :aggregate_failures do |  | ||||||
|       expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid) |  | ||||||
|       expect(subject[:version]).to eq(Gitlab::VERSION) |  | ||||||
|       expect(subject[:installation_type]).to eq('gitlab-development-kit') |  | ||||||
|       expect(subject[:active_user_count]).to eq(User.active.count) |  | ||||||
|       expect(subject[:recorded_at]).to be_a(Time) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#count' do |  | ||||||
|     let(:relation) { double(:relation) } |  | ||||||
| 
 |  | ||||||
|     it 'returns the count when counting succeeds' do |  | ||||||
|       allow(relation).to receive(:count).and_return(1) |  | ||||||
| 
 |  | ||||||
|       expect(described_class.count(relation)).to eq(1) |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'returns the fallback value when counting fails' do |  | ||||||
|       allow(relation).to receive(:count).and_raise(ActiveRecord::StatementInvalid.new('')) |  | ||||||
| 
 |  | ||||||
|       expect(described_class.count(relation, fallback: 15)).to eq(15) |  | ||||||
|     end |  | ||||||
|   end |  | ||||||
| 
 |  | ||||||
|   describe '#approximate_counts' do |  | ||||||
|     it 'gets approximate counts for selected models', :aggregate_failures do |  | ||||||
|       create(:label) |  | ||||||
| 
 |  | ||||||
|       expect(Gitlab::Database::Count).to receive(:approximate_counts) |  | ||||||
|                                            .with(described_class::APPROXIMATE_COUNT_MODELS).once.and_call_original |  | ||||||
| 
 |  | ||||||
|       counts = described_class.approximate_counts.values |  | ||||||
| 
 |  | ||||||
|       expect(counts.count).to eq(described_class::APPROXIMATE_COUNT_MODELS.count) |  | ||||||
|       expect(counts.any? { |count| count < 0 }).to be_falsey |  | ||||||
|     end |  | ||||||
| 
 |  | ||||||
|     it 'returns default values if counts can not be retrieved', :aggregate_failures do |  | ||||||
|       described_class::APPROXIMATE_COUNT_MODELS.map do |model| |  | ||||||
|         model.name.underscore.pluralize.to_sym |  | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       expect(Gitlab::Database::Count).to receive(:approximate_counts).and_return({}) |       describe '#data' do | ||||||
|       expect(described_class.approximate_counts.values.uniq).to eq([-1]) |         before do | ||||||
|  |           create(:jira_service, project: projects[0]) | ||||||
|  |           create(:jira_service, :without_properties_callback, project: projects[1]) | ||||||
|  |           create(:jira_service, :jira_cloud_service, project: projects[2]) | ||||||
|  |           create(:jira_service, :without_properties_callback, project: projects[3], | ||||||
|  |                  properties: { url: 'https://mysite.atlassian.net' }) | ||||||
|  |           create(:prometheus_service, project: projects[1]) | ||||||
|  |           create(:service, project: projects[0], type: 'SlackSlashCommandsService', active: true) | ||||||
|  |           create(:service, project: projects[1], type: 'SlackService', active: true) | ||||||
|  |           create(:service, project: projects[2], type: 'SlackService', active: true) | ||||||
|  |           create(:service, project: projects[2], type: 'MattermostService', active: false) | ||||||
|  |           create(:service, project: projects[2], type: 'MattermostService', active: true, template: true) | ||||||
|  |           create(:service, project: projects[2], type: 'CustomIssueTrackerService', active: true) | ||||||
|  |           create(:project_error_tracking_setting, project: projects[0]) | ||||||
|  |           create(:project_error_tracking_setting, project: projects[1], enabled: false) | ||||||
|  |           create(:alerts_service, project: projects[0]) | ||||||
|  |           create(:alerts_service, :inactive, project: projects[1]) | ||||||
|  |           create_list(:issue, 2, project: projects[0], author: User.alert_bot) | ||||||
|  |           create_list(:issue, 2, project: projects[1], author: User.alert_bot) | ||||||
|  |           create_list(:issue, 4, project: projects[0]) | ||||||
|  |           create(:zoom_meeting, project: projects[0], issue: projects[0].issues[0], issue_status: :added) | ||||||
|  |           create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[1], issue_status: :removed) | ||||||
|  |           create(:zoom_meeting, project: projects[0], issue: projects[0].issues[2], issue_status: :added) | ||||||
|  |           create_list(:zoom_meeting, 2, project: projects[0], issue: projects[0].issues[2], issue_status: :removed) | ||||||
|  |           create(:sentry_issue, issue: projects[0].issues[0]) | ||||||
|  | 
 | ||||||
|  |           # Enabled clusters | ||||||
|  |           gcp_cluster = create(:cluster_provider_gcp, :created).cluster | ||||||
|  |           create(:cluster_provider_aws, :created) | ||||||
|  |           create(:cluster_platform_kubernetes) | ||||||
|  |           create(:cluster, :group) | ||||||
|  | 
 | ||||||
|  |           # Disabled clusters | ||||||
|  |           create(:cluster, :disabled) | ||||||
|  |           create(:cluster, :group, :disabled) | ||||||
|  |           create(:cluster, :group, :disabled) | ||||||
|  | 
 | ||||||
|  |           # Applications | ||||||
|  |           create(:clusters_applications_helm, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_ingress, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_cert_manager, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_prometheus, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_crossplane, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_runner, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_knative, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_elastic_stack, :installed, cluster: gcp_cluster) | ||||||
|  |           create(:clusters_applications_jupyter, :installed, cluster: gcp_cluster) | ||||||
|  | 
 | ||||||
|  |           create(:grafana_integration, project: projects[0], enabled: true) | ||||||
|  |           create(:grafana_integration, project: projects[1], enabled: true) | ||||||
|  |           create(:grafana_integration, project: projects[2], enabled: false) | ||||||
|  | 
 | ||||||
|  |           allow(Gitlab::GrafanaEmbedUsageData).to receive(:issue_count).and_return(2) | ||||||
|  | 
 | ||||||
|  |           ProjectFeature.first.update_attribute('repository_access_level', 0) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         subject { described_class.data } | ||||||
|  | 
 | ||||||
|  |         it 'gathers usage data', :aggregate_failures do | ||||||
|  |           expect(subject.keys).to include(*%i( | ||||||
|  |             active_user_count | ||||||
|  |             counts | ||||||
|  |             recorded_at | ||||||
|  |             edition | ||||||
|  |             version | ||||||
|  |             installation_type | ||||||
|  |             uuid | ||||||
|  |             hostname | ||||||
|  |             mattermost_enabled | ||||||
|  |             signup_enabled | ||||||
|  |             ldap_enabled | ||||||
|  |             gravatar_enabled | ||||||
|  |             omniauth_enabled | ||||||
|  |             reply_by_email_enabled | ||||||
|  |             container_registry_enabled | ||||||
|  |             dependency_proxy_enabled | ||||||
|  |             gitlab_shared_runners_enabled | ||||||
|  |             gitlab_pages | ||||||
|  |             git | ||||||
|  |             gitaly | ||||||
|  |             database | ||||||
|  |             avg_cycle_analytics | ||||||
|  |             influxdb_metrics_enabled | ||||||
|  |             prometheus_metrics_enabled | ||||||
|  |             web_ide_clientside_preview_enabled | ||||||
|  |             ingress_modsecurity_enabled | ||||||
|  |           )) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         it 'gathers usage counts' do | ||||||
|  |           smau_keys = %i( | ||||||
|  |             snippet_create | ||||||
|  |             snippet_update | ||||||
|  |             snippet_comment | ||||||
|  |             merge_request_comment | ||||||
|  |             merge_request_create | ||||||
|  |             commit_comment | ||||||
|  |             wiki_pages_create | ||||||
|  |             wiki_pages_update | ||||||
|  |             wiki_pages_delete | ||||||
|  |             web_ide_views | ||||||
|  |             web_ide_commits | ||||||
|  |             web_ide_merge_requests | ||||||
|  |             web_ide_previews | ||||||
|  |             navbar_searches | ||||||
|  |             cycle_analytics_views | ||||||
|  |             productivity_analytics_views | ||||||
|  |             source_code_pushes | ||||||
|  |           ) | ||||||
|  | 
 | ||||||
|  |           expected_keys = %i( | ||||||
|  |             assignee_lists | ||||||
|  |             boards | ||||||
|  |             ci_builds | ||||||
|  |             ci_internal_pipelines | ||||||
|  |             ci_external_pipelines | ||||||
|  |             ci_pipeline_config_auto_devops | ||||||
|  |             ci_pipeline_config_repository | ||||||
|  |             ci_runners | ||||||
|  |             ci_triggers | ||||||
|  |             ci_pipeline_schedules | ||||||
|  |             auto_devops_enabled | ||||||
|  |             auto_devops_disabled | ||||||
|  |             deploy_keys | ||||||
|  |             deployments | ||||||
|  |             successful_deployments | ||||||
|  |             failed_deployments | ||||||
|  |             environments | ||||||
|  |             clusters | ||||||
|  |             clusters_enabled | ||||||
|  |             project_clusters_enabled | ||||||
|  |             group_clusters_enabled | ||||||
|  |             clusters_disabled | ||||||
|  |             project_clusters_disabled | ||||||
|  |             group_clusters_disabled | ||||||
|  |             clusters_platforms_eks | ||||||
|  |             clusters_platforms_gke | ||||||
|  |             clusters_platforms_user | ||||||
|  |             clusters_applications_helm | ||||||
|  |             clusters_applications_ingress | ||||||
|  |             clusters_applications_cert_managers | ||||||
|  |             clusters_applications_prometheus | ||||||
|  |             clusters_applications_crossplane | ||||||
|  |             clusters_applications_runner | ||||||
|  |             clusters_applications_knative | ||||||
|  |             clusters_applications_elastic_stack | ||||||
|  |             clusters_applications_jupyter | ||||||
|  |             in_review_folder | ||||||
|  |             grafana_integrated_projects | ||||||
|  |             groups | ||||||
|  |             issues | ||||||
|  |             issues_created_from_gitlab_error_tracking_ui | ||||||
|  |             issues_with_associated_zoom_link | ||||||
|  |             issues_using_zoom_quick_actions | ||||||
|  |             issues_with_embedded_grafana_charts_approx | ||||||
|  |             incident_issues | ||||||
|  |             keys | ||||||
|  |             label_lists | ||||||
|  |             labels | ||||||
|  |             lfs_objects | ||||||
|  |             merge_requests | ||||||
|  |             milestone_lists | ||||||
|  |             milestones | ||||||
|  |             notes | ||||||
|  |             pool_repositories | ||||||
|  |             projects | ||||||
|  |             projects_imported_from_github | ||||||
|  |             projects_asana_active | ||||||
|  |             projects_jira_active | ||||||
|  |             projects_jira_server_active | ||||||
|  |             projects_jira_cloud_active | ||||||
|  |             projects_slack_notifications_active | ||||||
|  |             projects_slack_slash_active | ||||||
|  |             projects_slack_active | ||||||
|  |             projects_slack_slash_commands_active | ||||||
|  |             projects_custom_issue_tracker_active | ||||||
|  |             projects_mattermost_active | ||||||
|  |             projects_prometheus_active | ||||||
|  |             projects_with_repositories_enabled | ||||||
|  |             projects_with_error_tracking_enabled | ||||||
|  |             projects_with_alerts_service_enabled | ||||||
|  |             pages_domains | ||||||
|  |             protected_branches | ||||||
|  |             releases | ||||||
|  |             remote_mirrors | ||||||
|  |             snippets | ||||||
|  |             suggestions | ||||||
|  |             todos | ||||||
|  |             uploads | ||||||
|  |             web_hooks | ||||||
|  |           ).push(*smau_keys) | ||||||
|  | 
 | ||||||
|  |           count_data = subject[:counts] | ||||||
|  | 
 | ||||||
|  |           expect(count_data[:boards]).to eq(1) | ||||||
|  |           expect(count_data[:projects]).to eq(4) | ||||||
|  |           expect(count_data.values_at(*smau_keys)).to all(be_an(Integer)) | ||||||
|  |           expect(count_data.keys).to include(*expected_keys) | ||||||
|  |           expect(expected_keys - count_data.keys).to be_empty | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         it 'gathers projects data correctly', :aggregate_failures do | ||||||
|  |           count_data = subject[:counts] | ||||||
|  | 
 | ||||||
|  |           expect(count_data[:projects]).to eq(4) | ||||||
|  |           expect(count_data[:projects_asana_active]).to eq(0) | ||||||
|  |           expect(count_data[:projects_prometheus_active]).to eq(1) | ||||||
|  |           expect(count_data[:projects_jira_active]).to eq(4) | ||||||
|  |           expect(count_data[:projects_jira_server_active]).to eq(2) | ||||||
|  |           expect(count_data[:projects_jira_cloud_active]).to eq(2) | ||||||
|  |           expect(count_data[:projects_slack_notifications_active]).to eq(2) | ||||||
|  |           expect(count_data[:projects_slack_slash_active]).to eq(1) | ||||||
|  |           expect(count_data[:projects_slack_active]).to eq(2) | ||||||
|  |           expect(count_data[:projects_slack_slash_commands_active]).to eq(1) | ||||||
|  |           expect(count_data[:projects_custom_issue_tracker_active]).to eq(1) | ||||||
|  |           expect(count_data[:projects_mattermost_active]).to eq(0) | ||||||
|  |           expect(count_data[:projects_with_repositories_enabled]).to eq(3) | ||||||
|  |           expect(count_data[:projects_with_error_tracking_enabled]).to eq(1) | ||||||
|  |           expect(count_data[:projects_with_alerts_service_enabled]).to eq(1) | ||||||
|  |           expect(count_data[:issues_created_from_gitlab_error_tracking_ui]).to eq(1) | ||||||
|  |           expect(count_data[:issues_with_associated_zoom_link]).to eq(2) | ||||||
|  |           expect(count_data[:issues_using_zoom_quick_actions]).to eq(3) | ||||||
|  |           expect(count_data[:issues_with_embedded_grafana_charts_approx]).to eq(2) | ||||||
|  |           expect(count_data[:incident_issues]).to eq(4) | ||||||
|  | 
 | ||||||
|  |           expect(count_data[:clusters_enabled]).to eq(4) | ||||||
|  |           expect(count_data[:project_clusters_enabled]).to eq(3) | ||||||
|  |           expect(count_data[:group_clusters_enabled]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_disabled]).to eq(3) | ||||||
|  |           expect(count_data[:project_clusters_disabled]).to eq(1) | ||||||
|  |           expect(count_data[:group_clusters_disabled]).to eq(2) | ||||||
|  |           expect(count_data[:group_clusters_enabled]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_platforms_eks]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_platforms_gke]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_platforms_user]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_helm]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_ingress]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_cert_managers]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_crossplane]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_prometheus]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_runner]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_knative]).to eq(1) | ||||||
|  |           expect(count_data[:clusters_applications_elastic_stack]).to eq(1) | ||||||
|  |           expect(count_data[:grafana_integrated_projects]).to eq(2) | ||||||
|  |           expect(count_data[:clusters_applications_jupyter]).to eq(1) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         it 'works when queries time out' do | ||||||
|  |           allow_any_instance_of(ActiveRecord::Relation) | ||||||
|  |             .to receive(:count).and_raise(ActiveRecord::StatementInvalid.new('')) | ||||||
|  | 
 | ||||||
|  |           expect { subject }.not_to raise_error | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       describe '#usage_data_counters' do | ||||||
|  |         subject { described_class.usage_data_counters } | ||||||
|  | 
 | ||||||
|  |         it { is_expected.to all(respond_to :totals) } | ||||||
|  | 
 | ||||||
|  |         describe 'the results of calling #totals on all objects in the array' do | ||||||
|  |           subject { described_class.usage_data_counters.map(&:totals) } | ||||||
|  | 
 | ||||||
|  |           it { is_expected.to all(be_a Hash) } | ||||||
|  |           it { is_expected.to all(have_attributes(keys: all(be_a Symbol), values: all(be_a Integer))) } | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         it 'does not have any conflicts' do | ||||||
|  |           all_keys = subject.flat_map { |counter| counter.totals.keys } | ||||||
|  | 
 | ||||||
|  |           expect(all_keys.size).to eq all_keys.to_set.size | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       describe '#features_usage_data_ce' do | ||||||
|  |         subject { described_class.features_usage_data_ce } | ||||||
|  | 
 | ||||||
|  |         it 'gathers feature usage data', :aggregate_failures do | ||||||
|  |           expect(subject[:mattermost_enabled]).to eq(Gitlab.config.mattermost.enabled) | ||||||
|  |           expect(subject[:signup_enabled]).to eq(Gitlab::CurrentSettings.allow_signup?) | ||||||
|  |           expect(subject[:ldap_enabled]).to eq(Gitlab.config.ldap.enabled) | ||||||
|  |           expect(subject[:gravatar_enabled]).to eq(Gitlab::CurrentSettings.gravatar_enabled?) | ||||||
|  |           expect(subject[:omniauth_enabled]).to eq(Gitlab::Auth.omniauth_enabled?) | ||||||
|  |           expect(subject[:reply_by_email_enabled]).to eq(Gitlab::IncomingEmail.enabled?) | ||||||
|  |           expect(subject[:container_registry_enabled]).to eq(Gitlab.config.registry.enabled) | ||||||
|  |           expect(subject[:dependency_proxy_enabled]).to eq(Gitlab.config.dependency_proxy.enabled) | ||||||
|  |           expect(subject[:gitlab_shared_runners_enabled]).to eq(Gitlab.config.gitlab_ci.shared_runners_enabled) | ||||||
|  |           expect(subject[:web_ide_clientside_preview_enabled]).to eq(Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       describe '#components_usage_data' do | ||||||
|  |         subject { described_class.components_usage_data } | ||||||
|  | 
 | ||||||
|  |         it 'gathers components usage data', :aggregate_failures do | ||||||
|  |           expect(subject[:gitlab_pages][:enabled]).to eq(Gitlab.config.pages.enabled) | ||||||
|  |           expect(subject[:gitlab_pages][:version]).to eq(Gitlab::Pages::VERSION) | ||||||
|  |           expect(subject[:git][:version]).to eq(Gitlab::Git.version) | ||||||
|  |           expect(subject[:database][:adapter]).to eq(Gitlab::Database.adapter_name) | ||||||
|  |           expect(subject[:database][:version]).to eq(Gitlab::Database.version) | ||||||
|  |           expect(subject[:gitaly][:version]).to be_present | ||||||
|  |           expect(subject[:gitaly][:servers]).to be >= 1 | ||||||
|  |           expect(subject[:gitaly][:filesystems]).to be_an(Array) | ||||||
|  |           expect(subject[:gitaly][:filesystems].first).to be_a(String) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       describe '#ingress_modsecurity_usage' do | ||||||
|  |         subject { described_class.ingress_modsecurity_usage } | ||||||
|  | 
 | ||||||
|  |         it 'gathers variable data' do | ||||||
|  |           allow_any_instance_of( | ||||||
|  |             ::Clusters::Applications::IngressModsecurityUsageService | ||||||
|  |           ).to receive(:execute).and_return( | ||||||
|  |             { | ||||||
|  |               ingress_modsecurity_blocking: 1, | ||||||
|  |               ingress_modsecurity_disabled: 2 | ||||||
|  |             } | ||||||
|  |           ) | ||||||
|  | 
 | ||||||
|  |           expect(subject[:ingress_modsecurity_blocking]).to eq(1) | ||||||
|  |           expect(subject[:ingress_modsecurity_disabled]).to eq(2) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       describe '#license_usage_data' do | ||||||
|  |         subject { described_class.license_usage_data } | ||||||
|  | 
 | ||||||
|  |         it 'gathers license data', :aggregate_failures do | ||||||
|  |           expect(subject[:uuid]).to eq(Gitlab::CurrentSettings.uuid) | ||||||
|  |           expect(subject[:version]).to eq(Gitlab::VERSION) | ||||||
|  |           expect(subject[:installation_type]).to eq('gitlab-development-kit') | ||||||
|  |           expect(subject[:active_user_count]).to eq(User.active.count) | ||||||
|  |           expect(subject[:recorded_at]).to be_a(Time) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       describe '#count' do | ||||||
|  |         let(:relation) { double(:relation) } | ||||||
|  | 
 | ||||||
|  |         it 'returns the count when counting succeeds' do | ||||||
|  |           allow(relation).to receive(:count).and_return(1) | ||||||
|  | 
 | ||||||
|  |           expect(described_class.count(relation, batch: false)).to eq(1) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         it 'returns the fallback value when counting fails' do | ||||||
|  |           allow(relation).to receive(:count).and_raise(ActiveRecord::StatementInvalid.new('')) | ||||||
|  | 
 | ||||||
|  |           expect(described_class.count(relation, fallback: 15, batch: false)).to eq(15) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       describe '#approximate_counts' do | ||||||
|  |         it 'gets approximate counts for selected models', :aggregate_failures do | ||||||
|  |           create(:label) | ||||||
|  | 
 | ||||||
|  |           expect(Gitlab::Database::Count).to receive(:approximate_counts) | ||||||
|  |                                                .with(described_class::APPROXIMATE_COUNT_MODELS).once.and_call_original | ||||||
|  | 
 | ||||||
|  |           counts = described_class.approximate_counts.values | ||||||
|  | 
 | ||||||
|  |           expect(counts.count).to eq(described_class::APPROXIMATE_COUNT_MODELS.count) | ||||||
|  |           expect(counts.any? { |count| count < 0 }).to be_falsey | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         it 'returns default values if counts can not be retrieved', :aggregate_failures do | ||||||
|  |           described_class::APPROXIMATE_COUNT_MODELS.map do |model| | ||||||
|  |             model.name.underscore.pluralize.to_sym | ||||||
|  |           end | ||||||
|  | 
 | ||||||
|  |           expect(Gitlab::Database::Count).to receive(:approximate_counts).and_return({}) | ||||||
|  |           expect(described_class.approximate_counts.values.uniq).to eq([-1]) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -35,6 +35,7 @@ describe ChatNotificationService do | ||||||
|     let(:user) { create(:user) } |     let(:user) { create(:user) } | ||||||
|     let(:project) { create(:project, :repository) } |     let(:project) { create(:project, :repository) } | ||||||
|     let(:webhook_url) { 'https://example.gitlab.com/' } |     let(:webhook_url) { 'https://example.gitlab.com/' } | ||||||
|  |     let(:data) { Gitlab::DataBuilder::Push.build_sample(subject.project, user) } | ||||||
| 
 | 
 | ||||||
|     before do |     before do | ||||||
|       allow(chat_service).to receive_messages( |       allow(chat_service).to receive_messages( | ||||||
|  | @ -51,9 +52,6 @@ describe ChatNotificationService do | ||||||
| 
 | 
 | ||||||
|     context 'with a repository' do |     context 'with a repository' do | ||||||
|       it 'returns true' do |       it 'returns true' do | ||||||
|         subject.project = project |  | ||||||
|         data = Gitlab::DataBuilder::Push.build_sample(project, user) |  | ||||||
| 
 |  | ||||||
|         expect(chat_service).to receive(:notify).and_return(true) |         expect(chat_service).to receive(:notify).and_return(true) | ||||||
|         expect(chat_service.execute(data)).to be true |         expect(chat_service.execute(data)).to be true | ||||||
|       end |       end | ||||||
|  | @ -62,11 +60,19 @@ describe ChatNotificationService do | ||||||
|     context 'with an empty repository' do |     context 'with an empty repository' do | ||||||
|       it 'returns true' do |       it 'returns true' do | ||||||
|         subject.project = create(:project, :empty_repo) |         subject.project = create(:project, :empty_repo) | ||||||
|         data = Gitlab::DataBuilder::Push.build_sample(subject.project, user) |  | ||||||
| 
 | 
 | ||||||
|         expect(chat_service).to receive(:notify).and_return(true) |         expect(chat_service).to receive(:notify).and_return(true) | ||||||
|         expect(chat_service.execute(data)).to be true |         expect(chat_service.execute(data)).to be true | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | 
 | ||||||
|  |     context 'with a project with name containing spaces' do | ||||||
|  |       it 'does not remove spaces' do | ||||||
|  |         allow(project).to receive(:full_name).and_return('Project Name') | ||||||
|  | 
 | ||||||
|  |         expect(chat_service).to receive(:get_message).with(any_args, hash_including(project_name: 'Project Name')) | ||||||
|  |         chat_service.execute(data) | ||||||
|  |       end | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -29,7 +29,7 @@ describe 'Milestones through GroupQuery' do | ||||||
|       it_behaves_like 'a working graphql query' |       it_behaves_like 'a working graphql query' | ||||||
| 
 | 
 | ||||||
|       it 'returns milestones successfully' do |       it 'returns milestones successfully' do | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(graphql_errors).to be_nil |         expect(graphql_errors).to be_nil | ||||||
|         expect_array_response(milestone_1.to_global_id.to_s, milestone_2.to_global_id.to_s, milestone_3.to_global_id.to_s, milestone_4.to_global_id.to_s) |         expect_array_response(milestone_1.to_global_id.to_s, milestone_2.to_global_id.to_s, milestone_3.to_global_id.to_s, milestone_4.to_global_id.to_s) | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -55,7 +55,7 @@ describe 'getting group information' do | ||||||
| 
 | 
 | ||||||
|         post_graphql(group_query(group1), current_user: user1) |         post_graphql(group_query(group1), current_user: user1) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(graphql_data['group']['id']).to eq(group1.to_global_id.to_s) |         expect(graphql_data['group']['id']).to eq(group1.to_global_id.to_s) | ||||||
|         expect(graphql_data['group']['name']).to eq(group1.name) |         expect(graphql_data['group']['name']).to eq(group1.name) | ||||||
|         expect(graphql_data['group']['path']).to eq(group1.path) |         expect(graphql_data['group']['path']).to eq(group1.path) | ||||||
|  |  | ||||||
|  | @ -33,7 +33,7 @@ describe 'getting task completion status information' do | ||||||
|     it 'returns the expected task completion status' do |     it 'returns the expected task completion status' do | ||||||
|       post_graphql(create_task_completion_status_query_for(type, item.iid), current_user: user1) |       post_graphql(create_task_completion_status_query_for(type, item.iid), current_user: user1) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       task_completion_status = graphql_data.dig('project', type, 'taskCompletionStatus') |       task_completion_status = graphql_data.dig('project', type, 'taskCompletionStatus') | ||||||
|       expect(task_completion_status).not_to be_nil |       expect(task_completion_status).not_to be_nil | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|       get api("/internal/check"), params: { secret_token: secret_token } |       get api("/internal/check"), params: { secret_token: secret_token } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['api_version']).to eq(API::API.version) |       expect(json_response['api_version']).to eq(API::API.version) | ||||||
|       expect(json_response['redis']).to be(true) |       expect(json_response['redis']).to be(true) | ||||||
|     end |     end | ||||||
|  | @ -34,13 +34,13 @@ describe API::Internal::Base do | ||||||
|         get api("/internal/check"), |         get api("/internal/check"), | ||||||
|             headers: { API::Helpers::GITLAB_SHARED_SECRET_HEADER => Base64.encode64(secret_token) } |             headers: { API::Helpers::GITLAB_SHARED_SECRET_HEADER => Base64.encode64(secret_token) } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns 401 when no credentials provided' do |       it 'returns 401 when no credentials provided' do | ||||||
|         get(api("/internal/check")) |         get(api("/internal/check")) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(401) |         expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | @ -126,7 +126,7 @@ describe API::Internal::Base do | ||||||
|       it 'returns the correct information about the key' do |       it 'returns the correct information about the key' do | ||||||
|         lfs_auth_key(key.id, project) |         lfs_auth_key(key.id, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['username']).to eq(user.username) |         expect(json_response['username']).to eq(user.username) | ||||||
|         expect(json_response['repository_http_path']).to eq(project.http_url_to_repo) |         expect(json_response['repository_http_path']).to eq(project.http_url_to_repo) | ||||||
|         expect(json_response['expires_in']).to eq(Gitlab::LfsToken::DEFAULT_EXPIRE_TIME) |         expect(json_response['expires_in']).to eq(Gitlab::LfsToken::DEFAULT_EXPIRE_TIME) | ||||||
|  | @ -136,7 +136,7 @@ describe API::Internal::Base do | ||||||
|       it 'returns the correct information about the user' do |       it 'returns the correct information about the user' do | ||||||
|         lfs_auth_user(user.id, project) |         lfs_auth_user(user.id, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['username']).to eq(user.username) |         expect(json_response['username']).to eq(user.username) | ||||||
|         expect(json_response['repository_http_path']).to eq(project.http_url_to_repo) |         expect(json_response['repository_http_path']).to eq(project.http_url_to_repo) | ||||||
|         expect(Gitlab::LfsToken.new(user).token_valid?(json_response['lfs_token'])).to be_truthy |         expect(Gitlab::LfsToken.new(user).token_valid?(json_response['lfs_token'])).to be_truthy | ||||||
|  | @ -145,19 +145,19 @@ describe API::Internal::Base do | ||||||
|       it 'returns a 404 when no key or user is provided' do |       it 'returns a 404 when no key or user is provided' do | ||||||
|         lfs_auth_project(project) |         lfs_auth_project(project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns a 404 when the wrong key is provided' do |       it 'returns a 404 when the wrong key is provided' do | ||||||
|         lfs_auth_key(key.id + 12345, project) |         lfs_auth_key(key.id + 12345, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns a 404 when the wrong user is provided' do |       it 'returns a 404 when the wrong user is provided' do | ||||||
|         lfs_auth_user(user.id + 12345, project) |         lfs_auth_user(user.id + 12345, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -167,7 +167,7 @@ describe API::Internal::Base do | ||||||
|       it 'returns the correct information about the key' do |       it 'returns the correct information about the key' do | ||||||
|         lfs_auth_key(key.id, project) |         lfs_auth_key(key.id, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['username']).to eq("lfs+deploy-key-#{key.id}") |         expect(json_response['username']).to eq("lfs+deploy-key-#{key.id}") | ||||||
|         expect(json_response['repository_http_path']).to eq(project.http_url_to_repo) |         expect(json_response['repository_http_path']).to eq(project.http_url_to_repo) | ||||||
|         expect(Gitlab::LfsToken.new(key).token_valid?(json_response['lfs_token'])).to be_truthy |         expect(Gitlab::LfsToken.new(key).token_valid?(json_response['lfs_token'])).to be_truthy | ||||||
|  | @ -179,7 +179,7 @@ describe API::Internal::Base do | ||||||
|     it "finds a user by key id" do |     it "finds a user by key id" do | ||||||
|       get(api("/internal/discover"), params: { key_id: key.id, secret_token: secret_token }) |       get(api("/internal/discover"), params: { key_id: key.id, secret_token: secret_token }) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(json_response['name']).to eq(user.name) |       expect(json_response['name']).to eq(user.name) | ||||||
|     end |     end | ||||||
|  | @ -187,7 +187,7 @@ describe API::Internal::Base do | ||||||
|     it "finds a user by username" do |     it "finds a user by username" do | ||||||
|       get(api("/internal/discover"), params: { username: user.username, secret_token: secret_token }) |       get(api("/internal/discover"), params: { username: user.username, secret_token: secret_token }) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(json_response['name']).to eq(user.name) |       expect(json_response['name']).to eq(user.name) | ||||||
|     end |     end | ||||||
|  | @ -195,7 +195,7 @@ describe API::Internal::Base do | ||||||
|     it 'responds successfully when a user is not found' do |     it 'responds successfully when a user is not found' do | ||||||
|       get(api('/internal/discover'), params: { username: 'noone', secret_token: secret_token }) |       get(api('/internal/discover'), params: { username: 'noone', secret_token: secret_token }) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(response.body).to eq('null') |       expect(response.body).to eq('null') | ||||||
|     end |     end | ||||||
|  | @ -203,7 +203,7 @@ describe API::Internal::Base do | ||||||
|     it 'response successfully when passing invalid params' do |     it 'response successfully when passing invalid params' do | ||||||
|       get(api('/internal/discover'), params: { nothing: 'to find a user', secret_token: secret_token }) |       get(api('/internal/discover'), params: { nothing: 'to find a user', secret_token: secret_token }) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(response.body).to eq('null') |       expect(response.body).to eq('null') | ||||||
|     end |     end | ||||||
|  | @ -284,7 +284,7 @@ describe API::Internal::Base do | ||||||
|             GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE: alt_obj_dirs_relative |             GIT_ALTERNATE_OBJECT_DIRECTORIES_RELATIVE: alt_obj_dirs_relative | ||||||
|           }.to_json) |           }.to_json) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(200) |           expect(response).to have_gitlab_http_status(:ok) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -292,7 +292,7 @@ describe API::Internal::Base do | ||||||
|         it 'responds with success' do |         it 'responds with success' do | ||||||
|           push(key, project.wiki) |           push(key, project.wiki) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(200) |           expect(response).to have_gitlab_http_status(:ok) | ||||||
|           expect(json_response["status"]).to be_truthy |           expect(json_response["status"]).to be_truthy | ||||||
|           expect(json_response["gl_project_path"]).to eq(project.wiki.full_path) |           expect(json_response["gl_project_path"]).to eq(project.wiki.full_path) | ||||||
|           expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") |           expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") | ||||||
|  | @ -304,7 +304,7 @@ describe API::Internal::Base do | ||||||
|         it 'responds with success' do |         it 'responds with success' do | ||||||
|           pull(key, project.wiki) |           pull(key, project.wiki) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(200) |           expect(response).to have_gitlab_http_status(:ok) | ||||||
|           expect(json_response["status"]).to be_truthy |           expect(json_response["status"]).to be_truthy | ||||||
|           expect(json_response["gl_project_path"]).to eq(project.wiki.full_path) |           expect(json_response["gl_project_path"]).to eq(project.wiki.full_path) | ||||||
|           expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") |           expect(json_response["gl_repository"]).to eq("wiki-#{project.id}") | ||||||
|  | @ -320,7 +320,7 @@ describe API::Internal::Base do | ||||||
|         it "has the correct payload" do |         it "has the correct payload" do | ||||||
|           pull(key, project) |           pull(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(200) |           expect(response).to have_gitlab_http_status(:ok) | ||||||
|           expect(json_response["status"]).to be_truthy |           expect(json_response["status"]).to be_truthy | ||||||
|           expect(json_response["gl_repository"]).to eq("project-#{project.id}") |           expect(json_response["gl_repository"]).to eq("project-#{project.id}") | ||||||
|           expect(json_response["gl_project_path"]).to eq(project.full_path) |           expect(json_response["gl_project_path"]).to eq(project.full_path) | ||||||
|  | @ -340,7 +340,7 @@ describe API::Internal::Base do | ||||||
|           it do |           it do | ||||||
|             push(key, project) |             push(key, project) | ||||||
| 
 | 
 | ||||||
|             expect(response).to have_gitlab_http_status(200) |             expect(response).to have_gitlab_http_status(:ok) | ||||||
|             expect(json_response["status"]).to be_truthy |             expect(json_response["status"]).to be_truthy | ||||||
|             expect(json_response["gl_repository"]).to eq("project-#{project.id}") |             expect(json_response["gl_repository"]).to eq("project-#{project.id}") | ||||||
|             expect(json_response["gl_project_path"]).to eq(project.full_path) |             expect(json_response["gl_project_path"]).to eq(project.full_path) | ||||||
|  | @ -409,7 +409,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           pull(key, project) |           pull(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|           expect(json_response["status"]).to be_falsey |           expect(json_response["status"]).to be_falsey | ||||||
|           expect(user.reload.last_activity_on).to be_nil |           expect(user.reload.last_activity_on).to be_nil | ||||||
|         end |         end | ||||||
|  | @ -419,7 +419,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           push(key, project) |           push(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|           expect(json_response["status"]).to be_falsey |           expect(json_response["status"]).to be_falsey | ||||||
|           expect(user.reload.last_activity_on).to be_nil |           expect(user.reload.last_activity_on).to be_nil | ||||||
|         end |         end | ||||||
|  | @ -464,7 +464,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           push(key, project) |           push(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(300) |           expect(response).to have_gitlab_http_status(:multiple_choices) | ||||||
|           expect(json_response['status']).to be_truthy |           expect(json_response['status']).to be_truthy | ||||||
|           expect(json_response['payload']).to eql(payload) |           expect(json_response['payload']).to eql(payload) | ||||||
|           expect(json_response['gl_console_messages']).to eql(console_messages) |           expect(json_response['gl_console_messages']).to eql(console_messages) | ||||||
|  | @ -483,7 +483,7 @@ describe API::Internal::Base do | ||||||
|           it "has the correct payload" do |           it "has the correct payload" do | ||||||
|             pull(key, project) |             pull(key, project) | ||||||
| 
 | 
 | ||||||
|             expect(response).to have_gitlab_http_status(200) |             expect(response).to have_gitlab_http_status(:ok) | ||||||
|             expect(json_response['gl_console_messages']).to eq([]) |             expect(json_response['gl_console_messages']).to eq([]) | ||||||
|           end |           end | ||||||
|         end |         end | ||||||
|  | @ -500,7 +500,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|             pull(key, project) |             pull(key, project) | ||||||
| 
 | 
 | ||||||
|             expect(response).to have_gitlab_http_status(200) |             expect(response).to have_gitlab_http_status(:ok) | ||||||
|             expect(json_response['gl_console_messages']).to eq(console_messages) |             expect(json_response['gl_console_messages']).to eq(console_messages) | ||||||
|           end |           end | ||||||
|         end |         end | ||||||
|  | @ -518,7 +518,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           pull(key, personal_project) |           pull(key, personal_project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|           expect(json_response["status"]).to be_falsey |           expect(json_response["status"]).to be_falsey | ||||||
|           expect(user.reload.last_activity_on).to be_nil |           expect(user.reload.last_activity_on).to be_nil | ||||||
|         end |         end | ||||||
|  | @ -528,7 +528,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           push(key, personal_project) |           push(key, personal_project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|           expect(json_response["status"]).to be_falsey |           expect(json_response["status"]).to be_falsey | ||||||
|           expect(user.reload.last_activity_on).to be_nil |           expect(user.reload.last_activity_on).to be_nil | ||||||
|         end |         end | ||||||
|  | @ -545,7 +545,7 @@ describe API::Internal::Base do | ||||||
|           end |           end | ||||||
|           push(key, personal_project) |           push(key, personal_project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(503) |           expect(response).to have_gitlab_http_status(:service_unavailable) | ||||||
|           expect(json_response['status']).to be_falsey |           expect(json_response['status']).to be_falsey | ||||||
|           expect(json_response['message']).to eq("Foo") |           expect(json_response['message']).to eq("Foo") | ||||||
|           expect(user.reload.last_activity_on).to be_nil |           expect(user.reload.last_activity_on).to be_nil | ||||||
|  | @ -563,7 +563,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           pull(key, project) |           pull(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(200) |           expect(response).to have_gitlab_http_status(:ok) | ||||||
|           expect(json_response["status"]).to be_truthy |           expect(json_response["status"]).to be_truthy | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -572,7 +572,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           push(key, project) |           push(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|           expect(json_response["status"]).to be_falsey |           expect(json_response["status"]).to be_falsey | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -589,7 +589,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           archive(key, project) |           archive(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(200) |           expect(response).to have_gitlab_http_status(:ok) | ||||||
|           expect(json_response["status"]).to be_truthy |           expect(json_response["status"]).to be_truthy | ||||||
|           expect(json_response["gitaly"]).not_to be_nil |           expect(json_response["gitaly"]).not_to be_nil | ||||||
|           expect(json_response["gitaly"]["repository"]).not_to be_nil |           expect(json_response["gitaly"]["repository"]).not_to be_nil | ||||||
|  | @ -604,7 +604,7 @@ describe API::Internal::Base do | ||||||
|         it do |         it do | ||||||
|           archive(key, project) |           archive(key, project) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(404) |           expect(response).to have_gitlab_http_status(:not_found) | ||||||
|           expect(json_response["status"]).to be_falsey |           expect(json_response["status"]).to be_falsey | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -616,7 +616,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|         pull(key, project) |         pull(key, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response["status"]).to be_falsey |         expect(json_response["status"]).to be_falsey | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -632,7 +632,7 @@ describe API::Internal::Base do | ||||||
|           } |           } | ||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response["status"]).to be_falsey |         expect(json_response["status"]).to be_falsey | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -641,7 +641,7 @@ describe API::Internal::Base do | ||||||
|       it do |       it do | ||||||
|         pull(OpenStruct.new(id: 0), project) |         pull(OpenStruct.new(id: 0), project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response["status"]).to be_falsey |         expect(json_response["status"]).to be_falsey | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -714,14 +714,14 @@ describe API::Internal::Base do | ||||||
|       it 'rejects the push' do |       it 'rejects the push' do | ||||||
|         push(key, project) |         push(key, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response['status']).to be_falsy |         expect(json_response['status']).to be_falsy | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'rejects the SSH pull' do |       it 'rejects the SSH pull' do | ||||||
|         pull(key, project) |         pull(key, project) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response['status']).to be_falsy |         expect(json_response['status']).to be_falsy | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -750,7 +750,7 @@ describe API::Internal::Base do | ||||||
|   # |   # | ||||||
|   #     post api("/internal/notify_post_receive"), valid_params |   #     post api("/internal/notify_post_receive"), valid_params | ||||||
|   # |   # | ||||||
|   #     expect(response).to have_gitlab_http_status(200) |   #     expect(response).to have_gitlab_http_status(:ok) | ||||||
|   #   end |   #   end | ||||||
|   # |   # | ||||||
|   #   it "calls the Gitaly client with the wiki's repository if it's a wiki" do |   #   it "calls the Gitaly client with the wiki's repository if it's a wiki" do | ||||||
|  | @ -762,7 +762,7 @@ describe API::Internal::Base do | ||||||
|   # |   # | ||||||
|   #     post api("/internal/notify_post_receive"), valid_wiki_params |   #     post api("/internal/notify_post_receive"), valid_wiki_params | ||||||
|   # |   # | ||||||
|   #     expect(response).to have_gitlab_http_status(200) |   #     expect(response).to have_gitlab_http_status(:ok) | ||||||
|   #   end |   #   end | ||||||
|   # |   # | ||||||
|   #   it "returns 500 if the gitaly call fails" do |   #   it "returns 500 if the gitaly call fails" do | ||||||
|  | @ -771,7 +771,7 @@ describe API::Internal::Base do | ||||||
|   # |   # | ||||||
|   #     post api("/internal/notify_post_receive"), valid_params |   #     post api("/internal/notify_post_receive"), valid_params | ||||||
|   # |   # | ||||||
|   #     expect(response).to have_gitlab_http_status(500) |   #     expect(response).to have_gitlab_http_status(:internal_server_error) | ||||||
|   #   end |   #   end | ||||||
|   # |   # | ||||||
|   #   context 'with a gl_repository parameter' do |   #   context 'with a gl_repository parameter' do | ||||||
|  | @ -792,7 +792,7 @@ describe API::Internal::Base do | ||||||
|   # |   # | ||||||
|   #       post api("/internal/notify_post_receive"), valid_params |   #       post api("/internal/notify_post_receive"), valid_params | ||||||
|   # |   # | ||||||
|   #       expect(response).to have_gitlab_http_status(200) |   #       expect(response).to have_gitlab_http_status(:ok) | ||||||
|   #     end |   #     end | ||||||
|   # |   # | ||||||
|   #     it "calls the Gitaly client with the wiki's repository if it's a wiki" do |   #     it "calls the Gitaly client with the wiki's repository if it's a wiki" do | ||||||
|  | @ -804,7 +804,7 @@ describe API::Internal::Base do | ||||||
|   # |   # | ||||||
|   #       post api("/internal/notify_post_receive"), valid_wiki_params |   #       post api("/internal/notify_post_receive"), valid_wiki_params | ||||||
|   # |   # | ||||||
|   #       expect(response).to have_gitlab_http_status(200) |   #       expect(response).to have_gitlab_http_status(:ok) | ||||||
|   #     end |   #     end | ||||||
|   #   end |   #   end | ||||||
|   # end |   # end | ||||||
|  | @ -961,7 +961,7 @@ describe API::Internal::Base do | ||||||
|       it 'outputs a broadcast message' do |       it 'outputs a broadcast message' do | ||||||
|         post api('/internal/post_receive'), params: valid_params |         post api('/internal/post_receive'), params: valid_params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['messages']).to include(build_alert_message(broadcast_message.message)) |         expect(json_response['messages']).to include(build_alert_message(broadcast_message.message)) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -970,7 +970,7 @@ describe API::Internal::Base do | ||||||
|       it 'does not output a broadcast message' do |       it 'does not output a broadcast message' do | ||||||
|         post api('/internal/post_receive'), params: valid_params |         post api('/internal/post_receive'), params: valid_params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(has_alert_messages?(json_response['messages'])).to be_falsey |         expect(has_alert_messages?(json_response['messages'])).to be_falsey | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -981,7 +981,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|         post api('/internal/post_receive'), params: valid_params |         post api('/internal/post_receive'), params: valid_params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(has_alert_messages?(json_response['messages'])).to be_falsey |         expect(has_alert_messages?(json_response['messages'])).to be_falsey | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -993,7 +993,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|         post api('/internal/post_receive'), params: valid_params |         post api('/internal/post_receive'), params: valid_params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['messages']).to include(build_basic_message(project_moved.message)) |         expect(json_response['messages']).to include(build_basic_message(project_moved.message)) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -1005,7 +1005,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|         post api('/internal/post_receive'), params: valid_params |         post api('/internal/post_receive'), params: valid_params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['messages']).to include(build_basic_message(project_created.message)) |         expect(json_response['messages']).to include(build_basic_message(project_created.message)) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -1018,7 +1018,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|         post api('/internal/post_receive'), params: valid_params |         post api('/internal/post_receive'), params: valid_params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -1032,7 +1032,7 @@ describe API::Internal::Base do | ||||||
| 
 | 
 | ||||||
|         post api('/internal/post_receive'), params: valid_params |         post api('/internal/post_receive'), params: valid_params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -22,7 +22,7 @@ describe API::Internal::Pages do | ||||||
|       it 'responds with 404 Not Found' do |       it 'responds with 404 Not Found' do | ||||||
|         query_host('pages.gitlab.io') |         query_host('pages.gitlab.io') | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -31,7 +31,7 @@ describe API::Internal::Pages do | ||||||
|         it 'responds with 401 Unauthorized' do |         it 'responds with 401 Unauthorized' do | ||||||
|           query_host('pages.gitlab.io') |           query_host('pages.gitlab.io') | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -51,7 +51,7 @@ describe API::Internal::Pages do | ||||||
|           it 'responds with 204 no content' do |           it 'responds with 204 no content' do | ||||||
|             query_host('pages.gitlab.io') |             query_host('pages.gitlab.io') | ||||||
| 
 | 
 | ||||||
|             expect(response).to have_gitlab_http_status(204) |             expect(response).to have_gitlab_http_status(:no_content) | ||||||
|             expect(response.body).to be_empty |             expect(response.body).to be_empty | ||||||
|           end |           end | ||||||
|         end |         end | ||||||
|  | @ -65,7 +65,7 @@ describe API::Internal::Pages do | ||||||
|             it 'responds with 204 No Content' do |             it 'responds with 204 No Content' do | ||||||
|               query_host('pages.gitlab.io') |               query_host('pages.gitlab.io') | ||||||
| 
 | 
 | ||||||
|               expect(response).to have_gitlab_http_status(204) |               expect(response).to have_gitlab_http_status(:no_content) | ||||||
|             end |             end | ||||||
|           end |           end | ||||||
| 
 | 
 | ||||||
|  | @ -75,7 +75,7 @@ describe API::Internal::Pages do | ||||||
| 
 | 
 | ||||||
|               query_host('pages.gitlab.io') |               query_host('pages.gitlab.io') | ||||||
| 
 | 
 | ||||||
|               expect(response).to have_gitlab_http_status(200) |               expect(response).to have_gitlab_http_status(:ok) | ||||||
|               expect(response).to match_response_schema('internal/pages/virtual_domain') |               expect(response).to match_response_schema('internal/pages/virtual_domain') | ||||||
| 
 | 
 | ||||||
|               expect(json_response['certificate']).to eq(pages_domain.certificate) |               expect(json_response['certificate']).to eq(pages_domain.certificate) | ||||||
|  | @ -114,7 +114,7 @@ describe API::Internal::Pages do | ||||||
| 
 | 
 | ||||||
|               query_host('mygroup.gitlab-pages.io') |               query_host('mygroup.gitlab-pages.io') | ||||||
| 
 | 
 | ||||||
|               expect(response).to have_gitlab_http_status(200) |               expect(response).to have_gitlab_http_status(:ok) | ||||||
|               expect(response).to match_response_schema('internal/pages/virtual_domain') |               expect(response).to match_response_schema('internal/pages/virtual_domain') | ||||||
| 
 | 
 | ||||||
|               expect(json_response['lookup_paths']).to eq( |               expect(json_response['lookup_paths']).to eq( | ||||||
|  | @ -141,7 +141,7 @@ describe API::Internal::Pages do | ||||||
| 
 | 
 | ||||||
|               query_host('mygroup.gitlab-pages.io') |               query_host('mygroup.gitlab-pages.io') | ||||||
| 
 | 
 | ||||||
|               expect(response).to have_gitlab_http_status(200) |               expect(response).to have_gitlab_http_status(:ok) | ||||||
|               expect(response).to match_response_schema('internal/pages/virtual_domain') |               expect(response).to match_response_schema('internal/pages/virtual_domain') | ||||||
| 
 | 
 | ||||||
|               expect(json_response['lookup_paths']).to eq( |               expect(json_response['lookup_paths']).to eq( | ||||||
|  |  | ||||||
|  | @ -72,7 +72,7 @@ describe API::Issues do | ||||||
|       it 'returns issues statistics' do |       it 'returns issues statistics' do | ||||||
|         get api("/groups/#{group.id}/issues_statistics", user), params: params |         get api("/groups/#{group.id}/issues_statistics", user), params: params | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['statistics']).not_to be_nil |         expect(json_response['statistics']).not_to be_nil | ||||||
|         expect(json_response['statistics']['counts']['all']).to eq counts[:all] |         expect(json_response['statistics']['counts']['all']).to eq counts[:all] | ||||||
|         expect(json_response['statistics']['counts']['closed']).to eq counts[:closed] |         expect(json_response['statistics']['counts']['closed']).to eq counts[:closed] | ||||||
|  | @ -343,7 +343,7 @@ describe API::Issues do | ||||||
|       it 'exposes known attributes' do |       it 'exposes known attributes' do | ||||||
|         get api(base_url, admin) |         get api(base_url, admin) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response.last.keys).to include(*%w(id iid project_id title description)) |         expect(json_response.last.keys).to include(*%w(id iid project_id title description)) | ||||||
|         expect(json_response.last).not_to have_key('subscribed') |         expect(json_response.last).not_to have_key('subscribed') | ||||||
|       end |       end | ||||||
|  | @ -527,7 +527,7 @@ describe API::Issues do | ||||||
|       it 'returns an array of issues with no milestone' do |       it 'returns an array of issues with no milestone' do | ||||||
|         get api(base_url, user), params: { milestone: no_milestone_title } |         get api(base_url, user), params: { milestone: no_milestone_title } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|         expect_paginated_array_response(group_confidential_issue.id) |         expect_paginated_array_response(group_confidential_issue.id) | ||||||
|       end |       end | ||||||
|  | @ -674,14 +674,14 @@ describe API::Issues do | ||||||
|         it 'returns error when multiple assignees are passed' do |         it 'returns error when multiple assignees are passed' do | ||||||
|           get api(base_url, user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } |           get api(base_url, user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(400) |           expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|           expect(json_response["error"]).to include("allows one value, but found 2") |           expect(json_response["error"]).to include("allows one value, but found 2") | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns error when assignee_username and assignee_id are passed together' do |         it 'returns error when assignee_username and assignee_id are passed together' do | ||||||
|           get api(base_url, user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } |           get api(base_url, user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(400) |           expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|           expect(json_response["error"]).to include("mutually exclusive") |           expect(json_response["error"]).to include("mutually exclusive") | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  |  | ||||||
|  | @ -93,7 +93,7 @@ describe API::Issues do | ||||||
|     it 'returns project issues statistics' do |     it 'returns project issues statistics' do | ||||||
|       get api("/issues_statistics", user), params: params |       get api("/issues_statistics", user), params: params | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['statistics']).not_to be_nil |       expect(json_response['statistics']).not_to be_nil | ||||||
|       expect(json_response['statistics']['counts']['all']).to eq counts[:all] |       expect(json_response['statistics']['counts']['all']).to eq counts[:all] | ||||||
|       expect(json_response['statistics']['counts']['closed']).to eq counts[:closed] |       expect(json_response['statistics']['counts']['closed']).to eq counts[:closed] | ||||||
|  | @ -196,7 +196,7 @@ describe API::Issues do | ||||||
| 
 | 
 | ||||||
|       get api("/projects/#{max_project_id + 1}/issues", non_member) |       get api("/projects/#{max_project_id + 1}/issues", non_member) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 on private projects for other users' do |     it 'returns 404 on private projects for other users' do | ||||||
|  | @ -205,7 +205,7 @@ describe API::Issues do | ||||||
| 
 | 
 | ||||||
|       get api("/projects/#{private_project.id}/issues", non_member) |       get api("/projects/#{private_project.id}/issues", non_member) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns no issues when user has access to project but not issues' do |     it 'returns no issues when user has access to project but not issues' do | ||||||
|  | @ -472,7 +472,7 @@ describe API::Issues do | ||||||
|     it 'exposes known attributes' do |     it 'exposes known attributes' do | ||||||
|       get api("#{base_url}/issues", user) |       get api("#{base_url}/issues", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response.last.keys).to include(*%w(id iid project_id title description)) |       expect(json_response.last.keys).to include(*%w(id iid project_id title description)) | ||||||
|       expect(json_response.last).not_to have_key('subscribed') |       expect(json_response.last).not_to have_key('subscribed') | ||||||
|     end |     end | ||||||
|  | @ -565,14 +565,14 @@ describe API::Issues do | ||||||
|       it 'returns error when multiple assignees are passed' do |       it 'returns error when multiple assignees are passed' do | ||||||
|         get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } |         get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(400) |         expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|         expect(json_response["error"]).to include("allows one value, but found 2") |         expect(json_response["error"]).to include("allows one value, but found 2") | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns error when assignee_username and assignee_id are passed together' do |       it 'returns error when assignee_username and assignee_id are passed together' do | ||||||
|         get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } |         get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(400) |         expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|         expect(json_response["error"]).to include("mutually exclusive") |         expect(json_response["error"]).to include("mutually exclusive") | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -583,14 +583,14 @@ describe API::Issues do | ||||||
|       it 'returns public issues' do |       it 'returns public issues' do | ||||||
|         get api("/projects/#{project.id}/issues/#{issue.iid}") |         get api("/projects/#{project.id}/issues/#{issue.iid}") | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'exposes known attributes' do |     it 'exposes known attributes' do | ||||||
|       get api("/projects/#{project.id}/issues/#{issue.iid}", user) |       get api("/projects/#{project.id}/issues/#{issue.iid}", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['id']).to eq(issue.id) |       expect(json_response['id']).to eq(issue.id) | ||||||
|       expect(json_response['iid']).to eq(issue.iid) |       expect(json_response['iid']).to eq(issue.iid) | ||||||
|       expect(json_response['project_id']).to eq(issue.project.id) |       expect(json_response['project_id']).to eq(issue.project.id) | ||||||
|  | @ -630,7 +630,7 @@ describe API::Issues do | ||||||
|     it 'exposes the closed_at attribute' do |     it 'exposes the closed_at attribute' do | ||||||
|       get api("/projects/#{project.id}/issues/#{closed_issue.iid}", user) |       get api("/projects/#{project.id}/issues/#{closed_issue.iid}", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['closed_at']).to be_present |       expect(json_response['closed_at']).to be_present | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -650,39 +650,39 @@ describe API::Issues do | ||||||
|     it 'returns a project issue by internal id' do |     it 'returns a project issue by internal id' do | ||||||
|       get api("/projects/#{project.id}/issues/#{issue.iid}", user) |       get api("/projects/#{project.id}/issues/#{issue.iid}", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['title']).to eq(issue.title) |       expect(json_response['title']).to eq(issue.title) | ||||||
|       expect(json_response['iid']).to eq(issue.iid) |       expect(json_response['iid']).to eq(issue.iid) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if issue id not found' do |     it 'returns 404 if issue id not found' do | ||||||
|       get api("/projects/#{project.id}/issues/54321", user) |       get api("/projects/#{project.id}/issues/54321", user) | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if the issue ID is used' do |     it 'returns 404 if the issue ID is used' do | ||||||
|       get api("/projects/#{project.id}/issues/#{issue.id}", user) |       get api("/projects/#{project.id}/issues/#{issue.id}", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'confidential issues' do |     context 'confidential issues' do | ||||||
|       it 'returns 404 for non project members' do |       it 'returns 404 for non project members' do | ||||||
|         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", non_member) |         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", non_member) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns 404 for project members with guest role' do |       it 'returns 404 for project members with guest role' do | ||||||
|         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", guest) |         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", guest) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns confidential issue for project members' do |       it 'returns confidential issue for project members' do | ||||||
|         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user) |         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['title']).to eq(confidential_issue.title) |         expect(json_response['title']).to eq(confidential_issue.title) | ||||||
|         expect(json_response['iid']).to eq(confidential_issue.iid) |         expect(json_response['iid']).to eq(confidential_issue.iid) | ||||||
|       end |       end | ||||||
|  | @ -690,7 +690,7 @@ describe API::Issues do | ||||||
|       it 'returns confidential issue for author' do |       it 'returns confidential issue for author' do | ||||||
|         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", author) |         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", author) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['title']).to eq(confidential_issue.title) |         expect(json_response['title']).to eq(confidential_issue.title) | ||||||
|         expect(json_response['iid']).to eq(confidential_issue.iid) |         expect(json_response['iid']).to eq(confidential_issue.iid) | ||||||
|       end |       end | ||||||
|  | @ -698,7 +698,7 @@ describe API::Issues do | ||||||
|       it 'returns confidential issue for assignee' do |       it 'returns confidential issue for assignee' do | ||||||
|         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", assignee) |         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", assignee) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['title']).to eq(confidential_issue.title) |         expect(json_response['title']).to eq(confidential_issue.title) | ||||||
|         expect(json_response['iid']).to eq(confidential_issue.iid) |         expect(json_response['iid']).to eq(confidential_issue.iid) | ||||||
|       end |       end | ||||||
|  | @ -706,7 +706,7 @@ describe API::Issues do | ||||||
|       it 'returns confidential issue for admin' do |       it 'returns confidential issue for admin' do | ||||||
|         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin) |         get api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['title']).to eq(confidential_issue.title) |         expect(json_response['title']).to eq(confidential_issue.title) | ||||||
|         expect(json_response['iid']).to eq(confidential_issue.iid) |         expect(json_response['iid']).to eq(confidential_issue.iid) | ||||||
|       end |       end | ||||||
|  | @ -744,7 +744,7 @@ describe API::Issues do | ||||||
|     it "returns 404 when issue doesn't exists" do |     it "returns 404 when issue doesn't exists" do | ||||||
|       get api("/projects/#{project.id}/issues/0/closed_by", user) |       get api("/projects/#{project.id}/issues/0/closed_by", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -774,7 +774,7 @@ describe API::Issues do | ||||||
|         get_related_merge_requests(project.id, issue.iid) |         get_related_merge_requests(project.id, issue.iid) | ||||||
| 
 | 
 | ||||||
|         expect_paginated_array_response(related_mr.id) |         expect_paginated_array_response(related_mr.id) | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response.last).not_to have_key('subscribed') |         expect(json_response.last).not_to have_key('subscribed') | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -785,7 +785,7 @@ describe API::Issues do | ||||||
| 
 | 
 | ||||||
|         get_related_merge_requests(private_project.id, private_issue.iid) |         get_related_merge_requests(private_project.id, private_issue.iid) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -824,7 +824,7 @@ describe API::Issues do | ||||||
|     it "returns 404 when issue doesn't exists" do |     it "returns 404 when issue doesn't exists" do | ||||||
|       get_related_merge_requests(project.id, 0, user) |       get_related_merge_requests(project.id, 0, user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -835,14 +835,14 @@ describe API::Issues do | ||||||
|       it 'returns unauthorized' do |       it 'returns unauthorized' do | ||||||
|         get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail") |         get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail") | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(401) |         expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'exposes known attributes' do |     it 'exposes known attributes' do | ||||||
|       get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin) |       get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", admin) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['user_agent']).to eq(user_agent_detail.user_agent) |       expect(json_response['user_agent']).to eq(user_agent_detail.user_agent) | ||||||
|       expect(json_response['ip_address']).to eq(user_agent_detail.ip_address) |       expect(json_response['ip_address']).to eq(user_agent_detail.ip_address) | ||||||
|       expect(json_response['akismet_submitted']).to eq(user_agent_detail.submitted) |       expect(json_response['akismet_submitted']).to eq(user_agent_detail.submitted) | ||||||
|  | @ -851,7 +851,7 @@ describe API::Issues do | ||||||
|     it 'returns unauthorized for non-admin users' do |     it 'returns unauthorized for non-admin users' do | ||||||
|       get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", user) |       get api("/projects/#{project.id}/issues/#{issue.iid}/user_agent_detail", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(403) |       expect(response).to have_gitlab_http_status(:forbidden) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -863,7 +863,7 @@ describe API::Issues do | ||||||
|     it 'returns 404 if the issue is confidential' do |     it 'returns 404 if the issue is confidential' do | ||||||
|       post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/participants", non_member) |       post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/participants", non_member) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -76,7 +76,7 @@ describe API::Issues do | ||||||
|     it 'returns issues statistics' do |     it 'returns issues statistics' do | ||||||
|       get api("/issues_statistics", user), params: params |       get api("/issues_statistics", user), params: params | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['statistics']).not_to be_nil |       expect(json_response['statistics']).not_to be_nil | ||||||
|       expect(json_response['statistics']['counts']['all']).to eq counts[:all] |       expect(json_response['statistics']['counts']['all']).to eq counts[:all] | ||||||
|       expect(json_response['statistics']['counts']['closed']).to eq counts[:closed] |       expect(json_response['statistics']['counts']['closed']).to eq counts[:closed] | ||||||
|  | @ -89,39 +89,39 @@ describe API::Issues do | ||||||
|       it 'returns an array of all issues' do |       it 'returns an array of all issues' do | ||||||
|         get api('/issues'), params: { scope: 'all' } |         get api('/issues'), params: { scope: 'all' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response).to be_an Array |         expect(json_response).to be_an Array | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns authentication error without any scope' do |       it 'returns authentication error without any scope' do | ||||||
|         get api('/issues') |         get api('/issues') | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_http_status(401) |         expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns authentication error when scope is assigned-to-me' do |       it 'returns authentication error when scope is assigned-to-me' do | ||||||
|         get api('/issues'), params: { scope: 'assigned-to-me' } |         get api('/issues'), params: { scope: 'assigned-to-me' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_http_status(401) |         expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns authentication error when scope is created-by-me' do |       it 'returns authentication error when scope is created-by-me' do | ||||||
|         get api('/issues'), params: { scope: 'created-by-me' } |         get api('/issues'), params: { scope: 'created-by-me' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_http_status(401) |         expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns an array of issues matching state in milestone' do |       it 'returns an array of issues matching state in milestone' do | ||||||
|         get api('/issues'), params: { milestone: 'foo', scope: 'all' } |         get api('/issues'), params: { milestone: 'foo', scope: 'all' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect_paginated_array_response([]) |         expect_paginated_array_response([]) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns an array of issues matching state in milestone' do |       it 'returns an array of issues matching state in milestone' do | ||||||
|         get api('/issues'), params: { milestone: milestone.title, scope: 'all' } |         get api('/issues'), params: { milestone: milestone.title, scope: 'all' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect_paginated_array_response([issue.id, closed_issue.id]) |         expect_paginated_array_response([issue.id, closed_issue.id]) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -129,19 +129,19 @@ describe API::Issues do | ||||||
|         it 'returns authentication error without any scope' do |         it 'returns authentication error without any scope' do | ||||||
|           get api('/issues_statistics') |           get api('/issues_statistics') | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns authentication error when scope is assigned_to_me' do |         it 'returns authentication error when scope is assigned_to_me' do | ||||||
|           get api('/issues_statistics'), params: { scope: 'assigned_to_me' } |           get api('/issues_statistics'), params: { scope: 'assigned_to_me' } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns authentication error when scope is created_by_me' do |         it 'returns authentication error when scope is created_by_me' do | ||||||
|           get api('/issues_statistics'), params: { scope: 'created_by_me' } |           get api('/issues_statistics'), params: { scope: 'created_by_me' } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_http_status(401) |           expect(response).to have_gitlab_http_status(:unauthorized) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         context 'no state is treated as all state' do |         context 'no state is treated as all state' do | ||||||
|  | @ -642,14 +642,14 @@ describe API::Issues do | ||||||
|         it 'accepts only predefined order by params' do |         it 'accepts only predefined order by params' do | ||||||
|           API::Helpers::IssuesHelpers.sort_options.each do |sort_opt| |           API::Helpers::IssuesHelpers.sort_options.each do |sort_opt| | ||||||
|             get api('/issues', user), params: { order_by: sort_opt, sort: 'asc' } |             get api('/issues', user), params: { order_by: sort_opt, sort: 'asc' } | ||||||
|             expect(response).to have_gitlab_http_status(200) |             expect(response).to have_gitlab_http_status(:ok) | ||||||
|           end |           end | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'fails to sort with non predefined options' do |         it 'fails to sort with non predefined options' do | ||||||
|           %w(milestone title abracadabra).each do |sort_opt| |           %w(milestone title abracadabra).each do |sort_opt| | ||||||
|             get api('/issues', user), params: { order_by: sort_opt, sort: 'asc' } |             get api('/issues', user), params: { order_by: sort_opt, sort: 'asc' } | ||||||
|             expect(response).to have_gitlab_http_status(400) |             expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|           end |           end | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -657,14 +657,14 @@ describe API::Issues do | ||||||
|       it 'matches V4 response schema' do |       it 'matches V4 response schema' do | ||||||
|         get api('/issues', user) |         get api('/issues', user) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(response).to match_response_schema('public_api/v4/issues') |         expect(response).to match_response_schema('public_api/v4/issues') | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns a related merge request count of 0 if there are no related merge requests' do |       it 'returns a related merge request count of 0 if there are no related merge requests' do | ||||||
|         get api('/issues', user) |         get api('/issues', user) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(response).to match_response_schema('public_api/v4/issues') |         expect(response).to match_response_schema('public_api/v4/issues') | ||||||
|         expect(json_response.first).to include('merge_requests_count' => 0) |         expect(json_response.first).to include('merge_requests_count' => 0) | ||||||
|       end |       end | ||||||
|  | @ -674,7 +674,7 @@ describe API::Issues do | ||||||
| 
 | 
 | ||||||
|         get api('/issues', user) |         get api('/issues', user) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(response).to match_response_schema('public_api/v4/issues') |         expect(response).to match_response_schema('public_api/v4/issues') | ||||||
|         expect(json_response.first).to include('merge_requests_count' => 1) |         expect(json_response.first).to include('merge_requests_count' => 1) | ||||||
|       end |       end | ||||||
|  | @ -767,14 +767,14 @@ describe API::Issues do | ||||||
|         it 'returns error when multiple assignees are passed' do |         it 'returns error when multiple assignees are passed' do | ||||||
|           get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } |           get api("/issues", user), params: { assignee_username: [assignee.username, another_assignee.username], scope: 'all' } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(400) |           expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|           expect(json_response["error"]).to include("allows one value, but found 2") |           expect(json_response["error"]).to include("allows one value, but found 2") | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'returns error when assignee_username and assignee_id are passed together' do |         it 'returns error when assignee_username and assignee_id are passed together' do | ||||||
|           get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } |           get api("/issues", user), params: { assignee_username: [assignee.username], assignee_id: another_assignee.id, scope: 'all' } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(400) |           expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|           expect(json_response["error"]).to include("mutually exclusive") |           expect(json_response["error"]).to include("mutually exclusive") | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -835,7 +835,7 @@ describe API::Issues do | ||||||
|     it 'exposes full reference path' do |     it 'exposes full reference path' do | ||||||
|       get api("/projects/#{project.id}/issues/#{issue.iid}", user) |       get api("/projects/#{project.id}/issues/#{issue.iid}", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['references']['short']).to eq("##{issue.iid}") |       expect(json_response['references']['short']).to eq("##{issue.iid}") | ||||||
|       expect(json_response['references']['relative']).to eq("##{issue.iid}") |       expect(json_response['references']['relative']).to eq("##{issue.iid}") | ||||||
|       expect(json_response['references']['full']).to eq("#{project.parent.path}/#{project.path}##{issue.iid}") |       expect(json_response['references']['full']).to eq("#{project.parent.path}/#{project.path}##{issue.iid}") | ||||||
|  | @ -845,12 +845,12 @@ describe API::Issues do | ||||||
|   describe 'DELETE /projects/:id/issues/:issue_iid' do |   describe 'DELETE /projects/:id/issues/:issue_iid' do | ||||||
|     it 'rejects a non member from deleting an issue' do |     it 'rejects a non member from deleting an issue' do | ||||||
|       delete api("/projects/#{project.id}/issues/#{issue.iid}", non_member) |       delete api("/projects/#{project.id}/issues/#{issue.iid}", non_member) | ||||||
|       expect(response).to have_gitlab_http_status(403) |       expect(response).to have_gitlab_http_status(:forbidden) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'rejects a developer from deleting an issue' do |     it 'rejects a developer from deleting an issue' do | ||||||
|       delete api("/projects/#{project.id}/issues/#{issue.iid}", author) |       delete api("/projects/#{project.id}/issues/#{issue.iid}", author) | ||||||
|       expect(response).to have_gitlab_http_status(403) |       expect(response).to have_gitlab_http_status(:forbidden) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     context 'when the user is project owner' do |     context 'when the user is project owner' do | ||||||
|  | @ -860,7 +860,7 @@ describe API::Issues do | ||||||
|       it 'deletes the issue if an admin requests it' do |       it 'deletes the issue if an admin requests it' do | ||||||
|         delete api("/projects/#{project.id}/issues/#{issue.iid}", owner) |         delete api("/projects/#{project.id}/issues/#{issue.iid}", owner) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(204) |         expect(response).to have_gitlab_http_status(:no_content) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it_behaves_like '412 response' do |       it_behaves_like '412 response' do | ||||||
|  | @ -872,14 +872,14 @@ describe API::Issues do | ||||||
|       it 'returns 404 when trying to delete an issue' do |       it 'returns 404 when trying to delete an issue' do | ||||||
|         delete api("/projects/#{project.id}/issues/123", user) |         delete api("/projects/#{project.id}/issues/123", user) | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 when using the issue ID instead of IID' do |     it 'returns 404 when using the issue ID instead of IID' do | ||||||
|       delete api("/projects/#{project.id}/issues/#{issue.id}", user) |       delete api("/projects/#{project.id}/issues/#{issue.id}", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -75,7 +75,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues", user), |         post api("/projects/#{project.id}/issues", user), | ||||||
|           params: { title: 'new issue', assignee_id: user2.id } |           params: { title: 'new issue', assignee_id: user2.id } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(201) |         expect(response).to have_gitlab_http_status(:created) | ||||||
|         expect(json_response['title']).to eq('new issue') |         expect(json_response['title']).to eq('new issue') | ||||||
|         expect(json_response['assignee']['name']).to eq(user2.name) |         expect(json_response['assignee']['name']).to eq(user2.name) | ||||||
|         expect(json_response['assignees'].first['name']).to eq(user2.name) |         expect(json_response['assignees'].first['name']).to eq(user2.name) | ||||||
|  | @ -85,7 +85,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues", user), |         post api("/projects/#{project.id}/issues", user), | ||||||
|           params: { title: 'new issue', assignee_id: '' } |           params: { title: 'new issue', assignee_id: '' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(201) |         expect(response).to have_gitlab_http_status(:created) | ||||||
|         expect(json_response['title']).to eq('new issue') |         expect(json_response['title']).to eq('new issue') | ||||||
|         expect(json_response['assignee']).to be_nil |         expect(json_response['assignee']).to be_nil | ||||||
|       end |       end | ||||||
|  | @ -96,7 +96,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues", user), |         post api("/projects/#{project.id}/issues", user), | ||||||
|           params: { title: 'new issue', assignee_ids: [user2.id, guest.id] } |           params: { title: 'new issue', assignee_ids: [user2.id, guest.id] } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(201) |         expect(response).to have_gitlab_http_status(:created) | ||||||
|         expect(json_response['title']).to eq('new issue') |         expect(json_response['title']).to eq('new issue') | ||||||
|         expect(json_response['assignees'].count).to eq(1) |         expect(json_response['assignees'].count).to eq(1) | ||||||
|       end |       end | ||||||
|  | @ -112,7 +112,7 @@ describe API::Issues do | ||||||
|       it 'renders 403' do |       it 'renders 403' do | ||||||
|         post api("/projects/#{project.id}/issues", not_member), params: { title: 'new issue' } |         post api("/projects/#{project.id}/issues", not_member), params: { title: 'new issue' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(403) |         expect(response).to have_gitlab_http_status(:forbidden) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -122,7 +122,7 @@ describe API::Issues do | ||||||
|           post api("/projects/#{project.id}/issues", admin), |           post api("/projects/#{project.id}/issues", admin), | ||||||
|             params: { title: 'new issue', iid: 9001 } |             params: { title: 'new issue', iid: 9001 } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(json_response['iid']).to eq 9001 |           expect(json_response['iid']).to eq 9001 | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -132,7 +132,7 @@ describe API::Issues do | ||||||
|           post api("/projects/#{project.id}/issues", user), |           post api("/projects/#{project.id}/issues", user), | ||||||
|             params: { title: 'new issue', iid: 9001 } |             params: { title: 'new issue', iid: 9001 } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(json_response['iid']).to eq 9001 |           expect(json_response['iid']).to eq 9001 | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -146,7 +146,7 @@ describe API::Issues do | ||||||
|           post api("/projects/#{group_project.id}/issues", user2), |           post api("/projects/#{group_project.id}/issues", user2), | ||||||
|             params: { title: 'new issue', iid: 9001 } |             params: { title: 'new issue', iid: 9001 } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(json_response['iid']).to eq 9001 |           expect(json_response['iid']).to eq 9001 | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -156,7 +156,7 @@ describe API::Issues do | ||||||
|           post api("/projects/#{project.id}/issues", user2), |           post api("/projects/#{project.id}/issues", user2), | ||||||
|             params: { title: 'new issue', iid: 9001 } |             params: { title: 'new issue', iid: 9001 } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(json_response['iid']).not_to eq 9001 |           expect(json_response['iid']).not_to eq 9001 | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -166,7 +166,7 @@ describe API::Issues do | ||||||
|           post api("/projects/#{project.id}/issues", admin), |           post api("/projects/#{project.id}/issues", admin), | ||||||
|             params: { title: 'new issue', iid: issue.iid } |             params: { title: 'new issue', iid: issue.iid } | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(409) |           expect(response).to have_gitlab_http_status(:conflict) | ||||||
|           expect(json_response['message']).to eq 'Duplicated issue' |           expect(json_response['message']).to eq 'Duplicated issue' | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -176,7 +176,7 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues", user), |       post api("/projects/#{project.id}/issues", user), | ||||||
|         params: { title: 'new issue', labels: 'label, label2', weight: 3, assignee_ids: [user2.id] } |         params: { title: 'new issue', labels: 'label, label2', weight: 3, assignee_ids: [user2.id] } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['title']).to eq('new issue') |       expect(json_response['title']).to eq('new issue') | ||||||
|       expect(json_response['description']).to be_nil |       expect(json_response['description']).to be_nil | ||||||
|       expect(json_response['labels']).to eq(%w(label label2)) |       expect(json_response['labels']).to eq(%w(label label2)) | ||||||
|  | @ -189,7 +189,7 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues", user), |       post api("/projects/#{project.id}/issues", user), | ||||||
|         params: { title: 'new issue', labels: %w(label label2), weight: 3, assignee_ids: [user2.id] } |         params: { title: 'new issue', labels: %w(label label2), weight: 3, assignee_ids: [user2.id] } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['title']).to eq('new issue') |       expect(json_response['title']).to eq('new issue') | ||||||
|       expect(json_response['description']).to be_nil |       expect(json_response['description']).to be_nil | ||||||
|       expect(json_response['labels']).to eq(%w(label label2)) |       expect(json_response['labels']).to eq(%w(label label2)) | ||||||
|  | @ -202,7 +202,7 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues", user), |       post api("/projects/#{project.id}/issues", user), | ||||||
|         params: { title: 'new issue', confidential: true } |         params: { title: 'new issue', confidential: true } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['title']).to eq('new issue') |       expect(json_response['title']).to eq('new issue') | ||||||
|       expect(json_response['confidential']).to be_truthy |       expect(json_response['confidential']).to be_truthy | ||||||
|     end |     end | ||||||
|  | @ -211,7 +211,7 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues", user), |       post api("/projects/#{project.id}/issues", user), | ||||||
|         params: { title: 'new issue', confidential: 'y' } |         params: { title: 'new issue', confidential: 'y' } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['title']).to eq('new issue') |       expect(json_response['title']).to eq('new issue') | ||||||
|       expect(json_response['confidential']).to be_truthy |       expect(json_response['confidential']).to be_truthy | ||||||
|     end |     end | ||||||
|  | @ -220,7 +220,7 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues", user), |       post api("/projects/#{project.id}/issues", user), | ||||||
|         params: { title: 'new issue', confidential: false } |         params: { title: 'new issue', confidential: false } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['title']).to eq('new issue') |       expect(json_response['title']).to eq('new issue') | ||||||
|       expect(json_response['confidential']).to be_falsy |       expect(json_response['confidential']).to be_falsy | ||||||
|     end |     end | ||||||
|  | @ -229,13 +229,13 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues", user), |       post api("/projects/#{project.id}/issues", user), | ||||||
|         params: { title: 'new issue', confidential: 'foo' } |         params: { title: 'new issue', confidential: 'foo' } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(400) |       expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|       expect(json_response['error']).to eq('confidential is invalid') |       expect(json_response['error']).to eq('confidential is invalid') | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns a 400 bad request if title not given' do |     it 'returns a 400 bad request if title not given' do | ||||||
|       post api("/projects/#{project.id}/issues", user), params: { labels: 'label, label2' } |       post api("/projects/#{project.id}/issues", user), params: { labels: 'label, label2' } | ||||||
|       expect(response).to have_gitlab_http_status(400) |       expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'allows special label names' do |     it 'allows special label names' do | ||||||
|  | @ -269,7 +269,7 @@ describe API::Issues do | ||||||
|     it 'returns 400 if title is too long' do |     it 'returns 400 if title is too long' do | ||||||
|       post api("/projects/#{project.id}/issues", user), |       post api("/projects/#{project.id}/issues", user), | ||||||
|         params: { title: 'g' * 256 } |         params: { title: 'g' * 256 } | ||||||
|       expect(response).to have_gitlab_http_status(400) |       expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|       expect(json_response['message']['title']).to eq([ |       expect(json_response['message']['title']).to eq([ | ||||||
|         'is too long (maximum is 255 characters)' |         'is too long (maximum is 255 characters)' | ||||||
|       ]) |       ]) | ||||||
|  | @ -317,7 +317,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues", user), |         post api("/projects/#{project.id}/issues", user), | ||||||
|           params: { title: 'new issue', due_date: due_date } |           params: { title: 'new issue', due_date: due_date } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(201) |         expect(response).to have_gitlab_http_status(:created) | ||||||
|         expect(json_response['title']).to eq('new issue') |         expect(json_response['title']).to eq('new issue') | ||||||
|         expect(json_response['description']).to be_nil |         expect(json_response['description']).to be_nil | ||||||
|         expect(json_response['due_date']).to eq(due_date) |         expect(json_response['due_date']).to eq(due_date) | ||||||
|  | @ -332,7 +332,7 @@ describe API::Issues do | ||||||
|         it 'sets the creation time on the new issue' do |         it 'sets the creation time on the new issue' do | ||||||
|           post api("/projects/#{project.id}/issues", admin), params: params |           post api("/projects/#{project.id}/issues", admin), params: params | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) |           expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -341,7 +341,7 @@ describe API::Issues do | ||||||
|         it 'sets the creation time on the new issue' do |         it 'sets the creation time on the new issue' do | ||||||
|           post api("/projects/#{project.id}/issues", user), params: params |           post api("/projects/#{project.id}/issues", user), params: params | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) |           expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -353,7 +353,7 @@ describe API::Issues do | ||||||
|           group.add_owner(user2) |           group.add_owner(user2) | ||||||
|           post api("/projects/#{group_project.id}/issues", user2), params: params |           post api("/projects/#{group_project.id}/issues", user2), params: params | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) |           expect(Time.parse(json_response['created_at'])).to be_like_time(creation_time) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -362,7 +362,7 @@ describe API::Issues do | ||||||
|         it 'ignores the given creation time' do |         it 'ignores the given creation time' do | ||||||
|           post api("/projects/#{project.id}/issues", user2), params: params |           post api("/projects/#{project.id}/issues", user2), params: params | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(201) |           expect(response).to have_gitlab_http_status(:created) | ||||||
|           expect(Time.parse(json_response['created_at'])).not_to be_like_time(creation_time) |           expect(Time.parse(json_response['created_at'])).not_to be_like_time(creation_time) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  | @ -417,7 +417,7 @@ describe API::Issues do | ||||||
|       it 'returns correct status and message' do |       it 'returns correct status and message' do | ||||||
|         post_issue |         post_issue | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(400) |         expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|         expect(json_response['message']).to eq({ 'error' => 'Spam detected' }) |         expect(json_response['message']).to eq({ 'error' => 'Spam detected' }) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -435,7 +435,7 @@ describe API::Issues do | ||||||
|       it 'returns correct status' do |       it 'returns correct status' do | ||||||
|         post_issue |         post_issue | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(201) |         expect(response).to have_gitlab_http_status(:created) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'creates a new spam log entry' do |       it 'creates a new spam log entry' do | ||||||
|  | @ -453,7 +453,7 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), |       post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), | ||||||
|         params: { to_project_id: target_project.id } |         params: { to_project_id: target_project.id } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['project_id']).to eq(target_project.id) |       expect(json_response['project_id']).to eq(target_project.id) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -462,7 +462,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), |         post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), | ||||||
|           params: { to_project_id: project.id } |           params: { to_project_id: project.id } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(400) |         expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|         expect(json_response['message']).to eq(s_('MoveIssue|Cannot move issue to project it originates from!')) |         expect(json_response['message']).to eq(s_('MoveIssue|Cannot move issue to project it originates from!')) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -472,7 +472,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), |         post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), | ||||||
|           params: { to_project_id: target_project2.id } |           params: { to_project_id: target_project2.id } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(400) |         expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|         expect(json_response['message']).to eq(s_('MoveIssue|Cannot move issue due to insufficient permissions!')) |         expect(json_response['message']).to eq(s_('MoveIssue|Cannot move issue due to insufficient permissions!')) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -481,7 +481,7 @@ describe API::Issues do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.iid}/move", admin), |       post api("/projects/#{project.id}/issues/#{issue.iid}/move", admin), | ||||||
|         params: { to_project_id: target_project2.id } |         params: { to_project_id: target_project2.id } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['project_id']).to eq(target_project2.id) |       expect(json_response['project_id']).to eq(target_project2.id) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -490,7 +490,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues/#{issue.id}/move", user), |         post api("/projects/#{project.id}/issues/#{issue.id}/move", user), | ||||||
|           params: { to_project_id: target_project.id } |           params: { to_project_id: target_project.id } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response['message']).to eq('404 Issue Not Found') |         expect(json_response['message']).to eq('404 Issue Not Found') | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -500,7 +500,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues/123/move", user), |         post api("/projects/#{project.id}/issues/123/move", user), | ||||||
|           params: { to_project_id: target_project.id } |           params: { to_project_id: target_project.id } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response['message']).to eq('404 Issue Not Found') |         expect(json_response['message']).to eq('404 Issue Not Found') | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -510,7 +510,7 @@ describe API::Issues do | ||||||
|         post api("/projects/0/issues/#{issue.iid}/move", user), |         post api("/projects/0/issues/#{issue.iid}/move", user), | ||||||
|           params: { to_project_id: target_project.id } |           params: { to_project_id: target_project.id } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         expect(json_response['message']).to eq('404 Project Not Found') |         expect(json_response['message']).to eq('404 Project Not Found') | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -520,7 +520,7 @@ describe API::Issues do | ||||||
|         post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), |         post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), | ||||||
|           params: { to_project_id: 0 } |           params: { to_project_id: 0 } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(404) |         expect(response).to have_gitlab_http_status(:not_found) | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | @ -529,32 +529,32 @@ describe API::Issues do | ||||||
|     it 'subscribes to an issue' do |     it 'subscribes to an issue' do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.iid}/subscribe", user2) |       post api("/projects/#{project.id}/issues/#{issue.iid}/subscribe", user2) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['subscribed']).to eq(true) |       expect(json_response['subscribed']).to eq(true) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 304 if already subscribed' do |     it 'returns 304 if already subscribed' do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.iid}/subscribe", user) |       post api("/projects/#{project.id}/issues/#{issue.iid}/subscribe", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(304) |       expect(response).to have_gitlab_http_status(:not_modified) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if the issue is not found' do |     it 'returns 404 if the issue is not found' do | ||||||
|       post api("/projects/#{project.id}/issues/123/subscribe", user) |       post api("/projects/#{project.id}/issues/123/subscribe", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if the issue ID is used instead of the iid' do |     it 'returns 404 if the issue ID is used instead of the iid' do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.id}/subscribe", user) |       post api("/projects/#{project.id}/issues/#{issue.id}/subscribe", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if the issue is confidential' do |     it 'returns 404 if the issue is confidential' do | ||||||
|       post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/subscribe", non_member) |       post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/subscribe", non_member) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -562,32 +562,32 @@ describe API::Issues do | ||||||
|     it 'unsubscribes from an issue' do |     it 'unsubscribes from an issue' do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.iid}/unsubscribe", user) |       post api("/projects/#{project.id}/issues/#{issue.iid}/unsubscribe", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(201) |       expect(response).to have_gitlab_http_status(:created) | ||||||
|       expect(json_response['subscribed']).to eq(false) |       expect(json_response['subscribed']).to eq(false) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 304 if not subscribed' do |     it 'returns 304 if not subscribed' do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.iid}/unsubscribe", user2) |       post api("/projects/#{project.id}/issues/#{issue.iid}/unsubscribe", user2) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(304) |       expect(response).to have_gitlab_http_status(:not_modified) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if the issue is not found' do |     it 'returns 404 if the issue is not found' do | ||||||
|       post api("/projects/#{project.id}/issues/123/unsubscribe", user) |       post api("/projects/#{project.id}/issues/123/unsubscribe", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if using the issue ID instead of iid' do |     it 'returns 404 if using the issue ID instead of iid' do | ||||||
|       post api("/projects/#{project.id}/issues/#{issue.id}/unsubscribe", user) |       post api("/projects/#{project.id}/issues/#{issue.id}/unsubscribe", user) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 if the issue is confidential' do |     it 'returns 404 if the issue is confidential' do | ||||||
|       post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/unsubscribe", non_member) |       post api("/projects/#{project.id}/issues/#{confidential_issue.iid}/unsubscribe", non_member) | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -73,7 +73,7 @@ describe API::Issues do | ||||||
|     it 'updates a project issue' do |     it 'updates a project issue' do | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.iid}", user), |       put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|         params: { title: 'updated title' } |         params: { title: 'updated title' } | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(json_response['title']).to eq('updated title') |       expect(json_response['title']).to eq('updated title') | ||||||
|     end |     end | ||||||
|  | @ -81,13 +81,13 @@ describe API::Issues do | ||||||
|     it 'returns 404 error if issue iid not found' do |     it 'returns 404 error if issue iid not found' do | ||||||
|       put api("/projects/#{project.id}/issues/44444", user), |       put api("/projects/#{project.id}/issues/44444", user), | ||||||
|         params: { title: 'updated title' } |         params: { title: 'updated title' } | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'returns 404 error if issue id is used instead of the iid' do |     it 'returns 404 error if issue id is used instead of the iid' do | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.id}", user), |       put api("/projects/#{project.id}/issues/#{issue.id}", user), | ||||||
|         params: { title: 'updated title' } |         params: { title: 'updated title' } | ||||||
|       expect(response).to have_gitlab_http_status(404) |       expect(response).to have_gitlab_http_status(:not_found) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     it 'allows special label names' do |     it 'allows special label names' do | ||||||
|  | @ -124,33 +124,33 @@ describe API::Issues do | ||||||
|       it 'returns 403 for non project members' do |       it 'returns 403 for non project members' do | ||||||
|         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", non_member), |         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", non_member), | ||||||
|           params: { title: 'updated title' } |           params: { title: 'updated title' } | ||||||
|         expect(response).to have_gitlab_http_status(403) |         expect(response).to have_gitlab_http_status(:forbidden) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'returns 403 for project members with guest role' do |       it 'returns 403 for project members with guest role' do | ||||||
|         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", guest), |         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", guest), | ||||||
|           params: { title: 'updated title' } |           params: { title: 'updated title' } | ||||||
|         expect(response).to have_gitlab_http_status(403) |         expect(response).to have_gitlab_http_status(:forbidden) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'updates a confidential issue for project members' do |       it 'updates a confidential issue for project members' do | ||||||
|         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user), | ||||||
|           params: { title: 'updated title' } |           params: { title: 'updated title' } | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['title']).to eq('updated title') |         expect(json_response['title']).to eq('updated title') | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'updates a confidential issue for author' do |       it 'updates a confidential issue for author' do | ||||||
|         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", author), |         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", author), | ||||||
|           params: { title: 'updated title' } |           params: { title: 'updated title' } | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['title']).to eq('updated title') |         expect(json_response['title']).to eq('updated title') | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'updates a confidential issue for admin' do |       it 'updates a confidential issue for admin' do | ||||||
|         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin), |         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", admin), | ||||||
|           params: { title: 'updated title' } |           params: { title: 'updated title' } | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['title']).to eq('updated title') |         expect(json_response['title']).to eq('updated title') | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -158,7 +158,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|           params: { confidential: true } |           params: { confidential: true } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['confidential']).to be_truthy |         expect(json_response['confidential']).to be_truthy | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -166,7 +166,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user), | ||||||
|           params: { confidential: false } |           params: { confidential: false } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['confidential']).to be_falsy |         expect(json_response['confidential']).to be_falsy | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -174,7 +174,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{confidential_issue.iid}", user), | ||||||
|           params: { confidential: 'foo' } |           params: { confidential: 'foo' } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(400) |         expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|         expect(json_response['error']).to eq('confidential is invalid') |         expect(json_response['error']).to eq('confidential is invalid') | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  | @ -214,7 +214,7 @@ describe API::Issues do | ||||||
|       it 'returns correct status and message' do |       it 'returns correct status and message' do | ||||||
|         update_issue |         update_issue | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(400) |         expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|         expect(json_response).to include('message' => { 'error' => 'Spam detected' }) |         expect(json_response).to include('message' => { 'error' => 'Spam detected' }) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -232,7 +232,7 @@ describe API::Issues do | ||||||
|       it 'returns correct status and message' do |       it 'returns correct status and message' do | ||||||
|         update_issue |         update_issue | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       it 'creates a new spam log entry' do |       it 'creates a new spam log entry' do | ||||||
|  | @ -248,7 +248,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|           params: { assignee_id: 0 } |           params: { assignee_id: 0 } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|         expect(json_response['assignee']).to be_nil |         expect(json_response['assignee']).to be_nil | ||||||
|       end |       end | ||||||
|  | @ -257,7 +257,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|           params: { assignee_id: user2.id } |           params: { assignee_id: user2.id } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|         expect(json_response['assignee']['name']).to eq(user2.name) |         expect(json_response['assignee']['name']).to eq(user2.name) | ||||||
|       end |       end | ||||||
|  | @ -267,7 +267,7 @@ describe API::Issues do | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.iid}", user), |       put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|         params: { assignee_ids: [0] } |         params: { assignee_ids: [0] } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(json_response['assignees']).to be_empty |       expect(json_response['assignees']).to be_empty | ||||||
|     end |     end | ||||||
|  | @ -276,7 +276,7 @@ describe API::Issues do | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.iid}", user), |       put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|         params: { assignee_ids: [user2.id] } |         params: { assignee_ids: [user2.id] } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(json_response['assignees'].first['name']).to eq(user2.name) |       expect(json_response['assignees'].first['name']).to eq(user2.name) | ||||||
|     end |     end | ||||||
|  | @ -286,7 +286,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|           params: { assignee_ids: [user2.id, guest.id] } |           params: { assignee_ids: [user2.id, guest.id] } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|         expect(json_response['assignees'].size).to eq(1) |         expect(json_response['assignees'].size).to eq(1) | ||||||
|       end |       end | ||||||
|  | @ -300,7 +300,7 @@ describe API::Issues do | ||||||
|     it 'does not update labels if not present' do |     it 'does not update labels if not present' do | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.iid}", user), |       put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|         params: { title: 'updated title' } |         params: { title: 'updated title' } | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['labels']).to eq([label.title]) |       expect(json_response['labels']).to eq([label.title]) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -309,7 +309,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { labels: '' } |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { labels: '' } | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['labels']).to eq([]) |       expect(json_response['labels']).to eq([]) | ||||||
|       expect(json_response['updated_at']).to be > Time.now |       expect(json_response['updated_at']).to be > Time.now | ||||||
|     end |     end | ||||||
|  | @ -319,7 +319,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { labels: [''] } |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { labels: [''] } | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['labels']).to eq([]) |       expect(json_response['labels']).to eq([]) | ||||||
|       expect(json_response['updated_at']).to be > Time.now |       expect(json_response['updated_at']).to be > Time.now | ||||||
|     end |     end | ||||||
|  | @ -329,7 +329,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|           params: { labels: 'foo,bar' } |           params: { labels: 'foo,bar' } | ||||||
|       end |       end | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['labels']).to include 'foo' |       expect(json_response['labels']).to include 'foo' | ||||||
|       expect(json_response['labels']).to include 'bar' |       expect(json_response['labels']).to include 'bar' | ||||||
|       expect(json_response['updated_at']).to be > Time.now |       expect(json_response['updated_at']).to be > Time.now | ||||||
|  | @ -340,7 +340,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|           params: { labels: %w(foo bar) } |           params: { labels: %w(foo bar) } | ||||||
|       end |       end | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['labels']).to include 'foo' |       expect(json_response['labels']).to include 'foo' | ||||||
|       expect(json_response['labels']).to include 'bar' |       expect(json_response['labels']).to include 'bar' | ||||||
|       expect(json_response['updated_at']).to be > Time.now |       expect(json_response['updated_at']).to be > Time.now | ||||||
|  | @ -377,7 +377,7 @@ describe API::Issues do | ||||||
|     it 'returns 400 if title is too long' do |     it 'returns 400 if title is too long' do | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.iid}", user), |       put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|         params: { title: 'g' * 256 } |         params: { title: 'g' * 256 } | ||||||
|       expect(response).to have_gitlab_http_status(400) |       expect(response).to have_gitlab_http_status(:bad_request) | ||||||
|       expect(json_response['message']['title']).to eq([ |       expect(json_response['message']['title']).to eq([ | ||||||
|         'is too long (maximum is 255 characters)' |         'is too long (maximum is 255 characters)' | ||||||
|       ]) |       ]) | ||||||
|  | @ -388,7 +388,7 @@ describe API::Issues do | ||||||
|     it 'updates a project issue' do |     it 'updates a project issue' do | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.iid}", user), |       put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|         params: { labels: 'label2', state_event: 'close' } |         params: { labels: 'label2', state_event: 'close' } | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
| 
 | 
 | ||||||
|       expect(json_response['labels']).to include 'label2' |       expect(json_response['labels']).to include 'label2' | ||||||
|       expect(json_response['state']).to eq 'closed' |       expect(json_response['state']).to eq 'closed' | ||||||
|  | @ -397,7 +397,7 @@ describe API::Issues do | ||||||
|     it 'reopens a project isssue' do |     it 'reopens a project isssue' do | ||||||
|       put api("/projects/#{project.id}/issues/#{closed_issue.iid}", user), params: { state_event: 'reopen' } |       put api("/projects/#{project.id}/issues/#{closed_issue.iid}", user), params: { state_event: 'reopen' } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['state']).to eq 'opened' |       expect(json_response['state']).to eq 'opened' | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  | @ -407,7 +407,7 @@ describe API::Issues do | ||||||
|         put api("/projects/#{project.id}/issues/#{issue.iid}", user), |         put api("/projects/#{project.id}/issues/#{issue.iid}", user), | ||||||
|           params: { labels: 'label3', state_event: 'close', updated_at: update_time } |           params: { labels: 'label3', state_event: 'close', updated_at: update_time } | ||||||
| 
 | 
 | ||||||
|         expect(response).to have_gitlab_http_status(200) |         expect(response).to have_gitlab_http_status(:ok) | ||||||
|         expect(json_response['labels']).to include 'label3' |         expect(json_response['labels']).to include 'label3' | ||||||
|         expect(Time.parse(json_response['updated_at'])).to be_like_time(update_time) |         expect(Time.parse(json_response['updated_at'])).to be_like_time(update_time) | ||||||
|       end |       end | ||||||
|  | @ -420,7 +420,7 @@ describe API::Issues do | ||||||
| 
 | 
 | ||||||
|       put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { due_date: due_date } |       put api("/projects/#{project.id}/issues/#{issue.iid}", user), params: { due_date: due_date } | ||||||
| 
 | 
 | ||||||
|       expect(response).to have_gitlab_http_status(200) |       expect(response).to have_gitlab_http_status(:ok) | ||||||
|       expect(json_response['due_date']).to eq(due_date) |       expect(json_response['due_date']).to eq(due_date) | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ describe API::Pages do | ||||||
|         it 'returns 204' do |         it 'returns 204' do | ||||||
|           delete api("/projects/#{project.id}/pages", admin) |           delete api("/projects/#{project.id}/pages", admin) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(204) |           expect(response).to have_gitlab_http_status(:no_content) | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         it 'removes the pages' do |         it 'removes the pages' do | ||||||
|  | @ -53,7 +53,7 @@ describe API::Pages do | ||||||
|         it 'returns 204' do |         it 'returns 204' do | ||||||
|           delete api("/projects/#{project.id}/pages", admin) |           delete api("/projects/#{project.id}/pages", admin) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(204) |           expect(response).to have_gitlab_http_status(:no_content) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -63,7 +63,7 @@ describe API::Pages do | ||||||
| 
 | 
 | ||||||
|           delete api("/projects/#{id}/pages", admin) |           delete api("/projects/#{id}/pages", admin) | ||||||
| 
 | 
 | ||||||
|           expect(response).to have_gitlab_http_status(404) |           expect(response).to have_gitlab_http_status(:not_found) | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  | @ -76,6 +76,7 @@ describe SubmitUsagePingService do | ||||||
| 
 | 
 | ||||||
|   context 'when usage ping is enabled' do |   context 'when usage ping is enabled' do | ||||||
|     before do |     before do | ||||||
|  |       allow(ActiveRecord::Base.connection).to receive(:transaction_open?).and_return(false) | ||||||
|       stub_application_setting(usage_ping_enabled: true) |       stub_application_setting(usage_ping_enabled: true) | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,6 +23,29 @@ filebeat: | ||||||
|     output.elasticsearch: |     output.elasticsearch: | ||||||
|       enabled: true |       enabled: true | ||||||
|       hosts: ["http://elastic-stack-elasticsearch-client:9200"] |       hosts: ["http://elastic-stack-elasticsearch-client:9200"] | ||||||
|  |     filebeat.prospectors: | ||||||
|  |     - type: log | ||||||
|  |       enabled: true | ||||||
|  |       paths: | ||||||
|  |         - /var/log/*.log | ||||||
|  |         - /var/log/messages | ||||||
|  |         - /var/log/syslog | ||||||
|  |     - type: docker | ||||||
|  |       containers.ids: | ||||||
|  |       - "*" | ||||||
|  |       json.keys_under_root: true | ||||||
|  |       json.ignore_decoding_error: true | ||||||
|  |       processors: | ||||||
|  |         - add_kubernetes_metadata: | ||||||
|  |         - drop_event: | ||||||
|  |             when: | ||||||
|  |               equals: | ||||||
|  |                 kubernetes.container.name: "filebeat" | ||||||
|  |         - decode_json_fields: | ||||||
|  |             fields: ["message"] | ||||||
|  |             when: | ||||||
|  |               equals: | ||||||
|  |                 kubernetes.container.name: "modsecurity-log" | ||||||
| 
 | 
 | ||||||
| fluentd: | fluentd: | ||||||
|   enabled: false |   enabled: false | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue