summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/features/merge_request/user_creates_merge_request_spec.rb5
-rw-r--r--spec/finders/prometheus_metrics_finder_spec.rb144
-rw-r--r--spec/frontend/helpers/monitor_helper_spec.js11
-rw-r--r--spec/frontend/notes/mock_data.js4
-rw-r--r--spec/frontend/registry/components/collapsible_container_spec.js53
-rw-r--r--spec/frontend/registry/components/table_registry_spec.js119
-rw-r--r--spec/frontend/vue_shared/components/notes/system_note_spec.js2
-rw-r--r--spec/javascripts/bootstrap_jquery_spec.js14
-rw-r--r--spec/javascripts/monitoring/components/dashboard_spec.js26
-rw-r--r--spec/javascripts/monitoring/store/mutations_spec.js14
-rw-r--r--spec/javascripts/notes/stores/collapse_utils_spec.js10
-rw-r--r--spec/lib/gitlab/graphql/connections/filterable_array_connection_spec.rb26
-rw-r--r--spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb30
-rw-r--r--spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb13
-rw-r--r--spec/support/helpers/graphql_helpers.rb21
-rw-r--r--spec/support/shared_examples/graphql/connection_paged_nodes.rb28
16 files changed, 451 insertions, 69 deletions
diff --git a/spec/features/merge_request/user_creates_merge_request_spec.rb b/spec/features/merge_request/user_creates_merge_request_spec.rb
index afb792c2ab9..67f6d8ebe32 100644
--- a/spec/features/merge_request/user_creates_merge_request_spec.rb
+++ b/spec/features/merge_request/user_creates_merge_request_spec.rb
@@ -25,6 +25,11 @@ describe "User creates a merge request", :js do
click_button("Compare branches")
+ page.within('.merge-request-form') do
+ expect(page.find('#merge_request_title')['placeholder']).to eq 'Title'
+ expect(page.find('#merge_request_description')['placeholder']).to eq 'Describe the goal of the changes and what reviewers should be aware of.'
+ end
+
fill_in("Title", with: title)
click_button("Submit merge request")
diff --git a/spec/finders/prometheus_metrics_finder_spec.rb b/spec/finders/prometheus_metrics_finder_spec.rb
new file mode 100644
index 00000000000..41b2e700e1e
--- /dev/null
+++ b/spec/finders/prometheus_metrics_finder_spec.rb
@@ -0,0 +1,144 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe PrometheusMetricsFinder do
+ describe '#execute' do
+ let(:finder) { described_class.new(params) }
+ let(:params) { {} }
+
+ subject { finder.execute }
+
+ context 'with params' do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:project_metric) { create(:prometheus_metric, project: project) }
+ let_it_be(:common_metric) { create(:prometheus_metric, :common) }
+ let_it_be(:unique_metric) do
+ create(
+ :prometheus_metric,
+ :common,
+ title: 'Unique title',
+ y_label: 'Unique y_label',
+ group: :kubernetes,
+ identifier: 'identifier',
+ created_at: 5.minutes.ago
+ )
+ end
+
+ context 'with appropriate indexes' do
+ before do
+ allow_any_instance_of(described_class).to receive(:appropriate_index?).and_return(true)
+ end
+
+ context 'with project' do
+ let(:params) { { project: project } }
+
+ it { is_expected.to eq([project_metric]) }
+ end
+
+ context 'with group' do
+ let(:params) { { group: project_metric.group } }
+
+ it { is_expected.to contain_exactly(common_metric, project_metric) }
+ end
+
+ context 'with title' do
+ let(:params) { { title: project_metric.title } }
+
+ it { is_expected.to contain_exactly(project_metric, common_metric) }
+ end
+
+ context 'with y_label' do
+ let(:params) { { y_label: project_metric.y_label } }
+
+ it { is_expected.to contain_exactly(project_metric, common_metric) }
+ end
+
+ context 'with common' do
+ let(:params) { { common: true } }
+
+ it { is_expected.to contain_exactly(common_metric, unique_metric) }
+ end
+
+ context 'with ordered' do
+ let(:params) { { ordered: true } }
+
+ it { is_expected.to eq([unique_metric, project_metric, common_metric]) }
+ end
+
+ context 'with indentifier' do
+ let(:params) { { identifier: unique_metric.identifier } }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ ArgumentError,
+ ':identifier must be scoped to a :project or :common'
+ )
+ end
+
+ context 'with common' do
+ let(:params) { { identifier: unique_metric.identifier, common: true } }
+
+ it { is_expected.to contain_exactly(unique_metric) }
+ end
+
+ context 'with id' do
+ let(:params) { { id: 14, identifier: 'string' } }
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ ArgumentError,
+ 'Only one of :identifier, :id is permitted'
+ )
+ end
+ end
+ end
+
+ context 'with id' do
+ let(:params) { { id: common_metric.id } }
+
+ it { is_expected.to contain_exactly(common_metric) }
+ end
+
+ context 'with multiple params' do
+ let(:params) do
+ {
+ group: project_metric.group,
+ title: project_metric.title,
+ y_label: project_metric.y_label,
+ common: true,
+ ordered: true
+ }
+ end
+
+ it { is_expected.to contain_exactly(common_metric) }
+ end
+ end
+
+ context 'without an appropriate index' do
+ let(:params) do
+ {
+ title: project_metric.title,
+ ordered: true
+ }
+ end
+
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ ArgumentError,
+ 'An index should exist for params: [:title]'
+ )
+ end
+ end
+ end
+
+ context 'without params' do
+ it 'raises an error' do
+ expect { subject }.to raise_error(
+ ArgumentError,
+ 'Please provide one or more of: [:project, :group, :title, :y_label, :identifier, :id, :common, :ordered]'
+ )
+ end
+ end
+ end
+end
diff --git a/spec/frontend/helpers/monitor_helper_spec.js b/spec/frontend/helpers/monitor_helper_spec.js
index c36b603b251..0798ca580e2 100644
--- a/spec/frontend/helpers/monitor_helper_spec.js
+++ b/spec/frontend/helpers/monitor_helper_spec.js
@@ -81,6 +81,17 @@ describe('monitor helper', () => {
expect(result.name).toEqual('brpop, brpop');
});
+ it('supports hyphenated template variables', () => {
+ const config = { ...defaultConfig, name: 'expired - {{ test-attribute }}' };
+
+ const [result] = monitorHelper.makeDataSeries(
+ [{ metric: { 'test-attribute': 'test-attribute-value' }, values: series }],
+ config,
+ );
+
+ expect(result.name).toEqual('expired - test-attribute-value');
+ });
+
it('updates multiple series names from templates', () => {
const config = {
...defaultConfig,
diff --git a/spec/frontend/notes/mock_data.js b/spec/frontend/notes/mock_data.js
index dc914ce8355..01cb70d395c 100644
--- a/spec/frontend/notes/mock_data.js
+++ b/spec/frontend/notes/mock_data.js
@@ -1094,8 +1094,9 @@ export const collapsedSystemNotes = [
noteable_type: 'Issue',
resolvable: false,
noteable_iid: 12,
+ start_description_version_id: undefined,
note: 'changed the description',
- note_html: ' <p dir="auto">changed the description 2 times within 1 minute </p>',
+ note_html: '<p dir="auto">changed the description</p>',
current_user: { can_edit: false, can_award_emoji: true },
resolved: false,
resolved_by: null,
@@ -1106,7 +1107,6 @@ export const collapsedSystemNotes = [
'/abuse_reports/new?ref_url=http%3A%2F%2Flocalhost%3A3000%2Fgitlab-org%2Fgitlab-shell%2Fissues%2F12%23note_905&user_id=1',
human_access: 'Owner',
path: '/gitlab-org/gitlab-shell/notes/905',
- times_updated: 2,
},
],
individual_note: true,
diff --git a/spec/frontend/registry/components/collapsible_container_spec.js b/spec/frontend/registry/components/collapsible_container_spec.js
index f93ebab1a4d..d035055afd3 100644
--- a/spec/frontend/registry/components/collapsible_container_spec.js
+++ b/spec/frontend/registry/components/collapsible_container_spec.js
@@ -1,10 +1,11 @@
import Vue from 'vue';
import Vuex from 'vuex';
import { mount, createLocalVue } from '@vue/test-utils';
-import collapsibleComponent from '~/registry/components/collapsible_container.vue';
-import { repoPropsData } from '../mock_data';
import createFlash from '~/flash';
+import Tracking from '~/tracking';
+import collapsibleComponent from '~/registry/components/collapsible_container.vue';
import * as getters from '~/registry/stores/getters';
+import { repoPropsData } from '../mock_data';
jest.mock('~/flash.js');
@@ -16,9 +17,10 @@ describe('collapsible registry container', () => {
let wrapper;
let store;
- const findDeleteBtn = w => w.find('.js-remove-repo');
- const findContainerImageTags = w => w.find('.container-image-tags');
- const findToggleRepos = w => w.findAll('.js-toggle-repo');
+ const findDeleteBtn = (w = wrapper) => w.find('.js-remove-repo');
+ const findContainerImageTags = (w = wrapper) => w.find('.container-image-tags');
+ const findToggleRepos = (w = wrapper) => w.findAll('.js-toggle-repo');
+ const findDeleteModal = (w = wrapper) => w.find({ ref: 'deleteModal' });
const mountWithStore = config => mount(collapsibleComponent, { ...config, store, localVue });
@@ -124,4 +126,45 @@ describe('collapsible registry container', () => {
expect(deleteBtn.exists()).toBe(false);
});
});
+
+ describe('tracking', () => {
+ const category = 'mock_page';
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ wrapper.vm.deleteItem = jest.fn().mockResolvedValue();
+ wrapper.vm.fetchRepos = jest.fn();
+ wrapper.setData({
+ tracking: {
+ ...wrapper.vm.tracking,
+ category,
+ },
+ });
+ });
+
+ it('send an event when delete button is clicked', () => {
+ const deleteBtn = findDeleteBtn();
+ deleteBtn.trigger('click');
+ expect(Tracking.event).toHaveBeenCalledWith(category, 'click_button', {
+ label: 'registry_repository_delete',
+ category,
+ });
+ });
+ it('send an event when cancel is pressed on modal', () => {
+ const deleteModal = findDeleteModal();
+ deleteModal.vm.$emit('cancel');
+ expect(Tracking.event).toHaveBeenCalledWith(category, 'cancel_delete', {
+ label: 'registry_repository_delete',
+ category,
+ });
+ });
+ it('send an event when confirm is clicked on modal', () => {
+ const deleteModal = findDeleteModal();
+ deleteModal.vm.$emit('ok');
+
+ expect(Tracking.event).toHaveBeenCalledWith(category, 'confirm_delete', {
+ label: 'registry_repository_delete',
+ category,
+ });
+ });
+ });
});
diff --git a/spec/frontend/registry/components/table_registry_spec.js b/spec/frontend/registry/components/table_registry_spec.js
index 7cb7c012d9d..ab88caf44e1 100644
--- a/spec/frontend/registry/components/table_registry_spec.js
+++ b/spec/frontend/registry/components/table_registry_spec.js
@@ -1,10 +1,14 @@
import Vue from 'vue';
import Vuex from 'vuex';
-import tableRegistry from '~/registry/components/table_registry.vue';
import { mount, createLocalVue } from '@vue/test-utils';
+import createFlash from '~/flash';
+import Tracking from '~/tracking';
+import tableRegistry from '~/registry/components/table_registry.vue';
import { repoPropsData } from '../mock_data';
import * as getters from '~/registry/stores/getters';
+jest.mock('~/flash');
+
const [firstImage, secondImage] = repoPropsData.list;
const localVue = createLocalVue();
@@ -15,11 +19,12 @@ describe('table registry', () => {
let wrapper;
let store;
- const findSelectAllCheckbox = w => w.find('.js-select-all-checkbox > input');
- const findSelectCheckboxes = w => w.findAll('.js-select-checkbox > input');
- const findDeleteButton = w => w.find('.js-delete-registry');
- const findDeleteButtonsRow = w => w.findAll('.js-delete-registry-row');
- const findPagination = w => w.find('.js-registry-pagination');
+ const findSelectAllCheckbox = (w = wrapper) => w.find('.js-select-all-checkbox > input');
+ const findSelectCheckboxes = (w = wrapper) => w.findAll('.js-select-checkbox > input');
+ const findDeleteButton = (w = wrapper) => w.find({ ref: 'bulkDeleteButton' });
+ const findDeleteButtonsRow = (w = wrapper) => w.findAll('.js-delete-registry-row');
+ const findPagination = (w = wrapper) => w.find('.js-registry-pagination');
+ const findDeleteModal = (w = wrapper) => w.find({ ref: 'deleteModal' });
const bulkDeletePath = 'path';
const mountWithStore = config => mount(tableRegistry, { ...config, store, localVue });
@@ -139,7 +144,7 @@ describe('table registry', () => {
},
});
wrapper.vm.handleMultipleDelete();
- expect(wrapper.vm.showError).toHaveBeenCalled();
+ expect(createFlash).toHaveBeenCalled();
});
});
@@ -169,6 +174,27 @@ describe('table registry', () => {
});
});
+ describe('modal event handlers', () => {
+ beforeEach(() => {
+ wrapper.vm.handleSingleDelete = jest.fn();
+ wrapper.vm.handleMultipleDelete = jest.fn();
+ });
+ it('on ok when one item is selected should call singleDelete', () => {
+ wrapper.setData({ itemsToBeDeleted: [0] });
+ wrapper.vm.onDeletionConfirmed();
+
+ expect(wrapper.vm.handleSingleDelete).toHaveBeenCalledWith(repoPropsData.list[0]);
+ expect(wrapper.vm.handleMultipleDelete).not.toHaveBeenCalled();
+ });
+ it('on ok when multiple items are selected should call muultiDelete', () => {
+ wrapper.setData({ itemsToBeDeleted: [0, 1, 2] });
+ wrapper.vm.onDeletionConfirmed();
+
+ expect(wrapper.vm.handleMultipleDelete).toHaveBeenCalled();
+ expect(wrapper.vm.handleSingleDelete).not.toHaveBeenCalled();
+ });
+ });
+
describe('pagination', () => {
const repo = {
repoPropsData,
@@ -265,4 +291,83 @@ describe('table registry', () => {
expect(deleteBtns.length).toBe(0);
});
});
+
+ describe('event tracking', () => {
+ const mockPageName = 'mock_page';
+
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ wrapper.vm.handleSingleDelete = jest.fn();
+ wrapper.vm.handleMultipleDelete = jest.fn();
+ document.body.dataset.page = mockPageName;
+ });
+
+ afterEach(() => {
+ document.body.dataset.page = null;
+ });
+
+ describe('single tag delete', () => {
+ beforeEach(() => {
+ wrapper.setData({ itemsToBeDeleted: [0] });
+ });
+
+ it('send an event when delete button is clicked', () => {
+ const deleteBtn = findDeleteButtonsRow();
+ deleteBtn.at(0).trigger('click');
+ expect(Tracking.event).toHaveBeenCalledWith(mockPageName, 'click_button', {
+ label: 'registry_tag_delete',
+ property: 'foo',
+ });
+ });
+ it('send an event when cancel is pressed on modal', () => {
+ const deleteModal = findDeleteModal();
+ deleteModal.vm.$emit('cancel');
+ expect(Tracking.event).toHaveBeenCalledWith(mockPageName, 'cancel_delete', {
+ label: 'registry_tag_delete',
+ property: 'foo',
+ });
+ });
+ it('send an event when confirm is clicked on modal', () => {
+ const deleteModal = findDeleteModal();
+ deleteModal.vm.$emit('ok');
+
+ expect(Tracking.event).toHaveBeenCalledWith(mockPageName, 'confirm_delete', {
+ label: 'registry_tag_delete',
+ property: 'foo',
+ });
+ });
+ });
+ describe('bulk tag delete', () => {
+ beforeEach(() => {
+ const items = [0, 1, 2];
+ wrapper.setData({ itemsToBeDeleted: items, selectedItems: items });
+ });
+
+ it('send an event when delete button is clicked', () => {
+ const deleteBtn = findDeleteButton();
+ deleteBtn.vm.$emit('click');
+ expect(Tracking.event).toHaveBeenCalledWith(mockPageName, 'click_button', {
+ label: 'bulk_registry_tag_delete',
+ property: 'foo',
+ });
+ });
+ it('send an event when cancel is pressed on modal', () => {
+ const deleteModal = findDeleteModal();
+ deleteModal.vm.$emit('cancel');
+ expect(Tracking.event).toHaveBeenCalledWith(mockPageName, 'cancel_delete', {
+ label: 'bulk_registry_tag_delete',
+ property: 'foo',
+ });
+ });
+ it('send an event when confirm is clicked on modal', () => {
+ const deleteModal = findDeleteModal();
+ deleteModal.vm.$emit('ok');
+
+ expect(Tracking.event).toHaveBeenCalledWith(mockPageName, 'confirm_delete', {
+ label: 'bulk_registry_tag_delete',
+ property: 'foo',
+ });
+ });
+ });
+ });
});
diff --git a/spec/frontend/vue_shared/components/notes/system_note_spec.js b/spec/frontend/vue_shared/components/notes/system_note_spec.js
index a65e3eb294a..c2e8359f78d 100644
--- a/spec/frontend/vue_shared/components/notes/system_note_spec.js
+++ b/spec/frontend/vue_shared/components/notes/system_note_spec.js
@@ -57,7 +57,7 @@ describe('system note component', () => {
// we need to strip them because they break layout of commit lists in system notes:
// https://gitlab.com/gitlab-org/gitlab-foss/uploads/b07a10670919254f0220d3ff5c1aa110/jqzI.png
it('removes wrapping paragraph from note HTML', () => {
- expect(vm.$el.querySelector('.system-note-message').innerHTML).toEqual('<span>closed</span>');
+ expect(vm.$el.querySelector('.system-note-message').innerHTML).toContain('<span>closed</span>');
});
it('should initMRPopovers onMount', () => {
diff --git a/spec/javascripts/bootstrap_jquery_spec.js b/spec/javascripts/bootstrap_jquery_spec.js
index 35340a3bc42..6957cf40301 100644
--- a/spec/javascripts/bootstrap_jquery_spec.js
+++ b/spec/javascripts/bootstrap_jquery_spec.js
@@ -1,5 +1,3 @@
-/* eslint-disable no-var */
-
import $ from 'jquery';
import '~/commons/bootstrap';
@@ -10,15 +8,13 @@ describe('Bootstrap jQuery extensions', function() {
});
it('adds the disabled attribute', function() {
- var $input;
- $input = $('input').first();
+ const $input = $('input').first();
$input.disable();
expect($input).toHaveAttr('disabled', 'disabled');
});
return it('adds the disabled class', function() {
- var $input;
- $input = $('input').first();
+ const $input = $('input').first();
$input.disable();
expect($input).toHaveClass('disabled');
@@ -30,15 +26,13 @@ describe('Bootstrap jQuery extensions', function() {
});
it('removes the disabled attribute', function() {
- var $input;
- $input = $('input').first();
+ const $input = $('input').first();
$input.enable();
expect($input).not.toHaveAttr('disabled');
});
return it('removes the disabled class', function() {
- var $input;
- $input = $('input').first();
+ const $input = $('input').first();
$input.enable();
expect($input).not.toHaveClass('disabled');
diff --git a/spec/javascripts/monitoring/components/dashboard_spec.js b/spec/javascripts/monitoring/components/dashboard_spec.js
index 674db7c7afb..0f20171726c 100644
--- a/spec/javascripts/monitoring/components/dashboard_spec.js
+++ b/spec/javascripts/monitoring/components/dashboard_spec.js
@@ -122,6 +122,32 @@ describe('Dashboard', () => {
});
});
+ describe('cluster health', () => {
+ let wrapper;
+
+ beforeEach(done => {
+ wrapper = shallowMount(DashboardComponent, {
+ localVue,
+ sync: false,
+ propsData: { ...propsData, hasMetrics: true },
+ store,
+ });
+
+ // all_dashboards is not defined in health dashboards
+ wrapper.vm.$store.commit(`monitoringDashboard/${types.SET_ALL_DASHBOARDS}`, undefined);
+ wrapper.vm.$nextTick(done);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders correctly', () => {
+ expect(wrapper.isVueInstance()).toBe(true);
+ expect(wrapper.exists()).toBe(true);
+ });
+ });
+
describe('requests information to the server', () => {
let spy;
beforeEach(() => {
diff --git a/spec/javascripts/monitoring/store/mutations_spec.js b/spec/javascripts/monitoring/store/mutations_spec.js
index 498c1a9e9b1..91948b83eec 100644
--- a/spec/javascripts/monitoring/store/mutations_spec.js
+++ b/spec/javascripts/monitoring/store/mutations_spec.js
@@ -144,7 +144,19 @@ describe('Monitoring mutations', () => {
});
describe('SET_ALL_DASHBOARDS', () => {
- it('stores the dashboards loaded from the git repository', () => {
+ it('stores `undefined` dashboards as an empty array', () => {
+ mutations[types.SET_ALL_DASHBOARDS](stateCopy, undefined);
+
+ expect(stateCopy.allDashboards).toEqual([]);
+ });
+
+ it('stores `null` dashboards as an empty array', () => {
+ mutations[types.SET_ALL_DASHBOARDS](stateCopy, null);
+
+ expect(stateCopy.allDashboards).toEqual([]);
+ });
+
+ it('stores dashboards loaded from the git repository', () => {
mutations[types.SET_ALL_DASHBOARDS](stateCopy, dashboardGitResponse);
expect(stateCopy.allDashboards).toEqual(dashboardGitResponse);
diff --git a/spec/javascripts/notes/stores/collapse_utils_spec.js b/spec/javascripts/notes/stores/collapse_utils_spec.js
index 8ede9319088..d3019f4b9a4 100644
--- a/spec/javascripts/notes/stores/collapse_utils_spec.js
+++ b/spec/javascripts/notes/stores/collapse_utils_spec.js
@@ -1,6 +1,5 @@
import {
isDescriptionSystemNote,
- changeDescriptionNote,
getTimeDifferenceMinutes,
collapseSystemNotes,
} from '~/notes/stores/collapse_utils';
@@ -24,15 +23,6 @@ describe('Collapse utils', () => {
);
});
- it('changes the description to contain the number of changed times', () => {
- const changedNote = changeDescriptionNote(mockSystemNote, 3, 5);
-
- expect(changedNote.times_updated).toEqual(3);
- expect(changedNote.note_html.trim()).toContain(
- '<p dir="auto">changed the description 3 times within 5 minutes </p>',
- );
- });
-
it('gets the time difference between two notes', () => {
const anotherSystemNote = {
created_at: '2018-05-14T21:33:00.000Z',
diff --git a/spec/lib/gitlab/graphql/connections/filterable_array_connection_spec.rb b/spec/lib/gitlab/graphql/connections/filterable_array_connection_spec.rb
new file mode 100644
index 00000000000..1fda84f777e
--- /dev/null
+++ b/spec/lib/gitlab/graphql/connections/filterable_array_connection_spec.rb
@@ -0,0 +1,26 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe Gitlab::Graphql::Connections::FilterableArrayConnection do
+ let(:callback) { proc { |nodes| nodes } }
+ let(:all_nodes) { Gitlab::Graphql::FilterableArray.new(callback, 1, 2, 3, 4, 5) }
+ let(:arguments) { {} }
+ subject(:connection) do
+ described_class.new(all_nodes, arguments, max_page_size: 3)
+ end
+
+ describe '#paged_nodes' do
+ let(:paged_nodes) { subject.paged_nodes }
+
+ it_behaves_like "connection with paged nodes"
+
+ context 'when callback filters some nodes' do
+ let(:callback) { proc { |nodes| nodes[1..-1] } }
+
+ it 'does not return filtered elements' do
+ expect(subject.paged_nodes).to contain_exactly(all_nodes[1], all_nodes[2])
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb b/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb
index ba1addadb5a..9dda2a41ec6 100644
--- a/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb
+++ b/spec/lib/gitlab/graphql/connections/keyset/connection_spec.rb
@@ -240,38 +240,16 @@ describe Gitlab::Graphql::Connections::Keyset::Connection do
end
describe '#paged_nodes' do
- let!(:projects) { create_list(:project, 5) }
+ let_it_be(:all_nodes) { create_list(:project, 5) }
+ let(:paged_nodes) { subject.paged_nodes }
- it 'returns the collection limited to max page size' do
- expect(subject.paged_nodes.size).to eq(3)
- end
-
- it 'is a loaded memoized array' do
- expect(subject.paged_nodes).to be_an(Array)
- expect(subject.paged_nodes.object_id).to eq(subject.paged_nodes.object_id)
- end
-
- context 'when `first` is passed' do
- let(:arguments) { { first: 2 } }
-
- it 'returns only the first elements' do
- expect(subject.paged_nodes).to contain_exactly(projects.first, projects.second)
- end
- end
-
- context 'when `last` is passed' do
- let(:arguments) { { last: 2 } }
-
- it 'returns only the last elements' do
- expect(subject.paged_nodes).to contain_exactly(projects[3], projects[4])
- end
- end
+ it_behaves_like "connection with paged nodes"
context 'when both are passed' do
let(:arguments) { { first: 2, last: 2 } }
it 'raises an error' do
- expect { subject.paged_nodes }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
+ expect { paged_nodes }.to raise_error(Gitlab::Graphql::Errors::ArgumentError)
end
end
diff --git a/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb b/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb
index 7f6283715f2..6361893c53c 100644
--- a/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb
+++ b/spec/lib/gitlab/prometheus/queries/knative_invocation_query_spec.rb
@@ -13,14 +13,19 @@ describe Gitlab::Prometheus::Queries::KnativeInvocationQuery do
context 'verify queries' do
before do
- allow(PrometheusMetric).to receive(:find_by_identifier).and_return(create(:prometheus_metric, query: prometheus_istio_query('test-name', 'test-ns')))
- allow(client).to receive(:query_range)
+ create(:prometheus_metric,
+ :common,
+ identifier: :system_metrics_knative_function_invocation_count,
+ query: 'sum(ceil(rate(istio_requests_total{destination_service_namespace="%{kube_namespace}", destination_app=~"%{function_name}.*"}[1m])*60))')
end
it 'has the query, but no data' do
- results = subject.query(serverless_func.id)
+ expect(client).to receive(:query_range).with(
+ 'sum(ceil(rate(istio_requests_total{destination_service_namespace="test-ns", destination_app=~"test-name.*"}[1m])*60))',
+ hash_including(:start, :stop)
+ )
- expect(results.queries[0][:query_range]).to eql('floor(sum(rate(istio_revision_request_count{destination_configuration="test-name", destination_namespace="test-ns"}[1m])*30))')
+ subject.query(serverless_func.id)
end
end
end
diff --git a/spec/support/helpers/graphql_helpers.rb b/spec/support/helpers/graphql_helpers.rb
index 6fb1d279456..80a3f7df05f 100644
--- a/spec/support/helpers/graphql_helpers.rb
+++ b/spec/support/helpers/graphql_helpers.rb
@@ -37,9 +37,12 @@ module GraphqlHelpers
# BatchLoader::GraphQL returns a wrapper, so we need to :sync in order
# to get the actual values
def batch_sync(max_queries: nil, &blk)
- result = batch(max_queries: nil, &blk)
+ wrapper = proc do
+ lazy_vals = yield
+ lazy_vals.is_a?(Array) ? lazy_vals.map(&:sync) : lazy_vals&.sync
+ end
- result.is_a?(Array) ? result.map(&:sync) : result&.sync
+ batch(max_queries: max_queries, &wrapper)
end
def graphql_query_for(name, attributes = {}, fields = nil)
@@ -157,7 +160,13 @@ module GraphqlHelpers
def attributes_to_graphql(attributes)
attributes.map do |name, value|
- "#{GraphqlHelpers.fieldnamerize(name.to_s)}: \"#{value}\""
+ value_str = if value.is_a?(Array)
+ '["' + value.join('","') + '"]'
+ else
+ "\"#{value}\""
+ end
+
+ "#{GraphqlHelpers.fieldnamerize(name.to_s)}: #{value_str}"
end.join(", ")
end
@@ -282,6 +291,12 @@ module GraphqlHelpers
def allow_high_graphql_recursion
allow_any_instance_of(Gitlab::Graphql::QueryAnalyzers::RecursionAnalyzer).to receive(:recursion_threshold).and_return 1000
end
+
+ def node_array(data, extract_attribute = nil)
+ data.map do |item|
+ extract_attribute ? item['node'][extract_attribute] : item['node']
+ end
+ end
end
# This warms our schema, doing this as part of loading the helpers to avoid
diff --git a/spec/support/shared_examples/graphql/connection_paged_nodes.rb b/spec/support/shared_examples/graphql/connection_paged_nodes.rb
new file mode 100644
index 00000000000..830d2d2d4b1
--- /dev/null
+++ b/spec/support/shared_examples/graphql/connection_paged_nodes.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+RSpec.shared_examples 'connection with paged nodes' do
+ it 'returns the collection limited to max page size' do
+ expect(paged_nodes.size).to eq(3)
+ end
+
+ it 'is a loaded memoized array' do
+ expect(paged_nodes).to be_an(Array)
+ expect(paged_nodes.object_id).to eq(paged_nodes.object_id)
+ end
+
+ context 'when `first` is passed' do
+ let(:arguments) { { first: 2 } }
+
+ it 'returns only the first elements' do
+ expect(paged_nodes).to contain_exactly(all_nodes.first, all_nodes.second)
+ end
+ end
+
+ context 'when `last` is passed' do
+ let(:arguments) { { last: 2 } }
+
+ it 'returns only the last elements' do
+ expect(paged_nodes).to contain_exactly(all_nodes[3], all_nodes[4])
+ end
+ end
+end