Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
02f78c1ee8
commit
39c4905723
|
|
@ -1 +1 @@
|
|||
13.23.1
|
||||
13.23.2
|
||||
|
|
|
|||
|
|
@ -1190,7 +1190,7 @@ table.code {
|
|||
}
|
||||
}
|
||||
|
||||
@media (max-width: map-get($grid-breakpoints, md)-1) {
|
||||
@media (max-width: map-get($grid-breakpoints, lg)-1) {
|
||||
.diffs .files {
|
||||
@include fixed-width-container;
|
||||
flex-direction: column;
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ $tabs-holder-z-index: 250;
|
|||
line-height: 0;
|
||||
}
|
||||
|
||||
@media (max-width: map-get($grid-breakpoints, md)-1) {
|
||||
@media (max-width: map-get($grid-breakpoints, lg)-1) {
|
||||
.diffs .files {
|
||||
.diff-tree-list {
|
||||
position: relative;
|
||||
|
|
|
|||
|
|
@ -1777,6 +1777,11 @@ body.gl-dark {
|
|||
--purple-800: #cbbbf2;
|
||||
--purple-900: #e1d8f9;
|
||||
--purple-950: #f4f0ff;
|
||||
--dark-icon-color-purple-1: #524a68;
|
||||
--dark-icon-color-purple-2: #715bae;
|
||||
--dark-icon-color-purple-3: #9a79f7;
|
||||
--dark-icon-color-orange-1: #665349;
|
||||
--dark-icon-color-orange-2: #b37a5d;
|
||||
--gl-text-color: #fafafa;
|
||||
--border-color: #4f4f4f;
|
||||
--white: #333;
|
||||
|
|
@ -2003,6 +2008,11 @@ body.gl-dark {
|
|||
--purple-800: #cbbbf2;
|
||||
--purple-900: #e1d8f9;
|
||||
--purple-950: #f4f0ff;
|
||||
--dark-icon-color-purple-1: #524a68;
|
||||
--dark-icon-color-purple-2: #715bae;
|
||||
--dark-icon-color-purple-3: #9a79f7;
|
||||
--dark-icon-color-orange-1: #665349;
|
||||
--dark-icon-color-orange-2: #b37a5d;
|
||||
--gl-text-color: #fafafa;
|
||||
--border-color: #4f4f4f;
|
||||
--white: #333;
|
||||
|
|
|
|||
|
|
@ -188,6 +188,12 @@ body.gl-dark {
|
|||
--purple-900: #{$purple-900};
|
||||
--purple-950: #{$purple-950};
|
||||
|
||||
--dark-icon-color-purple-1: #524a68;
|
||||
--dark-icon-color-purple-2: #715bae;
|
||||
--dark-icon-color-purple-3: #9a79f7;
|
||||
--dark-icon-color-orange-1: #665349;
|
||||
--dark-icon-color-orange-2: #b37a5d;
|
||||
|
||||
--gl-text-color: #{$gray-900};
|
||||
--border-color: #{$border-color};
|
||||
|
||||
|
|
|
|||
|
|
@ -20,4 +20,4 @@
|
|||
|
||||
- if can_admin_project
|
||||
%td
|
||||
= link_to s_('ProtectedBranch|Unprotect'), [@project, protected_branch, { update_section: 'js-protected-branches-settings' }], disabled: local_assigns[:disabled], data: { confirm: s_('ProtectedBranch|Branch will be writable for developers. Are you sure?') }, method: :delete, class: "btn gl-button btn-warning"
|
||||
= link_to s_('ProtectedBranch|Unprotect'), [@project, protected_branch, { update_section: 'js-protected-branches-settings' }], disabled: local_assigns[:disabled], aria: { label: s_('ProtectedBranch|Unprotect branch') }, data: { confirm: s_('ProtectedBranch|Branch will be writable for developers. Are you sure?'), confirm_btn_variant: 'danger' }, method: :delete, class: "btn gl-button btn-warning"
|
||||
|
|
|
|||
|
|
@ -19,4 +19,4 @@
|
|||
|
||||
- if can? current_user, :admin_project, @project
|
||||
%td
|
||||
= link_to 'Unprotect', [@project, protected_tag, { update_section: 'js-protected-tags-settings' }], data: { confirm: 'Tag will be writable for developers. Are you sure?' }, method: :delete, class: 'gl-button btn btn-danger-secondary'
|
||||
= link_to 'Unprotect', [@project, protected_tag, { update_section: 'js-protected-tags-settings' }], aria: { label: s_('ProtectedTags|Unprotect tag') }, data: { confirm: 'Tag will be writable for developers. Are you sure?', confirm_btn_variant: 'danger' }, method: :delete, class: 'gl-button btn btn-danger-secondary'
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 8.0 KiB |
|
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class CreateAlertManagementAlertMetricImages < Gitlab::Database::Migration[1.0]
|
||||
def up
|
||||
create_table :alert_management_alert_metric_images do |t|
|
||||
t.references :alert, null: false, index: true, foreign_key: { to_table: :alert_management_alerts, on_delete: :cascade }
|
||||
t.timestamps_with_timezone
|
||||
t.integer :file_store, limit: 2
|
||||
t.text :file, limit: 255, null: false
|
||||
t.text :url, limit: 255
|
||||
t.text :url_text, limit: 128
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :alert_management_alert_metric_images, if_exists: true
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
41b67585574f6309d8e32fe695e65fc43f15f6738db713c1a11e04558a5ec515
|
||||
|
|
@ -9917,6 +9917,29 @@ CREATE SEQUENCE alert_management_alert_assignees_id_seq
|
|||
|
||||
ALTER SEQUENCE alert_management_alert_assignees_id_seq OWNED BY alert_management_alert_assignees.id;
|
||||
|
||||
CREATE TABLE alert_management_alert_metric_images (
|
||||
id bigint NOT NULL,
|
||||
alert_id bigint NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
file_store smallint,
|
||||
file text NOT NULL,
|
||||
url text,
|
||||
url_text text,
|
||||
CONSTRAINT check_2587666252 CHECK ((char_length(url_text) <= 128)),
|
||||
CONSTRAINT check_4d811d9007 CHECK ((char_length(url) <= 255)),
|
||||
CONSTRAINT check_70fafae519 CHECK ((char_length(file) <= 255))
|
||||
);
|
||||
|
||||
CREATE SEQUENCE alert_management_alert_metric_images_id_seq
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NO MINVALUE
|
||||
NO MAXVALUE
|
||||
CACHE 1;
|
||||
|
||||
ALTER SEQUENCE alert_management_alert_metric_images_id_seq OWNED BY alert_management_alert_metric_images.id;
|
||||
|
||||
CREATE TABLE alert_management_alert_user_mentions (
|
||||
id bigint NOT NULL,
|
||||
alert_management_alert_id bigint NOT NULL,
|
||||
|
|
@ -21495,6 +21518,8 @@ ALTER TABLE ONLY agent_project_authorizations ALTER COLUMN id SET DEFAULT nextva
|
|||
|
||||
ALTER TABLE ONLY alert_management_alert_assignees ALTER COLUMN id SET DEFAULT nextval('alert_management_alert_assignees_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY alert_management_alert_metric_images ALTER COLUMN id SET DEFAULT nextval('alert_management_alert_metric_images_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY alert_management_alert_user_mentions ALTER COLUMN id SET DEFAULT nextval('alert_management_alert_user_mentions_id_seq'::regclass);
|
||||
|
||||
ALTER TABLE ONLY alert_management_alerts ALTER COLUMN id SET DEFAULT nextval('alert_management_alerts_id_seq'::regclass);
|
||||
|
|
@ -22865,6 +22890,9 @@ ALTER TABLE ONLY agent_project_authorizations
|
|||
ALTER TABLE ONLY alert_management_alert_assignees
|
||||
ADD CONSTRAINT alert_management_alert_assignees_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY alert_management_alert_metric_images
|
||||
ADD CONSTRAINT alert_management_alert_metric_images_pkey PRIMARY KEY (id);
|
||||
|
||||
ALTER TABLE ONLY alert_management_alert_user_mentions
|
||||
ADD CONSTRAINT alert_management_alert_user_mentions_pkey PRIMARY KEY (id);
|
||||
|
||||
|
|
@ -25408,6 +25436,8 @@ CREATE INDEX index_alert_assignees_on_alert_id ON alert_management_alert_assigne
|
|||
|
||||
CREATE UNIQUE INDEX index_alert_assignees_on_user_id_and_alert_id ON alert_management_alert_assignees USING btree (user_id, alert_id);
|
||||
|
||||
CREATE INDEX index_alert_management_alert_metric_images_on_alert_id ON alert_management_alert_metric_images USING btree (alert_id);
|
||||
|
||||
CREATE INDEX index_alert_management_alerts_on_domain ON alert_management_alerts USING btree (domain);
|
||||
|
||||
CREATE INDEX index_alert_management_alerts_on_environment_id ON alert_management_alerts USING btree (environment_id) WHERE (environment_id IS NOT NULL);
|
||||
|
|
@ -30470,6 +30500,9 @@ ALTER TABLE ONLY container_repositories
|
|||
ALTER TABLE ONLY clusters_applications_jupyter
|
||||
ADD CONSTRAINT fk_rails_331f0aff78 FOREIGN KEY (oauth_application_id) REFERENCES oauth_applications(id) ON DELETE SET NULL;
|
||||
|
||||
ALTER TABLE ONLY alert_management_alert_metric_images
|
||||
ADD CONSTRAINT fk_rails_338e55b408 FOREIGN KEY (alert_id) REFERENCES alert_management_alerts(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY suggestions
|
||||
ADD CONSTRAINT fk_rails_33b03a535c FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -372,19 +372,11 @@ For a complete list of upgrade notices and special considerations for older vers
|
|||
|
||||
## Upgrading GitLab Mattermost to 14.6
|
||||
|
||||
GitLab 14.6 includes Mattermost 6.1, and also includes the migrations for Mattermost 6.0. For information about upgrading and for ways to reduce the downtime of those migrations, read the [Important Upgrade Notes](https://docs.mattermost.com/administration/important-upgrade-notes.html) for both versions.
|
||||
GitLab 14.6 ships with Mattermost 6.1 including potentially long running database migrations for Mattermost 6.0. For information about upgrading and for ways to reduce the downtime caused by those migrations, read the [Important Upgrade Notes](https://docs.mattermost.com/administration/important-upgrade-notes.html) for both versions. If you need to perform any manual migrations, [connect to the bundled PostgreSQL database](#connecting-to-the-bundled-postgresql-database).
|
||||
|
||||
NOTE:
|
||||
The Mattermost upgrade notes refer to different impacts when used with a PostgreSQL versus a MySQL database. The GitLab Mattermost included with the GitLab Linux packages uses a PostgreSQL database.
|
||||
|
||||
If you need to connect in the database to perform any manual migrations, run the following:
|
||||
|
||||
```console
|
||||
sudo gitlab-psql -d mattermost_production
|
||||
```
|
||||
|
||||
You can then run the necessary queries that are described in the [Important Upgrade Notes](https://docs.mattermost.com/administration/important-upgrade-notes.html).
|
||||
|
||||
## Upgrading GitLab Mattermost from versions prior to 11.0
|
||||
|
||||
With version 11.0, GitLab introduced breaking changes which affected Mattermost configuration.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: reference
|
||||
---
|
||||
|
||||
# Files API rate limits **(FREE SELF)**
|
||||
# Rate limits on Repository files API **(FREE SELF)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68561) in GitLab 14.3.
|
||||
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75918) in GitLab 14.6. [Feature flag files_api_throttling](https://gitlab.com/gitlab-org/gitlab/-/issues/338903) removed.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
type: reference
|
||||
---
|
||||
|
||||
# Git LFS Rate Limits **(FREE SELF)**
|
||||
# Rate limits on Git LFS **(FREE SELF)**
|
||||
|
||||
[Git LFS (Large File Storage)](../../../topics/git/lfs/index.md) is a Git extension
|
||||
for handling large files. If you use Git LFS in your repository, common Git operations
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78364) in GitLab 14.8.
|
||||
|
||||
You can configure the per-user rate limit for requests to the users API endpoint to get a user by ID.
|
||||
You can configure the per user rate limit for requests to [Users API](../../../api/users.md).
|
||||
|
||||
To change getting a single user rate limit:
|
||||
To change the rate limit:
|
||||
|
||||
1. On the top bar, select **Menu > Admin**.
|
||||
1. On the left sidebar, select **Settings > Network**.
|
||||
|
|
|
|||
|
|
@ -23,11 +23,10 @@ module Gitlab
|
|||
override :readuntil
|
||||
def readuntil(terminator, ignore_eof = false)
|
||||
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
||||
check_timeout = Feature.enabled?(:header_read_timeout_buffered_io)
|
||||
|
||||
begin
|
||||
until idx = @rbuf.index(terminator)
|
||||
if check_timeout && (elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) > HEADER_READ_TIMEOUT
|
||||
if (elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time) > HEADER_READ_TIMEOUT
|
||||
raise Gitlab::HTTP::HeaderReadTimeout, "Request timed out after reading headers for #{elapsed} seconds"
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ agent_group_authorizations: :gitlab_main
|
|||
agent_project_authorizations: :gitlab_main
|
||||
alert_management_alert_assignees: :gitlab_main
|
||||
alert_management_alerts: :gitlab_main
|
||||
alert_management_alert_metric_images: :gitlab_main
|
||||
alert_management_alert_user_mentions: :gitlab_main
|
||||
alert_management_http_integrations: :gitlab_main
|
||||
allowed_email_domains: :gitlab_main
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ module Gitlab
|
|||
http = super
|
||||
http.hostname_override = hostname if hostname
|
||||
|
||||
if options[:use_read_total_timeout]
|
||||
if Feature.enabled?(:header_read_timeout_buffered_io)
|
||||
gitlab_http = Gitlab::NetHttpAdapter.new(http.address, http.port)
|
||||
|
||||
http.instance_variables.each do |variable|
|
||||
|
|
|
|||
|
|
@ -29301,6 +29301,9 @@ msgstr ""
|
|||
msgid "ProtectedBranch|Unprotect"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|Unprotect branch"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedBranch|What are protected branches?"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -29349,6 +29352,9 @@ msgstr ""
|
|||
msgid "ProtectedEnvironment|Your environment has been unprotected"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedTags|Unprotect tag"
|
||||
msgstr ""
|
||||
|
||||
msgid "ProtectedTags|default"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { getByRole } from '@testing-library/dom';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import mountComponent from 'helpers/vue_mount_component_helper';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { OPEN_REVERT_MODAL, OPEN_CHERRY_PICK_MODAL } from '~/projects/commit/constants';
|
||||
import modalEventHub from '~/projects/commit/event_hub';
|
||||
import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue';
|
||||
|
|
@ -127,7 +128,7 @@ describe('MRWidgetMerged', () => {
|
|||
|
||||
describe('methods', () => {
|
||||
describe('removeSourceBranch', () => {
|
||||
it('should set flag and call service then request main component to update the widget', (done) => {
|
||||
it('should set flag and call service then request main component to update the widget', async () => {
|
||||
jest.spyOn(vm.service, 'removeSourceBranch').mockReturnValue(
|
||||
new Promise((resolve) => {
|
||||
resolve({
|
||||
|
|
@ -139,14 +140,14 @@ describe('MRWidgetMerged', () => {
|
|||
);
|
||||
|
||||
vm.removeSourceBranch();
|
||||
setImmediate(() => {
|
||||
const args = eventHub.$emit.mock.calls[0];
|
||||
|
||||
expect(vm.isMakingRequest).toEqual(true);
|
||||
expect(args[0]).toEqual('MRWidgetUpdateRequested');
|
||||
expect(args[1]).not.toThrow();
|
||||
done();
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
const args = eventHub.$emit.mock.calls[0];
|
||||
|
||||
expect(vm.isMakingRequest).toEqual(true);
|
||||
expect(args[0]).toEqual('MRWidgetUpdateRequested');
|
||||
expect(args[1]).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import { GlSprintf } from '@gitlab/ui';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import simplePoll from '~/lib/utils/simple_poll';
|
||||
import CommitEdit from '~/vue_merge_request_widget/components/states/commit_edit.vue';
|
||||
import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/commit_message_dropdown.vue';
|
||||
|
|
@ -261,73 +262,68 @@ describe('ReadyToMerge', () => {
|
|||
|
||||
describe('methods', () => {
|
||||
describe('handleMergeButtonClick', () => {
|
||||
const returnPromise = (status) =>
|
||||
new Promise((resolve) => {
|
||||
resolve({
|
||||
data: {
|
||||
status,
|
||||
},
|
||||
});
|
||||
});
|
||||
const response = (status) => ({
|
||||
data: {
|
||||
status,
|
||||
},
|
||||
});
|
||||
|
||||
it('should handle merge when pipeline succeeds', (done) => {
|
||||
it('should handle merge when pipeline succeeds', async () => {
|
||||
createComponent();
|
||||
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
jest
|
||||
.spyOn(wrapper.vm.service, 'merge')
|
||||
.mockReturnValue(returnPromise('merge_when_pipeline_succeeds'));
|
||||
.mockResolvedValue(response('merge_when_pipeline_succeeds'));
|
||||
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
wrapper.setData({ removeSourceBranch: false });
|
||||
|
||||
wrapper.vm.handleMergeButtonClick(true);
|
||||
|
||||
setImmediate(() => {
|
||||
expect(wrapper.vm.isMakingRequest).toBeTruthy();
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('StateMachineValueChanged', {
|
||||
transition: 'start-auto-merge',
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
const params = wrapper.vm.service.merge.mock.calls[0][0];
|
||||
|
||||
expect(params).toEqual(
|
||||
expect.objectContaining({
|
||||
sha: wrapper.vm.mr.sha,
|
||||
commit_message: wrapper.vm.mr.commitMessage,
|
||||
should_remove_source_branch: false,
|
||||
auto_merge_strategy: 'merge_when_pipeline_succeeds',
|
||||
}),
|
||||
);
|
||||
done();
|
||||
expect(wrapper.vm.isMakingRequest).toBeTruthy();
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('MRWidgetUpdateRequested');
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('StateMachineValueChanged', {
|
||||
transition: 'start-auto-merge',
|
||||
});
|
||||
|
||||
const params = wrapper.vm.service.merge.mock.calls[0][0];
|
||||
|
||||
expect(params).toEqual(
|
||||
expect.objectContaining({
|
||||
sha: wrapper.vm.mr.sha,
|
||||
commit_message: wrapper.vm.mr.commitMessage,
|
||||
should_remove_source_branch: false,
|
||||
auto_merge_strategy: 'merge_when_pipeline_succeeds',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should handle merge failed', (done) => {
|
||||
it('should handle merge failed', async () => {
|
||||
createComponent();
|
||||
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
jest.spyOn(wrapper.vm.service, 'merge').mockReturnValue(returnPromise('failed'));
|
||||
jest.spyOn(wrapper.vm.service, 'merge').mockResolvedValue(response('failed'));
|
||||
wrapper.vm.handleMergeButtonClick(false, true);
|
||||
|
||||
setImmediate(() => {
|
||||
expect(wrapper.vm.isMakingRequest).toBeTruthy();
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined);
|
||||
await waitForPromises();
|
||||
|
||||
const params = wrapper.vm.service.merge.mock.calls[0][0];
|
||||
expect(wrapper.vm.isMakingRequest).toBeTruthy();
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('FailedToMerge', undefined);
|
||||
|
||||
expect(params.should_remove_source_branch).toBeTruthy();
|
||||
expect(params.auto_merge_strategy).toBeUndefined();
|
||||
done();
|
||||
});
|
||||
const params = wrapper.vm.service.merge.mock.calls[0][0];
|
||||
|
||||
expect(params.should_remove_source_branch).toBeTruthy();
|
||||
expect(params.auto_merge_strategy).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should handle merge action accepted case', (done) => {
|
||||
it('should handle merge action accepted case', async () => {
|
||||
createComponent();
|
||||
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
jest.spyOn(wrapper.vm.service, 'merge').mockReturnValue(returnPromise('success'));
|
||||
jest.spyOn(wrapper.vm.service, 'merge').mockResolvedValue(response('success'));
|
||||
jest.spyOn(wrapper.vm.mr, 'transitionStateMachine');
|
||||
wrapper.vm.handleMergeButtonClick();
|
||||
|
||||
|
|
@ -335,18 +331,17 @@ describe('ReadyToMerge', () => {
|
|||
transition: 'start-merge',
|
||||
});
|
||||
|
||||
setImmediate(() => {
|
||||
expect(wrapper.vm.isMakingRequest).toBeTruthy();
|
||||
expect(wrapper.vm.mr.transitionStateMachine).toHaveBeenCalledWith({
|
||||
transition: 'start-merge',
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
const params = wrapper.vm.service.merge.mock.calls[0][0];
|
||||
|
||||
expect(params.should_remove_source_branch).toBeTruthy();
|
||||
expect(params.auto_merge_strategy).toBeUndefined();
|
||||
done();
|
||||
expect(wrapper.vm.isMakingRequest).toBeTruthy();
|
||||
expect(wrapper.vm.mr.transitionStateMachine).toHaveBeenCalledWith({
|
||||
transition: 'start-merge',
|
||||
});
|
||||
|
||||
const params = wrapper.vm.service.merge.mock.calls[0][0];
|
||||
|
||||
expect(params.should_remove_source_branch).toBeTruthy();
|
||||
expect(params.auto_merge_strategy).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -364,20 +359,17 @@ describe('ReadyToMerge', () => {
|
|||
});
|
||||
|
||||
describe('handleRemoveBranchPolling', () => {
|
||||
const returnPromise = (state) =>
|
||||
new Promise((resolve) => {
|
||||
resolve({
|
||||
data: {
|
||||
source_branch_exists: state,
|
||||
},
|
||||
});
|
||||
});
|
||||
const response = (state) => ({
|
||||
data: {
|
||||
source_branch_exists: state,
|
||||
},
|
||||
});
|
||||
|
||||
it('should call start and stop polling when MR merged', (done) => {
|
||||
it('should call start and stop polling when MR merged', async () => {
|
||||
createComponent();
|
||||
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
jest.spyOn(wrapper.vm.service, 'poll').mockReturnValue(returnPromise(false));
|
||||
jest.spyOn(wrapper.vm.service, 'poll').mockResolvedValue(response(false));
|
||||
|
||||
let cpc = false; // continuePollingCalled
|
||||
let spc = false; // stopPollingCalled
|
||||
|
|
@ -390,28 +382,27 @@ describe('ReadyToMerge', () => {
|
|||
spc = true;
|
||||
},
|
||||
);
|
||||
setImmediate(() => {
|
||||
expect(wrapper.vm.service.poll).toHaveBeenCalled();
|
||||
|
||||
const args = eventHub.$emit.mock.calls[0];
|
||||
await waitForPromises();
|
||||
|
||||
expect(args[0]).toEqual('MRWidgetUpdateRequested');
|
||||
expect(args[1]).toBeDefined();
|
||||
args[1]();
|
||||
expect(wrapper.vm.service.poll).toHaveBeenCalled();
|
||||
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [false]);
|
||||
const args = eventHub.$emit.mock.calls[0];
|
||||
|
||||
expect(cpc).toBeFalsy();
|
||||
expect(spc).toBeTruthy();
|
||||
expect(args[0]).toEqual('MRWidgetUpdateRequested');
|
||||
expect(args[1]).toBeDefined();
|
||||
args[1]();
|
||||
|
||||
done();
|
||||
});
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('SetBranchRemoveFlag', [false]);
|
||||
|
||||
expect(cpc).toBeFalsy();
|
||||
expect(spc).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should continue polling until MR is merged', (done) => {
|
||||
it('should continue polling until MR is merged', async () => {
|
||||
createComponent();
|
||||
|
||||
jest.spyOn(wrapper.vm.service, 'poll').mockReturnValue(returnPromise(true));
|
||||
jest.spyOn(wrapper.vm.service, 'poll').mockResolvedValue(response(true));
|
||||
|
||||
let cpc = false; // continuePollingCalled
|
||||
let spc = false; // stopPollingCalled
|
||||
|
|
@ -424,12 +415,11 @@ describe('ReadyToMerge', () => {
|
|||
spc = true;
|
||||
},
|
||||
);
|
||||
setImmediate(() => {
|
||||
expect(cpc).toBeTruthy();
|
||||
expect(spc).toBeFalsy();
|
||||
|
||||
done();
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
expect(cpc).toBeTruthy();
|
||||
expect(spc).toBeFalsy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import Vue, { nextTick } from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import WorkInProgress from '~/vue_merge_request_widget/components/states/work_in_progress.vue';
|
||||
import toast from '~/vue_shared/plugins/global_toast';
|
||||
import eventHub from '~/vue_merge_request_widget/event_hub';
|
||||
|
|
@ -47,7 +48,7 @@ describe('Wip', () => {
|
|||
};
|
||||
|
||||
describe('handleRemoveDraft', () => {
|
||||
it('should make a request to service and handle response', (done) => {
|
||||
it('should make a request to service and handle response', async () => {
|
||||
const vm = createComponent();
|
||||
|
||||
jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
|
||||
|
|
@ -60,12 +61,12 @@ describe('Wip', () => {
|
|||
);
|
||||
|
||||
vm.handleRemoveDraft();
|
||||
setImmediate(() => {
|
||||
expect(vm.isMakingRequest).toBeTruthy();
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
|
||||
expect(toast).toHaveBeenCalledWith('Marked as ready. Merging is now allowed.');
|
||||
done();
|
||||
});
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(vm.isMakingRequest).toBeTruthy();
|
||||
expect(eventHub.$emit).toHaveBeenCalledWith('UpdateWidgetData', mrObj);
|
||||
expect(toast).toHaveBeenCalledWith('Marked as ready. Merging is now allowed.');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -91,13 +92,12 @@ describe('Wip', () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should not show removeWIP button is user cannot update MR', (done) => {
|
||||
it('should not show removeWIP button is user cannot update MR', async () => {
|
||||
vm.mr.removeWIPPath = '';
|
||||
|
||||
nextTick(() => {
|
||||
expect(el.querySelector('.js-remove-draft')).toEqual(null);
|
||||
done();
|
||||
});
|
||||
await nextTick();
|
||||
|
||||
expect(el.querySelector('.js-remove-draft')).toEqual(null);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -176,17 +176,18 @@ describe('AlertManagementStatus', () => {
|
|||
jest.spyOn(Tracking, 'event');
|
||||
});
|
||||
|
||||
it('should not track alert status updates when the tracking options do not exist', () => {
|
||||
it('should not track alert status updates when the tracking options do not exist', async () => {
|
||||
mountComponent({});
|
||||
Tracking.event.mockClear();
|
||||
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
|
||||
findFirstStatusOption().vm.$emit('click');
|
||||
setImmediate(() => {
|
||||
expect(Tracking.event).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(Tracking.event).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should track alert status updates when the tracking options exist', () => {
|
||||
it('should track alert status updates when the tracking options exist', async () => {
|
||||
const trackAlertStatusUpdateOptions = {
|
||||
category: 'Alert Management',
|
||||
action: 'update_alert_status',
|
||||
|
|
@ -196,11 +197,12 @@ describe('AlertManagementStatus', () => {
|
|||
Tracking.event.mockClear();
|
||||
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
|
||||
findFirstStatusOption().vm.$emit('click');
|
||||
|
||||
await nextTick();
|
||||
|
||||
const status = findFirstStatusOption().text();
|
||||
setImmediate(() => {
|
||||
const { category, action, label } = trackAlertStatusUpdateOptions;
|
||||
expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property: status });
|
||||
});
|
||||
const { category, action, label } = trackAlertStatusUpdateOptions;
|
||||
expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property: status });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import Vue from 'vue';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
|
||||
import mountComponent from 'helpers/vue_mount_component_helper';
|
||||
import { GREEN_BOX_IMAGE_URL, RED_BOX_IMAGE_URL } from 'spec/test_constants';
|
||||
|
|
@ -26,27 +26,25 @@ describe('DiffViewer', () => {
|
|||
vm.$destroy();
|
||||
});
|
||||
|
||||
it('renders image diff', (done) => {
|
||||
it('renders image diff', async () => {
|
||||
window.gon = {
|
||||
relative_url_root: '',
|
||||
};
|
||||
|
||||
createComponent({ ...requiredProps, projectPath: '' });
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe(
|
||||
`//-/raw/DEF/${RED_BOX_IMAGE_URL}`,
|
||||
);
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el.querySelector('.added img').getAttribute('src')).toBe(
|
||||
`//-/raw/ABC/${GREEN_BOX_IMAGE_URL}`,
|
||||
);
|
||||
expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe(
|
||||
`//-/raw/DEF/${RED_BOX_IMAGE_URL}`,
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.$el.querySelector('.added img').getAttribute('src')).toBe(
|
||||
`//-/raw/ABC/${GREEN_BOX_IMAGE_URL}`,
|
||||
);
|
||||
});
|
||||
|
||||
it('renders fallback download diff display', (done) => {
|
||||
it('renders fallback download diff display', async () => {
|
||||
createComponent({
|
||||
...requiredProps,
|
||||
diffViewerMode: 'added',
|
||||
|
|
@ -54,22 +52,18 @@ describe('DiffViewer', () => {
|
|||
oldPath: 'testold.abc',
|
||||
});
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.$el.querySelector('.deleted .file-info').textContent.trim()).toContain(
|
||||
'testold.abc',
|
||||
);
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el.querySelector('.deleted .btn.btn-default').textContent.trim()).toContain(
|
||||
'Download',
|
||||
);
|
||||
expect(vm.$el.querySelector('.deleted .file-info').textContent.trim()).toContain('testold.abc');
|
||||
|
||||
expect(vm.$el.querySelector('.added .file-info').textContent.trim()).toContain('test.abc');
|
||||
expect(vm.$el.querySelector('.added .btn.btn-default').textContent.trim()).toContain(
|
||||
'Download',
|
||||
);
|
||||
expect(vm.$el.querySelector('.deleted .btn.btn-default').textContent.trim()).toContain(
|
||||
'Download',
|
||||
);
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.$el.querySelector('.added .file-info').textContent.trim()).toContain('test.abc');
|
||||
expect(vm.$el.querySelector('.added .btn.btn-default').textContent.trim()).toContain(
|
||||
'Download',
|
||||
);
|
||||
});
|
||||
|
||||
describe('renamed file', () => {
|
||||
|
|
|
|||
|
|
@ -75,33 +75,29 @@ describe('ImageDiffViewer', () => {
|
|||
expect(metaInfoElements[1]).toHaveText('1.00 KiB');
|
||||
});
|
||||
|
||||
it('renders image diff for new', (done) => {
|
||||
it('renders image diff for new', async () => {
|
||||
createComponent({ ...allProps, diffMode: 'new', oldPath: '' });
|
||||
|
||||
setImmediate(() => {
|
||||
const metaInfoElement = vm.$el.querySelector('.image-info');
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el.querySelector('.added img').getAttribute('src')).toBe(GREEN_BOX_IMAGE_URL);
|
||||
expect(metaInfoElement).toHaveText('1.00 KiB');
|
||||
const metaInfoElement = vm.$el.querySelector('.image-info');
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.$el.querySelector('.added img').getAttribute('src')).toBe(GREEN_BOX_IMAGE_URL);
|
||||
expect(metaInfoElement).toHaveText('1.00 KiB');
|
||||
});
|
||||
|
||||
it('renders image diff for deleted', (done) => {
|
||||
it('renders image diff for deleted', async () => {
|
||||
createComponent({ ...allProps, diffMode: 'deleted', newPath: '' });
|
||||
|
||||
setImmediate(() => {
|
||||
const metaInfoElement = vm.$el.querySelector('.image-info');
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe(RED_BOX_IMAGE_URL);
|
||||
expect(metaInfoElement).toHaveText('2.00 KiB');
|
||||
const metaInfoElement = vm.$el.querySelector('.image-info');
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.$el.querySelector('.deleted img').getAttribute('src')).toBe(RED_BOX_IMAGE_URL);
|
||||
expect(metaInfoElement).toHaveText('2.00 KiB');
|
||||
});
|
||||
|
||||
it('renders image diff for renamed', (done) => {
|
||||
it('renders image diff for renamed', async () => {
|
||||
vm = new Vue({
|
||||
components: {
|
||||
imageDiffViewer,
|
||||
|
|
@ -127,25 +123,21 @@ describe('ImageDiffViewer', () => {
|
|||
`),
|
||||
}).$mount();
|
||||
|
||||
setImmediate(() => {
|
||||
const metaInfoElement = vm.$el.querySelector('.image-info');
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el.querySelector('img').getAttribute('src')).toBe(GREEN_BOX_IMAGE_URL);
|
||||
expect(vm.$el.querySelector('.overlay')).not.toBe(null);
|
||||
const metaInfoElement = vm.$el.querySelector('.image-info');
|
||||
|
||||
expect(metaInfoElement).toHaveText('2.00 KiB');
|
||||
expect(vm.$el.querySelector('img').getAttribute('src')).toBe(GREEN_BOX_IMAGE_URL);
|
||||
expect(vm.$el.querySelector('.overlay')).not.toBe(null);
|
||||
|
||||
done();
|
||||
});
|
||||
expect(metaInfoElement).toHaveText('2.00 KiB');
|
||||
});
|
||||
|
||||
describe('swipeMode', () => {
|
||||
beforeEach((done) => {
|
||||
beforeEach(() => {
|
||||
createComponent({ ...requiredProps });
|
||||
|
||||
setImmediate(() => {
|
||||
done();
|
||||
});
|
||||
return nextTick();
|
||||
});
|
||||
|
||||
it('switches to Swipe Mode', async () => {
|
||||
|
|
@ -157,12 +149,10 @@ describe('ImageDiffViewer', () => {
|
|||
});
|
||||
|
||||
describe('onionSkin', () => {
|
||||
beforeEach((done) => {
|
||||
beforeEach(() => {
|
||||
createComponent({ ...requiredProps });
|
||||
|
||||
setImmediate(() => {
|
||||
done();
|
||||
});
|
||||
return nextTick();
|
||||
});
|
||||
|
||||
it('switches to Onion Skin Mode', async () => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import Mousetrap from 'mousetrap';
|
||||
import Vue, { nextTick } from 'vue';
|
||||
import waitForPromises from 'helpers/wait_for_promises';
|
||||
import { file } from 'jest/ide/helpers';
|
||||
import { UP_KEY_CODE, DOWN_KEY_CODE, ENTER_KEY_CODE, ESC_KEY_CODE } from '~/lib/utils/keycodes';
|
||||
import FindFileComponent from '~/vue_shared/components/file_finder/index.vue';
|
||||
|
|
@ -31,7 +30,7 @@ describe('File finder item spec', () => {
|
|||
});
|
||||
|
||||
describe('with entries', () => {
|
||||
beforeEach((done) => {
|
||||
beforeEach(() => {
|
||||
createComponent({
|
||||
files: [
|
||||
{
|
||||
|
|
@ -48,7 +47,7 @@ describe('File finder item spec', () => {
|
|||
],
|
||||
});
|
||||
|
||||
setImmediate(done);
|
||||
return nextTick();
|
||||
});
|
||||
|
||||
it('renders list of blobs', () => {
|
||||
|
|
@ -57,68 +56,48 @@ describe('File finder item spec', () => {
|
|||
expect(vm.$el.textContent).not.toContain('folder');
|
||||
});
|
||||
|
||||
it('filters entries', (done) => {
|
||||
it('filters entries', async () => {
|
||||
vm.searchText = 'index';
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.$el.textContent).toContain('index.js');
|
||||
expect(vm.$el.textContent).not.toContain('component.js');
|
||||
await nextTick();
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.$el.textContent).toContain('index.js');
|
||||
expect(vm.$el.textContent).not.toContain('component.js');
|
||||
});
|
||||
|
||||
it('shows clear button when searchText is not empty', (done) => {
|
||||
it('shows clear button when searchText is not empty', async () => {
|
||||
vm.searchText = 'index';
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.$el.querySelector('.dropdown-input').classList).toContain('has-value');
|
||||
expect(vm.$el.querySelector('.dropdown-input-search').classList).toContain('hidden');
|
||||
await nextTick();
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.$el.querySelector('.dropdown-input').classList).toContain('has-value');
|
||||
expect(vm.$el.querySelector('.dropdown-input-search').classList).toContain('hidden');
|
||||
});
|
||||
|
||||
it('clear button resets searchText', (done) => {
|
||||
it('clear button resets searchText', async () => {
|
||||
vm.searchText = 'index';
|
||||
|
||||
waitForPromises()
|
||||
.then(() => {
|
||||
vm.clearSearchInput();
|
||||
})
|
||||
.then(waitForPromises)
|
||||
.then(() => {
|
||||
expect(vm.searchText).toBe('');
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
vm.clearSearchInput();
|
||||
|
||||
expect(vm.searchText).toBe('');
|
||||
});
|
||||
|
||||
it('clear button focuses search input', (done) => {
|
||||
it('clear button focuses search input', async () => {
|
||||
jest.spyOn(vm.$refs.searchInput, 'focus').mockImplementation(() => {});
|
||||
vm.searchText = 'index';
|
||||
|
||||
waitForPromises()
|
||||
.then(() => {
|
||||
vm.clearSearchInput();
|
||||
})
|
||||
.then(waitForPromises)
|
||||
.then(() => {
|
||||
expect(vm.$refs.searchInput.focus).toHaveBeenCalled();
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
vm.clearSearchInput();
|
||||
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$refs.searchInput.focus).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('listShowCount', () => {
|
||||
it('returns 1 when no filtered entries exist', (done) => {
|
||||
it('returns 1 when no filtered entries exist', () => {
|
||||
vm.searchText = 'testing 123';
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.listShowCount).toBe(1);
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.listShowCount).toBe(1);
|
||||
});
|
||||
|
||||
it('returns entries length when not filtered', () => {
|
||||
|
|
@ -131,26 +110,18 @@ describe('File finder item spec', () => {
|
|||
expect(vm.listHeight).toBe(55);
|
||||
});
|
||||
|
||||
it('returns 33 when entries dont exist', (done) => {
|
||||
it('returns 33 when entries dont exist', () => {
|
||||
vm.searchText = 'testing 123';
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.listHeight).toBe(33);
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.listHeight).toBe(33);
|
||||
});
|
||||
});
|
||||
|
||||
describe('filteredBlobsLength', () => {
|
||||
it('returns length of filtered blobs', (done) => {
|
||||
it('returns length of filtered blobs', () => {
|
||||
vm.searchText = 'index';
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.filteredBlobsLength).toBe(1);
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.filteredBlobsLength).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -158,7 +129,7 @@ describe('File finder item spec', () => {
|
|||
it('renders less DOM nodes if not visible by utilizing v-if', async () => {
|
||||
vm.visible = false;
|
||||
|
||||
await waitForPromises();
|
||||
await nextTick();
|
||||
|
||||
expect(vm.$el).toBeInstanceOf(Comment);
|
||||
});
|
||||
|
|
@ -166,33 +137,24 @@ describe('File finder item spec', () => {
|
|||
|
||||
describe('watches', () => {
|
||||
describe('searchText', () => {
|
||||
it('resets focusedIndex when updated', (done) => {
|
||||
it('resets focusedIndex when updated', async () => {
|
||||
vm.focusedIndex = 1;
|
||||
vm.searchText = 'test';
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.focusedIndex).toBe(0);
|
||||
await nextTick();
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.focusedIndex).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('visible', () => {
|
||||
it('resets searchText when changed to false', (done) => {
|
||||
it('resets searchText when changed to false', async () => {
|
||||
vm.searchText = 'test';
|
||||
vm.visible = true;
|
||||
vm.visible = false;
|
||||
|
||||
waitForPromises()
|
||||
.then(() => {
|
||||
vm.visible = false;
|
||||
})
|
||||
.then(waitForPromises)
|
||||
.then(() => {
|
||||
expect(vm.searchText).toBe('');
|
||||
})
|
||||
.then(done)
|
||||
.catch(done.fail);
|
||||
await nextTick();
|
||||
|
||||
expect(vm.searchText).toBe('');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -216,7 +178,7 @@ describe('File finder item spec', () => {
|
|||
});
|
||||
|
||||
describe('onKeyup', () => {
|
||||
it('opens file on enter key', (done) => {
|
||||
it('opens file on enter key', async () => {
|
||||
const event = new CustomEvent('keyup');
|
||||
event.keyCode = ENTER_KEY_CODE;
|
||||
|
||||
|
|
@ -224,14 +186,12 @@ describe('File finder item spec', () => {
|
|||
|
||||
vm.$refs.searchInput.dispatchEvent(event);
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.openFile).toHaveBeenCalledWith(vm.files[0]);
|
||||
await nextTick();
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.openFile).toHaveBeenCalledWith(vm.files[0]);
|
||||
});
|
||||
|
||||
it('closes file finder on esc key', (done) => {
|
||||
it('closes file finder on esc key', async () => {
|
||||
const event = new CustomEvent('keyup');
|
||||
event.keyCode = ESC_KEY_CODE;
|
||||
|
||||
|
|
@ -239,11 +199,9 @@ describe('File finder item spec', () => {
|
|||
|
||||
vm.$refs.searchInput.dispatchEvent(event);
|
||||
|
||||
setImmediate(() => {
|
||||
expect(vm.$emit).toHaveBeenCalledWith('toggle', false);
|
||||
await nextTick();
|
||||
|
||||
done();
|
||||
});
|
||||
expect(vm.$emit).toHaveBeenCalledWith('toggle', false);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -49,16 +49,6 @@ RSpec.describe Gitlab::BufferedIo do
|
|||
it 'raises a timeout error' do
|
||||
expect { readuntil }.to raise_error(Gitlab::HTTP::HeaderReadTimeout, /Request timed out after reading headers for 0\.[0-9]+ seconds/)
|
||||
end
|
||||
|
||||
context 'when the header_read_timeout feature is disabled' do
|
||||
before do
|
||||
stub_feature_flags(header_read_timeout_buffered_io: false)
|
||||
end
|
||||
|
||||
it 'does not raise a timeout error' do
|
||||
expect { readuntil }.to raise_error(RuntimeError, 'Test did not raise HeaderReadTimeout')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# rubocop:enable Style/FrozenStringLiteralComment
|
||||
|
|
|
|||
|
|
@ -27,11 +27,21 @@ RSpec.describe Gitlab::HTTPConnectionAdapter do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with header_read_timeout_buffered_io feature disabled' do
|
||||
before do
|
||||
stub_feature_flags(header_read_timeout_buffered_io: false)
|
||||
end
|
||||
|
||||
it 'uses the regular Net::HTTP class' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when local requests are allowed' do
|
||||
let(:options) { { allow_local_requests: true } }
|
||||
|
||||
it 'sets up the connection' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
expect(connection).to be_a(Gitlab::NetHttpAdapter)
|
||||
expect(connection.address).to eq('93.184.216.34')
|
||||
expect(connection.hostname_override).to eq('example.org')
|
||||
expect(connection.addr_port).to eq('example.org')
|
||||
|
|
@ -43,7 +53,7 @@ RSpec.describe Gitlab::HTTPConnectionAdapter do
|
|||
let(:options) { { allow_local_requests: false } }
|
||||
|
||||
it 'sets up the connection' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
expect(connection).to be_a(Gitlab::NetHttpAdapter)
|
||||
expect(connection.address).to eq('93.184.216.34')
|
||||
expect(connection.hostname_override).to eq('example.org')
|
||||
expect(connection.addr_port).to eq('example.org')
|
||||
|
|
@ -64,7 +74,7 @@ RSpec.describe Gitlab::HTTPConnectionAdapter do
|
|||
let(:options) { { allow_local_requests: true } }
|
||||
|
||||
it 'sets up the connection' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
expect(connection).to be_a(Gitlab::NetHttpAdapter)
|
||||
expect(connection.address).to eq('172.16.0.0')
|
||||
expect(connection.hostname_override).to be(nil)
|
||||
expect(connection.addr_port).to eq('172.16.0.0')
|
||||
|
|
@ -87,7 +97,7 @@ RSpec.describe Gitlab::HTTPConnectionAdapter do
|
|||
let(:options) { { allow_local_requests: true } }
|
||||
|
||||
it 'sets up the connection' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
expect(connection).to be_a(Gitlab::NetHttpAdapter)
|
||||
expect(connection.address).to eq('127.0.0.1')
|
||||
expect(connection.hostname_override).to be(nil)
|
||||
expect(connection.addr_port).to eq('127.0.0.1')
|
||||
|
|
@ -100,7 +110,7 @@ RSpec.describe Gitlab::HTTPConnectionAdapter do
|
|||
let(:uri) { URI('https://example.org:8080') }
|
||||
|
||||
it 'sets up the addr_port accordingly' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
expect(connection).to be_a(Gitlab::NetHttpAdapter)
|
||||
expect(connection.address).to eq('93.184.216.34')
|
||||
expect(connection.hostname_override).to eq('example.org')
|
||||
expect(connection.addr_port).to eq('example.org:8080')
|
||||
|
|
@ -115,7 +125,7 @@ RSpec.describe Gitlab::HTTPConnectionAdapter do
|
|||
end
|
||||
|
||||
it 'sets up the connection' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
expect(connection).to be_a(Gitlab::NetHttpAdapter)
|
||||
expect(connection.address).to eq('example.org')
|
||||
expect(connection.hostname_override).to eq(nil)
|
||||
expect(connection.addr_port).to eq('example.org')
|
||||
|
|
@ -129,7 +139,7 @@ RSpec.describe Gitlab::HTTPConnectionAdapter do
|
|||
end
|
||||
|
||||
it 'sets up the connection' do
|
||||
expect(connection).to be_a(Net::HTTP)
|
||||
expect(connection).to be_a(Gitlab::NetHttpAdapter)
|
||||
expect(connection.address).to eq('example.org')
|
||||
expect(connection.hostname_override).to eq(nil)
|
||||
expect(connection.addr_port).to eq('example.org')
|
||||
|
|
|
|||
|
|
@ -284,12 +284,9 @@ func TestUploadHandlerMultipartUploadSizeLimit(t *testing.T) {
|
|||
contentBuffer, contentType := createTestMultipartForm(t, make([]byte, uploadSize))
|
||||
response := testUploadArtifacts(t, contentType, ts.URL+Path, &contentBuffer)
|
||||
require.Equal(t, http.StatusRequestEntityTooLarge, response.Code)
|
||||
|
||||
// Poll because AbortMultipartUpload is async
|
||||
for i := 0; os.IsMultipartUpload(test.ObjectPath) && i < 100; i++ {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
require.False(t, os.IsMultipartUpload(test.ObjectPath), "MultipartUpload should not be in progress anymore")
|
||||
require.Eventually(t, func() bool {
|
||||
return !os.IsMultipartUpload(test.ObjectPath)
|
||||
}, time.Second, time.Millisecond, "MultipartUpload should not be in progress anymore")
|
||||
require.Empty(t, os.GetObjectMD5(test.ObjectPath), "upload should have failed, so the object should not exists")
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,29 +28,15 @@ func testDeadline() time.Time {
|
|||
|
||||
func requireFileGetsRemovedAsync(t *testing.T, filePath string) {
|
||||
var err error
|
||||
|
||||
// Poll because the file removal is async
|
||||
for i := 0; i < 100; i++ {
|
||||
require.Eventually(t, func() bool {
|
||||
_, err = os.Stat(filePath)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
return err != nil
|
||||
}, 10*time.Second, 10*time.Millisecond)
|
||||
require.True(t, os.IsNotExist(err), "File hasn't been deleted during cleanup")
|
||||
}
|
||||
|
||||
func requireObjectStoreDeletedAsync(t *testing.T, expectedDeletes int, osStub *test.ObjectstoreStub) {
|
||||
// Poll because the object removal is async
|
||||
for i := 0; i < 100; i++ {
|
||||
if osStub.DeletesCnt() == expectedDeletes {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
require.Equal(t, expectedDeletes, osStub.DeletesCnt(), "Object not deleted")
|
||||
require.Eventually(t, func() bool { return osStub.DeletesCnt() == expectedDeletes }, time.Second, time.Millisecond, "Object not deleted")
|
||||
}
|
||||
|
||||
func TestSaveFileWrongSize(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -56,13 +56,7 @@ func testObjectUploadNoErrors(t *testing.T, startObjectStore osFactory, useDelet
|
|||
if useDeleteURL {
|
||||
expectedDeleteCnt = 1
|
||||
}
|
||||
// Poll because the object removal is async
|
||||
for i := 0; i < 100; i++ {
|
||||
if osStub.DeletesCnt() == expectedDeleteCnt {
|
||||
break
|
||||
}
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
require.Eventually(t, func() bool { return osStub.DeletesCnt() == expectedDeleteCnt }, time.Second, time.Millisecond)
|
||||
|
||||
if useDeleteURL {
|
||||
require.Equal(t, 1, osStub.DeletesCnt(), "Object hasn't been deleted")
|
||||
|
|
|
|||
|
|
@ -180,11 +180,7 @@ func TestShutdown(t *testing.T) {
|
|||
}()
|
||||
|
||||
go func() {
|
||||
for countWatchers(runnerKey) == 0 {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
|
||||
require.Equal(t, 1, countWatchers(runnerKey))
|
||||
require.Eventually(t, func() bool { return countWatchers(runnerKey) == 1 }, 10*time.Second, time.Millisecond)
|
||||
|
||||
Shutdown()
|
||||
wg.Done()
|
||||
|
|
@ -192,11 +188,7 @@ func TestShutdown(t *testing.T) {
|
|||
|
||||
wg.Wait()
|
||||
|
||||
for countWatchers(runnerKey) == 1 {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
|
||||
require.Equal(t, 0, countWatchers(runnerKey))
|
||||
require.Eventually(t, func() bool { return countWatchers(runnerKey) == 0 }, 10*time.Second, time.Millisecond)
|
||||
|
||||
// Adding a key after the shutdown should result in an immediate response
|
||||
var val WatchKeyStatus
|
||||
|
|
|
|||
|
|
@ -581,15 +581,9 @@ func newProxy(url string) *proxy.Proxy {
|
|||
|
||||
func waitUntilDeleted(t *testing.T, path string) {
|
||||
var err error
|
||||
|
||||
// Poll because the file removal is async
|
||||
for i := 0; i < 100; i++ {
|
||||
require.Eventually(t, func() bool {
|
||||
_, err = os.Stat(path)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
return err != nil
|
||||
}, 10*time.Second, 10*time.Millisecond)
|
||||
require.True(t, os.IsNotExist(err), "expected the file to be deleted")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue