diff options
Diffstat (limited to 'spec')
-rw-r--r-- | spec/controllers/admin/gitaly_servers_controller_spec.rb | 15 | ||||
-rw-r--r-- | spec/controllers/groups_controller_spec.rb | 24 | ||||
-rw-r--r-- | spec/javascripts/job_spec.js | 21 | ||||
-rw-r--r-- | spec/javascripts/lib/utils/common_utils_spec.js | 39 | ||||
-rw-r--r-- | spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js | 131 | ||||
-rw-r--r-- | spec/lib/gitaly/server_spec.rb | 30 | ||||
-rw-r--r-- | spec/lib/gitlab/git/tree_spec.rb | 20 | ||||
-rw-r--r-- | spec/models/repository_spec.rb | 8 | ||||
-rw-r--r-- | spec/requests/api/members_spec.rb | 15 |
9 files changed, 175 insertions, 128 deletions
diff --git a/spec/controllers/admin/gitaly_servers_controller_spec.rb b/spec/controllers/admin/gitaly_servers_controller_spec.rb new file mode 100644 index 00000000000..b7378aa37d0 --- /dev/null +++ b/spec/controllers/admin/gitaly_servers_controller_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe Admin::GitalyServersController do + describe '#index' do + before do + sign_in(create(:admin)) + end + + it 'shows the gitaly servers page' do + get :index + + expect(response).to have_gitlab_http_status(200) + end + end +end diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index a9cfd964dd5..492fed42d31 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -85,6 +85,30 @@ describe GroupsController do end end + describe 'GET #activity' do + render_views + + before do + sign_in(user) + project + end + + context 'as json' do + it 'includes all projects in event feed' do + 3.times do + project = create(:project, group: group) + create(:event, project: project) + end + + get :activity, id: group.to_param, format: :json + + expect(response).to have_gitlab_http_status(200) + expect(json_response['count']).to eq(3) + expect(assigns(:projects).limit_value).to be_nil + end + end + end + describe 'POST #create' do context 'when creating subgroups', :nested_groups do [true, false].each do |can_create_group_status| diff --git a/spec/javascripts/job_spec.js b/spec/javascripts/job_spec.js index feb341d22e6..0452934ea9e 100644 --- a/spec/javascripts/job_spec.js +++ b/spec/javascripts/job_spec.js @@ -58,8 +58,7 @@ describe('Job', () => { it('updates the build trace on an interval', function () { const deferred1 = $.Deferred(); const deferred2 = $.Deferred(); - const deferred3 = $.Deferred(); - spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise(), deferred3.promise()); + spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise()); spyOn(urlUtils, 'visitUrl'); deferred1.resolve({ @@ -70,9 +69,7 @@ describe('Job', () => { complete: false, }); - deferred2.resolve(); - - deferred3.resolve({ + deferred2.resolve({ html: '<span>More</span>', status: 'running', state: 'finalstate', @@ -94,9 +91,8 @@ describe('Job', () => { it('replaces the entire build trace', () => { const deferred1 = $.Deferred(); const deferred2 = $.Deferred(); - const deferred3 = $.Deferred(); - spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise(), deferred3.promise()); + spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise()); spyOn(urlUtils, 'visitUrl'); @@ -107,9 +103,7 @@ describe('Job', () => { complete: false, }); - deferred2.resolve(); - - deferred3.resolve({ + deferred2.resolve({ html: '<span>Different</span>', status: 'running', append: false, @@ -170,9 +164,8 @@ describe('Job', () => { it('shows incremented size', () => { const deferred1 = $.Deferred(); const deferred2 = $.Deferred(); - const deferred3 = $.Deferred(); - spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise(), deferred3.promise()); + spyOn($, 'ajax').and.returnValues(deferred1.promise(), deferred2.promise()); spyOn(urlUtils, 'visitUrl'); @@ -184,8 +177,6 @@ describe('Job', () => { total: 100, }); - deferred2.resolve(); - this.job = new Job(); expect( @@ -194,7 +185,7 @@ describe('Job', () => { jasmine.clock().tick(4001); - deferred3.resolve({ + deferred2.resolve({ html: '<span>Update</span>', status: 'success', append: true, diff --git a/spec/javascripts/lib/utils/common_utils_spec.js b/spec/javascripts/lib/utils/common_utils_spec.js index 0a9d815f469..1052b4e7c20 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js +++ b/spec/javascripts/lib/utils/common_utils_spec.js @@ -1,6 +1,8 @@ /* eslint-disable promise/catch-or-return */ import * as commonUtils from '~/lib/utils/common_utils'; +import axios from '~/lib/utils/axios_utils'; +import MockAdapter from 'axios-mock-adapter'; describe('common_utils', () => { describe('parseUrl', () => { @@ -413,37 +415,48 @@ describe('common_utils', () => { describe('setCiStatusFavicon', () => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/-/jobs/1/status.json`; + let mock; beforeEach(() => { const favicon = document.createElement('link'); favicon.setAttribute('id', 'favicon'); document.body.appendChild(favicon); + mock = new MockAdapter(axios); }); afterEach(() => { + mock.restore(); document.body.removeChild(document.getElementById('favicon')); }); - it('should reset favicon in case of error', () => { - const favicon = document.getElementById('favicon'); - spyOn($, 'ajax').and.callFake(function (options) { - options.error(); - expect(favicon.getAttribute('href')).toEqual('null'); - }); + it('should reset favicon in case of error', (done) => { + mock.onGet(BUILD_URL).networkError(); - commonUtils.setCiStatusFavicon(BUILD_URL); + commonUtils.setCiStatusFavicon(BUILD_URL) + .then(() => { + const favicon = document.getElementById('favicon'); + expect(favicon.getAttribute('href')).toEqual('null'); + done(); + }) + // Error is already caught in catch() block of setCiStatusFavicon, + // It won't throw another error for us to catch + .catch(done.fail); }); - it('should set page favicon to CI status favicon based on provided status', () => { + it('should set page favicon to CI status favicon based on provided status', (done) => { const FAVICON_PATH = '//icon_status_success'; - const favicon = document.getElementById('favicon'); - spyOn($, 'ajax').and.callFake(function (options) { - options.success({ favicon: FAVICON_PATH }); - expect(favicon.getAttribute('href')).toEqual(FAVICON_PATH); + mock.onGet(BUILD_URL).reply(200, { + favicon: FAVICON_PATH, }); - commonUtils.setCiStatusFavicon(BUILD_URL); + commonUtils.setCiStatusFavicon(BUILD_URL) + .then(() => { + const favicon = document.getElementById('favicon'); + expect(favicon.getAttribute('href')).toEqual(FAVICON_PATH); + done(); + }) + .catch(done.fail); }); }); diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js index f86fb6a0b4b..637bf483deb 100644 --- a/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js +++ b/spec/javascripts/vue_mr_widget/components/mr_widget_related_links_spec.js @@ -1,117 +1,82 @@ import Vue from 'vue'; -import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links'; +import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue'; +import mountComponent from '../../helpers/vue_mount_component_helper'; -const createComponent = (data) => { - const Component = Vue.extend(relatedLinksComponent); +describe('MRWidgetRelatedLinks', () => { + let vm; - return new Component({ - el: document.createElement('div'), - propsData: data, - }); -}; + const createComponent = (data) => { + const Component = Vue.extend(relatedLinksComponent); -describe('MRWidgetRelatedLinks', () => { - describe('props', () => { - it('should have props', () => { - const { relatedLinks } = relatedLinksComponent.props; + return mountComponent(Component, data); + }; - expect(relatedLinks).toBeDefined(); - expect(relatedLinks.type instanceof Object).toBeTruthy(); - expect(relatedLinks.required).toBeTruthy(); - }); + afterEach(() => { + vm.$destroy(); }); describe('computed', () => { - const data = { - relatedLinks: { - closing: '/foo', - mentioned: '/foo', - assignToMe: '/foo', - }, - }; - - describe('hasLinks', () => { - it('should return correct value when we have links reference', () => { - const vm = createComponent(data); - expect(vm.hasLinks).toBeTruthy(); - - vm.relatedLinks.closing = null; - expect(vm.hasLinks).toBeTruthy(); - - vm.relatedLinks.mentioned = null; - expect(vm.hasLinks).toBeTruthy(); - - vm.relatedLinks.assignToMe = null; - expect(vm.hasLinks).toBeFalsy(); - }); - }); - describe('closesText', () => { - it('returns correct text for open merge request', () => { - data.state = 'open'; - const vm = createComponent(data); + it('returns Closes text for open merge request', () => { + vm = createComponent({ state: 'open', relatedLinks: {} }); expect(vm.closesText).toEqual('Closes'); }); it('returns correct text for closed merge request', () => { - data.state = 'closed'; - const vm = createComponent(data); + vm = createComponent({ state: 'closed', relatedLinks: {} }); expect(vm.closesText).toEqual('Did not close'); }); it('returns correct tense for merged request', () => { - data.state = 'merged'; - const vm = createComponent(data); + vm = createComponent({ state: 'merged', relatedLinks: {} }); expect(vm.closesText).toEqual('Closed'); }); }); }); - describe('template', () => { - it('should have only have closing issues text', () => { - const vm = createComponent({ - relatedLinks: { - closing: '<a href="#">#23</a> and <a>#42</a>', - }, - }); - const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); - - expect(content).toContain('Closes #23 and #42'); - expect(content).not.toContain('Mentions'); + it('should have only have closing issues text', () => { + vm = createComponent({ + relatedLinks: { + closing: '<a href="#">#23</a> and <a>#42</a>', + }, }); + const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); - it('should have only have mentioned issues text', () => { - const vm = createComponent({ - relatedLinks: { - mentioned: '<a href="#">#7</a>', - }, - }); + expect(content).toContain('Closes #23 and #42'); + expect(content).not.toContain('Mentions'); + }); - expect(vm.$el.innerText).toContain('Mentions #7'); - expect(vm.$el.innerText).not.toContain('Closes'); + it('should have only have mentioned issues text', () => { + vm = createComponent({ + relatedLinks: { + mentioned: '<a href="#">#7</a>', + }, }); - it('should have closing and mentioned issues at the same time', () => { - const vm = createComponent({ - relatedLinks: { - closing: '<a href="#">#7</a>', - mentioned: '<a href="#">#23</a> and <a>#42</a>', - }, - }); - const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); + expect(vm.$el.innerText).toContain('Mentions #7'); + expect(vm.$el.innerText).not.toContain('Closes'); + }); - expect(content).toContain('Closes #7'); - expect(content).toContain('Mentions #23 and #42'); + it('should have closing and mentioned issues at the same time', () => { + vm = createComponent({ + relatedLinks: { + closing: '<a href="#">#7</a>', + mentioned: '<a href="#">#23</a> and <a>#42</a>', + }, }); + const content = vm.$el.textContent.replace(/\n(\s)+/g, ' ').trim(); - it('should have assing issues link', () => { - const vm = createComponent({ - relatedLinks: { - assignToMe: '<a href="#">Assign yourself to these issues</a>', - }, - }); + expect(content).toContain('Closes #7'); + expect(content).toContain('Mentions #23 and #42'); + }); - expect(vm.$el.innerText).toContain('Assign yourself to these issues'); + it('should have assing issues link', () => { + vm = createComponent({ + relatedLinks: { + assignToMe: '<a href="#">Assign yourself to these issues</a>', + }, }); + + expect(vm.$el.innerText).toContain('Assign yourself to these issues'); }); }); diff --git a/spec/lib/gitaly/server_spec.rb b/spec/lib/gitaly/server_spec.rb new file mode 100644 index 00000000000..ed5d56e91d4 --- /dev/null +++ b/spec/lib/gitaly/server_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe Gitaly::Server do + describe '.all' do + let(:storages) { Gitlab.config.repositories.storages } + + it 'includes all storages' do + expect(storages.count).to eq(described_class.all.count) + expect(storages.keys).to eq(described_class.all.map(&:storage)) + end + end + + subject { described_class.all.first } + + it { is_expected.to respond_to(:server_version) } + it { is_expected.to respond_to(:git_binary_version) } + it { is_expected.to respond_to(:up_to_date?) } + it { is_expected.to respond_to(:address) } + + describe 'request memoization' do + context 'when requesting multiple properties', :request_store do + it 'uses memoization for the info request' do + expect do + subject.server_version + subject.up_to_date? + end.to change { Gitlab::GitalyClient.get_request_count }.by(1) + end + end + end +end diff --git a/spec/lib/gitlab/git/tree_spec.rb b/spec/lib/gitlab/git/tree_spec.rb index 86f7bcb8e38..001e406a930 100644 --- a/spec/lib/gitlab/git/tree_spec.rb +++ b/spec/lib/gitlab/git/tree_spec.rb @@ -80,22 +80,18 @@ describe Gitlab::Git::Tree, seed_helper: true do end describe '#where' do - context 'with gitaly disabled' do - before do - allow(Gitlab::GitalyClient).to receive(:feature_enabled?).and_return(false) - end - - it 'calls #tree_entries_from_rugged' do - expect(described_class).to receive(:tree_entries_from_rugged) - - described_class.where(repository, SeedRepo::Commit::ID, '/') + shared_examples '#where' do + it 'returns an empty array when called with an invalid ref' do + expect(described_class.where(repository, 'foobar-does-not-exist')).to eq([]) end end - it 'gets the tree entries from GitalyClient' do - expect_any_instance_of(Gitlab::GitalyClient::CommitService).to receive(:tree_entries) + context 'with gitaly' do + it_behaves_like '#where' + end - described_class.where(repository, SeedRepo::Commit::ID, '/') + context 'without gitaly', :skip_gitaly_mock do + it_behaves_like '#where' end end end diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb index d4070b320ed..1102b1c9006 100644 --- a/spec/models/repository_spec.rb +++ b/spec/models/repository_spec.rb @@ -772,8 +772,7 @@ describe Repository do user, 'LICENSE', 'Copyright!', message: 'Add LICENSE', branch_name: 'master') - allow(repository).to receive(:file_on_head) - .and_raise(Rugged::ReferenceError) + allow(repository).to receive(:root_ref).and_raise(Gitlab::Git::Repository::NoRepository) expect(repository.license_blob).to be_nil end @@ -885,7 +884,7 @@ describe Repository do end it 'returns nil for empty repository' do - allow(repository).to receive(:file_on_head).and_raise(Rugged::ReferenceError) + allow(repository).to receive(:root_ref).and_raise(Gitlab::Git::Repository::NoRepository) expect(repository.gitlab_ci_yml).to be_nil end end @@ -1937,8 +1936,7 @@ describe Repository do describe '#avatar' do it 'returns nil if repo does not exist' do - expect(repository).to receive(:file_on_head) - .and_raise(Rugged::ReferenceError) + allow(repository).to receive(:root_ref).and_raise(Gitlab::Git::Repository::NoRepository) expect(repository.avatar).to eq(nil) end diff --git a/spec/requests/api/members_spec.rb b/spec/requests/api/members_spec.rb index 73bd4785b11..ec500838eb2 100644 --- a/spec/requests/api/members_spec.rb +++ b/spec/requests/api/members_spec.rb @@ -44,6 +44,21 @@ describe API::Members do end end + it 'avoids N+1 queries' do + # Establish baseline + get api("/#{source_type.pluralize}/#{source.id}/members", master) + + control = ActiveRecord::QueryRecorder.new do + get api("/#{source_type.pluralize}/#{source.id}/members", master) + end + + project.add_developer(create(:user)) + + expect do + get api("/#{source_type.pluralize}/#{source.id}/members", master) + end.not_to exceed_query_limit(control) + end + it 'does not return invitees' do create(:"#{source_type}_member", invite_token: '123', invite_email: 'test@abc.com', source: source, user: nil) |