Skip to content
Snippets Groups Projects
Commit ab7cf450 authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 4204cf30
No related branches found
No related tags found
No related merge requests found
Showing
with 918 additions and 702 deletions
// This import path needs to be relative for now because this mock data is used in
// Karma specs too, where the helpers/test_constants alias can not be resolved
import { TEST_HOST } from '../helpers/test_constants';
export const mockHost = 'http://test.host';
export const mockProjectDir = '/frontend-fixtures/environments-project';
export const mockApiEndpoint = `${TEST_HOST}/monitoring/mock`;
 
export const anomalyDeploymentData = [
{
Loading
Loading
@@ -278,6 +283,49 @@ export const mockedQueryResultPayload = {
],
};
 
export const mockedQueryResultPayloadCoresTotal = {
metricId: '13_system_metrics_kubernetes_container_cores_total',
result: [
{
metric: {},
values: [
[1563272065.589, '9.396484375'],
[1563272125.589, '9.333984375'],
[1563272185.589, '9.333984375'],
[1563272245.589, '9.333984375'],
[1563272305.589, '9.333984375'],
[1563272365.589, '9.333984375'],
[1563272425.589, '9.38671875'],
[1563272485.589, '9.333984375'],
[1563272545.589, '9.333984375'],
[1563272605.589, '9.333984375'],
[1563272665.589, '9.333984375'],
[1563272725.589, '9.333984375'],
[1563272785.589, '9.396484375'],
[1563272845.589, '9.333984375'],
[1563272905.589, '9.333984375'],
[1563272965.589, '9.3984375'],
[1563273025.589, '9.337890625'],
[1563273085.589, '9.34765625'],
[1563273145.589, '9.337890625'],
[1563273205.589, '9.337890625'],
[1563273265.589, '9.337890625'],
[1563273325.589, '9.337890625'],
[1563273385.589, '9.337890625'],
[1563273445.589, '9.337890625'],
[1563273505.589, '9.337890625'],
[1563273565.589, '9.337890625'],
[1563273625.589, '9.337890625'],
[1563273685.589, '9.337890625'],
[1563273745.589, '9.337890625'],
[1563273805.589, '9.337890625'],
[1563273865.589, '9.390625'],
[1563273925.589, '9.390625'],
],
},
],
};
export const metricsGroupsAPIResponse = [
{
group: 'System metrics (Kubernetes)',
Loading
Loading
@@ -460,3 +508,130 @@ export const dashboardGitResponse = [
path: '.gitlab/dashboards/dashboard_2.yml',
},
];
export const graphDataPrometheusQuery = {
title: 'Super Chart A2',
type: 'single-stat',
weight: 2,
metrics: [
{
id: 'metric_a1',
metricId: '2',
query: 'max(go_memstats_alloc_bytes{job="prometheus"}) by (job) /1024/1024',
unit: 'MB',
label: 'Total Consumption',
metric_id: 2,
prometheus_endpoint_path:
'/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
result: [
{
metric: { job: 'prometheus' },
value: ['2019-06-26T21:03:20.881Z', 91],
},
],
},
],
};
export const graphDataPrometheusQueryRange = {
title: 'Super Chart A1',
type: 'area-chart',
weight: 2,
metrics: [
{
id: 'metric_a1',
metricId: '2',
query_range:
'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024',
unit: 'MB',
label: 'Total Consumption',
metric_id: 2,
prometheus_endpoint_path:
'/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
result: [
{
metric: {},
values: [[1495700554.925, '8.0390625'], [1495700614.925, '8.0390625']],
},
],
},
],
};
export const graphDataPrometheusQueryRangeMultiTrack = {
title: 'Super Chart A3',
type: 'heatmap',
weight: 3,
x_label: 'Status Code',
y_label: 'Time',
metrics: [
{
metricId: '1',
id: 'response_metrics_nginx_ingress_throughput_status_code',
query_range:
'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[60m])) by (status_code)',
unit: 'req / sec',
label: 'Status Code',
metric_id: 1,
prometheus_endpoint_path:
'/root/rails_nodb/environments/3/prometheus/api/v1/query_range?query=sum%28rate%28nginx_upstream_responses_total%7Bupstream%3D~%22%25%7Bkube_namespace%7D-%25%7Bci_environment_slug%7D-.%2A%22%7D%5B2m%5D%29%29+by+%28status_code%29',
result: [
{
metric: { status_code: '1xx' },
values: [
['2019-08-30T15:00:00.000Z', 0],
['2019-08-30T16:00:00.000Z', 2],
['2019-08-30T17:00:00.000Z', 0],
['2019-08-30T18:00:00.000Z', 0],
['2019-08-30T19:00:00.000Z', 0],
['2019-08-30T20:00:00.000Z', 3],
],
},
{
metric: { status_code: '2xx' },
values: [
['2019-08-30T15:00:00.000Z', 1],
['2019-08-30T16:00:00.000Z', 3],
['2019-08-30T17:00:00.000Z', 6],
['2019-08-30T18:00:00.000Z', 10],
['2019-08-30T19:00:00.000Z', 8],
['2019-08-30T20:00:00.000Z', 6],
],
},
{
metric: { status_code: '3xx' },
values: [
['2019-08-30T15:00:00.000Z', 1],
['2019-08-30T16:00:00.000Z', 2],
['2019-08-30T17:00:00.000Z', 3],
['2019-08-30T18:00:00.000Z', 3],
['2019-08-30T19:00:00.000Z', 2],
['2019-08-30T20:00:00.000Z', 1],
],
},
{
metric: { status_code: '4xx' },
values: [
['2019-08-30T15:00:00.000Z', 2],
['2019-08-30T16:00:00.000Z', 0],
['2019-08-30T17:00:00.000Z', 0],
['2019-08-30T18:00:00.000Z', 2],
['2019-08-30T19:00:00.000Z', 0],
['2019-08-30T20:00:00.000Z', 2],
],
},
{
metric: { status_code: '5xx' },
values: [
['2019-08-30T15:00:00.000Z', 0],
['2019-08-30T16:00:00.000Z', 1],
['2019-08-30T17:00:00.000Z', 0],
['2019-08-30T18:00:00.000Z', 0],
['2019-08-30T19:00:00.000Z', 0],
['2019-08-30T20:00:00.000Z', 2],
],
},
],
},
],
};
import { mount } from '@vue/test-utils';
import { trimText } from 'helpers/text_helper';
import Assignee from '~/sidebar/components/assignees/assignees.vue';
import UsersMock from './mock_data';
import UsersMockHelper from '../helpers/user_mock_data_helper';
describe('Assignee component', () => {
const getDefaultProps = () => ({
rootPath: 'http://localhost:3000',
users: [],
editable: false,
});
let wrapper;
const createWrapper = (propsData = getDefaultProps()) => {
wrapper = mount(Assignee, {
propsData,
sync: false,
attachToDocument: true,
});
};
const findComponentTextNoUsers = () => wrapper.find('.assign-yourself');
const findCollapsedChildren = () => wrapper.findAll('.sidebar-collapsed-icon > *');
afterEach(() => {
wrapper.destroy();
});
describe('No assignees/users', () => {
it('displays no assignee icon when collapsed', () => {
createWrapper();
const collapsedChildren = findCollapsedChildren();
expect(collapsedChildren.length).toBe(1);
expect(collapsedChildren.at(0).attributes('aria-label')).toBe('None');
expect(collapsedChildren.at(0).classes()).toContain('fa', 'fa-user');
});
it('displays only "None" when no users are assigned and the issue is read-only', () => {
createWrapper();
const componentTextNoUsers = trimText(findComponentTextNoUsers().text());
expect(componentTextNoUsers).toBe('None');
expect(componentTextNoUsers).not.toContain('assign yourself');
});
it('displays only "None" when no users are assigned and the issue can be edited', () => {
createWrapper({
...getDefaultProps(),
editable: true,
});
const componentTextNoUsers = trimText(findComponentTextNoUsers().text());
expect(componentTextNoUsers).toContain('None');
expect(componentTextNoUsers).toContain('assign yourself');
});
it('emits the assign-self event when "assign yourself" is clicked', () => {
createWrapper({
...getDefaultProps(),
editable: true,
});
jest.spyOn(wrapper.vm, '$emit');
wrapper.find('.assign-yourself .btn-link').trigger('click');
expect(wrapper.emitted('assign-self')).toBeTruthy();
});
});
describe('One assignee/user', () => {
it('displays one assignee icon when collapsed', () => {
createWrapper({
...getDefaultProps(),
users: [UsersMock.user],
});
const collapsedChildren = findCollapsedChildren();
const assignee = collapsedChildren.at(0);
expect(collapsedChildren.length).toBe(1);
expect(assignee.find('.avatar').attributes('src')).toBe(UsersMock.user.avatar);
expect(assignee.find('.avatar').attributes('alt')).toBe(`${UsersMock.user.name}'s avatar`);
expect(trimText(assignee.find('.author').text())).toBe(UsersMock.user.name);
});
});
describe('Two or more assignees/users', () => {
it('displays two assignee icons when collapsed', () => {
const users = UsersMockHelper.createNumberRandomUsers(2);
createWrapper({
...getDefaultProps(),
users,
});
const collapsedChildren = findCollapsedChildren();
expect(collapsedChildren.length).toBe(2);
const first = collapsedChildren.at(0);
expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar);
expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
expect(trimText(first.find('.author').text())).toBe(users[0].name);
const second = collapsedChildren.at(1);
expect(second.find('.avatar').attributes('src')).toBe(users[1].avatar);
expect(second.find('.avatar').attributes('alt')).toBe(`${users[1].name}'s avatar`);
expect(trimText(second.find('.author').text())).toBe(users[1].name);
});
it('displays one assignee icon and counter when collapsed', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
createWrapper({
...getDefaultProps(),
users,
});
const collapsedChildren = findCollapsedChildren();
expect(collapsedChildren.length).toBe(2);
const first = collapsedChildren.at(0);
expect(first.find('.avatar').attributes('src')).toBe(users[0].avatar);
expect(first.find('.avatar').attributes('alt')).toBe(`${users[0].name}'s avatar`);
expect(trimText(first.find('.author').text())).toBe(users[0].name);
const second = collapsedChildren.at(1);
expect(trimText(second.find('.avatar-counter').text())).toBe('+2');
});
it('Shows two assignees', () => {
const users = UsersMockHelper.createNumberRandomUsers(2);
createWrapper({
...getDefaultProps(),
users,
editable: true,
});
expect(wrapper.findAll('.user-item').length).toBe(users.length);
expect(wrapper.find('.user-list-more').exists()).toBe(false);
});
it('shows sorted assignee where "can merge" users are sorted first', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
users[0].can_merge = false;
users[1].can_merge = false;
users[2].can_merge = true;
createWrapper({
...getDefaultProps(),
users,
editable: true,
});
expect(wrapper.vm.sortedAssigness[0].can_merge).toBe(true);
});
it('passes the sorted assignees to the uncollapsed-assignee-list', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
users[0].can_merge = false;
users[1].can_merge = false;
users[2].can_merge = true;
createWrapper({
...getDefaultProps(),
users,
});
const userItems = wrapper.findAll('.user-list .user-item a');
expect(userItems.length).toBe(3);
expect(userItems.at(0).attributes('data-original-title')).toBe(users[2].name);
});
it('passes the sorted assignees to the collapsed-assignee-list', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
users[0].can_merge = false;
users[1].can_merge = false;
users[2].can_merge = true;
createWrapper({
...getDefaultProps(),
users,
});
const collapsedButton = wrapper.find('.sidebar-collapsed-user button');
expect(trimText(collapsedButton.text())).toBe(users[2].name);
});
});
});
const RESPONSE_MAP = {
GET: {
'/gitlab-org/gitlab-shell/issues/5.json': {
id: 45,
iid: 5,
author_id: 23,
description: 'Nulla ullam commodi delectus adipisci quis sit.',
lock_version: null,
milestone_id: 21,
position: 0,
state: 'closed',
title: 'Vel et nulla voluptatibus corporis dolor iste saepe laborum.',
updated_by_id: 1,
created_at: '2017-02-02T21: 49: 49.664Z',
updated_at: '2017-05-03T22: 26: 03.760Z',
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
human_total_time_spent: null,
branch_name: null,
confidential: false,
assignees: [
{
name: 'User 0',
username: 'user0',
id: 22,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/michaele.will',
},
],
due_date: null,
moved_to_id: null,
project_id: 4,
weight: null,
milestone: {
id: 21,
iid: 1,
project_id: 4,
title: 'v0.0',
description: 'Molestiae commodi laboriosam odio sunt eaque reprehenderit.',
state: 'active',
created_at: '2017-02-02T21: 49: 30.530Z',
updated_at: '2017-02-02T21: 49: 30.530Z',
due_date: null,
start_date: null,
},
labels: [],
},
'/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras': {
assignees: [
{
name: 'User 0',
username: 'user0',
id: 22,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/michaele.will',
},
],
human_time_estimate: null,
human_total_time_spent: null,
participants: [
{
name: 'User 0',
username: 'user0',
id: 22,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/michaele.will',
},
],
subscribed: true,
time_estimate: 0,
total_time_spent: 0,
},
'/autocomplete/projects?project_id=15': [
{
id: 0,
name_with_namespace: 'No project',
},
{
id: 20,
name_with_namespace: '<img src=x onerror=alert(document.domain)> foo / bar',
},
],
},
PUT: {
'/gitlab-org/gitlab-shell/issues/5.json': {
data: {},
},
},
POST: {
'/gitlab-org/gitlab-shell/issues/5/move': {
id: 123,
iid: 5,
author_id: 1,
description: 'some description',
lock_version: 5,
milestone_id: null,
state: 'opened',
title: 'some title',
updated_by_id: 1,
created_at: '2017-06-27T19:54:42.437Z',
updated_at: '2017-08-18T03:39:49.222Z',
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
human_total_time_spent: null,
branch_name: null,
confidential: false,
assignees: [],
due_date: null,
moved_to_id: null,
project_id: 7,
milestone: null,
labels: [],
web_url: '/root/some-project/issues/5',
},
'/gitlab-org/gitlab-shell/issues/5/toggle_subscription': {},
},
};
const mockData = {
responseMap: RESPONSE_MAP,
mediator: {
endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras',
toggleSubscriptionEndpoint: '/gitlab-org/gitlab-shell/issues/5/toggle_subscription',
moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move',
projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15',
editable: true,
currentUser: {
id: 1,
name: 'Administrator',
username: 'root',
avatar_url:
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
},
rootPath: '/',
fullPath: '/gitlab-org/gitlab-shell',
},
time: {
time_estimate: 3600,
total_time_spent: 0,
human_time_estimate: '1h',
human_total_time_spent: null,
},
user: {
avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 1,
name: 'Administrator',
username: 'root',
},
};
export default mockData;
# frozen_string_literal: true
require 'spec_helper'
describe Mutations::Issues::SetConfidential do
let(:issue) { create(:issue) }
let(:user) { create(:user) }
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }) }
describe '#resolve' do
let(:confidential) { true }
let(:mutated_issue) { subject[:issue] }
subject { mutation.resolve(project_path: issue.project.full_path, iid: issue.iid, confidential: confidential) }
it 'raises an error if the resource is not accessible to the user' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
context 'when the user can update the issue' do
before do
issue.project.add_developer(user)
end
it 'returns the issue as confidential' do
expect(mutated_issue).to eq(issue)
expect(mutated_issue.confidential).to be_truthy
expect(subject[:errors]).to be_empty
end
context 'when passing confidential as false' do
let(:confidential) { false }
it 'updates the issue confidentiality to false' do
expect(mutated_issue.confidential).to be_falsey
end
end
end
end
end
import {
anomalyMockGraphData as importedAnomalyMockGraphData,
metricsGroupsAPIResponse as importedMetricsGroupsAPIResponse,
environmentData as importedEnvironmentData,
dashboardGitResponse as importedDashboardGitResponse,
} from '../../frontend/monitoring/mock_data';
// No new code should be added to this file. Instead, modify the
// file this one re-exports from. For more detail about why, see:
// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/31349
 
export const anomalyMockGraphData = importedAnomalyMockGraphData;
export const metricsGroupsAPIResponse = importedMetricsGroupsAPIResponse;
export const environmentData = importedEnvironmentData;
export const dashboardGitResponse = importedDashboardGitResponse;
export const mockApiEndpoint = `${gl.TEST_HOST}/monitoring/mock`;
export const mockedQueryResultPayload = {
metricId: '17_system_metrics_kubernetes_container_memory_average',
result: [
{
metric: {},
values: [
[1563272065.589, '10.396484375'],
[1563272125.589, '10.333984375'],
[1563272185.589, '10.333984375'],
[1563272245.589, '10.333984375'],
[1563272305.589, '10.333984375'],
[1563272365.589, '10.333984375'],
[1563272425.589, '10.38671875'],
[1563272485.589, '10.333984375'],
[1563272545.589, '10.333984375'],
[1563272605.589, '10.333984375'],
[1563272665.589, '10.333984375'],
[1563272725.589, '10.333984375'],
[1563272785.589, '10.396484375'],
[1563272845.589, '10.333984375'],
[1563272905.589, '10.333984375'],
[1563272965.589, '10.3984375'],
[1563273025.589, '10.337890625'],
[1563273085.589, '10.34765625'],
[1563273145.589, '10.337890625'],
[1563273205.589, '10.337890625'],
[1563273265.589, '10.337890625'],
[1563273325.589, '10.337890625'],
[1563273385.589, '10.337890625'],
[1563273445.589, '10.337890625'],
[1563273505.589, '10.337890625'],
[1563273565.589, '10.337890625'],
[1563273625.589, '10.337890625'],
[1563273685.589, '10.337890625'],
[1563273745.589, '10.337890625'],
[1563273805.589, '10.337890625'],
[1563273865.589, '10.390625'],
[1563273925.589, '10.390625'],
],
},
],
};
export const mockedQueryResultPayloadCoresTotal = {
metricId: '13_system_metrics_kubernetes_container_cores_total',
result: [
{
metric: {},
values: [
[1563272065.589, '9.396484375'],
[1563272125.589, '9.333984375'],
[1563272185.589, '9.333984375'],
[1563272245.589, '9.333984375'],
[1563272305.589, '9.333984375'],
[1563272365.589, '9.333984375'],
[1563272425.589, '9.38671875'],
[1563272485.589, '9.333984375'],
[1563272545.589, '9.333984375'],
[1563272605.589, '9.333984375'],
[1563272665.589, '9.333984375'],
[1563272725.589, '9.333984375'],
[1563272785.589, '9.396484375'],
[1563272845.589, '9.333984375'],
[1563272905.589, '9.333984375'],
[1563272965.589, '9.3984375'],
[1563273025.589, '9.337890625'],
[1563273085.589, '9.34765625'],
[1563273145.589, '9.337890625'],
[1563273205.589, '9.337890625'],
[1563273265.589, '9.337890625'],
[1563273325.589, '9.337890625'],
[1563273385.589, '9.337890625'],
[1563273445.589, '9.337890625'],
[1563273505.589, '9.337890625'],
[1563273565.589, '9.337890625'],
[1563273625.589, '9.337890625'],
[1563273685.589, '9.337890625'],
[1563273745.589, '9.337890625'],
[1563273805.589, '9.337890625'],
[1563273865.589, '9.390625'],
[1563273925.589, '9.390625'],
],
},
],
};
export const graphDataPrometheusQuery = {
title: 'Super Chart A2',
type: 'single-stat',
weight: 2,
metrics: [
{
id: 'metric_a1',
metricId: '2',
query: 'max(go_memstats_alloc_bytes{job="prometheus"}) by (job) /1024/1024',
unit: 'MB',
label: 'Total Consumption',
metric_id: 2,
prometheus_endpoint_path:
'/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
result: [
{
metric: { job: 'prometheus' },
value: ['2019-06-26T21:03:20.881Z', 91],
},
],
},
],
};
export const graphDataPrometheusQueryRange = {
title: 'Super Chart A1',
type: 'area-chart',
weight: 2,
metrics: [
{
id: 'metric_a1',
metricId: '2',
query_range:
'avg(sum(container_memory_usage_bytes{container_name!="POD",pod_name=~"^%{ci_environment_slug}-(.*)",namespace="%{kube_namespace}"}) by (job)) without (job) /1024/1024/1024',
unit: 'MB',
label: 'Total Consumption',
metric_id: 2,
prometheus_endpoint_path:
'/root/kubernetes-gke-project/environments/35/prometheus/api/v1/query?query=max%28go_memstats_alloc_bytes%7Bjob%3D%22prometheus%22%7D%29+by+%28job%29+%2F1024%2F1024',
result: [
{
metric: {},
values: [[1495700554.925, '8.0390625'], [1495700614.925, '8.0390625']],
},
],
},
],
};
export const graphDataPrometheusQueryRangeMultiTrack = {
title: 'Super Chart A3',
type: 'heatmap',
weight: 3,
x_label: 'Status Code',
y_label: 'Time',
metrics: [
{
metricId: '1',
id: 'response_metrics_nginx_ingress_throughput_status_code',
query_range:
'sum(rate(nginx_upstream_responses_total{upstream=~"%{kube_namespace}-%{ci_environment_slug}-.*"}[60m])) by (status_code)',
unit: 'req / sec',
label: 'Status Code',
metric_id: 1,
prometheus_endpoint_path:
'/root/rails_nodb/environments/3/prometheus/api/v1/query_range?query=sum%28rate%28nginx_upstream_responses_total%7Bupstream%3D~%22%25%7Bkube_namespace%7D-%25%7Bci_environment_slug%7D-.%2A%22%7D%5B2m%5D%29%29+by+%28status_code%29',
result: [
{
metric: { status_code: '1xx' },
values: [
['2019-08-30T15:00:00.000Z', 0],
['2019-08-30T16:00:00.000Z', 2],
['2019-08-30T17:00:00.000Z', 0],
['2019-08-30T18:00:00.000Z', 0],
['2019-08-30T19:00:00.000Z', 0],
['2019-08-30T20:00:00.000Z', 3],
],
},
{
metric: { status_code: '2xx' },
values: [
['2019-08-30T15:00:00.000Z', 1],
['2019-08-30T16:00:00.000Z', 3],
['2019-08-30T17:00:00.000Z', 6],
['2019-08-30T18:00:00.000Z', 10],
['2019-08-30T19:00:00.000Z', 8],
['2019-08-30T20:00:00.000Z', 6],
],
},
{
metric: { status_code: '3xx' },
values: [
['2019-08-30T15:00:00.000Z', 1],
['2019-08-30T16:00:00.000Z', 2],
['2019-08-30T17:00:00.000Z', 3],
['2019-08-30T18:00:00.000Z', 3],
['2019-08-30T19:00:00.000Z', 2],
['2019-08-30T20:00:00.000Z', 1],
],
},
{
metric: { status_code: '4xx' },
values: [
['2019-08-30T15:00:00.000Z', 2],
['2019-08-30T16:00:00.000Z', 0],
['2019-08-30T17:00:00.000Z', 0],
['2019-08-30T18:00:00.000Z', 2],
['2019-08-30T19:00:00.000Z', 0],
['2019-08-30T20:00:00.000Z', 2],
],
},
{
metric: { status_code: '5xx' },
values: [
['2019-08-30T15:00:00.000Z', 0],
['2019-08-30T16:00:00.000Z', 1],
['2019-08-30T17:00:00.000Z', 0],
['2019-08-30T18:00:00.000Z', 0],
['2019-08-30T19:00:00.000Z', 0],
['2019-08-30T20:00:00.000Z', 2],
],
},
],
},
],
};
export * from '../../frontend/monitoring/mock_data';
import Vue from 'vue';
import Assignee from '~/sidebar/components/assignees/assignees.vue';
import UsersMock from './mock_data';
import UsersMockHelper from '../helpers/user_mock_data_helper';
describe('Assignee component', () => {
let component;
let AssigneeComponent;
beforeEach(() => {
AssigneeComponent = Vue.extend(Assignee);
});
describe('No assignees/users', () => {
it('displays no assignee icon when collapsed', () => {
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users: [],
editable: false,
},
}).$mount();
const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
expect(collapsed.childElementCount).toEqual(1);
expect(collapsed.children[0].getAttribute('aria-label')).toEqual('None');
expect(collapsed.children[0].classList.contains('fa')).toEqual(true);
expect(collapsed.children[0].classList.contains('fa-user')).toEqual(true);
});
it('displays only "None" when no users are assigned and the issue is read-only', () => {
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users: [],
editable: false,
},
}).$mount();
const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();
expect(componentTextNoUsers).toBe('None');
expect(componentTextNoUsers.indexOf('assign yourself')).toEqual(-1);
});
it('displays only "None" when no users are assigned and the issue can be edited', () => {
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users: [],
editable: true,
},
}).$mount();
const componentTextNoUsers = component.$el.querySelector('.assign-yourself').innerText.trim();
expect(componentTextNoUsers.indexOf('None')).toEqual(0);
expect(componentTextNoUsers.indexOf('assign yourself')).toBeGreaterThan(0);
});
it('emits the assign-self event when "assign yourself" is clicked', () => {
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users: [],
editable: true,
},
}).$mount();
spyOn(component, '$emit');
component.$el.querySelector('.assign-yourself .btn-link').click();
expect(component.$emit).toHaveBeenCalledWith('assign-self');
});
});
describe('One assignee/user', () => {
it('displays one assignee icon when collapsed', () => {
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users: [UsersMock.user],
editable: false,
},
}).$mount();
const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
const assignee = collapsed.children[0];
expect(collapsed.childElementCount).toEqual(1);
expect(assignee.querySelector('.avatar').getAttribute('src')).toEqual(UsersMock.user.avatar);
expect(assignee.querySelector('.avatar').getAttribute('alt')).toEqual(
`${UsersMock.user.name}'s avatar`,
);
expect(assignee.querySelector('.author').innerText.trim()).toEqual(UsersMock.user.name);
});
});
describe('Two or more assignees/users', () => {
it('has no "cannot merge" tooltip when every user can merge', () => {
const users = UsersMockHelper.createNumberRandomUsers(2);
users[0].can_merge = true;
users[1].can_merge = true;
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000/',
users,
editable: true,
issuableType: 'merge_request',
},
}).$mount();
expect(component.collapsedTooltipTitle).not.toContain('cannot merge');
});
it('displays two assignee icons when collapsed', () => {
const users = UsersMockHelper.createNumberRandomUsers(2);
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users,
editable: false,
},
}).$mount();
const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
expect(collapsed.childElementCount).toEqual(2);
const first = collapsed.children[0];
expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatar);
expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(
`${users[0].name}'s avatar`,
);
expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);
const second = collapsed.children[1];
expect(second.querySelector('.avatar').getAttribute('src')).toEqual(users[1].avatar);
expect(second.querySelector('.avatar').getAttribute('alt')).toEqual(
`${users[1].name}'s avatar`,
);
expect(second.querySelector('.author').innerText.trim()).toEqual(users[1].name);
});
it('displays one assignee icon and counter when collapsed', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users,
editable: false,
},
}).$mount();
const collapsed = component.$el.querySelector('.sidebar-collapsed-icon');
expect(collapsed.childElementCount).toEqual(2);
const first = collapsed.children[0];
expect(first.querySelector('.avatar').getAttribute('src')).toEqual(users[0].avatar);
expect(first.querySelector('.avatar').getAttribute('alt')).toEqual(
`${users[0].name}'s avatar`,
);
expect(first.querySelector('.author').innerText.trim()).toEqual(users[0].name);
const second = collapsed.children[1];
expect(second.querySelector('.avatar-counter').innerText.trim()).toEqual('+2');
});
it('Shows two assignees', () => {
const users = UsersMockHelper.createNumberRandomUsers(2);
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users,
editable: true,
},
}).$mount();
expect(component.$el.querySelectorAll('.user-item').length).toEqual(users.length);
expect(component.$el.querySelector('.user-list-more')).toBe(null);
});
it('shows sorted assignee where "can merge" users are sorted first', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
users[0].can_merge = false;
users[1].can_merge = false;
users[2].can_merge = true;
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users,
editable: true,
},
}).$mount();
expect(component.sortedAssigness[0].can_merge).toBe(true);
});
it('passes the sorted assignees to the uncollapsed-assignee-list', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
users[0].can_merge = false;
users[1].can_merge = false;
users[2].can_merge = true;
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users,
editable: false,
},
}).$mount();
const userItems = component.$el.querySelectorAll('.user-list .user-item a');
expect(userItems.length).toBe(3);
expect(userItems[0].dataset.originalTitle).toBe(users[2].name);
});
it('passes the sorted assignees to the collapsed-assignee-list', () => {
const users = UsersMockHelper.createNumberRandomUsers(3);
users[0].can_merge = false;
users[1].can_merge = false;
users[2].can_merge = true;
component = new AssigneeComponent({
propsData: {
rootPath: 'http://localhost:3000',
users,
editable: false,
},
}).$mount();
const collapsedButton = component.$el.querySelector('.sidebar-collapsed-user button');
expect(collapsedButton.innerText.trim()).toBe(users[2].name);
});
});
});
const RESPONSE_MAP = {
GET: {
'/gitlab-org/gitlab-shell/issues/5.json': {
id: 45,
iid: 5,
author_id: 23,
description: 'Nulla ullam commodi delectus adipisci quis sit.',
lock_version: null,
milestone_id: 21,
position: 0,
state: 'closed',
title: 'Vel et nulla voluptatibus corporis dolor iste saepe laborum.',
updated_by_id: 1,
created_at: '2017-02-02T21: 49: 49.664Z',
updated_at: '2017-05-03T22: 26: 03.760Z',
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
human_total_time_spent: null,
branch_name: null,
confidential: false,
assignees: [
{
name: 'User 0',
username: 'user0',
id: 22,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
web_url: 'http: //localhost:3001/michaele.will',
},
],
due_date: null,
moved_to_id: null,
project_id: 4,
weight: null,
milestone: {
id: 21,
iid: 1,
project_id: 4,
title: 'v0.0',
description: 'Molestiae commodi laboriosam odio sunt eaque reprehenderit.',
state: 'active',
created_at: '2017-02-02T21: 49: 30.530Z',
updated_at: '2017-02-02T21: 49: 30.530Z',
due_date: null,
start_date: null,
},
labels: [],
},
'/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras': {
assignees: [
{
name: 'User 0',
username: 'user0',
id: 22,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/michaele.will',
},
],
human_time_estimate: null,
human_total_time_spent: null,
participants: [
{
name: 'User 0',
username: 'user0',
id: 22,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/52e4ce24a915fb7e51e1ad3b57f4b00a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/user0',
},
{
name: 'Marguerite Bartell',
username: 'tajuana',
id: 18,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/4852a41fb41616bf8f140d3701673f53?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/tajuana',
},
{
name: 'Laureen Ritchie',
username: 'michaele.will',
id: 16,
state: 'active',
avatar_url:
'https://www.gravatar.com/avatar/e301827eb03be955c9c172cb9a8e4e8a?s=80\u0026d=identicon',
web_url: 'http://localhost:3001/michaele.will',
},
],
subscribed: true,
time_estimate: 0,
total_time_spent: 0,
},
'/autocomplete/projects?project_id=15': [
{
id: 0,
name_with_namespace: 'No project',
},
{
id: 20,
name_with_namespace: '<img src=x onerror=alert(document.domain)> foo / bar',
},
],
},
PUT: {
'/gitlab-org/gitlab-shell/issues/5.json': {
data: {},
},
},
POST: {
'/gitlab-org/gitlab-shell/issues/5/move': {
id: 123,
iid: 5,
author_id: 1,
description: 'some description',
lock_version: 5,
milestone_id: null,
state: 'opened',
title: 'some title',
updated_by_id: 1,
created_at: '2017-06-27T19:54:42.437Z',
updated_at: '2017-08-18T03:39:49.222Z',
time_estimate: 0,
total_time_spent: 0,
human_time_estimate: null,
human_total_time_spent: null,
branch_name: null,
confidential: false,
assignees: [],
due_date: null,
moved_to_id: null,
project_id: 7,
milestone: null,
labels: [],
web_url: '/root/some-project/issues/5',
},
'/gitlab-org/gitlab-shell/issues/5/toggle_subscription': {},
},
};
// No new code should be added to this file. Instead, modify the
// file this one re-exports from. For more detail about why, see:
// https://gitlab.com/gitlab-org/gitlab-foss/merge_requests/31349
 
const mockData = {
responseMap: RESPONSE_MAP,
mediator: {
endpoint: '/gitlab-org/gitlab-shell/issues/5.json?serializer=sidebar_extras',
toggleSubscriptionEndpoint: '/gitlab-org/gitlab-shell/issues/5/toggle_subscription',
moveIssueEndpoint: '/gitlab-org/gitlab-shell/issues/5/move',
projectsAutocompleteEndpoint: '/autocomplete/projects?project_id=15',
editable: true,
currentUser: {
id: 1,
name: 'Administrator',
username: 'root',
avatar_url:
'https://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
},
rootPath: '/',
fullPath: '/gitlab-org/gitlab-shell',
},
time: {
time_estimate: 3600,
total_time_spent: 0,
human_time_estimate: '1h',
human_total_time_spent: null,
},
user: {
avatar: 'https://gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 1,
name: 'Administrator',
username: 'root',
},
};
import mockData from '../../../spec/frontend/sidebar/mock_data';
 
export default mockData;
Loading
Loading
@@ -38,13 +38,29 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
.and_return(double(execute: kubernetes_namespace))
end
 
it { is_expected.to be_falsey }
context 'and the service_account_token is blank' do
let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: nil) }
context 'and the knative version role binding is missing' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: nil))
end
 
it { is_expected.to be_truthy }
end
context 'and the knative version role binding already exists' do
before do
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: true))
end
it { is_expected.to be_falsey }
context 'and the service_account_token is blank' do
let(:kubernetes_namespace) { instance_double(Clusters::KubernetesNamespace, service_account_token: nil) }
it { is_expected.to be_truthy }
end
end
end
end
 
Loading
Loading
@@ -115,6 +131,24 @@ describe Gitlab::Ci::Build::Prerequisite::KubernetesNamespace do
subject
end
end
context 'knative version role binding is missing' do
before do
allow(Clusters::KubernetesNamespaceFinder).to receive(:new)
.and_return(double(execute: kubernetes_namespace))
allow(Clusters::KnativeVersionRoleBindingFinder).to receive(:new)
.and_return(double(execute: nil))
end
it 'creates the knative version role binding' do
expect(Clusters::Kubernetes::CreateOrUpdateNamespaceService)
.to receive(:new)
.with(cluster: cluster, kubernetes_namespace: kubernetes_namespace)
.and_return(service)
subject
end
end
end
 
context 'completion is not required' do
Loading
Loading
Loading
Loading
@@ -17,13 +17,13 @@ describe Gitlab::Git::Commit, :seed_helper do
@committer = {
email: 'mike@smith.com',
name: "Mike Smith",
time: Time.now
time: Time.new(2000, 1, 1, 0, 0, 0, "+08:00")
}
 
@author = {
email: 'john@smith.com',
name: "John Smith",
time: Time.now
time: Time.new(2000, 1, 1, 0, 0, 0, "-08:00")
}
 
@parents = [rugged_repo.head.target]
Loading
Loading
@@ -48,7 +48,7 @@ describe Gitlab::Git::Commit, :seed_helper do
it { expect(@commit.id).to eq(@raw_commit.oid) }
it { expect(@commit.sha).to eq(@raw_commit.oid) }
it { expect(@commit.safe_message).to eq(@raw_commit.message) }
it { expect(@commit.created_at).to eq(@raw_commit.author[:time]) }
it { expect(@commit.created_at).to eq(@raw_commit.committer[:time]) }
it { expect(@commit.date).to eq(@raw_commit.committer[:time]) }
it { expect(@commit.author_email).to eq(@author[:email]) }
it { expect(@commit.author_name).to eq(@author[:name]) }
Loading
Loading
@@ -79,13 +79,27 @@ describe Gitlab::Git::Commit, :seed_helper do
it { expect(commit.id).to eq(id) }
it { expect(commit.sha).to eq(id) }
it { expect(commit.safe_message).to eq(body) }
it { expect(commit.created_at).to eq(Time.at(committer.date.seconds)) }
it { expect(commit.created_at).to eq(Time.at(committer.date.seconds).utc) }
it { expect(commit.author_email).to eq(author.email) }
it { expect(commit.author_name).to eq(author.name) }
it { expect(commit.committer_name).to eq(committer.name) }
it { expect(commit.committer_email).to eq(committer.email) }
it { expect(commit.parent_ids).to eq(gitaly_commit.parent_ids) }
 
context 'non-UTC dates' do
let(:seconds) { Time.now.to_i }
it 'sets timezones correctly' do
gitaly_commit.author.date.seconds = seconds
gitaly_commit.author.timezone = '-0800'
gitaly_commit.committer.date.seconds = seconds
gitaly_commit.committer.timezone = '+0800'
expect(commit.authored_date).to eq(Time.at(seconds, in: '-08:00'))
expect(commit.committed_date).to eq(Time.at(seconds, in: '+08:00'))
end
end
context 'body_size != body.size' do
let(:body) { (+"").force_encoding('ASCII-8BIT') }
 
Loading
Loading
Loading
Loading
@@ -1197,6 +1197,54 @@ describe Ci::Build do
end
end
 
describe '#expanded_kubernetes_namespace' do
let(:build) { create(:ci_build, environment: environment, options: options) }
subject { build.expanded_kubernetes_namespace }
context 'environment and namespace are not set' do
let(:environment) { nil }
let(:options) { nil }
it { is_expected.to be_nil }
end
context 'environment is specified' do
let(:environment) { 'production' }
context 'namespace is not set' do
let(:options) { nil }
it { is_expected.to be_nil }
end
context 'namespace is provided' do
let(:options) do
{
environment: {
name: environment,
kubernetes: {
namespace: namespace
}
}
}
end
context 'with a static value' do
let(:namespace) { 'production' }
it { is_expected.to eq namespace }
end
context 'with a dynamic value' do
let(:namespace) { 'deploy-$CI_COMMIT_REF_NAME'}
it { is_expected.to eq 'deploy-master' }
end
end
end
end
describe '#starts_environment?' do
subject { build.starts_environment? }
 
Loading
Loading
@@ -2987,6 +3035,32 @@ describe Ci::Build do
end
end
 
describe '#deployment_variables' do
let(:build) { create(:ci_build, environment: environment) }
let(:environment) { 'production' }
let(:kubernetes_namespace) { 'namespace' }
let(:project_variables) { double }
subject { build.deployment_variables(environment: environment) }
before do
allow(build).to receive(:expanded_kubernetes_namespace)
.and_return(kubernetes_namespace)
allow(build.project).to receive(:deployment_variables)
.with(environment: environment, kubernetes_namespace: kubernetes_namespace)
.and_return(project_variables)
end
it { is_expected.to eq(project_variables) }
context 'environment is nil' do
let(:environment) { nil }
it { is_expected.to be_empty }
end
end
describe '#scoped_variables_hash' do
context 'when overriding CI variables' do
before do
Loading
Loading
Loading
Loading
@@ -290,6 +290,26 @@ describe Clusters::Platforms::Kubernetes do
it { is_expected.to include(key: 'KUBE_TOKEN', value: platform.token, public: false, masked: true) }
it { is_expected.to include(key: 'KUBE_NAMESPACE', value: namespace) }
it { is_expected.to include(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) }
context 'custom namespace is provided' do
let(:custom_namespace) { 'custom-namespace' }
subject do
platform.predefined_variables(
project: project,
environment_name: environment_name,
kubernetes_namespace: custom_namespace
)
end
before do
allow(platform).to receive(:kubeconfig).with(custom_namespace).and_return(kubeconfig)
end
it { is_expected.to include(key: 'KUBE_TOKEN', value: platform.token, public: false, masked: true) }
it { is_expected.to include(key: 'KUBE_NAMESPACE', value: custom_namespace) }
it { is_expected.to include(key: 'KUBECONFIG', value: kubeconfig, public: false, file: true) }
end
end
end
 
Loading
Loading
Loading
Loading
@@ -359,7 +359,7 @@ eos
 
it { expect(data).to be_a(Hash) }
it { expect(data[:message]).to include('adds bar folder and branch-test text file to check Repository merged_to_root_ref method') }
it { expect(data[:timestamp]).to eq('2016-09-27T14:37:46Z') }
it { expect(data[:timestamp]).to eq('2016-09-27T14:37:46+00:00') }
it { expect(data[:added]).to contain_exactly("bar/branch-test.txt") }
it { expect(data[:modified]).to eq([]) }
it { expect(data[:removed]).to eq([]) }
Loading
Loading
Loading
Loading
@@ -106,6 +106,40 @@ describe Milestone do
end
end
 
describe '#merge_requests_enabled?' do
context "per project" do
it "is true for projects with MRs enabled" do
project = create(:project, :merge_requests_enabled)
milestone = create(:milestone, project: project)
expect(milestone.merge_requests_enabled?).to be(true)
end
it "is false for projects with MRs disabled" do
project = create(:project, :repository_enabled, :merge_requests_disabled)
milestone = create(:milestone, project: project)
expect(milestone.merge_requests_enabled?).to be(false)
end
it "is false for projects with repository disabled" do
project = create(:project, :repository_disabled)
milestone = create(:milestone, project: project)
expect(milestone.merge_requests_enabled?).to be(false)
end
end
context "per group" do
let(:group) { create(:group) }
let(:milestone) { create(:milestone, group: group) }
it "is always true for groups, for performance reasons" do
expect(milestone.merge_requests_enabled?).to be(true)
end
end
end
describe "unique milestone title" do
context "per project" do
it "does not accept the same title in a project twice" do
Loading
Loading
Loading
Loading
@@ -2765,8 +2765,9 @@ describe Project do
describe '#deployment_variables' do
let(:project) { create(:project) }
let(:environment) { 'production' }
let(:namespace) { 'namespace' }
 
subject { project.deployment_variables(environment: environment) }
subject { project.deployment_variables(environment: environment, kubernetes_namespace: namespace) }
 
before do
expect(project).to receive(:deployment_platform).with(environment: environment)
Loading
Loading
@@ -2785,7 +2786,7 @@ describe Project do
 
before do
expect(deployment_platform).to receive(:predefined_variables)
.with(project: project, environment_name: environment)
.with(project: project, environment_name: environment, kubernetes_namespace: namespace)
.and_return(platform_variables)
end
 
Loading
Loading
Loading
Loading
@@ -131,7 +131,7 @@ describe API::Branches do
end
 
new_branch_name = 'protected-branch'
CreateBranchService.new(project, current_user).execute(new_branch_name, 'master')
::Branches::CreateService.new(project, current_user).execute(new_branch_name, 'master')
create(:protected_branch, name: new_branch_name, project: project)
 
expect do
Loading
Loading
Loading
Loading
@@ -315,11 +315,11 @@ describe API::Files do
expect(range['commit']['message'])
.to eq("Files, encoding and much more\n\nSigned-off-by: Dmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>\n")
 
expect(range['commit']['authored_date']).to eq('2014-02-27T08:14:56.000Z')
expect(range['commit']['authored_date']).to eq('2014-02-27T10:14:56.000+02:00')
expect(range['commit']['author_name']).to eq('Dmitriy Zaporozhets')
expect(range['commit']['author_email']).to eq('dmitriy.zaporozhets@gmail.com')
 
expect(range['commit']['committed_date']).to eq('2014-02-27T08:14:56.000Z')
expect(range['commit']['committed_date']).to eq('2014-02-27T10:14:56.000+02:00')
expect(range['commit']['committer_name']).to eq('Dmitriy Zaporozhets')
expect(range['commit']['committer_email']).to eq('dmitriy.zaporozhets@gmail.com')
end
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe 'Setting an issue as confidential' do
include GraphqlHelpers
let(:current_user) { create(:user) }
let(:issue) { create(:issue) }
let(:project) { issue.project }
let(:input) { { confidential: true } }
let(:mutation) do
variables = {
project_path: project.full_path,
iid: issue.iid.to_s
}
graphql_mutation(:issue_set_confidential, variables.merge(input),
<<-QL.strip_heredoc
clientMutationId
errors
issue {
iid
confidential
}
QL
)
end
def mutation_response
graphql_mutation_response(:issue_set_confidential)
end
before do
project.add_developer(current_user)
end
it 'returns an error if the user is not allowed to update the issue' do
error = "The resource that you are attempting to access does not exist or you don't have permission to perform this action"
post_graphql_mutation(mutation, current_user: create(:user))
expect(graphql_errors).to include(a_hash_including('message' => error))
end
it 'updates the issue confidentiality' do
post_graphql_mutation(mutation, current_user: current_user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['issue']['confidential']).to be_truthy
end
end
# frozen_string_literal: true
require 'spec_helper'
describe 'Loading a user avatar' do
let(:user) { create(:user, :with_avatar) }
context 'when logged in' do
# The exact query count will vary depending on the 2FA settings of the
# instance, group, and user. Removing those extra 2FA queries in this case
# may not be a good idea, so we just set up the ideal case.
before do
stub_application_setting(require_two_factor_authentication: true)
login_as(create(:user, :two_factor))
end
# One each for: current user, avatar user, and upload record
it 'only performs three SQL queries' do
get user.avatar_url # Skip queries on first application load
expect(response).to have_gitlab_http_status(200)
expect { get user.avatar_url }.not_to exceed_query_limit(3)
end
end
context 'when logged out' do
# One each for avatar user and upload record
it 'only performs two SQL queries' do
get user.avatar_url # Skip queries on first application load
expect(response).to have_gitlab_http_status(200)
expect { get user.avatar_url }.not_to exceed_query_limit(2)
end
end
end
Loading
Loading
@@ -5,7 +5,7 @@ require 'spec_helper'
describe 'Instance Statistics', 'routing' do
include RSpec::Rails::RequestExampleGroup
 
it "routes '/-/instance_statistics' to conversational development index" do
expect(get('/-/instance_statistics')).to redirect_to('/-/instance_statistics/conversational_development_index')
it "routes '/-/instance_statistics' to dev ops score" do
expect(get('/-/instance_statistics')).to redirect_to('/-/instance_statistics/dev_ops_score')
end
end
Loading
Loading
@@ -2,9 +2,9 @@
 
require 'spec_helper'
 
describe CreateBranchService do
describe Branches::CreateService do
let(:user) { create(:user) }
let(:service) { described_class.new(project, user) }
subject(:service) { described_class.new(project, user) }
 
describe '#execute' do
context 'when repository is empty' do
Loading
Loading
@@ -30,7 +30,7 @@ describe CreateBranchService do
allow(project.repository).to receive(:add_branch).and_return(false)
end
 
it 'retruns an error with the branch name' do
it 'returns an error with the branch name' do
result = service.execute('my-feature', 'master')
 
expect(result[:status]).to eq(:error)
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment