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

Add latest changes from gitlab-org/gitlab@master

parent 63894d59
No related branches found
No related tags found
No related merge requests found
Showing
with 616 additions and 15 deletions
import Vue from 'vue';
import TokenedInput from '~/ide/components/shared/tokened_input.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import TokenedInput from '~/ide/components/shared/tokened_input.vue';
 
const TEST_PLACEHOLDER = 'Searching in test';
const TEST_TOKENS = [
Loading
Loading
import MockAdapter from 'axios-mock-adapter';
import actions, {
stageAllChanges,
unstageAllChanges,
Loading
Loading
@@ -18,7 +19,6 @@ import * as types from '~/ide/stores/mutation_types';
import router from '~/ide/ide_router';
import { resetStore, file } from '../helpers';
import testAction from '../../helpers/vuex_action_helper';
import MockAdapter from 'axios-mock-adapter';
import eventHub from '~/ide/eventhub';
 
const store = createStore();
Loading
Loading
import MockAdapter from 'axios-mock-adapter';
import testAction from 'spec/helpers/vuex_action_helper';
import axios from '~/lib/utils/axios_utils';
import state from '~/ide/stores/modules/branches/state';
import * as types from '~/ide/stores/modules/branches/mutation_types';
import testAction from 'spec/helpers/vuex_action_helper';
import {
requestBranches,
receiveBranchesError,
Loading
Loading
import { resetStore, file } from 'spec/ide/helpers';
import rootActions from '~/ide/stores/actions';
import { createStore } from '~/ide/stores';
import service from '~/ide/services';
Loading
Loading
@@ -7,7 +8,6 @@ import consts from '~/ide/stores/modules/commit/constants';
import * as mutationTypes from '~/ide/stores/modules/commit/mutation_types';
import * as actions from '~/ide/stores/modules/commit/actions';
import { commitActionTypes } from '~/ide/constants';
import { resetStore, file } from 'spec/ide/helpers';
import testAction from '../../../../helpers/vuex_action_helper';
 
const TEST_COMMIT_SHA = '123456789';
Loading
Loading
import MockAdapter from 'axios-mock-adapter';
import testAction from 'spec/helpers/vuex_action_helper';
import axios from '~/lib/utils/axios_utils';
import createState from '~/ide/stores/modules/file_templates/state';
import * as actions from '~/ide/stores/modules/file_templates/actions';
import * as types from '~/ide/stores/modules/file_templates/mutation_types';
import testAction from 'spec/helpers/vuex_action_helper';
 
describe('IDE file templates actions', () => {
let state;
Loading
Loading
import testAction from 'spec/helpers/vuex_action_helper';
import * as actions from '~/ide/stores/modules/pane/actions';
import * as types from '~/ide/stores/modules/pane/mutation_types';
import testAction from 'spec/helpers/vuex_action_helper';
 
describe('IDE pane module actions', () => {
const TEST_VIEW = { name: 'test' };
Loading
Loading
Loading
Loading
@@ -5,10 +5,16 @@ require 'spec_helper'
describe API::Helpers::Pagination do
subject { Class.new.include(described_class).new }
 
let(:expected_result) { double("result", to_a: double) }
let(:relation) { double("relation") }
let(:params) { {} }
before do
allow(subject).to receive(:params).and_return(params)
end
describe '#paginate' do
let(:relation) { double("relation") }
let(:offset_pagination) { double("offset pagination") }
let(:expected_result) { double("result") }
 
it 'delegates to OffsetPagination' do
expect(::Gitlab::Pagination::OffsetPagination).to receive(:new).with(subject).and_return(offset_pagination)
Loading
Loading
@@ -19,4 +25,50 @@ describe API::Helpers::Pagination do
expect(result).to eq(expected_result)
end
end
describe '#paginate_and_retrieve!' do
context 'for offset pagination' do
before do
allow(Gitlab::Pagination::Keyset).to receive(:available?).and_return(false)
end
it 'delegates to paginate' do
expect(subject).to receive(:paginate).with(relation).and_return(expected_result)
result = subject.paginate_and_retrieve!(relation)
expect(result).to eq(expected_result.to_a)
end
end
context 'for keyset pagination' do
let(:params) { { pagination: 'keyset' } }
let(:request_context) { double('request context') }
before do
allow(Gitlab::Pagination::Keyset::RequestContext).to receive(:new).with(subject).and_return(request_context)
end
context 'when keyset pagination is available' do
it 'delegates to KeysetPagination' do
expect(Gitlab::Pagination::Keyset).to receive(:available?).and_return(true)
expect(Gitlab::Pagination::Keyset).to receive(:paginate).with(request_context, relation).and_return(expected_result)
result = subject.paginate_and_retrieve!(relation)
expect(result).to eq(expected_result.to_a)
end
end
context 'when keyset pagination is not available' do
it 'renders a 501 error if keyset pagination isnt available yet' do
expect(Gitlab::Pagination::Keyset).to receive(:available?).with(request_context, relation).and_return(false)
expect(Gitlab::Pagination::Keyset).not_to receive(:paginate)
expect(subject).to receive(:error!).with(/not yet available/, 405)
subject.paginate_and_retrieve!(relation)
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe API::ProjectsBatchCounting do
subject do
Class.new do
include ::API::ProjectsBatchCounting
end
end
describe '.preload_and_batch_count!' do
let(:projects) { double }
let(:preloaded_projects) { double }
it 'preloads the relation' do
allow(subject).to receive(:execute_batch_counting).with(preloaded_projects)
expect(subject).to receive(:preload_relation).with(projects).and_return(preloaded_projects)
expect(subject.preload_and_batch_count!(projects)).to eq(preloaded_projects)
end
it 'executes batch counting' do
allow(subject).to receive(:preload_relation).with(projects).and_return(preloaded_projects)
expect(subject).to receive(:execute_batch_counting).with(preloaded_projects)
subject.preload_and_batch_count!(projects)
end
end
describe '.execute_batch_counting' do
let(:projects) { create_list(:project, 2) }
let(:count_service) { double }
it 'counts forks' do
allow(::Projects::BatchForksCountService).to receive(:new).with(projects).and_return(count_service)
expect(count_service).to receive(:refresh_cache)
subject.execute_batch_counting(projects)
end
it 'counts open issues' do
allow(::Projects::BatchOpenIssuesCountService).to receive(:new).with(projects).and_return(count_service)
expect(count_service).to receive(:refresh_cache)
subject.execute_batch_counting(projects)
end
context 'custom fork counting' do
subject do
Class.new do
include ::API::ProjectsBatchCounting
def self.forks_counting_projects(projects)
[projects.first]
end
end
end
it 'counts forks for other projects' do
allow(::Projects::BatchForksCountService).to receive(:new).with([projects.first]).and_return(count_service)
expect(count_service).to receive(:refresh_cache)
subject.execute_batch_counting(projects)
end
end
end
end
Loading
Loading
@@ -116,9 +116,9 @@ describe Gitlab::Auth::UserAuthFinders do
end
 
describe '#find_user_from_static_object_token' do
context 'when request format is archive' do
shared_examples 'static object request' do
before do
env['SCRIPT_NAME'] = 'project/-/archive/master.zip'
env['SCRIPT_NAME'] = path
end
 
context 'when token header param is present' do
Loading
Loading
@@ -126,7 +126,7 @@ describe Gitlab::Auth::UserAuthFinders do
it 'returns the user' do
request.headers['X-Gitlab-Static-Object-Token'] = user.static_object_token
 
expect(find_user_from_static_object_token(:archive)).to eq(user)
expect(find_user_from_static_object_token(format)).to eq(user)
end
end
 
Loading
Loading
@@ -134,7 +134,7 @@ describe Gitlab::Auth::UserAuthFinders do
it 'returns the user' do
request.headers['X-Gitlab-Static-Object-Token'] = 'foobar'
 
expect { find_user_from_static_object_token(:archive) }.to raise_error(Gitlab::Auth::UnauthorizedError)
expect { find_user_from_static_object_token(format) }.to raise_error(Gitlab::Auth::UnauthorizedError)
end
end
end
Loading
Loading
@@ -144,7 +144,7 @@ describe Gitlab::Auth::UserAuthFinders do
it 'returns the user' do
set_param(:token, user.static_object_token)
 
expect(find_user_from_static_object_token(:archive)).to eq(user)
expect(find_user_from_static_object_token(format)).to eq(user)
end
end
 
Loading
Loading
@@ -152,13 +152,27 @@ describe Gitlab::Auth::UserAuthFinders do
it 'returns the user' do
set_param(:token, 'foobar')
 
expect { find_user_from_static_object_token(:archive) }.to raise_error(Gitlab::Auth::UnauthorizedError)
expect { find_user_from_static_object_token(format) }.to raise_error(Gitlab::Auth::UnauthorizedError)
end
end
end
end
 
context 'when request format is not archive' do
context 'when request format is archive' do
it_behaves_like 'static object request' do
let_it_be(:path) { 'project/-/archive/master.zip' }
let_it_be(:format) { :archive }
end
end
context 'when request format is blob' do
it_behaves_like 'static object request' do
let_it_be(:path) { 'project/raw/master/README.md' }
let_it_be(:format) { :blob }
end
end
context 'when request format is not archive nor blob' do
before do
env['script_name'] = 'url'
end
Loading
Loading
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Pagination::Keyset::Page do
describe '#per_page' do
it 'limits to a maximum of 100 records per page' do
per_page = described_class.new(per_page: 101).per_page
expect(per_page).to eq(described_class::MAXIMUM_PAGE_SIZE)
end
it 'uses default value when given 0' do
per_page = described_class.new(per_page: 0).per_page
expect(per_page).to eq(described_class::DEFAULT_PAGE_SIZE)
end
it 'uses default value when given negative values' do
per_page = described_class.new(per_page: -1).per_page
expect(per_page).to eq(described_class::DEFAULT_PAGE_SIZE)
end
it 'uses the given value if it is within range' do
per_page = described_class.new(per_page: 10).per_page
expect(per_page).to eq(10)
end
end
describe '#next' do
let(:page) { described_class.new(order_by: order_by, lower_bounds: lower_bounds, per_page: per_page, end_reached: end_reached) }
subject { page.next(new_lower_bounds, new_end_reached) }
let(:order_by) { { id: :desc } }
let(:lower_bounds) { { id: 42 } }
let(:per_page) { 10 }
let(:end_reached) { false }
let(:new_lower_bounds) { { id: 21 } }
let(:new_end_reached) { true }
it 'copies over order_by' do
expect(subject.order_by).to eq(page.order_by)
end
it 'copies over per_page' do
expect(subject.per_page).to eq(page.per_page)
end
it 'dups the instance' do
expect(subject).not_to eq(page)
end
it 'sets lower_bounds only on new instance' do
expect(subject.lower_bounds).to eq(new_lower_bounds)
expect(page.lower_bounds).to eq(lower_bounds)
end
it 'sets end_reached only on new instance' do
expect(subject.end_reached?).to eq(new_end_reached)
expect(page.end_reached?).to eq(end_reached)
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Pagination::Keyset::Pager do
let(:relation) { Project.all.order(id: :asc) }
let(:request) { double('request', page: page, apply_headers: nil) }
let(:page) { Gitlab::Pagination::Keyset::Page.new(order_by: { id: :asc }, per_page: 3) }
let(:next_page) { double('next page') }
before_all do
create_list(:project, 7)
end
describe '#paginate' do
subject { described_class.new(request).paginate(relation) }
it 'loads the result relation only once' do
expect do
subject
end.not_to exceed_query_limit(1)
end
it 'passes information about next page to request' do
lower_bounds = relation.limit(page.per_page).last.slice(:id)
expect(page).to receive(:next).with(lower_bounds, false).and_return(next_page)
expect(request).to receive(:apply_headers).with(next_page)
subject
end
context 'when retrieving the last page' do
let(:relation) { Project.where('id > ?', Project.maximum(:id) - page.per_page).order(id: :asc) }
it 'indicates this is the last page' do
expect(request).to receive(:apply_headers) do |next_page|
expect(next_page.end_reached?).to be_truthy
end
subject
end
end
context 'when retrieving an empty page' do
let(:relation) { Project.where('id > ?', Project.maximum(:id) + 1).order(id: :asc) }
it 'indicates this is the last page' do
expect(request).to receive(:apply_headers) do |next_page|
expect(next_page.end_reached?).to be_truthy
end
subject
end
end
it 'returns an array with the loaded records' do
expect(subject).to eq(relation.limit(page.per_page).to_a)
end
context 'validating the order clause' do
let(:page) { Gitlab::Pagination::Keyset::Page.new(order_by: { created_at: :asc }, per_page: 3) }
it 'raises an error if has a different order clause than the page' do
expect { subject }.to raise_error(ArgumentError, /order_by does not match/)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Pagination::Keyset::RequestContext do
let(:request) { double('request', params: params) }
describe '#page' do
subject { described_class.new(request).page }
context 'with only order_by given' do
let(:params) { { order_by: :id } }
it 'extracts order_by/sorting information' do
page = subject
expect(page.order_by).to eq(id: :desc)
end
end
context 'with order_by and sort given' do
let(:params) { { order_by: :created_at, sort: :desc } }
it 'extracts order_by/sorting information and adds tie breaker' do
page = subject
expect(page.order_by).to eq(created_at: :desc, id: :desc)
end
end
context 'with no order_by information given' do
let(:params) { {} }
it 'defaults to tie breaker' do
page = subject
expect(page.order_by).to eq({ id: :desc })
end
end
context 'with per_page params given' do
let(:params) { { per_page: 10 } }
it 'extracts per_page information' do
page = subject
expect(page.per_page).to eq(params[:per_page])
end
end
end
describe '#apply_headers' do
let(:request) { double('request', url: "http://#{Gitlab.config.gitlab.host}/api/v4/projects?foo=bar") }
let(:params) { { foo: 'bar' } }
let(:request_context) { double('request context', params: params, request: request) }
let(:next_page) { double('next page', order_by: { id: :asc }, lower_bounds: { id: 42 }, end_reached?: false) }
subject { described_class.new(request_context).apply_headers(next_page) }
it 'sets Links header with same host/path as the original request' do
orig_uri = URI.parse(request_context.request.url)
expect(request_context).to receive(:header) do |name, header|
expect(name).to eq('Links')
first_link, _ = /<([^>]+)>; rel="next"/.match(header).captures
uri = URI.parse(first_link)
expect(uri.host).to eq(orig_uri.host)
expect(uri.path).to eq(orig_uri.path)
end
subject
end
it 'sets Links header with a link to the next page' do
orig_uri = URI.parse(request_context.request.url)
expect(request_context).to receive(:header) do |name, header|
expect(name).to eq('Links')
first_link, _ = /<([^>]+)>; rel="next"/.match(header).captures
query = CGI.parse(URI.parse(first_link).query)
expect(query.except('id_after')).to eq(CGI.parse(orig_uri.query).except('id_after'))
expect(query['id_after']).to eq(['42'])
end
subject
end
context 'with descending order' do
let(:next_page) { double('next page', order_by: { id: :desc }, lower_bounds: { id: 42 }, end_reached?: false) }
it 'sets Links header with a link to the next page' do
orig_uri = URI.parse(request_context.request.url)
expect(request_context).to receive(:header) do |name, header|
expect(name).to eq('Links')
first_link, _ = /<([^>]+)>; rel="next"/.match(header).captures
query = CGI.parse(URI.parse(first_link).query)
expect(query.except('id_before')).to eq(CGI.parse(orig_uri.query).except('id_before'))
expect(query['id_before']).to eq(['42'])
end
subject
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe Gitlab::Pagination::Keyset do
describe '.paginate' do
subject { described_class.paginate(request_context, relation) }
let(:request_context) { double }
let(:relation) { double }
let(:pager) { double }
let(:result) { double }
it 'uses Pager to paginate the relation' do
expect(Gitlab::Pagination::Keyset::Pager).to receive(:new).with(request_context).and_return(pager)
expect(pager).to receive(:paginate).with(relation).and_return(result)
expect(subject).to eq(result)
end
end
describe '.available?' do
subject { described_class }
let(:request_context) { double("request context", page: page)}
let(:page) { double("page", order_by: order_by) }
shared_examples_for 'keyset pagination is available' do
it 'returns true for Project' do
expect(subject.available?(request_context, Project.all)).to be_truthy
end
it 'return false for other types of relations' do
expect(subject.available?(request_context, User.all)).to be_falsey
end
end
context 'with order-by id asc' do
let(:order_by) { { id: :asc } }
it_behaves_like 'keyset pagination is available'
end
context 'with order-by id desc' do
let(:order_by) { { id: :desc } }
it_behaves_like 'keyset pagination is available'
end
context 'with other order-by columns' do
let(:order_by) { { created_at: :desc, id: :desc } }
it 'returns false for Project' do
expect(subject.available?(request_context, Project.all)).to be_falsey
end
it 'return false for other types of relations' do
expect(subject.available?(request_context, User.all)).to be_falsey
end
end
end
end
Loading
Loading
@@ -30,6 +30,16 @@ describe API::Deployments do
expect(json_response.last['iid']).to eq(deployment_3.iid)
end
 
context 'with updated_at filters specified' do
it 'returns projects deployments with last update in specified datetime range' do
get api("/projects/#{project.id}/deployments", user), params: { updated_before: 30.minutes.ago, updated_after: 90.minutes.ago }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.first['id']).to eq(deployment_3.id)
end
end
describe 'ordering' do
let(:order_by) { 'iid' }
let(:sort) { 'desc' }
Loading
Loading
Loading
Loading
@@ -237,6 +237,20 @@ describe API::Pipelines do
end
end
 
context 'when updated_at filters are specified' do
let!(:pipeline1) { create(:ci_pipeline, project: project, updated_at: 2.days.ago) }
let!(:pipeline2) { create(:ci_pipeline, project: project, updated_at: 4.days.ago) }
let!(:pipeline3) { create(:ci_pipeline, project: project, updated_at: 1.hour.ago) }
it 'returns pipelines with last update date in specified datetime range' do
get api("/projects/#{project.id}/pipelines", user), params: { updated_before: 1.day.ago, updated_after: 3.days.ago }
expect(response).to have_gitlab_http_status(:ok)
expect(response).to include_pagination_headers
expect(json_response.first['id']).to eq(pipeline1.id)
end
end
context 'when order_by and sort are specified' do
context 'when order_by user_id' do
before do
Loading
Loading
Loading
Loading
@@ -155,6 +155,35 @@ describe API::Projects do
project4
end
 
# This is a regression spec for https://gitlab.com/gitlab-org/gitlab/issues/37919
context 'batch counting forks and open issues and refreshing count caches' do
# We expect to count these projects (only the ones on the first page, not all matching ones)
let(:projects) { Project.public_to_user(nil).order(id: :desc).first(per_page) }
let(:per_page) { 2 }
let(:count_service) { double }
before do
# Create more projects, so we have more than one page
create_list(:project, 5, :public)
end
it 'batch counts project forks' do
expect(::Projects::BatchForksCountService).to receive(:new).with(projects).and_return(count_service)
expect(count_service).to receive(:refresh_cache)
get api("/projects?per_page=#{per_page}")
expect(response.status).to eq 200
end
it 'batch counts open issues' do
expect(::Projects::BatchOpenIssuesCountService).to receive(:new).with(projects).and_return(count_service)
expect(count_service).to receive(:refresh_cache)
get api("/projects?per_page=#{per_page}")
expect(response.status).to eq 200
end
end
context 'when unauthenticated' do
it_behaves_like 'projects response' do
let(:filter) { { search: project.name } }
Loading
Loading
@@ -570,6 +599,87 @@ describe API::Projects do
let(:projects) { Project.all }
end
end
context 'with keyset pagination' do
let(:current_user) { user }
let(:projects) { [public_project, project, project2, project3] }
context 'headers and records' do
let(:params) { { pagination: 'keyset', order_by: :id, sort: :asc, per_page: 1 } }
it 'includes a pagination header with link to the next page' do
get api('/projects', current_user), params: params
expect(response.header).to include('Links')
expect(response.header['Links']).to include('pagination=keyset')
expect(response.header['Links']).to include("id_after=#{public_project.id}")
end
it 'contains only the first project with per_page = 1' do
get api('/projects', current_user), params: params
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
expect(json_response.map { |p| p['id'] }).to contain_exactly(public_project.id)
end
it 'does not include a link if the end has reached and there is no more data' do
get api('/projects', current_user), params: params.merge(id_after: project2.id)
expect(response.header).not_to include('Links')
end
it 'responds with 501 if order_by is different from id' do
get api('/projects', current_user), params: params.merge(order_by: :created_at)
expect(response).to have_gitlab_http_status(405)
end
end
context 'with descending sorting' do
let(:params) { { pagination: 'keyset', order_by: :id, sort: :desc, per_page: 1 } }
it 'includes a pagination header with link to the next page' do
get api('/projects', current_user), params: params
expect(response.header).to include('Links')
expect(response.header['Links']).to include('pagination=keyset')
expect(response.header['Links']).to include("id_before=#{project3.id}")
end
it 'contains only the last project with per_page = 1' do
get api('/projects', current_user), params: params
expect(response).to have_gitlab_http_status(200)
expect(json_response).to be_an Array
expect(json_response.map { |p| p['id'] }).to contain_exactly(project3.id)
end
end
context 'retrieving the full relation' do
let(:params) { { pagination: 'keyset', order_by: :id, sort: :desc, per_page: 2 } }
it 'returns all projects' do
url = '/projects'
requests = 0
ids = []
while url && requests <= 5 # circuit breaker
requests += 1
get api(url, current_user), params: params
links = response.header['Links']
url = links&.match(/<[^>]+(\/projects\?[^>]+)>; rel="next"/) do |match|
match[1]
end
ids += JSON.parse(response.body).map { |p| p['id'] }
end
expect(ids).to contain_exactly(*projects.map(&:id))
end
end
end
end
 
describe 'POST /projects' do
Loading
Loading
Loading
Loading
@@ -91,6 +91,25 @@ describe Ci::RetryPipelineService, '#execute' do
end
end
 
context 'when there is a failed test in a DAG' do
before do
create_build('build', :success, 0)
create_build('build2', :success, 0)
test_build = create_build('test', :failed, 1)
create(:ci_build_need, build: test_build, name: 'build')
create(:ci_build_need, build: test_build, name: 'build2')
end
it 'retries the test' do
service.execute(pipeline)
expect(build('build')).to be_success
expect(build('build2')).to be_success
expect(build('test')).to be_pending
expect(build('test').needs.map(&:name)).to match_array(%w(build build2))
end
end
context 'when the last stage was skipepd' do
before do
create_build('build 1', :success, 0)
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