diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-04 15:17:40 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-02-04 15:17:40 +0300 |
commit | 9486811b62db7f35906bae75f912aa89804e721b (patch) | |
tree | 92da5045f0554bf89a60a96eb4ac1ffa96bfa427 /spec | |
parent | aa7870a90b5925412a38dd6a27522f83517b917e (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
22 files changed, 292 insertions, 163 deletions
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb index 98cc8d83e0c..e6553c027d6 100644 --- a/spec/controllers/oauth/authorizations_controller_spec.rb +++ b/spec/controllers/oauth/authorizations_controller_spec.rb @@ -4,7 +4,13 @@ require 'spec_helper' RSpec.describe Oauth::AuthorizationsController do let(:user) { create(:user) } - let!(:application) { create(:oauth_application, scopes: 'api read_user', redirect_uri: 'http://example.com') } + let(:application_scopes) { 'api read_user' } + + let!(:application) do + create(:oauth_application, scopes: application_scopes, + redirect_uri: 'http://example.com') + end + let(:params) do { response_type: "code", @@ -119,6 +125,92 @@ RSpec.describe Oauth::AuthorizationsController do expect(response).to have_gitlab_http_status(:ok) expect(response).to render_template('doorkeeper/authorizations/redirect') end + + context 'with gl_auth_type=login' do + let(:minimal_scope) { Gitlab::Auth::READ_USER_SCOPE.to_s } + + before do + params[:gl_auth_type] = 'login' + end + + shared_examples 'downgrades scopes' do + it 'downgrades the scopes' do + subject + + pre_auth = controller.send(:pre_auth) + + expect(pre_auth.scopes).to contain_exactly(minimal_scope) + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/new') + # See: config/locales/doorkeeper.en.yml + expect(response.body).to include("Read the authenticated user's personal information") + expect(response.body).not_to include("Access the authenticated user's API") + end + end + + shared_examples 'adds read_user scope' do + it 'modifies the client.application.scopes' do + expect { subject } + .to change { application.reload.scopes }.to include(minimal_scope) + end + + it 'does not remove pre-existing scopes' do + subject + + expect(application.scopes).to include(*application_scopes.split(/ /)) + end + end + + context 'the application has all scopes' do + let(:application_scopes) { 'api read_api read_user' } + + include_examples 'downgrades scopes' + end + + context 'the application has api and read_user scopes' do + let(:application_scopes) { 'api read_user' } + + include_examples 'downgrades scopes' + end + + context 'the application has read_api and read_user scopes' do + let(:application_scopes) { 'read_api read_user' } + + include_examples 'downgrades scopes' + end + + context 'the application has only api scopes' do + let(:application_scopes) { 'api' } + + include_examples 'downgrades scopes' + include_examples 'adds read_user scope' + end + + context 'the application has only read_api scopes' do + let(:application_scopes) { 'read_api' } + + include_examples 'downgrades scopes' + include_examples 'adds read_user scope' + end + + context 'the application has scopes we do not handle' do + let(:application_scopes) { Gitlab::Auth::PROFILE_SCOPE.to_s } + + before do + params[:scope] = application_scopes + end + + it 'does not modify the scopes' do + subject + + pre_auth = controller.send(:pre_auth) + + expect(pre_auth.scopes).to contain_exactly(application_scopes) + expect(response).to have_gitlab_http_status(:ok) + expect(response).to render_template('doorkeeper/authorizations/new') + end + end + end end end end diff --git a/spec/features/merge_request/user_comments_on_diff_spec.rb b/spec/features/merge_request/user_comments_on_diff_spec.rb index f9b554c5ed2..8f7ad9bd90e 100644 --- a/spec/features/merge_request/user_comments_on_diff_spec.rb +++ b/spec/features/merge_request/user_comments_on_diff_spec.rb @@ -158,7 +158,7 @@ RSpec.describe 'User comments on a diff', :js do it 'allows comments on previously hidden lines at the bottom of a file' do # Click +28, expand down, select 37 add and verify comment page.within('[data-path="files/ruby/popen.rb"]') do - all('.js-unfold-down')[1].click + all('.js-unfold-down:not([disabled])')[1].click end click_diff_line(find('div[data-path="files/ruby/popen.rb"] .left-side a[data-linenumber="30"]').find(:xpath, '../..'), 'left') add_comment('+28', '37') diff --git a/spec/features/merge_requests/user_mass_updates_spec.rb b/spec/features/merge_requests/user_mass_updates_spec.rb index 46c12784ea8..f781ba0827c 100644 --- a/spec/features/merge_requests/user_mass_updates_spec.rb +++ b/spec/features/merge_requests/user_mass_updates_spec.rb @@ -8,6 +8,8 @@ RSpec.describe 'Merge requests > User mass updates', :js do let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } before do + stub_feature_flags(mr_attention_requests: false) + project.add_maintainer(user) sign_in(user) end @@ -59,6 +61,18 @@ RSpec.describe 'Merge requests > User mass updates', :js do expect(find('.merge-request')).to have_link "Assigned to #{user.name}" end + + describe 'with attention requests feature flag on' do + before do + stub_feature_flags(mr_attention_requests: true) + end + + it 'updates merge request with assignee' do + change_assignee(user.name) + + expect(find('.issuable-meta a.author-link')[:title]).to eq "Attention requested from assignee #{user.name}, go to their profile." + end + end end describe 'remove assignee' do diff --git a/spec/frontend/cycle_analytics/metric_popover_spec.js b/spec/frontend/analytics/shared/components/metric_popover_spec.js index 5a622fcacd5..b799c911488 100644 --- a/spec/frontend/cycle_analytics/metric_popover_spec.js +++ b/spec/frontend/analytics/shared/components/metric_popover_spec.js @@ -1,6 +1,6 @@ import { GlLink, GlIcon } from '@gitlab/ui'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import MetricPopover from '~/cycle_analytics/components/metric_popover.vue'; +import MetricPopover from '~/analytics/shared/components/metric_popover.vue'; const MOCK_METRIC = { key: 'deployment-frequency', diff --git a/spec/frontend/cycle_analytics/metric_tile_spec.js b/spec/frontend/analytics/shared/components/metric_tile_spec.js index bebf3b8a65f..980dfad9eb0 100644 --- a/spec/frontend/cycle_analytics/metric_tile_spec.js +++ b/spec/frontend/analytics/shared/components/metric_tile_spec.js @@ -1,7 +1,7 @@ import { GlSingleStat } from '@gitlab/ui/dist/charts'; import { shallowMount } from '@vue/test-utils'; -import MetricTile from '~/cycle_analytics/components/metric_tile.vue'; -import MetricPopover from '~/cycle_analytics/components/metric_popover.vue'; +import MetricTile from '~/analytics/shared/components/metric_tile.vue'; +import MetricPopover from '~/analytics/shared/components/metric_popover.vue'; import { redirectTo } from '~/lib/utils/url_utility'; jest.mock('~/lib/utils/url_utility'); diff --git a/spec/frontend/analytics/shared/utils_spec.js b/spec/frontend/analytics/shared/utils_spec.js index 0513ccb2890..b48e2d971b5 100644 --- a/spec/frontend/analytics/shared/utils_spec.js +++ b/spec/frontend/analytics/shared/utils_spec.js @@ -1,9 +1,12 @@ +import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json'; import { filterBySearchTerm, extractFilterQueryParameters, extractPaginationQueryParameters, getDataZoomOption, + prepareTimeMetricsData, } from '~/analytics/shared/utils'; +import { slugify } from '~/lib/utils/text_utility'; import { objectToQuery } from '~/lib/utils/url_utility'; describe('filterBySearchTerm', () => { @@ -176,3 +179,36 @@ describe('getDataZoomOption', () => { }); }); }); + +describe('prepareTimeMetricsData', () => { + let prepared; + const [first, second] = metricsData; + delete second.identifier; // testing the case when identifier is missing + + const firstIdentifier = first.identifier; + const secondIdentifier = slugify(second.title); + + beforeEach(() => { + prepared = prepareTimeMetricsData([first, second], { + [firstIdentifier]: { description: 'Is a value that is good' }, + }); + }); + + it('will add a `identifier` based on the title', () => { + expect(prepared).toMatchObject([ + { identifier: firstIdentifier }, + { identifier: secondIdentifier }, + ]); + }); + + it('will add a `label` key', () => { + expect(prepared).toMatchObject([{ label: 'New Issues' }, { label: 'Commits' }]); + }); + + it('will add a popover description using the key if it is provided', () => { + expect(prepared).toMatchObject([ + { description: 'Is a value that is good' }, + { description: '' }, + ]); + }); +}); diff --git a/spec/frontend/cycle_analytics/base_spec.js b/spec/frontend/cycle_analytics/base_spec.js index 9a9415cc12a..7b1ef71da63 100644 --- a/spec/frontend/cycle_analytics/base_spec.js +++ b/spec/frontend/cycle_analytics/base_spec.js @@ -3,11 +3,11 @@ import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import Vuex from 'vuex'; import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue'; import BaseComponent from '~/cycle_analytics/components/base.vue'; import PathNavigation from '~/cycle_analytics/components/path_navigation.vue'; import StageTable from '~/cycle_analytics/components/stage_table.vue'; import ValueStreamFilters from '~/cycle_analytics/components/value_stream_filters.vue'; -import ValueStreamMetrics from '~/cycle_analytics/components/value_stream_metrics.vue'; import { NOT_ENOUGH_DATA_ERROR } from '~/cycle_analytics/constants'; import initState from '~/cycle_analytics/store/state'; import { diff --git a/spec/frontend/cycle_analytics/utils_spec.js b/spec/frontend/cycle_analytics/utils_spec.js index f98144d92a5..51405a1ba4d 100644 --- a/spec/frontend/cycle_analytics/utils_spec.js +++ b/spec/frontend/cycle_analytics/utils_spec.js @@ -1,13 +1,10 @@ -import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json'; import { transformStagesForPathNavigation, medianTimeToParsedSeconds, formatMedianValues, filterStagesByHiddenStatus, - prepareTimeMetricsData, buildCycleAnalyticsInitialData, } from '~/cycle_analytics/utils'; -import { slugify } from '~/lib/utils/text_utility'; import { selectedStage, allowedStages, @@ -89,39 +86,6 @@ describe('Value stream analytics utils', () => { }); }); - describe('prepareTimeMetricsData', () => { - let prepared; - const [first, second] = metricsData; - delete second.identifier; // testing the case when identifier is missing - - const firstIdentifier = first.identifier; - const secondIdentifier = slugify(second.title); - - beforeEach(() => { - prepared = prepareTimeMetricsData([first, second], { - [firstIdentifier]: { description: 'Is a value that is good' }, - }); - }); - - it('will add a `identifier` based on the title', () => { - expect(prepared).toMatchObject([ - { identifier: firstIdentifier }, - { identifier: secondIdentifier }, - ]); - }); - - it('will add a `label` key', () => { - expect(prepared).toMatchObject([{ label: 'New Issues' }, { label: 'Commits' }]); - }); - - it('will add a popover description using the key if it is provided', () => { - expect(prepared).toMatchObject([ - { description: 'Is a value that is good' }, - { description: '' }, - ]); - }); - }); - describe('buildCycleAnalyticsInitialData', () => { let res = null; const projectId = '5'; diff --git a/spec/frontend/cycle_analytics/value_stream_metrics_spec.js b/spec/frontend/cycle_analytics/value_stream_metrics_spec.js index a2d37699387..7a539b262fc 100644 --- a/spec/frontend/cycle_analytics/value_stream_metrics_spec.js +++ b/spec/frontend/cycle_analytics/value_stream_metrics_spec.js @@ -3,11 +3,11 @@ import { shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; import metricsData from 'test_fixtures/projects/analytics/value_stream_analytics/summary.json'; import waitForPromises from 'helpers/wait_for_promises'; +import ValueStreamMetrics from '~/analytics/shared/components/value_stream_metrics.vue'; import { METRIC_TYPE_SUMMARY } from '~/api/analytics_api'; -import ValueStreamMetrics from '~/cycle_analytics/components/value_stream_metrics.vue'; -import { METRICS_POPOVER_CONTENT } from '~/cycle_analytics/constants'; -import { prepareTimeMetricsData } from '~/cycle_analytics/utils'; -import MetricTile from '~/cycle_analytics/components/metric_tile.vue'; +import { METRICS_POPOVER_CONTENT } from '~/analytics/shared/constants'; +import { prepareTimeMetricsData } from '~/analytics/shared/utils'; +import MetricTile from '~/analytics/shared/components/metric_tile.vue'; import createFlash from '~/flash'; import { group } from './mock_data'; diff --git a/spec/frontend/diffs/components/diff_expansion_cell_spec.js b/spec/frontend/diffs/components/diff_expansion_cell_spec.js index f53f10d955d..cd472920bb9 100644 --- a/spec/frontend/diffs/components/diff_expansion_cell_spec.js +++ b/spec/frontend/diffs/components/diff_expansion_cell_spec.js @@ -91,7 +91,9 @@ describe('DiffExpansionCell', () => { }); expect(findExpandUp(wrapper).exists()).toBe(true); - expect(findExpandDown(wrapper).exists()).toBe(false); + expect(findExpandDown(wrapper).exists()).toBe(true); + expect(findExpandUp(wrapper).attributes('disabled')).not.toBeDefined(); + expect(findExpandDown(wrapper).attributes('disabled')).toBeDefined(); expect(findExpandAll(wrapper)).not.toBe(null); }); }); @@ -112,8 +114,10 @@ describe('DiffExpansionCell', () => { isBottom: true, }); - expect(findExpandUp(wrapper).exists()).toBe(false); expect(findExpandDown(wrapper).exists()).toBe(true); + expect(findExpandUp(wrapper).exists()).toBe(true); + expect(findExpandDown(wrapper).attributes('disabled')).not.toBeDefined(); + expect(findExpandUp(wrapper).attributes('disabled')).toBeDefined(); expect(findExpandAll(wrapper)).not.toBe(null); }); }); diff --git a/spec/frontend/google_tag_manager/index_spec.js b/spec/frontend/google_tag_manager/index_spec.js index f9199f32f1e..9112b0e17e7 100644 --- a/spec/frontend/google_tag_manager/index_spec.js +++ b/spec/frontend/google_tag_manager/index_spec.js @@ -224,8 +224,8 @@ describe('~/google_tag_manager/index', () => { { ecommerce: null }, { event: 'EECCheckout', - currencyCode: 'USD', ecommerce: { + currencyCode: 'USD', checkout: { actionField: { step: 1 }, products: [ @@ -254,8 +254,8 @@ describe('~/google_tag_manager/index', () => { expect(spy).toHaveBeenCalledWith({ ecommerce: null }); expect(spy).toHaveBeenCalledWith({ event: 'EECCheckout', - currencyCode: 'USD', ecommerce: { + currencyCode: 'USD', checkout: { actionField: { step: 1 }, products: [ @@ -291,8 +291,8 @@ describe('~/google_tag_manager/index', () => { expect(spy).toHaveBeenCalledWith({ ecommerce: null }); expect(spy).toHaveBeenCalledWith({ event: 'EECCheckout', - currencyCode: 'USD', ecommerce: { + currencyCode: 'USD', checkout: { actionField: { step: 1 }, products: [ @@ -347,8 +347,8 @@ describe('~/google_tag_manager/index', () => { { ecommerce: null }, { event: 'EECtransactionSuccess', - currencyCode: 'USD', ecommerce: { + currencyCode: 'USD', purchase: { actionField: { id: '123', diff --git a/spec/frontend/lib/utils/table_utility_spec.js b/spec/frontend/lib/utils/table_utility_spec.js index a67adac5efb..0ceccbe4c74 100644 --- a/spec/frontend/lib/utils/table_utility_spec.js +++ b/spec/frontend/lib/utils/table_utility_spec.js @@ -30,8 +30,10 @@ describe('table_utility', () => { ${'mergedAt'} | ${false} | ${'MERGED_AT_ASC'} ${'severity'} | ${true} | ${'SEVERITY_DESC'} ${'severity'} | ${false} | ${'SEVERITY_ASC'} + ${null} | ${null} | ${'SEVERITY'} + ${null} | ${null} | ${''} `( - 'returns $sortString when sortBy = "$sortBy" and sortDesc = "sortDesc"', + 'returns the expected sort object when the sort string is "$sortString"', ({ sortBy, sortDesc, sortString }) => { expect(tableUtils.sortStringToObject(sortString)).toStrictEqual({ sortBy, sortDesc }); }, diff --git a/spec/frontend/terraform/components/states_table_spec.js b/spec/frontend/terraform/components/states_table_spec.js index 9dbc8335851..fa9c8320b4f 100644 --- a/spec/frontend/terraform/components/states_table_spec.js +++ b/spec/frontend/terraform/components/states_table_spec.js @@ -1,4 +1,4 @@ -import { GlIcon, GlLoadingIcon, GlTooltip } from '@gitlab/ui'; +import { GlBadge, GlLoadingIcon, GlTooltip } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; import { nextTick } from 'vue'; import { useFakeDate } from 'helpers/fake_date'; @@ -139,7 +139,7 @@ describe('StatesTable', () => { const toolTip = state.find(GlTooltip); expect(state.text()).toContain(name); - expect(state.find(GlIcon).exists()).toBe(locked); + expect(state.find(GlBadge).exists()).toBe(locked); expect(state.find(GlLoadingIcon).exists()).toBe(loading); expect(toolTip.exists()).toBe(locked); diff --git a/spec/lib/gitlab/auth_spec.rb b/spec/lib/gitlab/auth_spec.rb index fc93910344c..706344831b8 100644 --- a/spec/lib/gitlab/auth_spec.rb +++ b/spec/lib/gitlab/auth_spec.rb @@ -10,29 +10,29 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do describe 'constants' do it 'API_SCOPES contains all scopes for API access' do - expect(subject::API_SCOPES).to eq %i[api read_user read_api] + expect(subject::API_SCOPES).to match_array %i[api read_user read_api] end it 'ADMIN_SCOPES contains all scopes for ADMIN access' do - expect(subject::ADMIN_SCOPES).to eq %i[sudo] + expect(subject::ADMIN_SCOPES).to match_array %i[sudo] end it 'REPOSITORY_SCOPES contains all scopes for REPOSITORY access' do - expect(subject::REPOSITORY_SCOPES).to eq %i[read_repository write_repository] + expect(subject::REPOSITORY_SCOPES).to match_array %i[read_repository write_repository] end it 'OPENID_SCOPES contains all scopes for OpenID Connect' do - expect(subject::OPENID_SCOPES).to eq [:openid] + expect(subject::OPENID_SCOPES).to match_array [:openid] end it 'DEFAULT_SCOPES contains all default scopes' do - expect(subject::DEFAULT_SCOPES).to eq [:api] + expect(subject::DEFAULT_SCOPES).to match_array [:api] end it 'optional_scopes contains all non-default scopes' do stub_container_registry_config(enabled: true) - expect(subject.optional_scopes).to eq %i[read_user read_api read_repository write_repository read_registry write_registry sudo openid profile email] + expect(subject.optional_scopes).to match_array %i[read_user read_api read_repository write_repository read_registry write_registry sudo openid profile email] end end @@ -40,21 +40,21 @@ RSpec.describe Gitlab::Auth, :use_clean_rails_memory_store_caching do it 'contains all non-default scopes' do stub_container_registry_config(enabled: true) - expect(subject.all_available_scopes).to eq %i[api read_user read_api read_repository write_repository read_registry write_registry sudo] + expect(subject.all_available_scopes).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo] end it 'contains for non-admin user all non-default scopes without ADMIN access' do stub_container_registry_config(enabled: true) user = create(:user, admin: false) - expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry write_registry] + expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry] end it 'contains for admin user all non-default scopes with ADMIN access' do stub_container_registry_config(enabled: true) user = create(:user, admin: true) - expect(subject.available_scopes_for(user)).to eq %i[api read_user read_api read_repository write_repository read_registry write_registry sudo] + expect(subject.available_scopes_for(user)).to match_array %i[api read_user read_api read_repository write_repository read_registry write_registry sudo] end context 'registry_scopes' do diff --git a/spec/lib/gitlab/omniauth_initializer_spec.rb b/spec/lib/gitlab/omniauth_initializer_spec.rb index 577d15b8495..42ae5844b95 100644 --- a/spec/lib/gitlab/omniauth_initializer_spec.rb +++ b/spec/lib/gitlab/omniauth_initializer_spec.rb @@ -101,5 +101,19 @@ RSpec.describe Gitlab::OmniauthInitializer do subject.execute([google_config]) end + + it 'configures defaults for gitlab' do + conf = { + 'name' => 'gitlab', + "args" => {} + } + + expect(devise_config).to receive(:omniauth).with( + :gitlab, + authorize_params: { gl_auth_type: 'login' } + ) + + subject.execute([conf]) + end end end diff --git a/spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb index 64fa8d26d81..4169546edad 100644 --- a/spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb +++ b/spec/lib/gitlab/usage_data_counters/jetbrains_plugin_activity_unique_counter_spec.rb @@ -2,62 +2,14 @@ require 'spec_helper' -RSpec.shared_examples 'a tracked jetbrains unique action' do |event| - before do - stub_application_setting(usage_ping_enabled: true) - end - - def count_unique(date_from:, date_to:) - Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: action, start_date: date_from, end_date: date_to) - end - - it 'tracks when the user agent is from jetbrains' do - aggregate_failures do - user_agent = { user_agent: 'gitlab-jetbrains-plugin/0.0.1 intellij-idea/2021.2.4 java/11.0.13 mac-os-x/aarch64/12.1' } - - expect(track_action(user: user1, **user_agent)).to be_truthy - expect(track_action(user: user1, **user_agent)).to be_truthy - expect(track_action(user: user2, **user_agent)).to be_truthy - - expect(count_unique(date_from: time - 1.week, date_to: time + 1.week)).to eq(2) - end - end - - it 'does not track when the user agent is not from jetbrains' do - aggregate_failures do - user_agent = { user_agent: 'normal_user_agent' } - - expect(track_action(user: user1, **user_agent)).to be_falsey - expect(track_action(user: user1, **user_agent)).to be_falsey - expect(track_action(user: user2, **user_agent)).to be_falsey - - expect(count_unique(date_from: time - 1.week, date_to: time + 1.week)).to eq(0) - end - end - - it 'does not track if user agent is not present' do - expect(track_action(user: nil, user_agent: nil)).to be_nil - end - - it 'does not track if user is not present' do - user_agent = { user_agent: 'gitlab-jetbrains-plugin/0.0.1 intellij-idea/2021.2.4 java/11.0.13 mac-os-x/aarch64/12.1' } - - expect(track_action(user: nil, **user_agent)).to be_nil - end -end - -RSpec.describe Gitlab::UsageDataCounters::JetBrainsPluginActivityUniqueCounter, :clean_gitlab_redis_shared_state do +RSpec.describe Gitlab::UsageDataCounters::JetBrainsPluginActivityUniqueCounter, :clean_gitlab_redis_shared_state do # rubocop:disable RSpec/FilePath let(:user1) { build(:user, id: 1) } let(:user2) { build(:user, id: 2) } let(:time) { Time.current } + let(:action) { described_class::JETBRAINS_API_REQUEST_ACTION } + let(:user_agent) { { user_agent: 'gitlab-jetbrains-plugin/0.0.1 intellij-idea/2021.2.4 java/11.0.13 mac-os-x/aarch64/12.1' } } context 'when tracking a jetbrains api request' do - it_behaves_like 'a tracked jetbrains unique action' do - let(:action) { described_class::JETBRAINS_API_REQUEST_ACTION } - - def track_action(params) - described_class.track_api_request_when_trackable(**params) - end - end + it_behaves_like 'a request from an extension' end end diff --git a/spec/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter_spec.rb b/spec/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter_spec.rb new file mode 100644 index 00000000000..640dadd8c0b --- /dev/null +++ b/spec/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::UsageDataCounters::VSCodeExtensionActivityUniqueCounter, :clean_gitlab_redis_shared_state do # rubocop:disable RSpec/FilePath + let(:user1) { build(:user, id: 1) } + let(:user2) { build(:user, id: 2) } + let(:time) { Time.current } + let(:action) { described_class::VS_CODE_API_REQUEST_ACTION } + let(:user_agent) { { user_agent: 'vs-code-gitlab-workflow/3.11.1 VSCode/1.52.1 Node.js/12.14.1 (darwin; x64)' } } + + context 'when tracking a vs code api request' do + it_behaves_like 'a request from an extension' + end +end diff --git a/spec/requests/openid_connect_spec.rb b/spec/requests/openid_connect_spec.rb index 8ee752da44e..70a310ba0d5 100644 --- a/spec/requests/openid_connect_spec.rb +++ b/spec/requests/openid_connect_spec.rb @@ -275,7 +275,7 @@ RSpec.describe 'OpenID Connect requests' do expect(response).to have_gitlab_http_status(:ok) expect(json_response['issuer']).to eq('http://localhost') expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys') - expect(json_response['scopes_supported']).to eq(%w[api read_user read_api read_repository write_repository sudo openid profile email]) + expect(json_response['scopes_supported']).to match_array %w[api read_user read_api read_repository write_repository sudo openid profile email] end context 'with a cross-origin request' do @@ -285,7 +285,7 @@ RSpec.describe 'OpenID Connect requests' do expect(response).to have_gitlab_http_status(:ok) expect(json_response['issuer']).to eq('http://localhost') expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys') - expect(json_response['scopes_supported']).to eq(%w[api read_user read_api read_repository write_repository sudo openid profile email]) + expect(json_response['scopes_supported']).to match_array %w[api read_user read_api read_repository write_repository sudo openid profile email] end it_behaves_like 'cross-origin GET request' diff --git a/spec/services/ci/process_sync_events_service_spec.rb b/spec/services/ci/process_sync_events_service_spec.rb index 3f4b2a0f7f2..6b9717fe57d 100644 --- a/spec/services/ci/process_sync_events_service_spec.rb +++ b/spec/services/ci/process_sync_events_service_spec.rb @@ -25,6 +25,8 @@ RSpec.describe Ci::ProcessSyncEventsService do project2.update!(group: parent_group_2) end + it { is_expected.to eq(service_results(2, 2, 2)) } + it 'consumes events' do expect { execute }.to change(Projects::SyncEvent, :count).from(2).to(0) @@ -36,20 +38,32 @@ RSpec.describe Ci::ProcessSyncEventsService do ) end - it 'enqueues Projects::ProcessSyncEventsWorker if any left' do - stub_const("#{described_class}::BATCH_SIZE", 1) + context 'when any event left after processing' do + before do + stub_const("#{described_class}::BATCH_SIZE", 1) + end - expect(Projects::ProcessSyncEventsWorker).to receive(:perform_async) + it { is_expected.to eq(service_results(2, 1, 1)) } - execute + it 'enqueues Projects::ProcessSyncEventsWorker' do + expect(Projects::ProcessSyncEventsWorker).to receive(:perform_async) + + execute + end end - it 'does not enqueue Projects::ProcessSyncEventsWorker if no left' do - stub_const("#{described_class}::BATCH_SIZE", 2) + context 'when no event left after processing' do + before do + stub_const("#{described_class}::BATCH_SIZE", 2) + end - expect(Projects::ProcessSyncEventsWorker).not_to receive(:perform_async) + it { is_expected.to eq(service_results(2, 2, 2)) } - execute + it 'does not enqueue Projects::ProcessSyncEventsWorker' do + expect(Projects::ProcessSyncEventsWorker).not_to receive(:perform_async) + + execute + end end context 'when there is no event' do @@ -57,27 +71,45 @@ RSpec.describe Ci::ProcessSyncEventsService do Projects::SyncEvent.delete_all end + it { is_expected.to eq(service_results(0, 0, nil)) } + it 'does nothing' do expect { execute }.not_to change(Projects::SyncEvent, :count) end end - it 'does not delete non-executed events' do - new_project = create(:project) - sync_event_class.delete_all + context 'when there is non-executed events' do + before do + new_project = create(:project) + sync_event_class.delete_all - project1.update!(group: parent_group_2) - new_project.update!(group: parent_group_1) - project2.update!(group: parent_group_1) + project1.update!(group: parent_group_2) + new_project.update!(group: parent_group_1) + project2.update!(group: parent_group_1) - new_project_sync_event = new_project.sync_events.last + @new_project_sync_event = new_project.sync_events.last - allow(sync_event_class).to receive(:preload_synced_relation).and_return( - sync_event_class.where.not(id: new_project_sync_event) - ) + allow(sync_event_class).to receive(:preload_synced_relation).and_return( + sync_event_class.where.not(id: @new_project_sync_event) + ) + end + + it { is_expected.to eq(service_results(3, 2, 2)) } + + it 'does not delete non-executed events' do + expect { execute }.to change(Projects::SyncEvent, :count).from(3).to(1) + expect(@new_project_sync_event.reload).to be_persisted + end + end + + private - expect { execute }.to change(Projects::SyncEvent, :count).from(3).to(1) - expect(new_project_sync_event.reload).to be_persisted + def service_results(total, consumable, processed) + { + estimated_total_events: total, + consumable_events: consumable, + processed_events: processed + }.compact end end diff --git a/spec/lib/gitlab/usage_data_counters/vscode_extenion_activity_unique_counter_spec.rb b/spec/support/shared_examples/lib/gitlab/usage_data_counters/code_review_extension_request_examples.rb index 7593d51fe76..6221366ab51 100644 --- a/spec/lib/gitlab/usage_data_counters/vscode_extenion_activity_unique_counter_spec.rb +++ b/spec/support/shared_examples/lib/gitlab/usage_data_counters/code_review_extension_request_examples.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.shared_examples 'a tracked vs code unique action' do |event| +RSpec.shared_examples 'a request from an extension' do |event| before do stub_application_setting(usage_ping_enabled: true) end @@ -11,10 +11,12 @@ RSpec.shared_examples 'a tracked vs code unique action' do |event| Gitlab::UsageDataCounters::HLLRedisCounter.unique_events(event_names: action, start_date: date_from, end_date: date_to) end - it 'tracks when the user agent is from vs code' do - aggregate_failures do - user_agent = { user_agent: 'vs-code-gitlab-workflow/3.11.1 VSCode/1.52.1 Node.js/12.14.1 (darwin; x64)' } + def track_action(params) + described_class.track_api_request_when_trackable(**params) + end + it 'tracks when the user agent is matching' do + aggregate_failures do expect(track_action(user: user1, **user_agent)).to be_truthy expect(track_action(user: user1, **user_agent)).to be_truthy expect(track_action(user: user2, **user_agent)).to be_truthy @@ -23,7 +25,7 @@ RSpec.shared_examples 'a tracked vs code unique action' do |event| end end - it 'does not track when the user agent is not from vs code' do + it 'does not track when the user agent is not matching' do aggregate_failures do user_agent = { user_agent: 'normal_user_agent' } @@ -40,24 +42,6 @@ RSpec.shared_examples 'a tracked vs code unique action' do |event| end it 'does not track if user is not present' do - user_agent = { user_agent: 'vs-code-gitlab-workflow/3.11.1 VSCode/1.52.1 Node.js/12.14.1 (darwin; x64)' } - expect(track_action(user: nil, **user_agent)).to be_nil end end - -RSpec.describe Gitlab::UsageDataCounters::VSCodeExtensionActivityUniqueCounter, :clean_gitlab_redis_shared_state do - let(:user1) { build(:user, id: 1) } - let(:user2) { build(:user, id: 2) } - let(:time) { Time.current } - - context 'when tracking a vs code api request' do - it_behaves_like 'a tracked vs code unique action' do - let(:action) { described_class::VS_CODE_API_REQUEST_ACTION } - - def track_action(params) - described_class.track_api_request_when_trackable(**params) - end - end - end -end diff --git a/spec/workers/namespaces/process_sync_events_worker_spec.rb b/spec/workers/namespaces/process_sync_events_worker_spec.rb index 59be1fffdb4..c15a74a2934 100644 --- a/spec/workers/namespaces/process_sync_events_worker_spec.rb +++ b/spec/workers/namespaces/process_sync_events_worker_spec.rb @@ -7,10 +7,12 @@ RSpec.describe Namespaces::ProcessSyncEventsWorker do let!(:group2) { create(:group) } let!(:group3) { create(:group) } + subject(:worker) { described_class.new } + include_examples 'an idempotent worker' describe '#perform' do - subject(:perform) { described_class.new.perform } + subject(:perform) { worker.perform } before do group2.update!(parent: group1) @@ -28,5 +30,13 @@ RSpec.describe Namespaces::ProcessSyncEventsWorker do an_object_having_attributes(namespace_id: group3.id, traversal_ids: [group1.id, group2.id, group3.id]) ) end + + it 'logs the service result', :aggregate_failures do + expect(worker).to receive(:log_extra_metadata_on_done).with(:estimated_total_events, 5) + expect(worker).to receive(:log_extra_metadata_on_done).with(:consumable_events, 5) + expect(worker).to receive(:log_extra_metadata_on_done).with(:processed_events, 5) + + perform + end end end diff --git a/spec/workers/projects/process_sync_events_worker_spec.rb b/spec/workers/projects/process_sync_events_worker_spec.rb index 600fbbc6b20..963e0ad1028 100644 --- a/spec/workers/projects/process_sync_events_worker_spec.rb +++ b/spec/workers/projects/process_sync_events_worker_spec.rb @@ -6,10 +6,12 @@ RSpec.describe Projects::ProcessSyncEventsWorker do let!(:group) { create(:group) } let!(:project) { create(:project) } + subject(:worker) { described_class.new } + include_examples 'an idempotent worker' describe '#perform' do - subject(:perform) { described_class.new.perform } + subject(:perform) { worker.perform } before do project.update!(namespace: group) @@ -24,5 +26,13 @@ RSpec.describe Projects::ProcessSyncEventsWorker do an_object_having_attributes(namespace_id: group.id) ) end + + it 'logs the service result', :aggregate_failures do + expect(worker).to receive(:log_extra_metadata_on_done).with(:estimated_total_events, 2) + expect(worker).to receive(:log_extra_metadata_on_done).with(:consumable_events, 2) + expect(worker).to receive(:log_extra_metadata_on_done).with(:processed_events, 2) + + perform + end end end |