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
path: root/spec
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-02-12 18:09:37 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-02-12 18:09:37 +0300
commit2c89e169769ead722394a79ed67fcd08e96863dd (patch)
tree0dadb576846c484475b895f75fab41f71cdb952e /spec
parentbd497e352ebd279536ae11855871162e82a3f88c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/projects/alerting/notifications_controller_spec.rb92
-rw-r--r--spec/factories/services.rb10
-rw-r--r--spec/features/projects/graph_spec.rb10
-rw-r--r--spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap7
-rw-r--r--spec/frontend/blob/components/blob_header_default_actions_spec.js18
-rw-r--r--spec/frontend/blob/components/blob_header_spec.js58
-rw-r--r--spec/frontend/blob/components/blob_header_viewer_switcher_spec.js31
-rw-r--r--spec/frontend/ide/ide_router_extension_spec.js48
-rw-r--r--spec/frontend/lib/utils/url_utility_spec.js6
-rw-r--r--spec/helpers/blob_helper_spec.rb4
-rw-r--r--spec/lib/container_registry/client_spec.rb53
-rw-r--r--spec/lib/gitlab/background_migration_spec.rb26
-rw-r--r--spec/models/chat_name_spec.rb2
-rw-r--r--spec/models/chat_team_spec.rb2
-rw-r--r--spec/models/ci/bridge_spec.rb6
-rw-r--r--spec/models/ci/build_metadata_spec.rb8
-rw-r--r--spec/models/ci/build_spec.rb18
-rw-r--r--spec/models/ci/build_trace_chunk_spec.rb4
-rw-r--r--spec/models/ci/processable_spec.rb4
-rw-r--r--spec/models/ci/runner_spec.rb6
-rw-r--r--spec/models/container_repository_spec.rb34
-rw-r--r--spec/models/diff_viewer/server_side_spec.rb2
-rw-r--r--spec/models/event_collection_spec.rb8
-rw-r--r--spec/models/guest_spec.rb6
-rw-r--r--spec/models/list_user_preference_spec.rb4
-rw-r--r--spec/models/pages_domain_spec.rb10
-rw-r--r--spec/models/project_services/alerts_service_spec.rb109
-rw-r--r--spec/models/project_services/microsoft_teams_service_spec.rb4
-rw-r--r--spec/models/project_services/prometheus_service_spec.rb2
-rw-r--r--spec/models/project_spec.rb32
-rw-r--r--spec/models/releases/source_spec.rb2
-rw-r--r--spec/requests/api/lsif_data_spec.rb3
-rw-r--r--spec/services/projects/alerting/notify_service_spec.rb34
-rw-r--r--spec/services/projects/container_repository/cleanup_tags_service_spec.rb4
-rw-r--r--spec/services/projects/container_repository/delete_tags_service_spec.rb214
-rw-r--r--spec/services/projects/lsif_data_service_spec.rb29
36 files changed, 714 insertions, 196 deletions
diff --git a/spec/controllers/projects/alerting/notifications_controller_spec.rb b/spec/controllers/projects/alerting/notifications_controller_spec.rb
new file mode 100644
index 00000000000..a56ac59215f
--- /dev/null
+++ b/spec/controllers/projects/alerting/notifications_controller_spec.rb
@@ -0,0 +1,92 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Alerting::NotificationsController do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:environment) { create(:environment, project: project) }
+
+ describe 'POST #create' do
+ let(:service_response) { ServiceResponse.success }
+ let(:notify_service) { instance_double(Projects::Alerting::NotifyService, execute: service_response) }
+
+ around do |example|
+ ForgeryProtection.with_forgery_protection { example.run }
+ end
+
+ before do
+ allow(Projects::Alerting::NotifyService).to receive(:new).and_return(notify_service)
+ end
+
+ def make_request(body = {})
+ post :create, params: project_params, body: body.to_json, as: :json
+ end
+
+ context 'when notification service succeeds' do
+ let(:payload) do
+ {
+ title: 'Alert title',
+ hosts: 'https://gitlab.com'
+ }
+ end
+
+ let(:permitted_params) { ActionController::Parameters.new(payload).permit! }
+
+ it 'responds with ok' do
+ make_request
+
+ expect(response).to have_gitlab_http_status(:ok)
+ end
+
+ it 'does not pass excluded parameters to the notify service' do
+ make_request(payload)
+
+ expect(Projects::Alerting::NotifyService)
+ .to have_received(:new)
+ .with(project, nil, permitted_params)
+ end
+ end
+
+ context 'when notification service fails' do
+ let(:service_response) { ServiceResponse.error(message: 'Unauthorized', http_status: 401) }
+
+ it 'responds with the service response' do
+ make_request
+
+ expect(response).to have_gitlab_http_status(:unauthorized)
+ end
+ end
+
+ context 'bearer token' do
+ context 'when set' do
+ it 'extracts bearer token' do
+ request.headers['HTTP_AUTHORIZATION'] = 'Bearer some token'
+
+ expect(notify_service).to receive(:execute).with('some token')
+
+ make_request
+ end
+
+ it 'pass nil if cannot extract a non-bearer token' do
+ request.headers['HTTP_AUTHORIZATION'] = 'some token'
+
+ expect(notify_service).to receive(:execute).with(nil)
+
+ make_request
+ end
+ end
+
+ context 'when missing' do
+ it 'passes nil' do
+ expect(notify_service).to receive(:execute).with(nil)
+
+ make_request
+ end
+ end
+ end
+ end
+
+ def project_params(opts = {})
+ opts.reverse_merge(namespace_id: project.namespace, project_id: project)
+ end
+end
diff --git a/spec/factories/services.rb b/spec/factories/services.rb
index 5d62b3cb9c9..ffa51abf26f 100644
--- a/spec/factories/services.rb
+++ b/spec/factories/services.rb
@@ -44,6 +44,16 @@ FactoryBot.define do
end
end
+ factory :alerts_service do
+ project
+ type { 'AlertsService' }
+ active { true }
+
+ trait :inactive do
+ active { false }
+ end
+ end
+
factory :drone_ci_service do
project
active { true }
diff --git a/spec/features/projects/graph_spec.rb b/spec/features/projects/graph_spec.rb
index 562dbeb816a..6b2a9a6b852 100644
--- a/spec/features/projects/graph_spec.rb
+++ b/spec/features/projects/graph_spec.rb
@@ -22,20 +22,12 @@ describe 'Project Graph', :js do
end
end
- shared_examples 'page should have languages graphs' do
- it 'renders languages' do
- expect(page).to have_content(/Ruby 66.* %/)
- expect(page).to have_content(/JavaScript 22.* %/)
- end
- end
-
context 'commits graph' do
before do
visit commits_project_graph_path(project, 'master')
end
it_behaves_like 'page should have commits graphs'
- it_behaves_like 'page should have languages graphs'
end
context 'languages graph' do
@@ -44,7 +36,6 @@ describe 'Project Graph', :js do
end
it_behaves_like 'page should have commits graphs'
- it_behaves_like 'page should have languages graphs'
end
context 'charts graph' do
@@ -53,7 +44,6 @@ describe 'Project Graph', :js do
end
it_behaves_like 'page should have commits graphs'
- it_behaves_like 'page should have languages graphs'
end
context 'chart graph with HTML escaped branch name' do
diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
index b77ca28b9d8..2878ad492a4 100644
--- a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
+++ b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap
@@ -12,13 +12,12 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `
class="file-actions d-none d-sm-block"
>
<viewer-switcher-stub
- activeviewer="rich"
- blob="[object Object]"
+ value="simple"
/>
<default-actions-stub
- activeviewer="rich"
- blob="[object Object]"
+ activeviewer="simple"
+ rawpath="/flightjs/flight/snippets/51/raw"
/>
</div>
</div>
diff --git a/spec/frontend/blob/components/blob_header_default_actions_spec.js b/spec/frontend/blob/components/blob_header_default_actions_spec.js
index fe0edffd12d..5da0d40ab14 100644
--- a/spec/frontend/blob/components/blob_header_default_actions_spec.js
+++ b/spec/frontend/blob/components/blob_header_default_actions_spec.js
@@ -8,7 +8,6 @@ import {
} from '~/blob/components/constants';
import { GlButtonGroup, GlButton } from '@gitlab/ui';
import { Blob } from './mock_data';
-import eventHub from '~/blob/event_hub';
describe('Blob Header Default Actions', () => {
let wrapper;
@@ -16,10 +15,10 @@ describe('Blob Header Default Actions', () => {
let buttons;
const hrefPrefix = 'http://localhost';
- function createComponent(blobProps = {}, propsData = {}) {
+ function createComponent(propsData = {}) {
wrapper = mount(BlobHeaderActions, {
propsData: {
- blob: Object.assign({}, Blob, blobProps),
+ rawPath: Blob.rawPath,
...propsData,
},
});
@@ -60,12 +59,9 @@ describe('Blob Header Default Actions', () => {
});
it('renders "Copy file contents" button as disables if the viewer is Rich', () => {
- createComponent(
- {},
- {
- activeViewer: RICH_BLOB_VIEWER,
- },
- );
+ createComponent({
+ activeViewer: RICH_BLOB_VIEWER,
+ });
buttons = wrapper.findAll(GlButton);
expect(buttons.at(0).attributes('disabled')).toBeTruthy();
@@ -74,10 +70,10 @@ describe('Blob Header Default Actions', () => {
describe('functionally', () => {
it('emits an event when a Copy Contents button is clicked', () => {
- jest.spyOn(eventHub, '$emit');
+ jest.spyOn(wrapper.vm, '$emit');
buttons.at(0).vm.$emit('click');
- expect(eventHub.$emit).toHaveBeenCalledWith('copy');
+ expect(wrapper.vm.$emit).toHaveBeenCalledWith('copy');
});
});
});
diff --git a/spec/frontend/blob/components/blob_header_spec.js b/spec/frontend/blob/components/blob_header_spec.js
index 7d1443fb069..d410ef10fc9 100644
--- a/spec/frontend/blob/components/blob_header_spec.js
+++ b/spec/frontend/blob/components/blob_header_spec.js
@@ -3,7 +3,6 @@ import BlobHeader from '~/blob/components/blob_header.vue';
import ViewerSwitcher from '~/blob/components/blob_header_viewer_switcher.vue';
import DefaultActions from '~/blob/components/blob_header_default_actions.vue';
import BlobFilepath from '~/blob/components/blob_header_filepath.vue';
-import eventHub from '~/blob/event_hub';
import { Blob } from './mock_data';
@@ -21,10 +20,6 @@ describe('Blob Header Default Actions', () => {
});
}
- beforeEach(() => {
- createComponent();
- });
-
afterEach(() => {
wrapper.destroy();
});
@@ -96,37 +91,48 @@ describe('Blob Header Default Actions', () => {
describe('functionality', () => {
const newViewer = 'Foo Bar';
+ const activeViewerType = 'Alpha Beta';
- it('listens to "switch-view" event when viewer switcher is shown and updates activeViewer', () => {
- expect(wrapper.vm.showViewerSwitcher).toBe(true);
- eventHub.$emit('switch-viewer', newViewer);
-
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.activeViewer).toBe(newViewer);
- });
- });
-
- it('does not update active viewer if the switcher is not shown', () => {
- const activeViewer = 'Alpha Beta';
+ const factory = (hideViewerSwitcher = false) => {
createComponent(
{},
+ {},
{
- data() {
- return {
- activeViewer,
- };
- },
- },
- {
- hideViewerSwitcher: true,
+ activeViewerType,
+ hideViewerSwitcher,
},
);
+ };
+
+ it('by default sets viewer data based on activeViewerType', () => {
+ factory();
+ expect(wrapper.vm.viewer).toBe(activeViewerType);
+ });
+
+ it('sets viewer to null if the viewer switcher should be hidden', () => {
+ factory(true);
+ expect(wrapper.vm.viewer).toBe(null);
+ });
+
+ it('watches the changes in viewer data and emits event when the change is registered', () => {
+ factory();
+ jest.spyOn(wrapper.vm, '$emit');
+ wrapper.vm.viewer = newViewer;
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.$emit).toHaveBeenCalledWith('viewer-changed', newViewer);
+ });
+ });
+
+ it('does not emit event if the switcher is not rendered', () => {
+ factory(true);
expect(wrapper.vm.showViewerSwitcher).toBe(false);
- eventHub.$emit('switch-viewer', newViewer);
+ jest.spyOn(wrapper.vm, '$emit');
+ wrapper.vm.viewer = newViewer;
return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm.activeViewer).toBe(activeViewer);
+ expect(wrapper.vm.$emit).not.toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js
index 88e9eeea994..f1a7ac8b21a 100644
--- a/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js
+++ b/spec/frontend/blob/components/blob_header_viewer_switcher_spec.js
@@ -7,18 +7,13 @@ import {
SIMPLE_BLOB_VIEWER_TITLE,
} from '~/blob/components/constants';
import { GlButtonGroup, GlButton } from '@gitlab/ui';
-import { Blob } from './mock_data';
-import eventHub from '~/blob/event_hub';
describe('Blob Header Viewer Switcher', () => {
let wrapper;
- function createComponent(blobProps = {}, propsData = {}) {
+ function createComponent(propsData = {}) {
wrapper = mount(BlobHeaderViewerSwitcher, {
- propsData: {
- blob: Object.assign({}, Blob, blobProps),
- ...propsData,
- },
+ propsData,
});
}
@@ -29,7 +24,7 @@ describe('Blob Header Viewer Switcher', () => {
describe('intiialization', () => {
it('is initialized with simple viewer as active', () => {
createComponent();
- expect(wrapper.vm.activeViewer).toBe(SIMPLE_BLOB_VIEWER);
+ expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
});
});
@@ -60,42 +55,42 @@ describe('Blob Header Viewer Switcher', () => {
let simpleBtn;
let richBtn;
- function factory(propsOptions = {}) {
- createComponent({}, propsOptions);
+ function factory(propsData = {}) {
+ createComponent(propsData);
buttons = wrapper.findAll(GlButton);
simpleBtn = buttons.at(0);
richBtn = buttons.at(1);
- jest.spyOn(eventHub, '$emit');
+ jest.spyOn(wrapper.vm, '$emit');
}
it('does not switch the viewer if the selected one is already active', () => {
factory();
- expect(wrapper.vm.activeViewer).toBe(SIMPLE_BLOB_VIEWER);
+ expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
simpleBtn.vm.$emit('click');
- expect(wrapper.vm.activeViewer).toBe(SIMPLE_BLOB_VIEWER);
- expect(eventHub.$emit).not.toHaveBeenCalled();
+ expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
+ expect(wrapper.vm.$emit).not.toHaveBeenCalled();
});
it('emits an event when a Rich Viewer button is clicked', () => {
factory();
- expect(wrapper.vm.activeViewer).toBe(SIMPLE_BLOB_VIEWER);
+ expect(wrapper.vm.value).toBe(SIMPLE_BLOB_VIEWER);
richBtn.vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('switch-viewer', RICH_BLOB_VIEWER);
+ expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', RICH_BLOB_VIEWER);
});
});
it('emits an event when a Simple Viewer button is clicked', () => {
factory({
- activeViewer: RICH_BLOB_VIEWER,
+ value: RICH_BLOB_VIEWER,
});
simpleBtn.vm.$emit('click');
return wrapper.vm.$nextTick().then(() => {
- expect(eventHub.$emit).toHaveBeenCalledWith('switch-viewer', SIMPLE_BLOB_VIEWER);
+ expect(wrapper.vm.$emit).toHaveBeenCalledWith('input', SIMPLE_BLOB_VIEWER);
});
});
});
diff --git a/spec/frontend/ide/ide_router_extension_spec.js b/spec/frontend/ide/ide_router_extension_spec.js
new file mode 100644
index 00000000000..3e29ecc4a90
--- /dev/null
+++ b/spec/frontend/ide/ide_router_extension_spec.js
@@ -0,0 +1,48 @@
+import VueRouter from 'vue-router';
+import IdeRouter from '~/ide/ide_router_extension';
+
+jest.mock('vue-router');
+
+describe('IDE overrides of VueRouter', () => {
+ const paths = branch => [
+ `${branch}`,
+ `/${branch}`,
+ `/${branch}/-/`,
+ `/edit/${branch}`,
+ `/edit/${branch}/-/`,
+ `/blob/${branch}`,
+ `/blob/${branch}/-/`,
+ `/blob/${branch}/-/src/merge_requests/2`,
+ `/blob/${branch}/-/src/blob/`,
+ `/tree/${branch}/-/src/blob/`,
+ `/tree/${branch}/-/src/tree/`,
+ ];
+ let router;
+
+ beforeEach(() => {
+ VueRouter.mockClear();
+ router = new IdeRouter({
+ mode: 'history',
+ });
+ });
+
+ it.each`
+ path | expected
+ ${'#-test'} | ${'%23-test'}
+ ${'#test'} | ${'%23test'}
+ ${'test#'} | ${'test%23'}
+ ${'test-#'} | ${'test-%23'}
+ ${'test-#-hash'} | ${'test-%23-hash'}
+ ${'test/hash#123'} | ${'test/hash%23123'}
+ `('finds project path when route is $path', ({ path, expected }) => {
+ paths(path).forEach(route => {
+ const expectedPath = route.replace(path, expected);
+
+ router.push(route);
+ expect(VueRouter.prototype.push).toHaveBeenCalledWith(expectedPath, undefined, undefined);
+
+ router.resolve(route);
+ expect(VueRouter.prototype.resolve).toHaveBeenCalledWith(expectedPath, undefined, undefined);
+ });
+ });
+});
diff --git a/spec/frontend/lib/utils/url_utility_spec.js b/spec/frontend/lib/utils/url_utility_spec.js
index 989de1a8337..d0abf2c03a9 100644
--- a/spec/frontend/lib/utils/url_utility_spec.js
+++ b/spec/frontend/lib/utils/url_utility_spec.js
@@ -28,6 +28,12 @@ describe('URL utility', () => {
gon.relative_url_root = '';
});
+ it('escapes special characters', () => {
+ expect(urlUtils.webIDEUrl('/gitlab-org/gitlab-#-foss/merge_requests/1')).toBe(
+ '/-/ide/project/gitlab-org/gitlab-%23-foss/merge_requests/1',
+ );
+ });
+
describe('without relative_url_root', () => {
it('returns IDE path with route', () => {
expect(urlUtils.webIDEUrl('/gitlab-org/gitlab-foss/merge_requests/1')).toBe(
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 2d0c4723648..a9f4b03eba5 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -244,8 +244,8 @@ describe BlobHelper do
it 'escapes special characters' do
Rails.application.routes.default_url_options[:script_name] = nil
- expect(helper.ide_edit_path(project, "testing/#hashes", "readme.md#test")).to eq("/-/ide/project/#{project.namespace.path}/#{project.path}/edit/testing/#hashes/-/readme.md%23test")
- expect(helper.ide_edit_path(project, "testing/#hashes", "src#/readme.md#test")).to eq("/-/ide/project/#{project.namespace.path}/#{project.path}/edit/testing/#hashes/-/src%23/readme.md%23test")
+ expect(helper.ide_edit_path(project, "testing/#hashes", "readme.md#test")).to eq("/-/ide/project/#{project.full_path}/edit/testing/%23hashes/-/readme.md%23test")
+ expect(helper.ide_edit_path(project, "testing/#hashes", "src#/readme.md#test")).to eq("/-/ide/project/#{project.full_path}/edit/testing/%23hashes/-/src%23/readme.md%23test")
end
it 'does not escape "/" character' do
diff --git a/spec/lib/container_registry/client_spec.rb b/spec/lib/container_registry/client_spec.rb
index a493b96b1e4..5d2334a6d8f 100644
--- a/spec/lib/container_registry/client_spec.rb
+++ b/spec/lib/container_registry/client_spec.rb
@@ -146,4 +146,57 @@ describe ContainerRegistry::Client do
expect(subject).to eq 'sha256:123'
end
end
+
+ describe '#delete_repository_tag_by_name' do
+ subject { client.delete_repository_tag_by_name('group/test', 'a') }
+
+ context 'when the tag exists' do
+ before do
+ stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a")
+ .to_return(status: 200, body: "")
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the tag does not exist' do
+ before do
+ stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a")
+ .to_return(status: 404, body: "")
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when an error occurs' do
+ before do
+ stub_request(:delete, "http://container-registry/v2/group/test/tags/reference/a")
+ .to_return(status: 500, body: "")
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#supports_tag_delete?' do
+ subject { client.supports_tag_delete? }
+
+ context 'when the server supports tag deletion' do
+ before do
+ stub_request(:options, "http://container-registry/v2/name/tags/reference/tag")
+ .to_return(status: 200, body: "", headers: { 'Allow' => 'DELETE' })
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when the server does not support tag deletion' do
+ before do
+ stub_request(:options, "http://container-registry/v2/name/tags/reference/tag")
+ .to_return(status: 404, body: "")
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/lib/gitlab/background_migration_spec.rb b/spec/lib/gitlab/background_migration_spec.rb
index 9546550bfc5..71959f54b38 100644
--- a/spec/lib/gitlab/background_migration_spec.rb
+++ b/spec/lib/gitlab/background_migration_spec.rb
@@ -165,6 +165,32 @@ describe Gitlab::BackgroundMigration do
end
end
+ describe '.remaining', :redis do
+ context 'when there are jobs remaining' do
+ let(:queue) { Array.new(12) }
+
+ before do
+ allow(Sidekiq::Queue).to receive(:new)
+ .with(described_class.queue)
+ .and_return(Array.new(12))
+
+ Sidekiq::Testing.disable! do
+ BackgroundMigrationWorker.perform_in(10.minutes, 'Foo')
+ end
+ end
+
+ it 'returns the enqueued jobs plus the scheduled jobs' do
+ expect(described_class.remaining).to eq(13)
+ end
+ end
+
+ context 'when there are no jobs remaining' do
+ it 'returns zero' do
+ expect(described_class.remaining).to be_zero
+ end
+ end
+ end
+
describe '.exists?' do
context 'when there are enqueued jobs present' do
let(:queue) do
diff --git a/spec/models/chat_name_spec.rb b/spec/models/chat_name_spec.rb
index 82991937644..863c28a86fb 100644
--- a/spec/models/chat_name_spec.rb
+++ b/spec/models/chat_name_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe ChatName do
- set(:chat_name) { create(:chat_name) }
+ let_it_be(:chat_name) { create(:chat_name) }
subject { chat_name }
it { is_expected.to belong_to(:service) }
diff --git a/spec/models/chat_team_spec.rb b/spec/models/chat_team_spec.rb
index 76beb3d506b..107fdaccc68 100644
--- a/spec/models/chat_team_spec.rb
+++ b/spec/models/chat_team_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe ChatTeam do
- set(:chat_team) { create(:chat_team) }
+ let_it_be(:chat_team) { create(:chat_team) }
subject { chat_team }
# Associations
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb
index c9d6687f0ea..31e13122b95 100644
--- a/spec/models/ci/bridge_spec.rb
+++ b/spec/models/ci/bridge_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
describe Ci::Bridge do
- set(:project) { create(:project) }
- set(:target_project) { create(:project, name: 'project', namespace: create(:namespace, name: 'my')) }
- set(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:target_project) { create(:project, name: 'project', namespace: create(:namespace, name: 'my')) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
let(:bridge) do
create(:ci_bridge, :variables, status: :created,
diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb
index da95a2d30f5..588e5872cc8 100644
--- a/spec/models/ci/build_metadata_spec.rb
+++ b/spec/models/ci/build_metadata_spec.rb
@@ -3,11 +3,11 @@
require 'spec_helper'
describe Ci::BuildMetadata do
- set(:user) { create(:user) }
- set(:group) { create(:group) }
- set(:project) { create(:project, :repository, group: group, build_timeout: 2000) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, :repository, group: group, build_timeout: 2000) }
- set(:pipeline) do
+ let_it_be(:pipeline) do
create(:ci_pipeline, project: project,
sha: project.commit.id,
ref: project.default_branch,
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 91185446488..8f2626037a1 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -3,11 +3,11 @@
require 'spec_helper'
describe Ci::Build do
- set(:user) { create(:user) }
- set(:group) { create(:group) }
- set(:project) { create(:project, :repository, group: group) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:group, reload: true) { create(:group) }
+ let_it_be(:project, reload: true) { create(:project, :repository, group: group) }
- set(:pipeline) do
+ let_it_be(:pipeline, reload: true) do
create(:ci_pipeline, project: project,
sha: project.commit.id,
ref: project.default_branch,
@@ -3612,7 +3612,7 @@ describe Ci::Build do
end
describe '.matches_tag_ids' do
- set(:build) { create(:ci_build, project: project, user: user) }
+ let_it_be(:build, reload: true) { create(:ci_build, project: project, user: user) }
let(:tag_ids) { ::ActsAsTaggableOn::Tag.named_any(tag_list).ids }
subject { described_class.where(id: build).matches_tag_ids(tag_ids) }
@@ -3659,7 +3659,7 @@ describe Ci::Build do
end
describe '.matches_tags' do
- set(:build) { create(:ci_build, project: project, user: user) }
+ let_it_be(:build, reload: true) { create(:ci_build, project: project, user: user) }
subject { described_class.where(id: build).with_any_tags }
@@ -3685,7 +3685,7 @@ describe Ci::Build do
end
describe 'pages deployments' do
- set(:build) { create(:ci_build, project: project, user: user) }
+ let_it_be(:build, reload: true) { create(:ci_build, project: project, user: user) }
context 'when job is "pages"' do
before do
@@ -3852,7 +3852,7 @@ describe Ci::Build do
end
describe '#artifacts_metadata_entry' do
- set(:build) { create(:ci_build, project: project) }
+ let_it_be(:build) { create(:ci_build, project: project) }
let(:path) { 'other_artifacts_0.1.2/another-subdirectory/banana_sample.gif' }
around do |example|
@@ -3952,7 +3952,7 @@ describe Ci::Build do
end
describe '#supported_runner?' do
- set(:build) { create(:ci_build) }
+ let_it_be(:build) { create(:ci_build) }
subject { build.supported_runner?(runner_features) }
diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb
index ca49233dde1..f08f05a09bf 100644
--- a/spec/models/ci/build_trace_chunk_spec.rb
+++ b/spec/models/ci/build_trace_chunk_spec.rb
@@ -5,7 +5,7 @@ require 'spec_helper'
describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
include ExclusiveLeaseHelpers
- set(:build) { create(:ci_build, :running) }
+ let_it_be(:build) { create(:ci_build, :running) }
let(:chunk_index) { 0 }
let(:data_store) { :redis }
let(:raw_data) { nil }
@@ -24,7 +24,7 @@ describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state do
context 'FastDestroyAll' do
let(:parent) { create(:project) }
let(:pipeline) { create(:ci_pipeline, project: parent) }
- let(:build) { create(:ci_build, :running, :trace_live, pipeline: pipeline, project: parent) }
+ let!(:build) { create(:ci_build, :running, :trace_live, pipeline: pipeline, project: parent) }
let(:subjects) { build.trace_chunks }
describe 'Forbid #destroy and #destroy_all' do
diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb
index 370606a73bc..f3d743fc272 100644
--- a/spec/models/ci/processable_spec.rb
+++ b/spec/models/ci/processable_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
describe Ci::Processable do
- set(:project) { create(:project) }
- set(:pipeline) { create(:ci_pipeline, project: project) }
+ let_it_be(:project) { create(:project) }
+ let_it_be(:pipeline) { create(:ci_pipeline, project: project) }
describe '#aggregated_needs_names' do
let(:with_aggregated_needs) { pipeline.processables.select_with_aggregated_needs(project) }
diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb
index 3e494d19233..0192c8ed17d 100644
--- a/spec/models/ci/runner_spec.rb
+++ b/spec/models/ci/runner_spec.rb
@@ -38,8 +38,8 @@ describe Ci::Runner do
end
context 'runner_type validations' do
- set(:group) { create(:group) }
- set(:project) { create(:project) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project) }
let(:group_runner) { create(:ci_runner, :group, groups: [group]) }
let(:project_runner) { create(:ci_runner, :project, projects: [project]) }
let(:instance_runner) { create(:ci_runner, :instance) }
@@ -322,7 +322,7 @@ describe Ci::Runner do
end
describe '#can_pick?' do
- set(:pipeline) { create(:ci_pipeline) }
+ let_it_be(:pipeline) { create(:ci_pipeline) }
let(:build) { create(:ci_build, pipeline: pipeline) }
let(:runner_project) { build.project }
let(:runner) { create(:ci_runner, :project, projects: [runner_project], tag_list: tag_list, run_untagged: run_untagged) }
diff --git a/spec/models/container_repository_spec.rb b/spec/models/container_repository_spec.rb
index 0a3065140bf..5ed812652c5 100644
--- a/spec/models/container_repository_spec.rb
+++ b/spec/models/container_repository_spec.rb
@@ -85,7 +85,7 @@ describe ContainerRepository do
context 'when action succeeds' do
it 'returns status that indicates success' do
expect(repository.client)
- .to receive(:delete_repository_tag)
+ .to receive(:delete_repository_tag_by_digest)
.twice
.and_return(true)
@@ -96,7 +96,7 @@ describe ContainerRepository do
context 'when action fails' do
it 'returns status that indicates failure' do
expect(repository.client)
- .to receive(:delete_repository_tag)
+ .to receive(:delete_repository_tag_by_digest)
.twice
.and_return(false)
@@ -105,6 +105,36 @@ describe ContainerRepository do
end
end
+ describe '#delete_tag_by_name' do
+ let(:repository) do
+ create(:container_repository, name: 'my_image',
+ tags: { latest: '123', rc1: '234' },
+ project: project)
+ end
+
+ context 'when action succeeds' do
+ it 'returns status that indicates success' do
+ expect(repository.client)
+ .to receive(:delete_repository_tag_by_name)
+ .with(repository.path, "latest")
+ .and_return(true)
+
+ expect(repository.delete_tag_by_name('latest')).to be_truthy
+ end
+ end
+
+ context 'when action fails' do
+ it 'returns status that indicates failure' do
+ expect(repository.client)
+ .to receive(:delete_repository_tag_by_name)
+ .with(repository.path, "latest")
+ .and_return(false)
+
+ expect(repository.delete_tag_by_name('latest')).to be_falsey
+ end
+ end
+ end
+
describe '#location' do
context 'when registry is running on a custom port' do
before do
diff --git a/spec/models/diff_viewer/server_side_spec.rb b/spec/models/diff_viewer/server_side_spec.rb
index 27de0584b8a..0a14eae26f3 100644
--- a/spec/models/diff_viewer/server_side_spec.rb
+++ b/spec/models/diff_viewer/server_side_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe DiffViewer::ServerSide do
- set(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
let(:commit) { project.commit_by(oid: '570e7b2abdd848b95f2f578043fc23bd6f6fd24d') }
let!(:diff_file) { commit.diffs.diff_file_with_new_path('files/ruby/popen.rb') }
diff --git a/spec/models/event_collection_spec.rb b/spec/models/event_collection_spec.rb
index c421ffa000d..e6f80a4c4d0 100644
--- a/spec/models/event_collection_spec.rb
+++ b/spec/models/event_collection_spec.rb
@@ -4,10 +4,10 @@ require 'spec_helper'
describe EventCollection do
describe '#to_a' do
- set(:group) { create(:group) }
- set(:project) { create(:project_empty_repo, group: group) }
- set(:projects) { Project.where(id: project.id) }
- set(:user) { create(:user) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project_empty_repo, group: group) }
+ let_it_be(:projects) { Project.where(id: project.id) }
+ let_it_be(:user) { create(:user) }
context 'with project events' do
before do
diff --git a/spec/models/guest_spec.rb b/spec/models/guest_spec.rb
index 93862e98172..57eb077031c 100644
--- a/spec/models/guest_spec.rb
+++ b/spec/models/guest_spec.rb
@@ -3,9 +3,9 @@
require 'spec_helper'
describe Guest do
- set(:public_project) { create(:project, :public) }
- set(:private_project) { create(:project, :private) }
- set(:internal_project) { create(:project, :internal) }
+ let_it_be(:public_project, reload: true) { create(:project, :public) }
+ let_it_be(:private_project) { create(:project, :private) }
+ let_it_be(:internal_project) { create(:project, :internal) }
describe '.can_pull?' do
context 'when project is private' do
diff --git a/spec/models/list_user_preference_spec.rb b/spec/models/list_user_preference_spec.rb
index 1335a3700dc..10a7bf41f4e 100644
--- a/spec/models/list_user_preference_spec.rb
+++ b/spec/models/list_user_preference_spec.rb
@@ -3,8 +3,8 @@
require 'spec_helper'
describe ListUserPreference do
- set(:user) { create(:user) }
- set(:list) { create(:list) }
+ let_it_be(:user) { create(:user) }
+ let_it_be(:list) { create(:list) }
before do
list.update_preferences_for(user, { collapsed: true })
diff --git a/spec/models/pages_domain_spec.rb b/spec/models/pages_domain_spec.rb
index a88db3b87af..99b7c4f148a 100644
--- a/spec/models/pages_domain_spec.rb
+++ b/spec/models/pages_domain_spec.rb
@@ -352,9 +352,9 @@ describe PagesDomain do
end
context 'configuration updates when attributes change' do
- set(:project1) { create(:project) }
- set(:project2) { create(:project) }
- set(:domain) { create(:pages_domain) }
+ let_it_be(:project1) { create(:project) }
+ let_it_be(:project2) { create(:project) }
+ let_it_be(:domain) { create(:pages_domain) }
where(:attribute, :old_value, :new_value, :update_expected) do
now = Time.now
@@ -402,8 +402,8 @@ describe PagesDomain do
end
context 'TLS configuration' do
- set(:domain_without_tls) { create(:pages_domain, :without_certificate, :without_key) }
- set(:domain) { create(:pages_domain) }
+ let_it_be(:domain_without_tls) { create(:pages_domain, :without_certificate, :without_key) }
+ let_it_be(:domain) { create(:pages_domain) }
let(:cert1) { domain.certificate }
let(:cert2) { cert1 + ' ' }
diff --git a/spec/models/project_services/alerts_service_spec.rb b/spec/models/project_services/alerts_service_spec.rb
new file mode 100644
index 00000000000..4e63ece26d8
--- /dev/null
+++ b/spec/models/project_services/alerts_service_spec.rb
@@ -0,0 +1,109 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe AlertsService do
+ let_it_be(:project) { create(:project) }
+ let(:service_params) { { project: project, active: active } }
+ let(:active) { true }
+ let(:service) { described_class.new(service_params) }
+
+ shared_context 'when active' do
+ let(:active) { true }
+ end
+
+ shared_context 'when inactive' do
+ let(:active) { false }
+ end
+
+ shared_context 'when persisted' do
+ before do
+ service.save!
+ service.reload
+ end
+ end
+
+ describe '#url' do
+ include Gitlab::Routing
+
+ subject { service.url }
+
+ it { is_expected.to eq(project_alerts_notify_url(project, format: :json)) }
+ end
+
+ describe '#json_fields' do
+ subject { service.json_fields }
+
+ it { is_expected.to eq(%w(active token)) }
+ end
+
+ describe '#as_json' do
+ subject { service.as_json(only: service.json_fields) }
+
+ it { is_expected.to eq('active' => true, 'token' => nil) }
+ end
+
+ describe '#token' do
+ shared_context 'reset token' do
+ before do
+ service.token = ''
+ service.valid?
+ end
+ end
+
+ shared_context 'assign token' do |token|
+ before do
+ service.token = token
+ service.valid?
+ end
+ end
+
+ shared_examples 'valid token' do
+ it { is_expected.to match(/\A\h{32}\z/) }
+ end
+
+ shared_examples 'no token' do
+ it { is_expected.to be_blank }
+ end
+
+ subject { service.token }
+
+ context 'when active' do
+ include_context 'when active'
+
+ context 'when resetting' do
+ let!(:previous_token) { service.token }
+
+ include_context 'reset token'
+
+ it_behaves_like 'valid token'
+
+ it { is_expected.not_to eq(previous_token) }
+ end
+
+ context 'when assigning' do
+ include_context 'assign token', 'random token'
+
+ it_behaves_like 'valid token'
+ end
+ end
+
+ context 'when inactive' do
+ include_context 'when inactive'
+
+ context 'when resetting' do
+ let!(:previous_token) { service.token }
+
+ include_context 'reset token'
+
+ it_behaves_like 'no token'
+ end
+ end
+
+ context 'when persisted' do
+ include_context 'when persisted'
+
+ it_behaves_like 'valid token'
+ end
+ end
+end
diff --git a/spec/models/project_services/microsoft_teams_service_spec.rb b/spec/models/project_services/microsoft_teams_service_spec.rb
index 83d3c8b3a70..d93b8a2cb40 100644
--- a/spec/models/project_services/microsoft_teams_service_spec.rb
+++ b/spec/models/project_services/microsoft_teams_service_spec.rb
@@ -37,9 +37,9 @@ describe MicrosoftTeamsService do
end
describe "#execute" do
- let(:user) { create(:user) }
+ let(:user) { create(:user) }
- set(:project) { create(:project, :repository, :wiki_repo) }
+ let_it_be(:project) { create(:project, :repository, :wiki_repo) }
before do
allow(chat_service).to receive_messages(
diff --git a/spec/models/project_services/prometheus_service_spec.rb b/spec/models/project_services/prometheus_service_spec.rb
index 49005d8c681..1922bb065cf 100644
--- a/spec/models/project_services/prometheus_service_spec.rb
+++ b/spec/models/project_services/prometheus_service_spec.rb
@@ -169,7 +169,7 @@ describe PrometheusService, :use_clean_rails_memory_store_caching do
end
context 'cluster belongs to projects group' do
- set(:group) { create(:group) }
+ let_it_be(:group) { create(:group) }
let(:project) { create(:prometheus_project, group: group) }
let(:cluster) { create(:cluster_for_group, :with_installed_helm, groups: [group]) }
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index f847cb63ddc..9dc362594dd 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -3901,7 +3901,7 @@ describe Project do
end
context 'legacy storage' do
- set(:project) { create(:project, :repository, :legacy_storage) }
+ let_it_be(:project) { create(:project, :repository, :legacy_storage) }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:project_storage) { project.send(:storage) }
@@ -4000,7 +4000,7 @@ describe Project do
end
context 'hashed storage' do
- set(:project) { create(:project, :repository, skip_disk_validation: true) }
+ let_it_be(:project) { create(:project, :repository, skip_disk_validation: true) }
let(:gitlab_shell) { Gitlab::Shell.new }
let(:hash) { Digest::SHA2.hexdigest(project.id.to_s) }
let(:hashed_prefix) { File.join('@hashed', hash[0..1], hash[2..3]) }
@@ -4090,7 +4090,7 @@ describe Project do
end
describe '#has_ci?' do
- set(:project) { create(:project) }
+ let_it_be(:project, reload: true) { create(:project) }
let(:repository) { double }
before do
@@ -4134,7 +4134,7 @@ describe Project do
Feature.get(:force_autodevops_on_by_default).enable_percentage_of_actors(0)
end
- set(:project) { create(:project) }
+ let_it_be(:project, reload: true) { create(:project) }
subject { project.auto_devops_enabled? }
@@ -4269,7 +4269,7 @@ describe Project do
end
describe '#has_auto_devops_implicitly_enabled?' do
- set(:project) { create(:project) }
+ let_it_be(:project, reload: true) { create(:project) }
context 'when disabled in settings' do
before do
@@ -4330,7 +4330,7 @@ describe Project do
end
describe '#has_auto_devops_implicitly_disabled?' do
- set(:project) { create(:project) }
+ let_it_be(:project, reload: true) { create(:project) }
before do
allow(Feature).to receive(:enabled?).and_call_original
@@ -4408,7 +4408,7 @@ describe Project do
end
describe '#api_variables' do
- set(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
it 'exposes API v4 URL' do
expect(project.api_variables.first[:key]).to eq 'CI_API_V4_URL'
@@ -4605,7 +4605,7 @@ describe Project do
end
describe '#write_repository_config' do
- set(:project) { create(:project, :repository) }
+ let_it_be(:project) { create(:project, :repository) }
it 'writes full path in .git/config when key is missing' do
project.write_repository_config
@@ -4696,7 +4696,7 @@ describe Project do
end
describe '#has_active_hooks?' do
- set(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
it { expect(project.has_active_hooks?).to be_falsey }
@@ -4723,7 +4723,7 @@ describe Project do
end
describe '#has_active_services?' do
- set(:project) { create(:project) }
+ let_it_be(:project) { create(:project) }
it { expect(project.has_active_services?).to be_falsey }
@@ -5009,8 +5009,8 @@ describe Project do
describe '#members_among' do
let(:users) { create_list(:user, 3) }
- set(:group) { create(:group) }
- set(:project) { create(:project, namespace: group) }
+ let_it_be(:group) { create(:group) }
+ let_it_be(:project) { create(:project, namespace: group) }
before do
project.add_guest(users.first)
@@ -5584,6 +5584,14 @@ describe Project do
end
end
+ describe '#alerts_service_activated?' do
+ let!(:project) { create(:project) }
+
+ subject { project.alerts_service_activated? }
+
+ it { is_expected.to be_falsey }
+ end
+
def rugged_config
rugged_repo(project.repository).config
end
diff --git a/spec/models/releases/source_spec.rb b/spec/models/releases/source_spec.rb
index c8ac8e31c97..d7af6fd90a6 100644
--- a/spec/models/releases/source_spec.rb
+++ b/spec/models/releases/source_spec.rb
@@ -3,7 +3,7 @@
require 'spec_helper'
describe Releases::Source do
- set(:project) { create(:project, :repository, name: 'finance-cal') }
+ let_it_be(:project) { create(:project, :repository, name: 'finance-cal') }
let(:tag_name) { 'v1.0' }
describe '.all' do
diff --git a/spec/requests/api/lsif_data_spec.rb b/spec/requests/api/lsif_data_spec.rb
index ca3a30bd1d0..2e0670ded95 100644
--- a/spec/requests/api/lsif_data_spec.rb
+++ b/spec/requests/api/lsif_data_spec.rb
@@ -60,7 +60,8 @@ describe API::LsifData do
'end_char' => 18,
'end_line' => 8,
'start_char' => 13,
- 'start_line' => 8
+ 'start_line' => 8,
+ 'definition_url' => project_blob_path(project, "#{commit.id}/morestrings/reverse.go", anchor: 'L5')
})
end
diff --git a/spec/services/projects/alerting/notify_service_spec.rb b/spec/services/projects/alerting/notify_service_spec.rb
new file mode 100644
index 00000000000..efd168a0a8a
--- /dev/null
+++ b/spec/services/projects/alerting/notify_service_spec.rb
@@ -0,0 +1,34 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Projects::Alerting::NotifyService do
+ let_it_be(:project, reload: true) { create(:project) }
+
+ shared_examples 'does not process incident issues' do |http_status:|
+ it 'does not process issues' do
+ expect(IncidentManagement::ProcessAlertWorker)
+ .not_to receive(:perform_async)
+
+ expect(subject.status).to eq(:error)
+ expect(subject.http_status).to eq(http_status)
+ end
+ end
+
+ describe '#execute' do
+ let(:token) { 'invalid-token' }
+ let(:starts_at) { Time.now.change(usec: 0) }
+ let(:service) { described_class.new(project, nil, payload) }
+ let(:payload_raw) do
+ {
+ 'title' => 'alert title',
+ 'start_time' => starts_at.rfc3339
+ }
+ end
+ let(:payload) { ActionController::Parameters.new(payload_raw).permit! }
+
+ subject { service.execute(token) }
+
+ it_behaves_like 'does not process incident issues', http_status: 403
+ end
+end
diff --git a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
index 78b969c8a0e..cd4d1e3fe67 100644
--- a/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/cleanup_tags_service_spec.rb
@@ -41,7 +41,7 @@ describe Projects::ContainerRepository::CleanupTagsService do
let(:params) { {} }
it 'does not remove anything' do
- expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag)
+ expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag_by_digest)
is_expected.to include(status: :success, deleted: [])
end
@@ -156,7 +156,7 @@ describe Projects::ContainerRepository::CleanupTagsService do
def expect_delete(digest)
expect_any_instance_of(ContainerRegistry::Client)
- .to receive(:delete_repository_tag)
+ .to receive(:delete_repository_tag_by_digest)
.with(repository.path, digest) { true }
end
end
diff --git a/spec/services/projects/container_repository/delete_tags_service_spec.rb b/spec/services/projects/container_repository/delete_tags_service_spec.rb
index decbbb7597f..e17e4b6f7c9 100644
--- a/spec/services/projects/container_repository/delete_tags_service_spec.rb
+++ b/spec/services/projects/container_repository/delete_tags_service_spec.rb
@@ -18,10 +18,6 @@ describe Projects::ContainerRepository::DeleteTagsService do
stub_container_registry_tags(
repository: repository.path,
tags: %w(latest A Ba Bb C D E))
-
- stub_tag_digest('latest', 'sha256:configA')
- stub_tag_digest('A', 'sha256:configA')
- stub_tag_digest('Ba', 'sha256:configB')
end
describe '#execute' do
@@ -38,82 +34,178 @@ describe Projects::ContainerRepository::DeleteTagsService do
project.add_developer(user)
end
- context 'when no params are specified' do
- let(:params) { {} }
+ context 'when the registry supports fast delete' do
+ context 'and the feature is enabled' do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:repository) { create(:container_repository, :root, project: project) }
- it 'does not remove anything' do
- expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag)
+ before do
+ allow(repository.client).to receive(:supports_tag_delete?).and_return(true)
+ end
- is_expected.to include(status: :error)
- end
- end
+ context 'with tags to delete' do
+ let_it_be(:tags) { %w[A Ba] }
- context 'with empty tags' do
- let(:tags) { [] }
+ it 'deletes the tags by name' do
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/A")
+ .to_return(status: 200, body: "")
- it 'does not remove anything' do
- expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag)
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/Ba")
+ .to_return(status: 200, body: "")
- is_expected.to include(status: :error)
- end
- end
+ expect_delete_tag_by_name('A')
+ expect_delete_tag_by_name('Ba')
+
+ is_expected.to include(status: :success)
+ end
+
+ it 'succeeds when tag delete returns 404' do
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/A")
+ .to_return(status: 200, body: "")
+
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/Ba")
+ .to_return(status: 404, body: "")
+
+ is_expected.to include(status: :success)
+ end
+
+ context 'with failures' do
+ context 'when the delete request fails' do
+ before do
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/A")
+ .to_return(status: 500, body: "")
+
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/tags/reference/Ba")
+ .to_return(status: 500, body: "")
+ end
- context 'with tags to delete' do
- let(:tags) { %w[A Ba] }
+ it { is_expected.to include(status: :error) }
+ end
+ end
+ end
+
+ context 'when no params are specified' do
+ let_it_be(:params) { {} }
+
+ it 'does not remove anything' do
+ expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag_by_name)
+
+ is_expected.to include(status: :error)
+ end
+ end
- it 'deletes the tags using a dummy image' do
- stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
+ context 'with empty tags' do
+ let_it_be(:tags) { [] }
- stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A")
- .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+ it 'does not remove anything' do
+ expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag_by_name)
- stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba")
- .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+ is_expected.to include(status: :error)
+ end
+ end
+ end
+ context 'and the feature is disabled' do
+ before do
+ stub_feature_flags(container_registry_fast_tag_delete: false)
+ end
- expect_delete_tag('sha256:dummy')
+ it 'fallbacks to slow delete' do
+ expect(service).not_to receive(:fast_delete)
+ expect(service).to receive(:slow_delete).with(repository, tags)
- is_expected.to include(status: :success)
+ subject
+ end
end
+ end
+ context 'when the registry does not support fast delete' do
+ let_it_be(:project) { create(:project, :private) }
+ let_it_be(:repository) { create(:container_repository, :root, project: project) }
- it 'succedes when tag delete returns 404' do
- stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
+ before do
+ stub_tag_digest('latest', 'sha256:configA')
+ stub_tag_digest('A', 'sha256:configA')
+ stub_tag_digest('Ba', 'sha256:configB')
- stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A")
- .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+ allow(repository.client).to receive(:supports_tag_delete?).and_return(false)
+ end
- stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba")
- .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+ context 'when no params are specified' do
+ let_it_be(:params) { {} }
- stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/manifests/sha256:dummy")
- .to_return(status: 404, body: "", headers: {})
+ it 'does not remove anything' do
+ expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag_by_digest)
- is_expected.to include(status: :success)
+ is_expected.to include(status: :error)
+ end
end
- context 'with failures' do
- context 'when the dummy manifest generation fails' do
- before do
- stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3', success: false)
- end
+ context 'with empty tags' do
+ let_it_be(:tags) { [] }
+
+ it 'does not remove anything' do
+ expect_any_instance_of(ContainerRegistry::Client).not_to receive(:delete_repository_tag_by_digest)
+
+ is_expected.to include(status: :error)
+ end
+ end
+
+ context 'with tags to delete' do
+ let_it_be(:tags) { %w[A Ba] }
- it { is_expected.to include(status: :error) }
+ it 'deletes the tags using a dummy image' do
+ stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
+
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A")
+ .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba")
+ .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+
+ expect_delete_tag_by_digest('sha256:dummy')
+
+ is_expected.to include(status: :success)
end
- context 'when updating the tags fails' do
- before do
- stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
+ it 'succeeds when tag delete returns 404' do
+ stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
- stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A")
- .to_return(status: 500, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A")
+ .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
- stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba")
- .to_return(status: 500, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba")
+ .to_return(status: 200, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/manifests/sha256:dummy")
+ .to_return(status: 404, body: "", headers: {})
+
+ is_expected.to include(status: :success)
+ end
- stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/manifests/sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3")
- .to_return(status: 200, body: "", headers: {})
+ context 'with failures' do
+ context 'when the dummy manifest generation fails' do
+ before do
+ stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3', success: false)
+ end
+
+ it { is_expected.to include(status: :error) }
end
- it { is_expected.to include(status: :error) }
+ context 'when updating the tags fails' do
+ before do
+ stub_upload("{\n \"config\": {\n }\n}", 'sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3')
+
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/A")
+ .to_return(status: 500, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+
+ stub_request(:put, "http://registry.gitlab/v2/#{repository.path}/manifests/Ba")
+ .to_return(status: 500, body: "", headers: { 'docker-content-digest' => 'sha256:dummy' })
+
+ stub_request(:delete, "http://registry.gitlab/v2/#{repository.path}/manifests/sha256:4435000728ee66e6a80e55637fc22725c256b61de344a2ecdeaac6bdb36e8bc3")
+ .to_return(status: 200, body: "", headers: {})
+ end
+
+ it { is_expected.to include(status: :error) }
+ end
end
end
end
@@ -141,9 +233,21 @@ describe Projects::ContainerRepository::DeleteTagsService do
.with(repository.path, content, digest) { double(success?: success ) }
end
- def expect_delete_tag(digest)
+ def expect_delete_tag_by_digest(digest)
expect_any_instance_of(ContainerRegistry::Client)
- .to receive(:delete_repository_tag)
+ .to receive(:delete_repository_tag_by_digest)
.with(repository.path, digest) { true }
+
+ expect_any_instance_of(ContainerRegistry::Client)
+ .not_to receive(:delete_repository_tag_by_name)
+ end
+
+ def expect_delete_tag_by_name(name)
+ expect_any_instance_of(ContainerRegistry::Client)
+ .to receive(:delete_repository_tag_by_name)
+ .with(repository.path, name) { true }
+
+ expect_any_instance_of(ContainerRegistry::Client)
+ .not_to receive(:delete_repository_tag_by_digest)
end
end
diff --git a/spec/services/projects/lsif_data_service_spec.rb b/spec/services/projects/lsif_data_service_spec.rb
index b3c37c01c4d..29a99a96c41 100644
--- a/spec/services/projects/lsif_data_service_spec.rb
+++ b/spec/services/projects/lsif_data_service_spec.rb
@@ -23,43 +23,51 @@ describe Projects::LsifDataService do
end
context 'for main.go' do
+ let(:path_prefix) { "/#{project.full_path}/-/blob/#{commit_id}" }
+
it 'returns lsif ranges for the file' do
expect(service.execute).to eq([
{
end_char: 9,
end_line: 6,
start_char: 5,
- start_line: 6
+ start_line: 6,
+ definition_url: "#{path_prefix}/main.go#L7"
},
{
end_char: 36,
end_line: 3,
start_char: 1,
- start_line: 3
+ start_line: 3,
+ definition_url: "#{path_prefix}/main.go#L4"
},
{
end_char: 12,
end_line: 7,
start_char: 1,
- start_line: 7
+ start_line: 7,
+ definition_url: "#{path_prefix}/main.go#L4"
},
{
end_char: 20,
end_line: 7,
start_char: 13,
- start_line: 7
+ start_line: 7,
+ definition_url: "#{path_prefix}/morestrings/reverse.go#L11"
},
{
end_char: 12,
end_line: 8,
start_char: 1,
- start_line: 8
+ start_line: 8,
+ definition_url: "#{path_prefix}/main.go#L4"
},
{
end_char: 18,
end_line: 8,
start_char: 13,
- start_line: 8
+ start_line: 8,
+ definition_url: "#{path_prefix}/morestrings/reverse.go#L5"
}
])
end
@@ -73,7 +81,8 @@ describe Projects::LsifDataService do
end_char: 2,
end_line: 11,
start_char: 1,
- start_line: 11
+ start_line: 11,
+ definition_url: "/#{project.full_path}/-/blob/#{commit_id}/morestrings/reverse.go#L12"
})
end
end
@@ -87,7 +96,7 @@ describe Projects::LsifDataService do
end
end
- describe '#doc_id_from' do
+ describe '#doc_id' do
context 'when the passed path matches multiple files' do
let(:path) { 'check/main.go' }
let(:docs) do
@@ -100,7 +109,9 @@ describe Projects::LsifDataService do
end
it 'fetches the document with the shortest absolute path' do
- expect(service.__send__(:doc_id_from, docs)).to eq(3)
+ service.instance_variable_set(:@docs, docs)
+
+ expect(service.__send__(:doc_id)).to eq(3)
end
end
end