Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-19 15:09:13 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-19 15:09:13 +0300
commitcd3e2c7b9355f8990ab294b34b5e4add4f3985fa (patch)
tree77264b3e569ec95da8476f604d3d5cf4b03e85dc
parentc1fc5da123a1fe670e32740669a9d5e59eff38f5 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--GITLAB_WORKHORSE_VERSION2
-rw-r--r--app/assets/javascripts/blob/template_selector.js4
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js7
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue41
-rw-r--r--app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue116
-rw-r--r--app/assets/javascripts/clusters/stores/clusters_store.js9
-rw-r--r--app/assets/javascripts/repository/components/preview/index.vue13
-rw-r--r--app/assets/stylesheets/framework/dropdowns.scss6
-rw-r--r--app/controllers/groups_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb2
-rw-r--r--changelogs/unreleased/allow_toggle_modsecurity_settings.yml5
-rw-r--r--changelogs/unreleased/rk4bir-master-patch-77755.yml5
-rw-r--r--lib/gitlab/diff/highlight_cache.rb8
-rw-r--r--lib/gitlab/git/blob.rb8
-rw-r--r--locale/gitlab.pot5
-rw-r--r--spec/frontend/clusters/components/applications_spec.js25
-rw-r--r--spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js107
-rw-r--r--spec/frontend/clusters/stores/clusters_store_spec.js2
-rw-r--r--spec/lib/gitlab/diff/highlight_cache_spec.rb8
-rw-r--r--spec/lib/gitlab/git/blob_spec.rb8
20 files changed, 343 insertions, 40 deletions
diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION
index 72963fb08c2..426cb9d6d8c 100644
--- a/GITLAB_WORKHORSE_VERSION
+++ b/GITLAB_WORKHORSE_VERSION
@@ -1 +1 @@
-8.21.0
+8.22.0
diff --git a/app/assets/javascripts/blob/template_selector.js b/app/assets/javascripts/blob/template_selector.js
index b0de4dc8628..2427e25a17d 100644
--- a/app/assets/javascripts/blob/template_selector.js
+++ b/app/assets/javascripts/blob/template_selector.js
@@ -92,10 +92,10 @@ export default class TemplateSelector {
}
startLoadingSpinner() {
- this.$dropdownIcon.addClass('fa-spinner fa-spin').removeClass('fa-chevron-down');
+ this.$dropdownIcon.addClass('spinner').removeClass('fa-chevron-down');
}
stopLoadingSpinner() {
- this.$dropdownIcon.addClass('fa-chevron-down').removeClass('fa-spinner fa-spin');
+ this.$dropdownIcon.addClass('fa-chevron-down').removeClass('spinner');
}
}
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index b764348eb3c..d35dca7b939 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -255,6 +255,7 @@ export default class Clusters {
eventHub.$on('setKnativeHostname', data => this.setKnativeHostname(data));
eventHub.$on('uninstallApplication', data => this.uninstallApplication(data));
eventHub.$on('setCrossplaneProviderStack', data => this.setCrossplaneProviderStack(data));
+ eventHub.$on('setIngressModSecurityEnabled', data => this.setIngressModSecurityEnabled(data));
// Add event listener to all the banner close buttons
this.addBannerCloseHandler(this.unreachableContainer, 'unreachable');
this.addBannerCloseHandler(this.authenticationFailureContainer, 'authentication_failure');
@@ -268,6 +269,7 @@ export default class Clusters {
eventHub.$off('setKnativeHostname');
eventHub.$off('setCrossplaneProviderStack');
eventHub.$off('uninstallApplication');
+ eventHub.$off('setIngressModSecurityEnabled');
}
initPolling(method, successCallback, errorCallback) {
@@ -513,6 +515,11 @@ export default class Clusters {
this.store.updateAppProperty(appId, 'validationError', null);
}
+ setIngressModSecurityEnabled({ id, modSecurityEnabled }) {
+ this.store.updateAppProperty(id, 'isEditingModSecurityEnabled', true);
+ this.store.updateAppProperty(id, 'modsecurity_enabled', modSecurityEnabled);
+ }
+
destroy() {
this.destroyed = true;
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index fe2ad562ad5..9429e10e6ed 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -21,6 +21,7 @@ import KnativeDomainEditor from './knative_domain_editor.vue';
import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants';
import eventHub from '~/clusters/event_hub';
import CrossplaneProviderStack from './crossplane_provider_stack.vue';
+import IngressModsecuritySettings from './ingress_modsecurity_settings.vue';
export default {
components: {
@@ -29,6 +30,7 @@ export default {
GlLoadingIcon,
KnativeDomainEditor,
CrossplaneProviderStack,
+ IngressModsecuritySettings,
},
props: {
type: {
@@ -129,18 +131,6 @@ export default {
crossplaneInstalled() {
return this.applications.crossplane.status === APPLICATION_STATUS.INSTALLED;
},
- ingressModSecurityDescription() {
- const escapedUrl = _.escape(this.ingressModSecurityHelpPath);
-
- return sprintf(
- s__('ClusterIntegration|Learn more about %{startLink}ModSecurity%{endLink}'),
- {
- startLink: `<a href="${escapedUrl}" target="_blank" rel="noopener noreferrer">`,
- endLink: '</a>',
- },
- false,
- );
- },
ingressDescription() {
return sprintf(
_.escape(
@@ -241,6 +231,9 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
}
return null;
},
+ ingress() {
+ return this.applications.ingress;
+ },
},
created() {
this.helmInstallIllustration = helmInstallIllustration;
@@ -329,6 +322,7 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
:uninstall-successful="applications.ingress.uninstallSuccessful"
:uninstall-failed="applications.ingress.uninstallFailed"
:disabled="!helmInstalled"
+ :updateable="false"
title-link="https://kubernetes.io/docs/concepts/services-networking/ingress/"
>
<div slot="description">
@@ -340,25 +334,10 @@ Crossplane runs inside your Kubernetes cluster and supports secure connectivity
}}
</p>
- <template>
- <div class="form-group">
- <div class="form-check form-check-inline">
- <input
- v-model="applications.ingress.modsecurity_enabled"
- :disabled="ingressInstalled"
- type="checkbox"
- autocomplete="off"
- class="form-check-input"
- />
- <label class="form-check-label label-bold" for="ingress-enable-modsecurity">
- {{ s__('ClusterIntegration|Enable Web Application Firewall') }}
- </label>
- </div>
- <p class="form-text text-muted">
- <strong v-html="ingressModSecurityDescription"></strong>
- </p>
- </div>
- </template>
+ <ingress-modsecurity-settings
+ :ingress="ingress"
+ :ingress-mod-security-help-path="ingressModSecurityHelpPath"
+ />
<template v-if="ingressInstalled">
<div class="form-group">
diff --git a/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue
new file mode 100644
index 00000000000..c30015f31de
--- /dev/null
+++ b/app/assets/javascripts/clusters/components/ingress_modsecurity_settings.vue
@@ -0,0 +1,116 @@
+<script>
+import _ from 'lodash';
+import { __ } from '../../locale';
+import LoadingButton from '~/vue_shared/components/loading_button.vue';
+import { APPLICATION_STATUS, INGRESS } from '~/clusters/constants';
+import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
+import eventHub from '~/clusters/event_hub';
+
+const { UPDATING, UNINSTALLING } = APPLICATION_STATUS;
+
+export default {
+ components: {
+ LoadingButton,
+ GlAlert,
+ GlSprintf,
+ GlLink,
+ },
+ props: {
+ ingress: {
+ type: Object,
+ required: true,
+ },
+ ingressModSecurityHelpPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ computed: {
+ modSecurityEnabled: {
+ get() {
+ return this.ingress.modsecurity_enabled;
+ },
+ set(isEnabled) {
+ eventHub.$emit('setIngressModSecurityEnabled', {
+ id: INGRESS,
+ modSecurityEnabled: isEnabled,
+ });
+ },
+ },
+ ingressModSecurityDescription() {
+ return _.escape(this.ingressModSecurityHelpPath);
+ },
+ saving() {
+ return [UPDATING].includes(this.ingress.status);
+ },
+ saveButtonDisabled() {
+ return [UNINSTALLING, UPDATING].includes(this.ingress.status);
+ },
+ saveButtonLabel() {
+ return this.saving ? __('Saving') : __('Save changes');
+ },
+ ingressInstalled() {
+ return this.ingress.installed;
+ },
+ },
+ methods: {
+ updateApplication() {
+ eventHub.$emit('updateApplication', {
+ id: INGRESS,
+ params: { modsecurity_enabled: this.ingress.modsecurity_enabled },
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-alert
+ v-if="ingress.updateFailed"
+ class="mb-3"
+ variant="danger"
+ :dismissible="false"
+ @dismiss="alert = null"
+ >
+ {{
+ s__('ClusterIntegration|Something went wrong while updating the Web Application Firewall.')
+ }}
+ </gl-alert>
+ <div class="form-group">
+ <div class="form-check form-check-inline">
+ <input
+ v-model="modSecurityEnabled"
+ type="checkbox"
+ autocomplete="off"
+ class="form-check-input"
+ />
+ <label class="form-check-label label-bold" for="ingress-enable-modsecurity">
+ {{ s__('ClusterIntegration|Enable Web Application Firewall') }}
+ </label>
+ </div>
+ <p class="form-text text-muted">
+ <strong>
+ <gl-sprintf
+ :message="s__('ClusterIntegration|Learn more about %{linkStart}ModSecurity%{linkEnd}')"
+ >
+ <template #link="{ content }">
+ <gl-link :href="ingressModSecurityDescription" target="_blank"
+ >{{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </strong>
+ </p>
+ <loading-button
+ v-if="ingressInstalled"
+ class="btn-success mt-1"
+ :loading="saving"
+ :disabled="saveButtonDisabled"
+ :label="saveButtonLabel"
+ @click="updateApplication"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/clusters/stores/clusters_store.js b/app/assets/javascripts/clusters/stores/clusters_store.js
index 939c396e1b9..ffe71455b2d 100644
--- a/app/assets/javascripts/clusters/stores/clusters_store.js
+++ b/app/assets/javascripts/clusters/stores/clusters_store.js
@@ -54,6 +54,8 @@ export default class ClusterStore {
modsecurity_enabled: false,
externalIp: null,
externalHostname: null,
+ isEditingModSecurityEnabled: false,
+ updateFailed: false,
},
cert_manager: {
...applicationInitialState,
@@ -208,8 +210,11 @@ export default class ClusterStore {
if (appId === INGRESS) {
this.state.applications.ingress.externalIp = serverAppEntry.external_ip;
this.state.applications.ingress.externalHostname = serverAppEntry.external_hostname;
- this.state.applications.ingress.modsecurity_enabled =
- serverAppEntry.modsecurity_enabled || this.state.applications.ingress.modsecurity_enabled;
+ if (!this.state.applications.ingress.isEditingModSecurityEnabled) {
+ this.state.applications.ingress.modsecurity_enabled =
+ serverAppEntry.modsecurity_enabled ||
+ this.state.applications.ingress.modsecurity_enabled;
+ }
} else if (appId === CERT_MANAGER) {
this.state.applications.cert_manager.email =
this.state.applications.cert_manager.email || serverAppEntry.email;
diff --git a/app/assets/javascripts/repository/components/preview/index.vue b/app/assets/javascripts/repository/components/preview/index.vue
index 2bc93c3f1c1..78ae719ba0d 100644
--- a/app/assets/javascripts/repository/components/preview/index.vue
+++ b/app/assets/javascripts/repository/components/preview/index.vue
@@ -1,4 +1,6 @@
<script>
+import $ from 'jquery';
+import '~/behaviors/markdown/render_gfm';
import { GlLink, GlLoadingIcon } from '@gitlab/ui';
import getReadmeQuery from '../../queries/getReadme.query.graphql';
@@ -30,6 +32,15 @@ export default {
loading: 0,
};
},
+ watch: {
+ readme(newVal) {
+ if (newVal) {
+ this.$nextTick(() => {
+ $(this.$refs.readme).renderGFM();
+ });
+ }
+ },
+ },
};
</script>
@@ -45,7 +56,7 @@ export default {
</div>
<div class="blob-viewer">
<gl-loading-icon v-if="loading > 0" size="md" color="dark" class="my-4 mx-auto" />
- <div v-else-if="readme" v-html="readme.html"></div>
+ <div v-else-if="readme" ref="readme" v-html="readme.html"></div>
</div>
</article>
</template>
diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss
index 41f3603506f..005e5efbdaf 100644
--- a/app/assets/stylesheets/framework/dropdowns.scss
+++ b/app/assets/stylesheets/framework/dropdowns.scss
@@ -150,6 +150,12 @@
right: 8px;
}
+ .spinner {
+ position: absolute;
+ top: 9px;
+ right: 8px;
+ }
+
.ic-chevron-down {
position: absolute;
top: $gl-padding-8;
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 958dc27984f..80c7a803392 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -97,7 +97,7 @@ class GroupsController < Groups::ApplicationController
end
def edit
- @badge_api_endpoint = expose_url(api_v4_groups_badges_path(id: @group.id))
+ @badge_api_endpoint = expose_path(api_v4_groups_badges_path(id: @group.id))
end
def projects
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 31b86946ca2..045aa38230c 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -50,7 +50,7 @@ class ProjectsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord
def edit
- @badge_api_endpoint = expose_url(api_v4_projects_badges_path(id: @project.id))
+ @badge_api_endpoint = expose_path(api_v4_projects_badges_path(id: @project.id))
render_edit
end
diff --git a/changelogs/unreleased/allow_toggle_modsecurity_settings.yml b/changelogs/unreleased/allow_toggle_modsecurity_settings.yml
new file mode 100644
index 00000000000..7535d00c58d
--- /dev/null
+++ b/changelogs/unreleased/allow_toggle_modsecurity_settings.yml
@@ -0,0 +1,5 @@
+---
+title: Allow enabling/disabling modsecurity from UI
+merge_request: 24747
+author:
+type: added
diff --git a/changelogs/unreleased/rk4bir-master-patch-77755.yml b/changelogs/unreleased/rk4bir-master-patch-77755.yml
new file mode 100644
index 00000000000..b904dad6660
--- /dev/null
+++ b/changelogs/unreleased/rk4bir-master-patch-77755.yml
@@ -0,0 +1,5 @@
+---
+title: Migrated from .fa-spinner to .spinner in app/assets/javascripts/blob/template_selector.js
+merge_request: 25045
+author: Raihan Kabir (gitlab/rk4bir)
+type: changed
diff --git a/lib/gitlab/diff/highlight_cache.rb b/lib/gitlab/diff/highlight_cache.rb
index 0a8fbb9a673..3940b3fca4b 100644
--- a/lib/gitlab/diff/highlight_cache.rb
+++ b/lib/gitlab/diff/highlight_cache.rb
@@ -17,6 +17,14 @@ module Gitlab
buckets [100, 1000, 10000, 100000, 1000000, 10000000]
end
+ define_counter :gitlab_redis_diff_caching_hit do
+ docstring 'Redis diff caching hits'
+ end
+
+ define_counter :gitlab_redis_diff_caching_miss do
+ docstring 'Redis diff caching misses'
+ end
+
def initialize(diff_collection)
@diff_collection = diff_collection
end
diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb
index cbde713e3b9..ba1a474c523 100644
--- a/lib/gitlab/git/blob.rb
+++ b/lib/gitlab/git/blob.rb
@@ -124,6 +124,8 @@ module Gitlab
self.__send__("#{key}=", options[key.to_sym]) # rubocop:disable GitlabSecurity/PublicSend
end
+ record_metric_blob_size
+
# Retain the actual size before it is encoded
@loaded_size = @data.bytesize if @data
@loaded_all_data = @loaded_size == size
@@ -202,6 +204,12 @@ module Gitlab
private
+ def record_metric_blob_size
+ return unless size
+
+ self.class.gitlab_blob_size.observe({}, size)
+ end
+
def has_lfs_version_key?
!empty? && text_in_repo? && data.start_with?("version https://git-lfs.github.com/spec")
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index eb5adf8070b..e0209671160 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4310,7 +4310,7 @@ msgstr ""
msgid "ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}."
msgstr ""
-msgid "ClusterIntegration|Learn more about %{startLink}ModSecurity%{endLink}"
+msgid "ClusterIntegration|Learn more about %{linkStart}ModSecurity%{linkEnd}"
msgstr ""
msgid "ClusterIntegration|Learn more about %{startLink}Regions %{externalLinkIcon}%{endLink}."
@@ -4595,6 +4595,9 @@ msgstr ""
msgid "ClusterIntegration|Something went wrong while updating Knative domain name."
msgstr ""
+msgid "ClusterIntegration|Something went wrong while updating the Web Application Firewall."
+msgstr ""
+
msgid "ClusterIntegration|Specifying a domain will allow you to use Auto Review Apps and Auto Deploy stages for %{auto_devops_start}Auto DevOps%{auto_devops_end}. The domain should have a wildcard DNS configured matching the domain."
msgstr ""
diff --git a/spec/frontend/clusters/components/applications_spec.js b/spec/frontend/clusters/components/applications_spec.js
index c3336edfe59..3e25c825fe8 100644
--- a/spec/frontend/clusters/components/applications_spec.js
+++ b/spec/frontend/clusters/components/applications_spec.js
@@ -7,6 +7,7 @@ import { APPLICATIONS_MOCK_STATE } from '../services/mock_data';
import eventHub from '~/clusters/event_hub';
import KnativeDomainEditor from '~/clusters/components/knative_domain_editor.vue';
import CrossplaneProviderStack from '~/clusters/components/crossplane_provider_stack.vue';
+import IngressModsecuritySettings from '~/clusters/components/ingress_modsecurity_settings.vue';
describe('Applications', () => {
let vm;
@@ -156,6 +157,30 @@ describe('Applications', () => {
});
describe('Ingress application', () => {
+ describe('with nested component', () => {
+ const propsData = {
+ applications: {
+ ...APPLICATIONS_MOCK_STATE,
+ ingress: {
+ title: 'Ingress',
+ status: 'installed',
+ },
+ },
+ };
+
+ let wrapper;
+ beforeEach(() => {
+ wrapper = shallowMount(Applications, { propsData });
+ });
+ afterEach(() => {
+ wrapper.destroy();
+ });
+ it('renders IngressModsecuritySettings', () => {
+ const modsecuritySettings = wrapper.find(IngressModsecuritySettings);
+ expect(modsecuritySettings.exists()).toBe(true);
+ });
+ });
+
describe('when installed', () => {
describe('with ip address', () => {
it('renders ip address with a clipboard button', () => {
diff --git a/spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js b/spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js
new file mode 100644
index 00000000000..e7d2b7bf5c5
--- /dev/null
+++ b/spec/frontend/clusters/components/ingress_modsecurity_settings_spec.js
@@ -0,0 +1,107 @@
+import { shallowMount } from '@vue/test-utils';
+import IngressModsecuritySettings from '~/clusters/components/ingress_modsecurity_settings.vue';
+import LoadingButton from '~/vue_shared/components/loading_button.vue';
+import { APPLICATION_STATUS, INGRESS } from '~/clusters/constants';
+import { GlAlert } from '@gitlab/ui';
+import eventHub from '~/clusters/event_hub';
+
+const { UPDATING } = APPLICATION_STATUS;
+
+describe('IngressModsecuritySettings', () => {
+ let wrapper;
+
+ const defaultProps = {
+ modsecurity_enabled: false,
+ status: 'installable',
+ installed: false,
+ };
+
+ const createComponent = (props = defaultProps) => {
+ wrapper = shallowMount(IngressModsecuritySettings, {
+ propsData: {
+ ingress: {
+ ...defaultProps,
+ ...props,
+ },
+ },
+ });
+ };
+
+ const findSaveButton = () => wrapper.find(LoadingButton);
+ const findModSecurityCheckbox = () => wrapper.find('input').element;
+
+ describe('when ingress is installed', () => {
+ beforeEach(() => {
+ createComponent({ installed: true });
+ jest.spyOn(eventHub, '$emit');
+ });
+
+ it('renders save button', () => {
+ expect(findSaveButton().exists()).toBe(true);
+ expect(findModSecurityCheckbox().checked).toBe(false);
+ });
+
+ describe('and the save changes button is clicked', () => {
+ beforeEach(() => {
+ findSaveButton().vm.$emit('click');
+ });
+
+ it('triggers save event and pass current modsecurity value', () =>
+ wrapper.vm.$nextTick().then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('updateApplication', {
+ id: INGRESS,
+ params: { modsecurity_enabled: false },
+ });
+ }));
+ });
+
+ it('triggers set event to be propagated with the current modsecurity value', () => {
+ wrapper.setData({ modSecurityEnabled: true });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(eventHub.$emit).toHaveBeenCalledWith('setIngressModSecurityEnabled', {
+ id: INGRESS,
+ modSecurityEnabled: true,
+ });
+ });
+ });
+
+ describe(`when ingress status is ${UPDATING}`, () => {
+ beforeEach(() => {
+ createComponent({ installed: true, status: UPDATING });
+ });
+
+ it('renders loading spinner in save button', () => {
+ expect(findSaveButton().props('loading')).toBe(true);
+ });
+
+ it('renders disabled save button', () => {
+ expect(findSaveButton().props('disabled')).toBe(true);
+ });
+
+ it('renders save button with "Saving" label', () => {
+ expect(findSaveButton().props('label')).toBe('Saving');
+ });
+ });
+
+ describe('when ingress fails to update', () => {
+ beforeEach(() => {
+ createComponent({ updateFailed: true });
+ });
+
+ it('displays a error message', () => {
+ expect(wrapper.find(GlAlert).exists()).toBe(true);
+ });
+ });
+ });
+
+ describe('when ingress is not installed', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('does not render the save button', () => {
+ expect(findSaveButton().exists()).toBe(false);
+ expect(findModSecurityCheckbox().checked).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/clusters/stores/clusters_store_spec.js b/spec/frontend/clusters/stores/clusters_store_spec.js
index f2dbdd0638b..d3775c6cfba 100644
--- a/spec/frontend/clusters/stores/clusters_store_spec.js
+++ b/spec/frontend/clusters/stores/clusters_store_spec.js
@@ -81,8 +81,10 @@ describe('Clusters Store', () => {
externalIp: null,
externalHostname: null,
installed: false,
+ isEditingModSecurityEnabled: false,
installFailed: true,
uninstallable: false,
+ updateFailed: false,
uninstallSuccessful: false,
uninstallFailed: false,
validationError: null,
diff --git a/spec/lib/gitlab/diff/highlight_cache_spec.rb b/spec/lib/gitlab/diff/highlight_cache_spec.rb
index 218c393c409..eb8072a554e 100644
--- a/spec/lib/gitlab/diff/highlight_cache_spec.rb
+++ b/spec/lib/gitlab/diff/highlight_cache_spec.rb
@@ -149,5 +149,13 @@ describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
it 'defines :gitlab_redis_diff_caching_memory_usage_bytes histogram' do
expect(described_class).to respond_to(:gitlab_redis_diff_caching_memory_usage_bytes)
end
+
+ it 'defines :gitlab_redis_diff_caching_hit' do
+ expect(described_class).to respond_to(:gitlab_redis_diff_caching_hit)
+ end
+
+ it 'defines :gitlab_redis_diff_caching_miss' do
+ expect(described_class).to respond_to(:gitlab_redis_diff_caching_miss)
+ end
end
end
diff --git a/spec/lib/gitlab/git/blob_spec.rb b/spec/lib/gitlab/git/blob_spec.rb
index 521c03058ca..3277e02aafa 100644
--- a/spec/lib/gitlab/git/blob_spec.rb
+++ b/spec/lib/gitlab/git/blob_spec.rb
@@ -12,10 +12,18 @@ describe Gitlab::Git::Blob, :seed_helper do
let(:blob) { Gitlab::Git::Blob.new(name: 'test') }
it 'handles nil data' do
+ expect(described_class).not_to receive(:gitlab_blob_size)
+
expect(blob.name).to eq('test')
expect(blob.size).to eq(nil)
expect(blob.loaded_size).to eq(nil)
end
+
+ it 'records blob size' do
+ expect(described_class).to receive(:gitlab_blob_size).and_call_original
+
+ Gitlab::Git::Blob.new(name: 'test', size: 1234)
+ end
end
shared_examples '.find' do