Commit 25ad8786 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch 'alert-endpoint-trigger-test' into 'master'

Alert endpoint trigger test

See merge request gitlab-org/gitlab!35970
parents bc18b58b baf38c4e
...@@ -5,18 +5,21 @@ import { ...@@ -5,18 +5,21 @@ import {
GlForm, GlForm,
GlFormGroup, GlFormGroup,
GlFormInput, GlFormInput,
GlFormInputGroup,
GlFormTextarea,
GlLink, GlLink,
GlModal, GlModal,
GlModalDirective, GlModalDirective,
GlSprintf, GlSprintf,
GlFormSelect, GlFormSelect,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { debounce } from 'lodash';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import ToggleButton from '~/vue_shared/components/toggle_button.vue'; import ToggleButton from '~/vue_shared/components/toggle_button.vue';
import csrf from '~/lib/utils/csrf'; import csrf from '~/lib/utils/csrf';
import service from '../services'; import service from '../services';
import { i18n, serviceOptions } from '../constants'; import { i18n, serviceOptions, JSON_VALIDATE_DELAY } from '../constants';
export default { export default {
i18n, i18n,
...@@ -27,7 +30,9 @@ export default { ...@@ -27,7 +30,9 @@ export default {
GlForm, GlForm,
GlFormGroup, GlFormGroup,
GlFormInput, GlFormInput,
GlFormInputGroup,
GlFormSelect, GlFormSelect,
GlFormTextarea,
GlLink, GlLink,
GlModal, GlModal,
GlSprintf, GlSprintf,
...@@ -73,6 +78,11 @@ export default { ...@@ -73,6 +78,11 @@ export default {
feedbackMessage: null, feedbackMessage: null,
isFeedbackDismissed: false, isFeedbackDismissed: false,
}, },
testAlert: {
json: null,
error: null,
},
canSaveForm: false,
}; };
}, },
computed: { computed: {
...@@ -109,12 +119,32 @@ export default { ...@@ -109,12 +119,32 @@ export default {
showFeedbackMsg() { showFeedbackMsg() {
return this.feedback.feedbackMessage && !this.isFeedbackDismissed; return this.feedback.feedbackMessage && !this.isFeedbackDismissed;
}, },
showAlertSave() {
return (
this.feedback.feedbackMessage === this.$options.i18n.testAlertFailed &&
!this.isFeedbackDismissed
);
},
prometheusInfo() { prometheusInfo() {
return !this.isGeneric ? this.$options.i18n.prometheusInfo : ''; return !this.isGeneric ? this.$options.i18n.prometheusInfo : '';
}, },
prometheusFeatureEnabled() { prometheusFeatureEnabled() {
return !this.isGeneric && this.glFeatures.alertIntegrationsDropdown; return !this.isGeneric && this.glFeatures.alertIntegrationsDropdown;
}, },
jsonIsValid() {
return this.testAlert.error === null;
},
canTestAlert() {
return this.selectedService.active && this.testAlert.json !== null;
},
canSaveConfig() {
return !this.loading && this.canSaveForm;
},
},
watch: {
'testAlert.json': debounce(function debouncedJsonValidate() {
this.validateJson();
}, JSON_VALIDATE_DELAY),
}, },
created() { created() {
if (this.glFeatures.alertIntegrationsDropdown) { if (this.glFeatures.alertIntegrationsDropdown) {
...@@ -126,6 +156,9 @@ export default { ...@@ -126,6 +156,9 @@ export default {
} }
}, },
methods: { methods: {
clearJson() {
this.testAlert.json = null;
},
dismissFeedback() { dismissFeedback() {
this.feedback = { ...this.feedback, feedbackMessage: null }; this.feedback = { ...this.feedback, feedbackMessage: null };
this.isFeedbackDismissed = false; this.isFeedbackDismissed = false;
...@@ -135,6 +168,7 @@ export default { ...@@ -135,6 +168,7 @@ export default {
.updateGenericKey({ endpoint: this.generic.formPath, params: { service: { token: '' } } }) .updateGenericKey({ endpoint: this.generic.formPath, params: { service: { token: '' } } })
.then(({ data: { token } }) => { .then(({ data: { token } }) => {
this.authorizationKey.generic = token; this.authorizationKey.generic = token;
this.setFeedback({ feedbackMessage: this.$options.i18n.authKeyRest, variant: 'success' });
}) })
.catch(() => { .catch(() => {
this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' }); this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' });
...@@ -145,11 +179,24 @@ export default { ...@@ -145,11 +179,24 @@ export default {
.updatePrometheusKey({ endpoint: this.prometheus.prometheusResetKeyPath }) .updatePrometheusKey({ endpoint: this.prometheus.prometheusResetKeyPath })
.then(({ data: { token } }) => { .then(({ data: { token } }) => {
this.authorizationKey.prometheus = token; this.authorizationKey.prometheus = token;
this.setFeedback({ feedbackMessage: this.$options.i18n.authKeyRest, variant: 'success' });
}) })
.catch(() => { .catch(() => {
this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' }); this.setFeedback({ feedbackMessage: this.$options.i18n.errorKeyMsg, variant: 'danger' });
}); });
}, },
toggleService(value) {
this.canSaveForm = true;
if (!this.glFeatures.alertIntegrationsDropdown) {
this.toggleActivated(value);
}
if (this.isGeneric) {
this.activated.generic = value;
} else {
this.activated.prometheus = value;
}
},
toggleActivated(value) { toggleActivated(value) {
return this.isGeneric return this.isGeneric
? this.toggleGenericActivated(value) ? this.toggleGenericActivated(value)
...@@ -164,15 +211,14 @@ export default { ...@@ -164,15 +211,14 @@ export default {
}) })
.then(() => { .then(() => {
this.activated.generic = value; this.activated.generic = value;
this.toggleSuccess(value);
if (value) { })
this.setFeedback({ .catch(() => {
feedbackMessage: this.$options.i18n.endPointActivated, this.setFeedback({
variant: 'success', feedbackMessage: this.$options.i18n.errorMsg,
}); variant: 'danger',
} });
}) })
.catch(() => {})
.finally(() => { .finally(() => {
this.loading = false; this.loading = false;
}); });
...@@ -191,12 +237,7 @@ export default { ...@@ -191,12 +237,7 @@ export default {
}) })
.then(() => { .then(() => {
this.activated.prometheus = value; this.activated.prometheus = value;
if (value) { this.toggleSuccess(value);
this.setFeedback({
feedbackMessage: this.$options.i18n.endPointActivated,
variant: 'success',
});
}
}) })
.catch(() => { .catch(() => {
this.setFeedback({ this.setFeedback({
...@@ -208,16 +249,61 @@ export default { ...@@ -208,16 +249,61 @@ export default {
this.loading = false; this.loading = false;
}); });
}, },
toggleSuccess(value) {
if (value) {
this.setFeedback({
feedbackMessage: this.$options.i18n.endPointActivated,
variant: 'info',
});
} else {
this.setFeedback({
feedbackMessage: this.$options.i18n.changesSaved,
variant: 'info',
});
}
},
setFeedback({ feedbackMessage, variant }) { setFeedback({ feedbackMessage, variant }) {
this.feedback = { feedbackMessage, variant }; this.feedback = { feedbackMessage, variant };
}, },
onSubmit(evt) { validateJson() {
// TODO: Add form submit as part of https://gitlab.com/gitlab-org/gitlab/-/issues/215356 this.testAlert.error = null;
evt.preventDefault(); try {
JSON.parse(this.testAlert.json);
} catch (e) {
this.testAlert.error = JSON.stringify(e.message);
}
}, },
onReset(evt) { validateTestAlert() {
// TODO: Add form reset as part of https://gitlab.com/gitlab-org/gitlab/-/issues/215356 this.loading = true;
evt.preventDefault(); this.validateJson();
return service
.updateTestAlert({
endpoint: this.selectedService.url,
data: this.testAlert.json,
authKey: this.selectedService.authKey,
})
.then(() => {
this.setFeedback({
feedbackMessage: this.$options.i18n.testAlertSuccess,
variant: 'success',
});
})
.catch(() => {
this.setFeedback({
feedbackMessage: this.$options.i18n.testAlertFailed,
variant: 'danger',
});
})
.finally(() => {
this.loading = false;
});
},
onSubmit() {
this.toggleActivated(this.selectedService.active);
},
onReset() {
this.testAlert.json = null;
this.dismissFeedback();
}, },
}, },
}; };
...@@ -227,6 +313,15 @@ export default { ...@@ -227,6 +313,15 @@ export default {
<div> <div>
<gl-alert v-if="showFeedbackMsg" :variant="feedback.variant" @dismiss="dismissFeedback"> <gl-alert v-if="showFeedbackMsg" :variant="feedback.variant" @dismiss="dismissFeedback">
{{ feedback.feedbackMessage }} {{ feedback.feedbackMessage }}
<gl-button
v-if="showAlertSave"
variant="danger"
category="primary"
class="gl-display-block gl-mt-3"
@click="toggleActivated(selectedService.active)"
>
{{ __('Save anyway') }}
</gl-button>
</gl-alert> </gl-alert>
<div data-testid="alert-settings-description" class="gl-mt-5"> <div data-testid="alert-settings-description" class="gl-mt-5">
<p v-for="section in sections" :key="section.text"> <p v-for="section in sections" :key="section.text">
...@@ -237,7 +332,7 @@ export default { ...@@ -237,7 +332,7 @@ export default {
</gl-sprintf> </gl-sprintf>
</p> </p>
</div> </div>
<gl-form @submit="onSubmit" @reset="onReset"> <gl-form @submit.prevent="onSubmit" @reset.prevent="onReset">
<gl-form-group <gl-form-group
v-if="glFeatures.alertIntegrationsDropdown" v-if="glFeatures.alertIntegrationsDropdown"
:label="$options.i18n.integrationsLabel" :label="$options.i18n.integrationsLabel"
...@@ -248,6 +343,7 @@ export default { ...@@ -248,6 +343,7 @@ export default {
v-model="selectedEndpoint" v-model="selectedEndpoint"
:options="options" :options="options"
data-testid="alert-settings-select" data-testid="alert-settings-select"
@change="clearJson"
/> />
<span class="gl-text-gray-400"> <span class="gl-text-gray-400">
<gl-sprintf :message="$options.i18n.integrationsInfo"> <gl-sprintf :message="$options.i18n.integrationsInfo">
...@@ -272,7 +368,7 @@ export default { ...@@ -272,7 +368,7 @@ export default {
:disabled-input="loading" :disabled-input="loading"
:is-loading="loading" :is-loading="loading"
:value="selectedService.active" :value="selectedService.active"
@change="toggleActivated" @change="toggleService"
/> />
</gl-form-group> </gl-form-group>
<gl-form-group <gl-form-group
...@@ -293,12 +389,15 @@ export default { ...@@ -293,12 +389,15 @@ export default {
</span> </span>
</gl-form-group> </gl-form-group>
<gl-form-group :label="$options.i18n.urlLabel" label-for="url" label-class="label-bold"> <gl-form-group :label="$options.i18n.urlLabel" label-for="url" label-class="label-bold">
<div class="input-group"> <gl-form-input-group id="url" :readonly="true" :value="selectedService.url">
<gl-form-input id="url" :readonly="true" :value="selectedService.url" /> <template #append>
<span class="input-group-append"> <clipboard-button
<clipboard-button :text="selectedService.url" :title="$options.i18n.copyToClipboard" /> :text="selectedService.url"
</span> :title="$options.i18n.copyToClipboard"
</div> class="gl-m-0!"
/>
</template>
</gl-form-input-group>
<span class="gl-text-gray-400"> <span class="gl-text-gray-400">
{{ prometheusInfo }} {{ prometheusInfo }}
</span> </span>
...@@ -308,15 +407,20 @@ export default { ...@@ -308,15 +407,20 @@ export default {
label-for="authorization-key" label-for="authorization-key"
label-class="label-bold" label-class="label-bold"
> >
<div class="input-group"> <gl-form-input-group
<gl-form-input id="authorization-key" :readonly="true" :value="selectedService.authKey" /> id="authorization-key"
<span class="input-group-append"> class="gl-mb-2"
:readonly="true"
:value="selectedService.authKey"
>
<template #append>
<clipboard-button <clipboard-button
:text="selectedService.authKey" :text="selectedService.authKey"
:title="$options.i18n.copyToClipboard" :title="$options.i18n.copyToClipboard"
class="gl-m-0!"
/> />
</span> </template>
</div> </gl-form-input-group>
<gl-button v-gl-modal.authKeyModal class="gl-mt-3">{{ $options.i18n.resetKey }}</gl-button> <gl-button v-gl-modal.authKeyModal class="gl-mt-3">{{ $options.i18n.resetKey }}</gl-button>
<gl-modal <gl-modal
modal-id="authKeyModal" modal-id="authKeyModal"
...@@ -328,11 +432,32 @@ export default { ...@@ -328,11 +432,32 @@ export default {
{{ $options.i18n.restKeyInfo }} {{ $options.i18n.restKeyInfo }}
</gl-modal> </gl-modal>
</gl-form-group> </gl-form-group>
<gl-form-group
v-if="glFeatures.alertIntegrationsDropdown"
:label="$options.i18n.alertJson"
label-for="alert-json"
label-class="label-bold"
:invalid-feedback="testAlert.error"
>
<gl-form-textarea
id="alert-json"
v-model.trim="testAlert.json"
:disabled="!selectedService.active"
:state="jsonIsValid"
:placeholder="$options.i18n.alertJsonPlaceholder"
rows="6"
max-rows="10"
/>
</gl-form-group>
<gl-button :disabled="!canTestAlert" @click="validateTestAlert">{{
$options.i18n.testAlertInfo
}}</gl-button>
<div <div
class="footer-block row-content-block gl-display-flex gl-justify-content-space-between d-none" v-if="glFeatures.alertIntegrationsDropdown"
class="footer-block row-content-block gl-display-flex gl-justify-content-space-between"
> >
<gl-button type="submit" variant="success" category="primary"> <gl-button type="submit" variant="success" category="primary" :disabled="!canSaveConfig">
{{ __('Save and test changes') }} {{ __('Save changes') }}
</gl-button> </gl-button>
<gl-button type="reset" variant="default" category="primary"> <gl-button type="reset" variant="default" category="primary">
{{ __('Cancel') }} {{ __('Cancel') }}
......
...@@ -21,6 +21,7 @@ export const i18n = { ...@@ -21,6 +21,7 @@ export const i18n = {
'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.', 'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.',
), ),
endPointActivated: s__('AlertSettings|Alerts endpoint successfully activated.'), endPointActivated: s__('AlertSettings|Alerts endpoint successfully activated.'),
changesSaved: s__('AlertSettings|Your changes were successfully updated.'),
prometheusInfo: s__('AlertSettings|Add URL and auth key to your Prometheus config file'), prometheusInfo: s__('AlertSettings|Add URL and auth key to your Prometheus config file'),
integrationsInfo: s__( integrationsInfo: s__(
'AlertSettings|Learn more about our %{linkStart}upcoming integrations%{linkEnd}', 'AlertSettings|Learn more about our %{linkStart}upcoming integrations%{linkEnd}',
...@@ -32,10 +33,20 @@ export const i18n = { ...@@ -32,10 +33,20 @@ export const i18n = {
authKeyLabel: s__('AlertSettings|Authorization key'), authKeyLabel: s__('AlertSettings|Authorization key'),
urlLabel: s__('AlertSettings|Webhook URL'), urlLabel: s__('AlertSettings|Webhook URL'),
activeLabel: s__('AlertSettings|Active'), activeLabel: s__('AlertSettings|Active'),
apiBaseUrlHelpText: s__(' AlertSettings|URL cannot be blank and must start with http or https'), apiBaseUrlHelpText: s__('AlertSettings|URL cannot be blank and must start with http or https'),
testAlertInfo: s__('AlertSettings|Test alert payload'),
alertJson: s__('AlertSettings|Alert test payload'),
alertJsonPlaceholder: s__('AlertSettings|Enter test alert JSON....'),
testAlertFailed: s__('AlertSettings|Test failed. Do you still want to save your changes anyway?'),
testAlertSuccess: s__(
'AlertSettings|Test alert sent successfully. If you have made other changes, please save them now.',
),
authKeyRest: s__('AlertSettings|Authorization key has been successfully reset'),
}; };
export const serviceOptions = [ export const serviceOptions = [
{ value: 'generic', text: s__('AlertSettings|Generic') }, { value: 'generic', text: s__('AlertSettings|Generic') },
{ value: 'prometheus', text: s__('AlertSettings|External Prometheus') }, { value: 'prometheus', text: s__('AlertSettings|External Prometheus') },
]; ];
export const JSON_VALIDATE_DELAY = 250;
/* eslint-disable @gitlab/require-i18n-strings */
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
export default { export default {
...@@ -24,4 +25,12 @@ export default { ...@@ -24,4 +25,12 @@ export default {
}, },
}); });
}, },
updateTestAlert({ endpoint, data, authKey }) {
return axios.post(endpoint, data, {
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${authKey}`,
},
});
},
}; };
...@@ -17,7 +17,7 @@ module OperationsHelper ...@@ -17,7 +17,7 @@ module OperationsHelper
def alerts_settings_data def alerts_settings_data
{ {
'prometheus_activated' => prometheus_service.activated?.to_s, 'prometheus_activated' => prometheus_service.manual_configuration?.to_s,
'activated' => alerts_service.activated?.to_s, 'activated' => alerts_service.activated?.to_s,
'prometheus_form_path' => scoped_integration_path(prometheus_service), 'prometheus_form_path' => scoped_integration_path(prometheus_service),
'form_path' => scoped_integration_path(alerts_service), 'form_path' => scoped_integration_path(alerts_service),
......
...@@ -16,9 +16,6 @@ msgstr "" ...@@ -16,9 +16,6 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
msgid " AlertSettings|URL cannot be blank and must start with http or https"
msgstr ""
msgid " %{start} to %{end}" msgid " %{start} to %{end}"
msgstr "" msgstr ""
...@@ -2086,15 +2083,24 @@ msgstr "" ...@@ -2086,15 +2083,24 @@ msgstr ""
msgid "AlertSettings|Add URL and auth key to your Prometheus config file" msgid "AlertSettings|Add URL and auth key to your Prometheus config file"
msgstr "" msgstr ""
msgid "AlertSettings|Alert test payload"
msgstr ""
msgid "AlertSettings|Alerts endpoint successfully activated." msgid "AlertSettings|Alerts endpoint successfully activated."
msgstr "" msgstr ""
msgid "AlertSettings|Authorization key" msgid "AlertSettings|Authorization key"
msgstr "" msgstr ""
msgid "AlertSettings|Authorization key has been successfully reset"
msgstr ""
msgid "AlertSettings|Copy" msgid "AlertSettings|Copy"
msgstr "" msgstr ""
msgid "AlertSettings|Enter test alert JSON...."
msgstr ""
msgid "AlertSettings|External Prometheus" msgid "AlertSettings|External Prometheus"
msgstr "" msgstr ""
...@@ -2119,6 +2125,15 @@ msgstr "" ...@@ -2119,6 +2125,15 @@ msgstr ""
msgid "AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint." msgid "AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint."
msgstr "" msgstr ""
msgid "AlertSettings|Test alert payload"
msgstr ""
msgid "AlertSettings|Test alert sent successfully. If you have made other changes, please save them now."
msgstr ""
msgid "AlertSettings|Test failed. Do you still want to save your changes anyway?"
msgstr ""
msgid "AlertSettings|There was an error updating the the alert settings. Please refresh the page to try again." msgid "AlertSettings|There was an error updating the the alert settings. Please refresh the page to try again."
msgstr "" msgstr ""
...@@ -2128,6 +2143,9 @@ msgstr "" ...@@ -2128,6 +2143,9 @@ msgstr ""
msgid "AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again." msgid "AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again."
msgstr "" msgstr ""
msgid "AlertSettings|URL cannot be blank and must start with http or https"
msgstr ""
msgid "AlertSettings|Webhook URL" msgid "AlertSettings|Webhook URL"
msgstr "" msgstr ""
...@@ -2137,6 +2155,9 @@ msgstr "" ...@@ -2137,6 +2155,9 @@ msgstr ""
msgid "AlertSettings|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page." msgid "AlertSettings|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page."
msgstr "" msgstr ""
msgid "AlertSettings|Your changes were successfully updated."
msgstr ""
msgid "AlertSettings|http://prometheus.example.com/" msgid "AlertSettings|http://prometheus.example.com/"
msgstr "" msgstr ""
...@@ -19939,9 +19960,6 @@ msgstr "" ...@@ -19939,9 +19960,6 @@ msgstr ""
msgid "Save Changes" msgid "Save Changes"
msgstr "" msgstr ""
msgid "Save and test changes"
msgstr ""
msgid "Save anyway" msgid "Save anyway"
msgstr "" msgstr ""
......
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`AlertsSettingsForm prometheus is active renders a valid "select" 1`] = `"<gl-form-select-stub options=\\"[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"prometheus\\"></gl-form-select-stub>"`;
exports[`AlertsSettingsForm with default values renders the initial template 1`] = ` exports[`AlertsSettingsForm with default values renders the initial template 1`] = `
"<div> "<div>
<!----> <!---->
...@@ -20,29 +18,20 @@ exports[`AlertsSettingsForm with default values renders the initial template 1`] ...@@ -20,29 +18,20 @@ exports[`AlertsSettingsForm with default values renders the initial template 1`]
</gl-form-group-stub> </gl-form-group-stub>
<!----> <!---->
<gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\" label-class=\\"label-bold\\"> <gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\" label-class=\\"label-bold\\">
<div class=\\"input-group\\"> <gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"true\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-400\\">
<gl-form-input-stub id=\\"url\\" readonly=\\"true\\" value=\\"/alerts/notify.json\\"></gl-form-input-stub> <span class=\\"input-group-append\\"><clipboard-button-stub text=\\"/alerts/notify.json\\" title=\\"Copy\\" tooltipplacement=\\"top\\" cssclass=\\"btn-default\\"></clipboard-button-stub></span>
</div> <span class=\\"gl-text-gray-400\\">
</span> </span>
</gl-form-group-stub> </gl-form-group-stub>
<gl-form-group-stub label=\\"Authorization key\\" label-for=\\"authorization-key\\" label-class=\\"label-bold\\"> <gl-form-group-stub label=\\"Authorization key\\" label-for=\\"authorization-key\\" label-class=\\"label-bold\\">
<div class=\\"input-group\\"> <gl-form-input-group-stub value=\\"abcedfg123\\" predefinedoptions=\\"[object Object]\\" id=\\"authorization-key\\" readonly=\\"true\\" class=\\"gl-mb-2\\"></gl-form-input-group-stub>
<gl-form-input-stub id=\\"authorization-key\\" readonly=\\"true\\" value=\\"abcedfg123\\"></gl-form-input-stub> <span class=\\"input-group-append\\"><clipboard-button-stub text=\\"abcedfg123\\" title=\\"Copy\\" tooltipplacement=\\"top\\" cssclass=\\"btn-default\\"></clipboard-button-stub></span>
</div>
<gl-button-stub category=\\"tertiary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" class=\\"gl-mt-3\\" role=\\"button\\" tabindex=\\"0\\">Reset key</gl-button-stub> <gl-button-stub category=\\"tertiary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" class=\\"gl-mt-3\\" role=\\"button\\" tabindex=\\"0\\">Reset key</gl-button-stub>
<gl-modal-stub modalid=\\"authKeyModal\\" titletag=\\"h4\\" modalclass=\\"\\" size=\\"md\\" title=\\"Reset key\\" ok-title=\\"Reset key\\" ok-variant=\\"danger\\"> <gl-modal-stub modalid=\\"authKeyModal\\" titletag=\\"h4\\" modalclass=\\"\\" size=\\"md\\" title=\\"Reset key\\" ok-title=\\"Reset key\\" ok-variant=\\"danger\\">
Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in. Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.
</gl-modal-stub> </gl-modal-stub>
</gl-form-group-stub> </gl-form-group-stub>
<div class=\\"footer-block row-content-block gl-display-flex gl-justify-content-space-between d-none\\"> <!---->
<gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" type=\\"submit\\"> <gl-button-stub category=\\"tertiary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\">Test alert payload</gl-button-stub>
Save and test changes <!---->
</gl-button-stub>
<gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" type=\\"reset\\">
Cancel
</gl-button-stub>
</div>
</gl-form-stub> </gl-form-stub>
</div>" </div>"
`; `;
...@@ -36,8 +36,12 @@ describe('AlertsSettingsForm', () => { ...@@ -36,8 +36,12 @@ describe('AlertsSettingsForm', () => {
props = defaultProps, props = defaultProps,
{ methods } = {}, { methods } = {},
alertIntegrationsDropdown = false, alertIntegrationsDropdown = false,
data,
) => { ) => {
wrapper = shallowMount(AlertsSettingsForm, { wrapper = shallowMount(AlertsSettingsForm, {
data() {
return { ...data };
},
propsData: { propsData: {
...defaultProps, ...defaultProps,
...props, ...props,
...@@ -52,6 +56,7 @@ describe('AlertsSettingsForm', () => { ...@@ -52,6 +56,7 @@ describe('AlertsSettingsForm', () => {
}; };
const findSelect = () => wrapper.find('[data-testid="alert-settings-select"]'); const findSelect = () => wrapper.find('[data-testid="alert-settings-select"]');
const findJsonInput = () => wrapper.find('#alert-json');
const findUrl = () => wrapper.find('#url'); const findUrl = () => wrapper.find('#url');
const findAuthorizationKey = () => wrapper.find('#authorization-key'); const findAuthorizationKey = () => wrapper.find('#authorization-key');
const findApiUrl = () => wrapper.find('#api-url'); const findApiUrl = () => wrapper.find('#api-url');
...@@ -115,13 +120,13 @@ describe('AlertsSettingsForm', () => { ...@@ -115,13 +120,13 @@ describe('AlertsSettingsForm', () => {
describe('activate toggle', () => { describe('activate toggle', () => {
it('triggers toggleActivated method', () => { it('triggers toggleActivated method', () => {
const toggleActivated = jest.fn(); const toggleService = jest.fn();
const methods = { toggleActivated }; const methods = { toggleService };
createComponent(defaultProps, { methods }); createComponent(defaultProps, { methods });
wrapper.find(ToggleButton).vm.$emit('change', true); wrapper.find(ToggleButton).vm.$emit('change', true);
expect(toggleActivated).toHaveBeenCalled(); expect(toggleService).toHaveBeenCalled();
}); });
describe('error is encountered', () => { describe('error is encountered', () => {
...@@ -149,7 +154,7 @@ describe('AlertsSettingsForm', () => { ...@@ -149,7 +154,7 @@ describe('AlertsSettingsForm', () => {
}); });
it('renders a valid "select"', () => { it('renders a valid "select"', () => {
expect(findSelect().html()).toMatchSnapshot(); expect(findSelect().exists()).toBe(true);
}); });
it('shows the API URL input', () => { it('shows the API URL input', () => {
...@@ -160,9 +165,53 @@ describe('AlertsSettingsForm', () => { ...@@ -160,9 +165,53 @@ describe('AlertsSettingsForm', () => {
expect(findUrl().exists()).toBe(true); expect(findUrl().exists()).toBe(true);
expect(findUrl().attributes('value')).toBe(PROMETHEUS_URL); expect(findUrl().attributes('value')).toBe(PROMETHEUS_URL);
}); });
});
describe('trigger test alert', () => {
beforeEach(() => {
createComponent({ generic: { ...defaultProps.generic, initialActivated: true } }, {}, true);
});
it('should enable the JSON input', () => {
expect(findJsonInput().exists()).toBe(true);
expect(findJsonInput().props('value')).toBe(null);
});
it('should validate JSON input', () => {
createComponent({ generic: { ...defaultProps.generic } }, {}, true, {
testAlertJson: '{ "value": "test" }',
});
findJsonInput().vm.$emit('change');
return wrapper.vm.$nextTick().then(() => {
expect(findJsonInput().attributes('state')).toBe('true');
});
});
it('should not show a footer block', () => { describe('alert service is toggled', () => {
expect(wrapper.find('.footer-block').classes('d-none')).toBe(true); it('should show a info alert if successful', () => {
const formPath = 'some/path';
const toggleService = true;
mockAxios.onPut(formPath).replyOnce(200);
createComponent({ generic: { ...defaultProps.generic, formPath } });
return wrapper.vm.toggleGenericActivated(toggleService).then(() => {
expect(wrapper.find(GlAlert).attributes('variant')).toBe('info');
});
});
it('should show a error alert if failed', () => {
const formPath = 'some/path';
const toggleService = true;
mockAxios.onPut(formPath).replyOnce(404);
createComponent({ generic: { ...defaultProps.generic, formPath } });
return wrapper.vm.toggleGenericActivated(toggleService).then(() => {
expect(wrapper.find(GlAlert).attributes('variant')).toBe('danger');
});
});
}); });
}); });
}); });
...@@ -45,7 +45,9 @@ RSpec.describe OperationsHelper do ...@@ -45,7 +45,9 @@ RSpec.describe OperationsHelper do
end end
context 'with external Prometheus configured' do context 'with external Prometheus configured' do
let_it_be(:prometheus_service, reload: true) { create(:prometheus_service, project: project) } let_it_be(:prometheus_service, reload: true) do
create(:prometheus_service, project: project)
end
context 'with external Prometheus enabled' do context 'with external Prometheus enabled' do
it 'returns the correct values' do it 'returns the correct values' do
...@@ -57,16 +59,31 @@ RSpec.describe OperationsHelper do ...@@ -57,16 +59,31 @@ RSpec.describe OperationsHelper do
end end
context 'with external Prometheus disabled' do context 'with external Prometheus disabled' do
shared_examples 'Prometheus is disabled' do
it 'returns the correct values' do
expect(subject).to include(
'prometheus_activated' => 'false',
'prometheus_api_url' => prometheus_service.api_url
)
end
end
let(:cluster_managed) { false }
before do before do
# Prometheus services uses manual_configuration as an alias for active, beware allow(prometheus_service)
.to receive(:prometheus_available?)
.and_return(cluster_managed)
prometheus_service.update!(manual_configuration: false) prometheus_service.update!(manual_configuration: false)
end end
it 'returns the correct values' do include_examples 'Prometheus is disabled'
expect(subject).to include(
'prometheus_activated' => 'false', context 'when cluster managed' do
'prometheus_api_url' => prometheus_service.api_url let(:cluster_managed) { true }
)
include_examples 'Prometheus is disabled'
end 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