Commit c6e1fec3 authored by Peter Hegman's avatar Peter Hegman

Merge branch 'disable-error-tracking-by-default' into 'master'

Disallow integrated error tracking by default

See merge request gitlab-org/gitlab!81767
parents 20b7d4cf 99ebbe65
......@@ -26,7 +26,7 @@ import {
trackErrorStatusUpdateOptions,
} from '../utils';
import { severityLevel, severityLevelVariant, errorStatus } from './constants';
import { severityLevel, severityLevelVariant, errorStatus } from '../constants';
import Stacktrace from './stacktrace.vue';
const SENTRY_TIMEOUT = 10000;
......
<script>
import {
GlAlert,
GlEmptyState,
GlButton,
GlIcon,
......@@ -10,6 +11,7 @@ import {
GlDropdown,
GlDropdownItem,
GlDropdownDivider,
GlSprintf,
GlTooltipDirective,
GlPagination,
} from '@gitlab/ui';
......@@ -21,6 +23,7 @@ import { __ } from '~/locale';
import Tracking from '~/tracking';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { trackErrorListViewsOptions, trackErrorStatusUpdateOptions } from '../utils';
import { I18N_ERROR_TRACKING_LIST } from '../constants';
import ErrorTrackingActions from './error_tracking_actions.vue';
export const tableDataClass = 'table-col d-flex d-md-table-cell align-items-center';
......@@ -29,6 +32,7 @@ export default {
FIRST_PAGE: 1,
PREV_PAGE: 1,
NEXT_PAGE: 2,
i18n: I18N_ERROR_TRACKING_LIST,
fields: [
{
key: 'error',
......@@ -71,6 +75,7 @@ export default {
frequency: __('Frequency'),
},
components: {
GlAlert,
GlEmptyState,
GlButton,
GlDropdown,
......@@ -81,6 +86,7 @@ export default {
GlLoadingIcon,
GlTable,
GlFormInput,
GlSprintf,
GlPagination,
TimeAgo,
ErrorTrackingActions,
......@@ -117,12 +123,17 @@ export default {
type: String,
required: true,
},
showIntegratedTrackingDisabledAlert: {
type: Boolean,
required: false,
},
},
hasLocalStorage: AccessorUtils.canUseLocalStorage(),
data() {
return {
errorSearchQuery: '',
pageValue: this.$options.FIRST_PAGE,
isAlertDismissed: false,
};
},
computed: {
......@@ -142,6 +153,9 @@ export default {
errorTrackingHelpUrl() {
return helpPagePath('operations/error_tracking');
},
showIntegratedDisabledAlert() {
return !this.isAlertDismissed && this.showIntegratedTrackingDisabledAlert;
},
},
watch: {
pagination() {
......@@ -150,6 +164,8 @@ export default {
}
},
},
epicLink: 'https://gitlab.com/gitlab-org/gitlab/-/issues/353639',
featureFlagLink: helpPagePath('operations/error_tracking'),
created() {
if (this.errorTrackingEnabled) {
this.setEndpoint(this.indexPath);
......@@ -232,6 +248,34 @@ export default {
<template>
<div class="error-list">
<div v-if="errorTrackingEnabled">
<gl-alert
v-if="showIntegratedDisabledAlert"
variant="danger"
data-testid="integrated-disabled-alert"
@dismiss="isAlertDismissed = true"
>
<gl-sprintf :message="this.$options.i18n.integratedErrorTrackingDisabledText">
<template #epicLink="{ content }">
<gl-link :href="$options.epicLink" target="_blank">{{ content }}</gl-link>
</template>
<template #flagLink="{ content }">
<gl-link :href="$options.featureFlagLink" target="_blank">{{ content }}</gl-link>
</template>
<template #settingsLink="{ content }">
<gl-link :href="enableErrorTrackingLink" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
<div>
<gl-button
category="primary"
variant="confirm"
:href="enableErrorTrackingLink"
class="gl-mr-auto gl-mt-3"
>
{{ $options.i18n.viewProjectSettingsButton }}
</gl-button>
</div>
</gl-alert>
<div
class="row flex-column flex-md-row align-items-md-center m-0 mt-sm-2 p-3 p-sm-3 bg-secondary border"
>
......
import { s__ } from '~/locale';
export const severityLevel = {
FATAL: 'fatal',
ERROR: 'error',
......@@ -19,3 +21,10 @@ export const errorStatus = {
RESOLVED: 'resolved',
UNRESOLVED: 'unresolved',
};
export const I18N_ERROR_TRACKING_LIST = {
integratedErrorTrackingDisabledText: s__(
'ErrorTracking|Integrated error tracking is %{epicLinkStart}turned off by default%{epicLinkEnd} and no longer active for this project. To re-enable error tracking on self-hosted instances, you can either %{flagLinkStart}turn on the feature flag%{flagLinkEnd} for integrated error tracking, or provide a %{settingsLinkStart}Sentry API URL and Auth Token%{settingsLinkEnd} on your project settings page. However, error tracking is not ready for production use and cannot be enabled on GitLab.com.',
),
viewProjectSettingsButton: s__('ErrorTracking|View project settings'),
};
......@@ -14,10 +14,15 @@ export default () => {
projectPath,
listPath,
} = domEl.dataset;
let { errorTrackingEnabled, userCanEnableErrorTracking } = domEl.dataset;
let {
errorTrackingEnabled,
userCanEnableErrorTracking,
showIntegratedTrackingDisabledAlert,
} = domEl.dataset;
errorTrackingEnabled = parseBoolean(errorTrackingEnabled);
userCanEnableErrorTracking = parseBoolean(userCanEnableErrorTracking);
showIntegratedTrackingDisabledAlert = parseBoolean(showIntegratedTrackingDisabledAlert);
// eslint-disable-next-line no-new
new Vue({
......@@ -36,6 +41,7 @@ export default () => {
userCanEnableErrorTracking,
projectPath,
listPath,
showIntegratedTrackingDisabledAlert,
},
});
},
......
<script>
import {
GlAlert,
GlButton,
GlFormGroup,
GlFormCheckbox,
GlFormRadioGroup,
GlFormRadio,
GlFormInputGroup,
GlLink,
GlSprintf,
} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { helpPagePath } from '~/helpers/help_page_helper';
import { I18N_ERROR_TRACKING_SETTINGS } from '../constants';
import ErrorTrackingForm from './error_tracking_form.vue';
import ProjectDropdown from './project_dropdown.vue';
export default {
i18n: I18N_ERROR_TRACKING_SETTINGS,
components: {
ErrorTrackingForm,
GlAlert,
GlButton,
GlFormCheckbox,
GlFormGroup,
GlFormRadioGroup,
GlFormRadio,
GlFormInputGroup,
GlLink,
GlSprintf,
ProjectDropdown,
ClipboardButton,
},
mixins: [glFeatureFlagsMixin()],
props: {
initialApiHost: {
type: String,
......@@ -62,6 +73,11 @@ export default {
default: null,
},
},
data() {
return {
isAlertDismissed: false,
};
},
computed: {
...mapGetters([
'dropdownLabel',
......@@ -81,12 +97,34 @@ export default {
showGitlabDsnSetting() {
return this.integrated && this.enabled && this.gitlabDsn;
},
showIntegratedErrorTracking() {
return this.glFeatures.integratedErrorTracking === true;
},
setInitialEnabled() {
if (this.showIntegratedErrorTracking) {
return this.initialEnabled;
}
if (this.initialIntegrated === 'true') {
return 'false';
}
return this.initialEnabled;
},
showIntegratedTrackingDisabledAlert() {
return (
!this.isAlertDismissed &&
!this.showIntegratedErrorTracking &&
this.initialIntegrated === 'true' &&
this.initialEnabled === 'true'
);
},
},
epicLink: 'https://gitlab.com/gitlab-org/gitlab/-/issues/353639',
featureFlagLink: helpPagePath('operations/error_tracking'),
created() {
this.setInitialState({
apiHost: this.initialApiHost,
enabled: this.initialEnabled,
integrated: this.initialIntegrated,
enabled: this.setInitialEnabled,
integrated: this.showIntegratedErrorTracking && this.initialIntegrated,
project: this.initialProject,
token: this.initialToken,
listProjectsEndpoint: this.listProjectsEndpoint,
......@@ -104,21 +142,41 @@ export default {
handleSubmit() {
this.updateSettings();
},
dismissAlert() {
this.isAlertDismissed = true;
},
},
};
</script>
<template>
<div>
<gl-alert v-if="showIntegratedTrackingDisabledAlert" variant="danger" @dismiss="dismissAlert">
<gl-sprintf :message="this.$options.i18n.integratedErrorTrackingDisabledText">
<template #epicLink="{ content }">
<gl-link :href="$options.epicLink" target="_blank">{{ content }}</gl-link>
</template>
<template #flagLink="{ content }">
<gl-link :href="$options.featureFlagLink" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</gl-alert>
<gl-form-group
:label="s__('ErrorTracking|Enable error tracking')"
label-for="error-tracking-enabled"
>
<gl-form-checkbox id="error-tracking-enabled" :checked="enabled" @change="updateEnabled">
<gl-form-checkbox
id="error-tracking-enabled"
:checked="enabled"
data-testid="error-tracking-enabled"
@change="updateEnabled"
>
{{ s__('ErrorTracking|Active') }}
</gl-form-checkbox>
</gl-form-group>
<gl-form-group
v-if="showIntegratedErrorTracking"
:label="s__('ErrorTracking|Error tracking backend')"
data-testid="tracking-backend-settings"
>
......
import { s__ } from '~/locale';
export const I18N_ERROR_TRACKING_SETTINGS = {
integratedErrorTrackingDisabledText: s__(
'ErrorTracking|Integrated error tracking is %{epicLinkStart}turned off by default%{epicLinkEnd} and no longer active for this project. To re-enable error tracking on self-hosted instances, you can either %{flagLinkStart}turn on the feature flag%{flagLinkEnd} for integrated error tracking, or provide a Sentry API URL and Auth Token below. However, error tracking is not ready for production use and cannot be enabled on GitLab.com.',
),
};
......@@ -6,6 +6,10 @@ class Projects::ErrorTrackingController < Projects::ErrorTracking::BaseControlle
before_action :authorize_read_sentry_issue!
before_action :set_issue_id, only: :details
before_action only: [:index] do
push_frontend_feature_flag(:integrated_error_tracking, project)
end
def index
respond_to do |format|
format.html
......
......@@ -7,6 +7,10 @@ module Projects
before_action :authorize_admin_operations!
before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token]
before_action do
push_frontend_feature_flag(:integrated_error_tracking, project)
end
respond_to :json, only: [:reset_alerting_token, :reset_pagerduty_token]
helper_method :error_tracking_setting
......
......@@ -12,7 +12,8 @@ module Projects::ErrorTrackingHelper
'error-tracking-enabled' => error_tracking_enabled.to_s,
'project-path' => project.full_path,
'list-path' => project_error_tracking_index_path(project),
'illustration-path' => image_path('illustrations/cluster_popover.svg')
'illustration-path' => image_path('illustrations/cluster_popover.svg'),
'show-integrated-tracking-disabled-alert' => show_integrated_tracking_disabled_alert?(project).to_s
}
end
......@@ -27,4 +28,15 @@ module Projects::ErrorTrackingHelper
'issue-stack-trace-path' => stack_trace_project_error_tracking_index_path(*opts)
}
end
private
def show_integrated_tracking_disabled_alert?(project)
return false if ::Feature.enabled?(:integrated_error_tracking, project)
setting ||= project.error_tracking_setting ||
project.build_error_tracking_setting
setting.integrated_enabled?
end
end
......@@ -59,6 +59,10 @@ module ErrorTracking
integrated
end
def integrated_enabled?
enabled? && integrated_client?
end
def gitlab_dsn
strong_memoize(:gitlab_dsn) do
client_key&.sentry_dsn
......
---
name: integrated_error_tracking
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81767
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/353956
milestone: '14.9'
type: development
group: group::respond
default_enabled: false
......@@ -129,7 +129,17 @@ If another event occurs, the error reverts to unresolved.
## Integrated error tracking
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329596) in GitLab 14.4.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329596) in GitLab 14.4.
> - [Disabled](https://gitlab.com/gitlab-org/gitlab/-/issues/353639) in GitLab 14.9 [with a flag](../administration/feature_flags.md) named `integrated_error_tracking`. Disabled by default.
FLAG:
By default this feature is not available. To make it available on self-managed GitLab, ask an
administrator to [enable the feature flag](../administration/feature_flags.md)
named `integrated_error_tracking`. The feature is not ready for production use.
On GitLab.com, this feature is not available.
WARNING:
Turning on integrated error tracking may impact performance, depending on your error rates.
Integrated error tracking is a lightweight alternative to Sentry backend.
You still use Sentry SDK with your application. But you don't need to deploy Sentry
......
......@@ -9,6 +9,12 @@ module API
expose :sentry_external_url
expose :api_url
expose :integrated
def integrated
return false unless ::Feature.enabled?(:integrated_error_tracking, object.project)
object.integrated_client?
end
end
class ClientKey < Grape::Entity
......
......@@ -28,8 +28,8 @@ module API
end
def feature_enabled?
project.error_tracking_setting&.enabled? &&
project.error_tracking_setting&.integrated_client?
Feature.enabled?(:integrated_error_tracking, project) &&
project.error_tracking_setting&.integrated_enabled?
end
def find_client_key(public_key)
......
......@@ -14443,6 +14443,12 @@ msgstr ""
msgid "ErrorTracking|If you self-host Sentry, enter your Sentry instance's full URL. If you use Sentry's hosted solution, enter https://sentry.io"
msgstr ""
msgid "ErrorTracking|Integrated error tracking is %{epicLinkStart}turned off by default%{epicLinkEnd} and no longer active for this project. To re-enable error tracking on self-hosted instances, you can either %{flagLinkStart}turn on the feature flag%{flagLinkEnd} for integrated error tracking, or provide a %{settingsLinkStart}Sentry API URL and Auth Token%{settingsLinkEnd} on your project settings page. However, error tracking is not ready for production use and cannot be enabled on GitLab.com."
msgstr ""
msgid "ErrorTracking|Integrated error tracking is %{epicLinkStart}turned off by default%{epicLinkEnd} and no longer active for this project. To re-enable error tracking on self-hosted instances, you can either %{flagLinkStart}turn on the feature flag%{flagLinkEnd} for integrated error tracking, or provide a Sentry API URL and Auth Token below. However, error tracking is not ready for production use and cannot be enabled on GitLab.com."
msgstr ""
msgid "ErrorTracking|No projects available"
msgstr ""
......@@ -14452,6 +14458,9 @@ msgstr ""
msgid "ErrorTracking|To enable project selection, enter a valid Auth Token."
msgstr ""
msgid "ErrorTracking|View project settings"
msgstr ""
msgid "Errors"
msgstr ""
......
......@@ -10,11 +10,7 @@ import {
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import {
severityLevel,
severityLevelVariant,
errorStatus,
} from '~/error_tracking/components/constants';
import { severityLevel, severityLevelVariant, errorStatus } from '~/error_tracking/constants';
import ErrorDetails from '~/error_tracking/components/error_details.vue';
import Stacktrace from '~/error_tracking/components/stacktrace.vue';
import {
......
......@@ -7,6 +7,7 @@ import ErrorTrackingActions from '~/error_tracking/components/error_tracking_act
import ErrorTrackingList from '~/error_tracking/components/error_tracking_list.vue';
import { trackErrorListViewsOptions, trackErrorStatusUpdateOptions } from '~/error_tracking/utils';
import Tracking from '~/tracking';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import errorsList from './list_mock.json';
Vue.use(Vuex);
......@@ -25,28 +26,33 @@ describe('ErrorTrackingList', () => {
const findLoadingIcon = () => wrapper.find(GlLoadingIcon);
const findPagination = () => wrapper.find(GlPagination);
const findErrorActions = () => wrapper.find(ErrorTrackingActions);
const findIntegratedDisabledAlert = () => wrapper.findByTestId('integrated-disabled-alert');
function mountComponent({
errorTrackingEnabled = true,
userCanEnableErrorTracking = true,
showIntegratedTrackingDisabledAlert = false,
stubs = {},
} = {}) {
wrapper = mount(ErrorTrackingList, {
store,
propsData: {
indexPath: '/path',
listPath: '/error_tracking',
projectPath: 'project/test',
enableErrorTrackingLink: '/link',
userCanEnableErrorTracking,
errorTrackingEnabled,
illustrationPath: 'illustration/path',
},
stubs: {
...stubChildren(ErrorTrackingList),
...stubs,
},
});
wrapper = extendedWrapper(
mount(ErrorTrackingList, {
store,
propsData: {
indexPath: '/path',
listPath: '/error_tracking',
projectPath: 'project/test',
enableErrorTrackingLink: '/link',
userCanEnableErrorTracking,
errorTrackingEnabled,
showIntegratedTrackingDisabledAlert,
illustrationPath: 'illustration/path',
},
stubs: {
...stubChildren(ErrorTrackingList),
...stubs,
},
}),
);
}
beforeEach(() => {
......@@ -223,6 +229,31 @@ describe('ErrorTrackingList', () => {
});
});
describe('When the integrated tracking diabled alert should be shown', () => {
beforeEach(() => {
mountComponent({
showIntegratedTrackingDisabledAlert: true,
stubs: {
GlAlert: false,
},
});
});
it('shows the alert box', () => {
expect(findIntegratedDisabledAlert().exists()).toBe(true);
});
describe('when alert is dismissed', () => {
it('hides the alert box', async () => {
findIntegratedDisabledAlert().vm.$emit('dismiss');
await nextTick();
expect(findIntegratedDisabledAlert().exists()).toBe(false);
});
});
});
describe('When the ignore button on an error is clicked', () => {
beforeEach(() => {
store.state.list.loading = false;
......
......@@ -18,19 +18,27 @@ describe('error tracking settings app', () => {
let store;
let wrapper;
function mountComponent() {
const defaultProps = {
initialEnabled: 'true',
initialIntegrated: 'false',
initialApiHost: TEST_HOST,
initialToken: 'someToken',
initialProject: null,
listProjectsEndpoint: TEST_HOST,
operationsSettingsEndpoint: TEST_HOST,
gitlabDsn: TEST_GITLAB_DSN,
};
function mountComponent({
glFeatures = { integratedErrorTracking: false },
props = defaultProps,
} = {}) {
wrapper = extendedWrapper(
shallowMount(ErrorTrackingSettings, {
store, // Override the imported store
propsData: {
initialEnabled: 'true',
initialIntegrated: 'false',
initialApiHost: TEST_HOST,
initialToken: 'someToken',
initialProject: null,
listProjectsEndpoint: TEST_HOST,
operationsSettingsEndpoint: TEST_HOST,
gitlabDsn: TEST_GITLAB_DSN,
propsData: { ...props },
provide: {
glFeatures,
},
stubs: {
GlFormInputGroup, // we need this non-shallow to query for a component within a slot
......@@ -47,6 +55,7 @@ describe('error tracking settings app', () => {
const findElementWithText = (wrappers, text) => wrappers.filter((item) => item.text() === text);
const findSentrySettings = () => wrapper.findByTestId('sentry-setting-form');
const findDsnSettings = () => wrapper.findByTestId('gitlab-dsn-setting-form');
const findEnabledCheckbox = () => wrapper.findByTestId('error-tracking-enabled');
const enableGitLabErrorTracking = async () => {
findBackendSettingsRadioGroup().vm.$emit('change', true);
......@@ -88,62 +97,104 @@ describe('error tracking settings app', () => {
});
describe('tracking-backend settings', () => {
it('contains a form-group with the correct label', () => {
expect(findBackendSettingsSection().attributes('label')).toBe('Error tracking backend');
it('does not contain backend settings section', () => {
expect(findBackendSettingsSection().exists()).toBe(false);
});
it('contains a radio group', () => {
expect(findBackendSettingsRadioGroup().exists()).toBe(true);
it('shows the sentry form', () => {
expect(findSentrySettings().exists()).toBe(true);
});
it('contains the correct radio buttons', () => {
expect(findBackendSettingsRadioButtons()).toHaveLength(2);
describe('enabled setting is true', () => {
describe('integrated setting is true', () => {
beforeEach(() => {
mountComponent({
props: { ...defaultProps, initialEnabled: 'true', initialIntegrated: 'true' },
});
});
it('displays enabled as false', () => {
expect(findEnabledCheckbox().attributes('checked')).toBeUndefined();
});
});
describe('integrated setting is false', () => {
beforeEach(() => {
mountComponent({
props: { ...defaultProps, initialEnabled: 'true', initialIntegrated: 'false' },
});
});
expect(findElementWithText(findBackendSettingsRadioButtons(), 'Sentry')).toHaveLength(1);
expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1);
it('displays enabled as true', () => {
expect(findEnabledCheckbox().attributes('checked')).toBe('true');
});
});
});
it('hides the Sentry settings when GitLab is selected as a tracking-backend', async () => {
expect(findSentrySettings().exists()).toBe(true);
describe('integrated_error_tracking feature flag enabled', () => {
beforeEach(() => {
mountComponent({
glFeatures: { integratedErrorTracking: true },
});
});
await enableGitLabErrorTracking();
it('contains a form-group with the correct label', () => {
expect(findBackendSettingsSection().attributes('label')).toBe('Error tracking backend');
});
expect(findSentrySettings().exists()).toBe(false);
});
it('contains a radio group', () => {
expect(findBackendSettingsRadioGroup().exists()).toBe(true);
});
describe('GitLab DSN section', () => {
it('is visible when GitLab is selected as a tracking-backend and DSN is present', async () => {
expect(findDsnSettings().exists()).toBe(false);
it('contains the correct radio buttons', () => {
expect(findBackendSettingsRadioButtons()).toHaveLength(2);
expect(findElementWithText(findBackendSettingsRadioButtons(), 'Sentry')).toHaveLength(1);
expect(findElementWithText(findBackendSettingsRadioButtons(), 'GitLab')).toHaveLength(1);
});
it('hides the Sentry settings when GitLab is selected as a tracking-backend', async () => {
expect(findSentrySettings().exists()).toBe(true);
await enableGitLabErrorTracking();
expect(findDsnSettings().exists()).toBe(true);
expect(findSentrySettings().exists()).toBe(false);
});
it('contains copy-to-clipboard functionality for the GitLab DSN string', async () => {
await enableGitLabErrorTracking();
describe('GitLab DSN section', () => {
it('is visible when GitLab is selected as a tracking-backend and DSN is present', async () => {
expect(findDsnSettings().exists()).toBe(false);
await enableGitLabErrorTracking();
expect(findDsnSettings().exists()).toBe(true);
});
const clipBoardInput = findDsnSettings().findComponent(GlFormInputGroup);
const clipBoardButton = findDsnSettings().findComponent(ClipboardButton);
it('contains copy-to-clipboard functionality for the GitLab DSN string', async () => {
await enableGitLabErrorTracking();
expect(clipBoardInput.props('value')).toBe(TEST_GITLAB_DSN);
expect(clipBoardInput.attributes('readonly')).toBeTruthy();
expect(clipBoardButton.props('text')).toBe(TEST_GITLAB_DSN);
const clipBoardInput = findDsnSettings().findComponent(GlFormInputGroup);
const clipBoardButton = findDsnSettings().findComponent(ClipboardButton);
expect(clipBoardInput.props('value')).toBe(TEST_GITLAB_DSN);
expect(clipBoardInput.attributes('readonly')).toBeTruthy();
expect(clipBoardButton.props('text')).toBe(TEST_GITLAB_DSN);
});
});
});
it.each([true, false])(
'calls the `updateIntegrated` action when the setting changes to `%s`',
(integrated) => {
jest.spyOn(store, 'dispatch').mockImplementation();
it.each([true, false])(
'calls the `updateIntegrated` action when the setting changes to `%s`',
(integrated) => {
jest.spyOn(store, 'dispatch').mockImplementation();
expect(store.dispatch).toHaveBeenCalledTimes(0);
expect(store.dispatch).toHaveBeenCalledTimes(0);
findBackendSettingsRadioGroup().vm.$emit('change', integrated);
findBackendSettingsRadioGroup().vm.$emit('change', integrated);
expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledWith('updateIntegrated', integrated);
},
);
expect(store.dispatch).toHaveBeenCalledTimes(1);
expect(store.dispatch).toHaveBeenCalledWith('updateIntegrated', integrated);
},
);
});
});
});
......@@ -34,7 +34,8 @@ RSpec.describe Projects::ErrorTrackingHelper do
'error-tracking-enabled' => 'false',
'list-path' => list_path,
'project-path' => project_path,
'illustration-path' => match_asset_path('/assets/illustrations/cluster_popover.svg')
'illustration-path' => match_asset_path('/assets/illustrations/cluster_popover.svg'),
'show-integrated-tracking-disabled-alert' => 'false'
)
end
end
......@@ -67,6 +68,37 @@ RSpec.describe Projects::ErrorTrackingHelper do
)
end
end
context 'with integrated error tracking feature' do
using RSpec::Parameterized::TableSyntax
where(:feature_flag, :enabled, :integrated, :show_alert) do
false | true | true | true
false | true | false | false
false | false | true | false
false | false | false | false
true | true | true | false
true | true | false | false
true | false | true | false
true | false | false | false
end
with_them do
before do
stub_feature_flags(integrated_error_tracking: feature_flag)
error_tracking_setting.update_columns(
enabled: enabled,
integrated: integrated
)
end
specify do
expect(helper.error_tracking_data(current_user, project)).to include(
'show-integrated-tracking-disabled-alert' => show_alert.to_s
)
end
end
end
end
context 'when user is not maintainer' do
......
......@@ -535,6 +535,25 @@ RSpec.describe ErrorTracking::ProjectErrorTrackingSetting do
end
end
describe '#integrated_enabled?' do
using RSpec::Parameterized::TableSyntax
where(:enabled, :integrated, :integrated_enabled) do
true | false | false
false | true | false
true | true | true
end
with_them do
before do
subject.enabled = enabled
subject.integrated = integrated
end
it { expect(subject.integrated_enabled?).to eq(integrated_enabled) }
end
end
describe '#gitlab_dsn' do
let!(:client_key) { create(:error_tracking_client_key, project: project) }
......
......@@ -26,7 +26,6 @@ RSpec.describe API::ErrorTracking::Collector do
RSpec.shared_examples 'successful request' do
it 'writes to the database and returns OK', :aggregate_failures do
expect { subject }.to change { ErrorTracking::ErrorEvent.count }.by(1)
expect(response).to have_gitlab_http_status(:ok)
end
end
......@@ -42,6 +41,14 @@ RSpec.describe API::ErrorTracking::Collector do
it_behaves_like 'successful request'
context 'intergrated error tracking feature flag is disabled' do
before do
stub_feature_flags(integrated_error_tracking: false)
end
it_behaves_like 'not found'
end
context 'error tracking feature is disabled' do
before do
setting.update!(enabled: false)
......
......@@ -23,6 +23,21 @@ RSpec.describe API::ErrorTracking::ProjectSettings do
end
end
shared_examples 'returns project settings with false for integrated' do
specify do
make_request
expect(response).to have_gitlab_http_status(:ok)
expect(json_response).to eq(
'active' => setting.reload.enabled,
'project_name' => setting.project_name,
'sentry_external_url' => setting.sentry_external_url,
'api_url' => setting.api_url,
'integrated' => false
)
end
end
shared_examples 'returns 404' do
it 'returns no project settings' do
make_request
......@@ -46,7 +61,17 @@ RSpec.describe API::ErrorTracking::ProjectSettings do
end
context 'patch settings' do
it_behaves_like 'returns project settings'
context 'integrated_error_tracking feature enabled' do
it_behaves_like 'returns project settings'
end
context 'integrated_error_tracking feature disabled' do
before do
stub_feature_flags(integrated_error_tracking: false)
end
it_behaves_like 'returns project settings with false for integrated'
end
it 'updates enabled flag' do
expect(setting).to be_enabled
......@@ -84,13 +109,19 @@ RSpec.describe API::ErrorTracking::ProjectSettings do
context 'with integrated param' do
let(:params) { { active: true, integrated: true } }
it 'updates the integrated flag' do
expect(setting.integrated).to be_falsey
context 'integrated_error_tracking feature enabled' do
before do
stub_feature_flags(integrated_error_tracking: true)
end
make_request
it 'updates the integrated flag' do
expect(setting.integrated).to be_falsey
make_request
expect(json_response).to include('integrated' => true)
expect(setting.reload.integrated).to be_truthy
expect(json_response).to include('integrated' => true)
expect(setting.reload.integrated).to be_truthy
end
end
end
end
......@@ -170,7 +201,21 @@ RSpec.describe API::ErrorTracking::ProjectSettings do
end
context 'get settings' do
it_behaves_like 'returns project settings'
context 'integrated_error_tracking feature enabled' do
before do
stub_feature_flags(integrated_error_tracking: true)
end
it_behaves_like 'returns project settings'
end
context 'integrated_error_tracking feature disabled' do
before do
stub_feature_flags(integrated_error_tracking: false)
end
it_behaves_like 'returns project settings with false for integrated'
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment