summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/factories/uploads.rb7
-rw-r--r--spec/fixtures/api/schemas/entities/merge_request_widget.json2
-rw-r--r--spec/helpers/submodule_helper_spec.rb21
-rw-r--r--spec/javascripts/environments/environment_item_spec.js2
-rw-r--r--spec/javascripts/environments/mock_data.js12
-rw-r--r--spec/javascripts/performance_bar/components/performance_bar_app_spec.js61
-rw-r--r--spec/javascripts/performance_bar/index_spec.js83
-rw-r--r--spec/javascripts/test_bundle.js11
-rw-r--r--spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js37
-rw-r--r--spec/javascripts/vue_mr_widget/mock_data.js2
-rw-r--r--spec/javascripts/vue_shared/components/memory_graph_spec.js2
-rw-r--r--spec/lib/gitlab/closing_issue_extractor_spec.rb14
-rw-r--r--spec/lib/gitlab/git/diff_spec.rb2
-rw-r--r--spec/lib/gitlab/git/index_spec.rb16
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb84
-rw-r--r--spec/lib/gitlab/import_export/avatar_saver_spec.rb1
-rw-r--r--spec/lib/gitlab/import_export/uploads_manager_spec.rb80
-rw-r--r--spec/lib/gitlab/import_export/uploads_saver_spec.rb5
-rw-r--r--spec/models/deployment_spec.rb18
-rw-r--r--spec/models/environment_spec.rb17
-rw-r--r--spec/requests/api/commits_spec.rb54
-rw-r--r--spec/requests/api/projects_spec.rb33
-rw-r--r--spec/serializers/merge_request_widget_entity_spec.rb15
-rw-r--r--spec/support/shared_contexts/merge_requests_allowing_collaboration.rb15
-rw-r--r--spec/uploaders/file_uploader_spec.rb9
25 files changed, 399 insertions, 204 deletions
diff --git a/spec/factories/uploads.rb b/spec/factories/uploads.rb
index b45f6f30e40..a81b2169b89 100644
--- a/spec/factories/uploads.rb
+++ b/spec/factories/uploads.rb
@@ -28,6 +28,13 @@ FactoryBot.define do
secret SecureRandom.hex
end
+ trait :with_file do
+ after(:create) do |upload|
+ FileUtils.mkdir_p(File.dirname(upload.absolute_path))
+ FileUtils.touch(upload.absolute_path)
+ end
+ end
+
trait :object_storage do
store ObjectStorage::Store::REMOTE
end
diff --git a/spec/fixtures/api/schemas/entities/merge_request_widget.json b/spec/fixtures/api/schemas/entities/merge_request_widget.json
index 38ce92a5dc7..3b741d51598 100644
--- a/spec/fixtures/api/schemas/entities/merge_request_widget.json
+++ b/spec/fixtures/api/schemas/entities/merge_request_widget.json
@@ -29,8 +29,10 @@
"merge_when_pipeline_succeeds": { "type": "boolean" },
"source_branch": { "type": "string" },
"source_project_id": { "type": "integer" },
+ "source_project_full_path": { "type": ["string", "null"]},
"target_branch": { "type": "string" },
"target_project_id": { "type": "integer" },
+ "target_project_full_path": { "type": ["string", "null"]},
"allow_collaboration": { "type": "boolean"},
"metrics": {
"oneOf": [
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index 5a2e4b34069..a64f8a11ef2 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -92,11 +92,10 @@ describe SubmoduleHelper do
context 'in-repository submodule' do
let(:group) { create(:group, name: "Master Project", path: "master-project") }
let(:project) { create(:project, group: group) }
- before do
- self.instance_variable_set(:@project, project)
- end
it 'in-repository' do
+ allow(repo).to receive(:project).and_return(project)
+
stub_url('./')
expect(submodule_links(submodule_item)).to eq(["/master-project/#{project.path}", "/master-project/#{project.path}/tree/hash"])
end
@@ -167,32 +166,28 @@ describe SubmoduleHelper do
let(:project) { create(:project, group: group) }
let(:commit_id) { sample_commit[:id] }
- before do
- self.instance_variable_set(:@project, project)
- end
-
it 'one level down' do
- result = relative_self_links('../test.git', commit_id)
+ result = relative_self_links('../test.git', commit_id, project)
expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
end
it 'with trailing whitespace' do
- result = relative_self_links('../test.git ', commit_id)
+ result = relative_self_links('../test.git ', commit_id, project)
expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
end
it 'two levels down' do
- result = relative_self_links('../../test.git', commit_id)
+ result = relative_self_links('../../test.git', commit_id, project)
expect(result).to eq(["/#{group.path}/test", "/#{group.path}/test/tree/#{commit_id}"])
end
it 'one level down with namespace and repo' do
- result = relative_self_links('../foobar/test.git', commit_id)
+ result = relative_self_links('../foobar/test.git', commit_id, project)
expect(result).to eq(["/foobar/test", "/foobar/test/tree/#{commit_id}"])
end
it 'two levels down with namespace and repo' do
- result = relative_self_links('../foobar/baz/test.git', commit_id)
+ result = relative_self_links('../foobar/baz/test.git', commit_id, project)
expect(result).to eq(["/baz/test", "/baz/test/tree/#{commit_id}"])
end
@@ -201,7 +196,7 @@ describe SubmoduleHelper do
let(:project) { create(:project, namespace: user.namespace) }
it 'one level down with personal project' do
- result = relative_self_links('../test.git', commit_id)
+ result = relative_self_links('../test.git', commit_id, project)
expect(result).to eq(["/#{user.username}/test", "/#{user.username}/test/tree/#{commit_id}"])
end
end
diff --git a/spec/javascripts/environments/environment_item_spec.js b/spec/javascripts/environments/environment_item_spec.js
index 7a34126eef7..0b933dda431 100644
--- a/spec/javascripts/environments/environment_item_spec.js
+++ b/spec/javascripts/environments/environment_item_spec.js
@@ -104,7 +104,7 @@ describe('Environment item', () => {
},
],
},
- 'stop_action?': true,
+ has_stop_action: true,
environment_path: 'root/ci-folders/environments/31',
created_at: '2016-11-07T11:11:16.525Z',
updated_at: '2016-11-10T15:55:58.778Z',
diff --git a/spec/javascripts/environments/mock_data.js b/spec/javascripts/environments/mock_data.js
index 8a1e26935d9..7bb57f938b8 100644
--- a/spec/javascripts/environments/mock_data.js
+++ b/spec/javascripts/environments/mock_data.js
@@ -7,7 +7,7 @@ export const environmentsList = [
external_url: null,
environment_type: null,
last_deployment: null,
- 'stop_action?': false,
+ has_stop_action: false,
environment_path: '/root/review-app/environments/7',
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
@@ -22,7 +22,7 @@ export const environmentsList = [
external_url: null,
environment_type: 'build',
last_deployment: null,
- 'stop_action?': false,
+ has_stop_action: false,
environment_path: '/root/review-app/environments/12',
stop_path: '/root/review-app/environments/12/stop',
created_at: '2017-02-01T19:42:18.400Z',
@@ -41,7 +41,7 @@ export const serverData = [
external_url: null,
environment_type: null,
last_deployment: null,
- 'stop_action?': false,
+ has_stop_action: false,
environment_path: '/root/review-app/environments/7',
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
@@ -58,7 +58,7 @@ export const serverData = [
external_url: null,
environment_type: 'build',
last_deployment: null,
- 'stop_action?': false,
+ has_stop_action: false,
environment_path: '/root/review-app/environments/12',
stop_path: '/root/review-app/environments/12/stop',
created_at: '2017-02-01T19:42:18.400Z',
@@ -77,7 +77,7 @@ export const environment = {
external_url: null,
environment_type: null,
last_deployment: null,
- 'stop_action?': false,
+ has_stop_action: false,
environment_path: '/root/review-app/environments/7',
stop_path: '/root/review-app/environments/7/stop',
created_at: '2017-01-31T10:53:46.894Z',
@@ -95,7 +95,7 @@ export const folder = {
external_url: null,
environment_type: 'build',
last_deployment: null,
- 'stop_action?': false,
+ has_stop_action: false,
environment_path: '/root/review-app/environments/12',
stop_path: '/root/review-app/environments/12/stop',
created_at: '2017-02-01T19:42:18.400Z',
diff --git a/spec/javascripts/performance_bar/components/performance_bar_app_spec.js b/spec/javascripts/performance_bar/components/performance_bar_app_spec.js
index 9ab9ab1c9f4..7926db44429 100644
--- a/spec/javascripts/performance_bar/components/performance_bar_app_spec.js
+++ b/spec/javascripts/performance_bar/components/performance_bar_app_spec.js
@@ -1,39 +1,15 @@
import Vue from 'vue';
-import axios from '~/lib/utils/axios_utils';
import performanceBarApp from '~/performance_bar/components/performance_bar_app.vue';
-import PerformanceBarService from '~/performance_bar/services/performance_bar_service';
import PerformanceBarStore from '~/performance_bar/stores/performance_bar_store';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
-import MockAdapter from 'axios-mock-adapter';
-describe('performance bar', () => {
- let mock;
+describe('performance bar app', () => {
let vm;
beforeEach(() => {
const store = new PerformanceBarStore();
- mock = new MockAdapter(axios);
-
- mock.onGet('/-/peek/results').reply(
- 200,
- {
- data: {
- gc: {
- invokes: 0,
- invoke_time: '0.00',
- use_size: 0,
- total_size: 0,
- total_object: 0,
- gc_time: '0.00',
- },
- host: { hostname: 'web-01' },
- },
- },
- {},
- );
-
vm = mountComponent(Vue.extend(performanceBarApp), {
store,
env: 'development',
@@ -45,44 +21,9 @@ describe('performance bar', () => {
afterEach(() => {
vm.$destroy();
- mock.restore();
});
it('sets the class to match the environment', () => {
expect(vm.$el.getAttribute('class')).toContain('development');
});
-
- describe('loadRequestDetails', () => {
- beforeEach(() => {
- spyOn(vm.store, 'addRequest').and.callThrough();
- });
-
- it('does nothing if the request cannot be tracked', () => {
- spyOn(vm.store, 'canTrackRequest').and.callFake(() => false);
-
- vm.loadRequestDetails('123', 'https://gitlab.com/');
-
- expect(vm.store.addRequest).not.toHaveBeenCalled();
- });
-
- it('adds the request immediately', () => {
- vm.loadRequestDetails('123', 'https://gitlab.com/');
-
- expect(vm.store.addRequest).toHaveBeenCalledWith(
- '123',
- 'https://gitlab.com/',
- );
- });
-
- it('makes an HTTP request for the request details', () => {
- spyOn(PerformanceBarService, 'fetchRequestDetails').and.callThrough();
-
- vm.loadRequestDetails('456', 'https://gitlab.com/');
-
- expect(PerformanceBarService.fetchRequestDetails).toHaveBeenCalledWith(
- '/-/peek/results',
- '456',
- );
- });
- });
});
diff --git a/spec/javascripts/performance_bar/index_spec.js b/spec/javascripts/performance_bar/index_spec.js
new file mode 100644
index 00000000000..1784bd64adb
--- /dev/null
+++ b/spec/javascripts/performance_bar/index_spec.js
@@ -0,0 +1,83 @@
+import axios from '~/lib/utils/axios_utils';
+import performanceBar from '~/performance_bar';
+import PerformanceBarService from '~/performance_bar/services/performance_bar_service';
+
+import MockAdapter from 'axios-mock-adapter';
+
+describe('performance bar wrapper', () => {
+ let mock;
+ let vm;
+
+ beforeEach(() => {
+ const peekWrapper = document.createElement('div');
+
+ peekWrapper.setAttribute('id', 'js-peek');
+ peekWrapper.setAttribute('data-env', 'development');
+ peekWrapper.setAttribute('data-request-id', '123');
+ peekWrapper.setAttribute('data-peek-url', '/-/peek/results');
+ peekWrapper.setAttribute('data-profile-url', '?lineprofiler=true');
+
+ document.body.appendChild(peekWrapper);
+
+ mock = new MockAdapter(axios);
+
+ mock.onGet('/-/peek/results').reply(
+ 200,
+ {
+ data: {
+ gc: {
+ invokes: 0,
+ invoke_time: '0.00',
+ use_size: 0,
+ total_size: 0,
+ total_object: 0,
+ gc_time: '0.00',
+ },
+ host: { hostname: 'web-01' },
+ },
+ },
+ {},
+ );
+
+ vm = performanceBar({ container: '#js-peek' });
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ mock.restore();
+ });
+
+ describe('loadRequestDetails', () => {
+ beforeEach(() => {
+ spyOn(vm.store, 'addRequest').and.callThrough();
+ });
+
+ it('does nothing if the request cannot be tracked', () => {
+ spyOn(vm.store, 'canTrackRequest').and.callFake(() => false);
+
+ vm.loadRequestDetails('123', 'https://gitlab.com/');
+
+ expect(vm.store.addRequest).not.toHaveBeenCalled();
+ });
+
+ it('adds the request immediately', () => {
+ vm.loadRequestDetails('123', 'https://gitlab.com/');
+
+ expect(vm.store.addRequest).toHaveBeenCalledWith(
+ '123',
+ 'https://gitlab.com/',
+ );
+ });
+
+ it('makes an HTTP request for the request details', () => {
+ spyOn(PerformanceBarService, 'fetchRequestDetails').and.callThrough();
+
+ vm.loadRequestDetails('456', 'https://gitlab.com/');
+
+ expect(PerformanceBarService.fetchRequestDetails).toHaveBeenCalledWith(
+ '/-/peek/results',
+ '456',
+ );
+ });
+ });
+});
diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js
index a0ca8f8b4c3..bc00fdfd73c 100644
--- a/spec/javascripts/test_bundle.js
+++ b/spec/javascripts/test_bundle.js
@@ -6,6 +6,7 @@ import '~/commons';
import Vue from 'vue';
import VueResource from 'vue-resource';
import Translate from '~/vue_shared/translate';
+import jasmineDiff from 'jasmine-diff';
import { getDefaultAdapter } from '~/lib/utils/axios_utils';
import { FIXTURES_PATH, TEST_HOST } from './test_constants';
@@ -35,7 +36,15 @@ Vue.use(Translate);
jasmine.getFixtures().fixturesPath = FIXTURES_PATH;
jasmine.getJSONFixtures().fixturesPath = FIXTURES_PATH;
-beforeAll(() => jasmine.addMatchers(customMatchers));
+beforeAll(() => {
+ jasmine.addMatchers(
+ jasmineDiff(jasmine, {
+ colors: true,
+ inline: true,
+ }),
+ );
+ jasmine.addMatchers(customMatchers);
+});
// globalize common libraries
window.$ = $;
diff --git a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
index 61b7bd2c226..8ac2f26979b 100644
--- a/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
+++ b/spec/javascripts/vue_mr_widget/components/mr_widget_header_spec.js
@@ -119,6 +119,7 @@ describe('MRWidgetHeader', () => {
beforeEach(() => {
vm = mountComponent(Component, {
mr: {
+ iid: 1,
divergedCommitsCount: 12,
sourceBranch: 'mr-widget-refactor',
sourceBranchLink: '<a href="/foo/bar/mr-widget-refactor">mr-widget-refactor</a>',
@@ -130,6 +131,8 @@ describe('MRWidgetHeader', () => {
emailPatchesPath: '/mr/email-patches',
plainDiffPath: '/mr/plainDiffPath',
statusPath: 'abc',
+ sourceProjectFullPath: 'root/gitlab-ce',
+ targetProjectFullPath: 'gitlab-org/gitlab-ce',
},
});
});
@@ -146,16 +149,40 @@ describe('MRWidgetHeader', () => {
const button = vm.$el.querySelector('.js-web-ide');
expect(button.textContent.trim()).toEqual('Open in Web IDE');
- expect(button.getAttribute('href')).toEqual('/-/ide/projectabc');
+ expect(button.getAttribute('href')).toEqual(
+ '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=gitlab-org%2Fgitlab-ce',
+ );
});
- it('renders web ide button with relative URL', () => {
+ it('renders web ide button with blank query string if target & source project branch', done => {
+ vm.mr.targetProjectFullPath = 'root/gitlab-ce';
+
+ vm.$nextTick(() => {
+ const button = vm.$el.querySelector('.js-web-ide');
+
+ expect(button.textContent.trim()).toEqual('Open in Web IDE');
+ expect(button.getAttribute('href')).toEqual(
+ '/-/ide/project/root/gitlab-ce/merge_requests/1?target_project=',
+ );
+
+ done();
+ });
+ });
+
+ it('renders web ide button with relative URL', done => {
gon.relative_url_root = '/gitlab';
+ vm.mr.iid = 2;
- const button = vm.$el.querySelector('.js-web-ide');
+ vm.$nextTick(() => {
+ const button = vm.$el.querySelector('.js-web-ide');
- expect(button.textContent.trim()).toEqual('Open in Web IDE');
- expect(button.getAttribute('href')).toEqual('/-/ide/projectabc');
+ expect(button.textContent.trim()).toEqual('Open in Web IDE');
+ expect(button.getAttribute('href')).toEqual(
+ '/gitlab/-/ide/project/root/gitlab-ce/merge_requests/2?target_project=gitlab-org%2Fgitlab-ce',
+ );
+
+ done();
+ });
});
it('renders download dropdown with links', () => {
diff --git a/spec/javascripts/vue_mr_widget/mock_data.js b/spec/javascripts/vue_mr_widget/mock_data.js
index 9d2a15ff009..c0b5a7d4455 100644
--- a/spec/javascripts/vue_mr_widget/mock_data.js
+++ b/spec/javascripts/vue_mr_widget/mock_data.js
@@ -29,8 +29,10 @@ export default {
source_branch: 'daaaa',
source_branch_link: 'daaaa',
source_project_id: 19,
+ source_project_full_path: '/group1/project1',
target_branch: 'master',
target_project_id: 19,
+ target_project_full_path: '/group2/project2',
metrics: {
merged_by: {
name: 'Administrator',
diff --git a/spec/javascripts/vue_shared/components/memory_graph_spec.js b/spec/javascripts/vue_shared/components/memory_graph_spec.js
index 73a69df019e..65d8ed39ade 100644
--- a/spec/javascripts/vue_shared/components/memory_graph_spec.js
+++ b/spec/javascripts/vue_shared/components/memory_graph_spec.js
@@ -113,7 +113,7 @@ describe('MemoryGraph', () => {
const circleEl = el.querySelector('circle');
expect(circleEl).toBeDefined();
expect(circleEl.getAttribute('r')).toBe('1.5');
- expect(circleEl.getAttribute('tranform')).toBe('translate(0 -1)');
+ expect(circleEl.getAttribute('transform')).toBe('translate(0 -1)');
expect(circleEl.getAttribute('cx')).toBe(`${dotX}`);
expect(circleEl.getAttribute('cy')).toBe(`${dotY}`);
done();
diff --git a/spec/lib/gitlab/closing_issue_extractor_spec.rb b/spec/lib/gitlab/closing_issue_extractor_spec.rb
index 3a0688b7cbb..1f35d1e4880 100644
--- a/spec/lib/gitlab/closing_issue_extractor_spec.rb
+++ b/spec/lib/gitlab/closing_issue_extractor_spec.rb
@@ -379,6 +379,20 @@ describe Gitlab::ClosingIssueExtractor do
.to match_array([issue, other_issue, third_issue])
end
+ it 'allows non-comma-separated issue numbers in single line message' do
+ message = "Closes #{reference} #{reference2} #{reference3}"
+
+ expect(subject.closed_by_message(message))
+ .to match_array([issue, other_issue, third_issue])
+ end
+
+ it 'allows mixed comma-separated and non-comma-separated issue numbers in single line message' do
+ message = "Closes #{reference}, #{reference2} and #{reference3}"
+
+ expect(subject.closed_by_message(message))
+ .to match_array([issue, other_issue, third_issue])
+ end
+
it 'fetches issues in multi-line message' do
message = "Awesome commit (closes #{reference})\nAlso fixes #{reference2}"
diff --git a/spec/lib/gitlab/git/diff_spec.rb b/spec/lib/gitlab/git/diff_spec.rb
index 7c3d2af819b..11ab376ab8f 100644
--- a/spec/lib/gitlab/git/diff_spec.rb
+++ b/spec/lib/gitlab/git/diff_spec.rb
@@ -269,7 +269,7 @@ EOT
before do
# TODO use a Gitaly diff object instead
rugged_commit = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- repository.lookup('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
+ repository.rugged.rev_parse('5937ac0a7beb003549fc5fd26fc247adbce4a52e')
end
@diffs = rugged_commit.parents[0].diff(rugged_commit).patches
diff --git a/spec/lib/gitlab/git/index_spec.rb b/spec/lib/gitlab/git/index_spec.rb
index 16e6bd35449..e51b875be11 100644
--- a/spec/lib/gitlab/git/index_spec.rb
+++ b/spec/lib/gitlab/git/index_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::Git::Index, seed_helper: true do
let(:index) { described_class.new(repository) }
before do
- index.read_tree(repository.lookup('master').tree)
+ index.read_tree(lookup('master').tree)
end
around do |example|
@@ -30,7 +30,7 @@ describe Gitlab::Git::Index, seed_helper: true do
entry = index.get(options[:file_path])
expect(entry).not_to be_nil
- expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
+ expect(lookup(entry[:oid]).content).to eq(options[:content])
end
end
@@ -54,7 +54,7 @@ describe Gitlab::Git::Index, seed_helper: true do
index.create(options)
entry = index.get(options[:file_path])
- expect(repository.lookup(entry[:oid]).content).to eq(Base64.decode64(options[:content]))
+ expect(lookup(entry[:oid]).content).to eq(Base64.decode64(options[:content]))
end
end
@@ -68,7 +68,7 @@ describe Gitlab::Git::Index, seed_helper: true do
index.create(options)
entry = index.get(options[:file_path])
- expect(repository.lookup(entry[:oid]).content).to eq("Hello,\nWorld")
+ expect(lookup(entry[:oid]).content).to eq("Hello,\nWorld")
end
end
end
@@ -135,7 +135,7 @@ describe Gitlab::Git::Index, seed_helper: true do
entry = index.get(options[:file_path])
- expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
+ expect(lookup(entry[:oid]).content).to eq(options[:content])
end
it 'preserves file mode' do
@@ -190,7 +190,7 @@ describe Gitlab::Git::Index, seed_helper: true do
entry = index.get(options[:file_path])
expect(entry).not_to be_nil
- expect(repository.lookup(entry[:oid]).content).to eq(options[:content])
+ expect(lookup(entry[:oid]).content).to eq(options[:content])
end
it 'preserves file mode' do
@@ -232,4 +232,8 @@ describe Gitlab::Git::Index, seed_helper: true do
end
end
end
+
+ def lookup(revision)
+ repository.rugged.rev_parse(revision)
+ end
end
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index 64b08dd9c4b..6480f6c407d 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -321,90 +321,6 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- context '#submodules' do
- around do |example|
- # TODO #submodules will be removed, has been migrated to gitaly
- Gitlab::GitalyClient::StorageSettings.allow_disk_access do
- example.run
- end
- end
-
- let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '') }
-
- context 'where repo has submodules' do
- let(:submodules) { repository.send(:submodules, 'master') }
- let(:submodule) { submodules.first }
-
- it { expect(submodules).to be_kind_of Hash }
- it { expect(submodules.empty?).to be_falsey }
-
- it 'should have valid data' do
- expect(submodule).to eq([
- "six", {
- "id" => "409f37c4f05865e4fb208c771485f211a22c4c2d",
- "name" => "six",
- "url" => "git://github.com/randx/six.git"
- }
- ])
- end
-
- it 'should handle nested submodules correctly' do
- nested = submodules['nested/six']
- expect(nested['name']).to eq('nested/six')
- expect(nested['url']).to eq('git://github.com/randx/six.git')
- expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196')
- end
-
- it 'should handle deeply nested submodules correctly' do
- nested = submodules['deeper/nested/six']
- expect(nested['name']).to eq('deeper/nested/six')
- expect(nested['url']).to eq('git://github.com/randx/six.git')
- expect(nested['id']).to eq('24fb71c79fcabc63dfd8832b12ee3bf2bf06b196')
- end
-
- it 'should not have an entry for an invalid submodule' do
- expect(submodules).not_to have_key('invalid/path')
- end
-
- it 'should not have an entry for an uncommited submodule dir' do
- submodules = repository.send(:submodules, 'fix-existing-submodule-dir')
- expect(submodules).not_to have_key('submodule-existing-dir')
- end
-
- it 'should handle tags correctly' do
- submodules = repository.send(:submodules, 'v1.2.1')
-
- expect(submodules.first).to eq([
- "six", {
- "id" => "409f37c4f05865e4fb208c771485f211a22c4c2d",
- "name" => "six",
- "url" => "git://github.com/randx/six.git"
- }
- ])
- end
-
- it 'should not break on invalid syntax' do
- allow(repository).to receive(:blob_content).and_return(<<-GITMODULES.strip_heredoc)
- [submodule "six"]
- path = six
- url = git://github.com/randx/six.git
-
- [submodule]
- foo = bar
- GITMODULES
-
- expect(submodules).to have_key('six')
- end
- end
-
- context 'where repo doesn\'t have submodules' do
- let(:submodules) { repository.send(:submodules, '6d39438') }
- it 'should return an empty hash' do
- expect(submodules).to be_empty
- end
- end
- end
-
describe '#commit_count' do
shared_examples 'simple commit counting' do
it { expect(repository.commit_count("master")).to eq(25) }
diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
index 2223f163177..90e6d653d34 100644
--- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb
@@ -9,6 +9,7 @@ describe Gitlab::ImportExport::AvatarSaver do
before do
FileUtils.mkdir_p("#{shared.export_path}/avatar/")
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
+ stub_feature_flags(import_export_object_storage: false)
end
after do
diff --git a/spec/lib/gitlab/import_export/uploads_manager_spec.rb b/spec/lib/gitlab/import_export/uploads_manager_spec.rb
new file mode 100644
index 00000000000..9c3870a0af8
--- /dev/null
+++ b/spec/lib/gitlab/import_export/uploads_manager_spec.rb
@@ -0,0 +1,80 @@
+require 'spec_helper'
+
+describe Gitlab::ImportExport::UploadsManager do
+ let(:shared) { project.import_export_shared }
+ let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
+ let(:project) { create(:project) }
+ let(:exported_file_path) { "#{shared.export_path}/uploads/#{upload.secret}/#{File.basename(upload.path)}" }
+
+ subject(:manager) { described_class.new(project: project, shared: shared) }
+
+ before do
+ allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
+ FileUtils.mkdir_p(shared.export_path)
+ end
+
+ after do
+ FileUtils.rm_rf(shared.export_path)
+ end
+
+ describe '#save' do
+ context 'when the project has uploads locally stored' do
+ let(:upload) { create(:upload, :issuable_upload, :with_file, model: project) }
+
+ before do
+ project.uploads << upload
+ end
+
+ it 'does not cause errors' do
+ manager.save
+
+ expect(shared.errors).to be_empty
+ end
+
+ it 'copies the file in the correct location when there is an upload' do
+ manager.save
+
+ expect(File).to exist(exported_file_path)
+ end
+ end
+
+ context 'using object storage' do
+ let!(:upload) { create(:upload, :issuable_upload, :object_storage, model: project) }
+
+ before do
+ stub_feature_flags(import_export_object_storage: true)
+ stub_uploads_object_storage(FileUploader)
+ end
+
+ it 'saves the file' do
+ fake_uri = double
+
+ expect(fake_uri).to receive(:open).and_return(StringIO.new('File content'))
+ expect(URI).to receive(:parse).and_return(fake_uri)
+
+ manager.save
+
+ expect(File.read(exported_file_path)).to eq('File content')
+ end
+ end
+
+ describe '#restore' do
+ context 'using object storage' do
+ before do
+ stub_feature_flags(import_export_object_storage: true)
+ stub_uploads_object_storage(FileUploader)
+
+ FileUtils.mkdir_p(File.join(shared.export_path, 'uploads/72a497a02fe3ee09edae2ed06d390038'))
+ FileUtils.touch(File.join(shared.export_path, 'uploads/72a497a02fe3ee09edae2ed06d390038', "dummy.txt"))
+ end
+
+ it 'restores the file' do
+ manager.restore
+
+ expect(project.uploads.size).to eq(1)
+ expect(project.uploads.first.build_uploader.filename).to eq('dummy.txt')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/import_export/uploads_saver_spec.rb b/spec/lib/gitlab/import_export/uploads_saver_spec.rb
index 095687fa89d..c716edd9397 100644
--- a/spec/lib/gitlab/import_export/uploads_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/uploads_saver_spec.rb
@@ -7,6 +7,7 @@ describe Gitlab::ImportExport::UploadsSaver do
let(:shared) { project.import_export_shared }
before do
+ stub_feature_flags(import_export_object_storage: false)
allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path)
end
@@ -30,7 +31,7 @@ describe Gitlab::ImportExport::UploadsSaver do
it 'copies the uploads to the export path' do
saver.save
- uploads = Dir.glob(File.join(saver.uploads_export_path, '**/*')).map { |file| File.basename(file) }
+ uploads = Dir.glob(File.join(shared.export_path, 'uploads/**/*')).map { |file| File.basename(file) }
expect(uploads).to include('banana_sample.gif')
end
@@ -52,7 +53,7 @@ describe Gitlab::ImportExport::UploadsSaver do
it 'copies the uploads to the export path' do
saver.save
- uploads = Dir.glob(File.join(saver.uploads_export_path, '**/*')).map { |file| File.basename(file) }
+ uploads = Dir.glob(File.join(shared.export_path, 'uploads/**/*')).map { |file| File.basename(file) }
expect(uploads).to include('banana_sample.gif')
end
diff --git a/spec/models/deployment_spec.rb b/spec/models/deployment_spec.rb
index e01906f4b6c..b335e0fbeb3 100644
--- a/spec/models/deployment_spec.rb
+++ b/spec/models/deployment_spec.rb
@@ -157,22 +157,4 @@ describe Deployment do
end
end
end
-
- describe '#stop_action?' do
- subject { deployment.stop_action? }
-
- context 'when no other actions' do
- let(:deployment) { build(:deployment) }
-
- it { is_expected.to be_falsey }
- end
-
- context 'when matching action is defined' do
- let(:build) { create(:ci_build) }
- let(:deployment) { FactoryBot.build(:deployment, deployable: build, on_stop: 'close_app') }
- let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
-
- it { is_expected.to be_truthy }
- end
- end
end
diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb
index 4bded9efe91..c65e0b81451 100644
--- a/spec/models/environment_spec.rb
+++ b/spec/models/environment_spec.rb
@@ -170,8 +170,8 @@ describe Environment do
end
end
- describe '#stop_action?' do
- subject { environment.stop_action? }
+ describe '#stop_action_available?' do
+ subject { environment.stop_action_available? }
context 'when no other actions' do
it { is_expected.to be_falsey }
@@ -179,8 +179,17 @@ describe Environment do
context 'when matching action is defined' do
let(:build) { create(:ci_build) }
- let!(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') }
- let!(:close_action) { create(:ci_build, :manual, pipeline: build.pipeline, name: 'close_app') }
+
+ let!(:deployment) do
+ create(:deployment, environment: environment,
+ deployable: build,
+ on_stop: 'close_app')
+ end
+
+ let!(:close_action) do
+ create(:ci_build, :manual, pipeline: build.pipeline,
+ name: 'close_app')
+ end
context 'when environment is available' do
before do
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 113703fac38..246947e58a8 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -514,6 +514,38 @@ describe API::Commits do
expect(response).to have_gitlab_http_status(400)
end
end
+
+ context 'when committing into a fork as a maintainer' do
+ include_context 'merge request allowing collaboration'
+
+ let(:project_id) { forked_project.id }
+
+ def push_params(branch_name)
+ {
+ branch: branch_name,
+ commit_message: 'Hello world',
+ actions: [
+ {
+ action: 'create',
+ file_path: 'foo/bar/baz.txt',
+ content: 'puts 8'
+ }
+ ]
+ }
+ end
+
+ it 'allows pushing to the source branch of the merge request' do
+ post api(url, user), push_params('feature')
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+
+ it 'denies pushing to another branch' do
+ post api(url, user), push_params('other-branch')
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
end
describe 'GET /projects/:id/repository/commits/:sha/refs' do
@@ -1065,11 +1097,29 @@ describe API::Commits do
it 'returns 400 if you are not allowed to push to the target branch' do
post api(route, current_user), branch: 'feature'
- expect(response).to have_gitlab_http_status(400)
- expect(json_response['message']).to eq('You are not allowed to push into this branch')
+ expect(response).to have_gitlab_http_status(:forbidden)
+ expect(json_response['message']).to match(/You are not allowed to push into this branch/)
end
end
end
+
+ context 'when cherry picking to a fork as a maintainer' do
+ include_context 'merge request allowing collaboration'
+
+ let(:project_id) { forked_project.id }
+
+ it 'allows access from a maintainer that to the source branch' do
+ post api(route, user), branch: 'feature'
+
+ expect(response).to have_gitlab_http_status(:created)
+ end
+
+ it 'denies cherry picking to another branch' do
+ post api(route, user), branch: 'master'
+
+ expect(response).to have_gitlab_http_status(:forbidden)
+ end
+ end
end
describe 'POST /projects/:id/repository/commits/:sha/comments' do
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 8389cb7cf9c..f72c01561d8 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -237,6 +237,39 @@ describe API::Projects do
end
end
+ context 'and using archived' do
+ let!(:archived_project) { create(:project, creator_id: user.id, namespace: user.namespace, archived: true) }
+
+ it 'returns archived projects' do
+ get api('/projects?archived=true', user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(Project.public_or_visible_to_user(user).where(archived: true).size)
+ expect(json_response.map { |project| project['id'] }).to include(archived_project.id)
+ end
+
+ it 'returns non-archived projects' do
+ get api('/projects?archived=false', user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.length).to eq(Project.public_or_visible_to_user(user).where(archived: false).size)
+ expect(json_response.map { |project| project['id'] }).not_to include(archived_project.id)
+ end
+
+ it 'returns every project' do
+ get api('/projects', user)
+
+ expect(response).to have_gitlab_http_status(200)
+ expect(response).to include_pagination_headers
+ expect(json_response).to be_an Array
+ expect(json_response.map { |project| project['id'] }).to contain_exactly(*Project.public_or_visible_to_user(user).pluck(:id))
+ end
+ end
+
context 'and using search' do
it_behaves_like 'projects response' do
let(:filter) { { search: project.name } }
diff --git a/spec/serializers/merge_request_widget_entity_spec.rb b/spec/serializers/merge_request_widget_entity_spec.rb
index d2072198d83..0ba2539a717 100644
--- a/spec/serializers/merge_request_widget_entity_spec.rb
+++ b/spec/serializers/merge_request_widget_entity_spec.rb
@@ -11,6 +11,21 @@ describe MergeRequestWidgetEntity do
described_class.new(resource, request: request).as_json
end
+ describe 'source_project_full_path' do
+ it 'includes the full path of the source project' do
+ expect(subject[:source_project_full_path]).to be_present
+ end
+
+ context 'when the source project is missing' do
+ it 'returns `nil` for the source project' do
+ resource.allow_broken = true
+ resource.update!(source_project: nil)
+
+ expect(subject[:source_project_full_path]).to be_nil
+ end
+ end
+ end
+
describe 'pipeline' do
let(:pipeline) { create(:ci_empty_pipeline, project: project, ref: resource.source_branch, sha: resource.source_branch_sha, head_pipeline_of: resource) }
diff --git a/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb
new file mode 100644
index 00000000000..05424d08b9d
--- /dev/null
+++ b/spec/support/shared_contexts/merge_requests_allowing_collaboration.rb
@@ -0,0 +1,15 @@
+shared_context 'merge request allowing collaboration' do
+ include ProjectForksHelper
+
+ let(:canonical) { create(:project, :public, :repository) }
+ let(:forked_project) { fork_project(canonical, nil, repository: true) }
+
+ before do
+ canonical.add_maintainer(user)
+ create(:merge_request,
+ target_project: canonical,
+ source_project: forked_project,
+ source_branch: 'feature',
+ allow_collaboration: true)
+ end
+end
diff --git a/spec/uploaders/file_uploader_spec.rb b/spec/uploaders/file_uploader_spec.rb
index 7ba28b4fc1f..3efe512a59c 100644
--- a/spec/uploaders/file_uploader_spec.rb
+++ b/spec/uploaders/file_uploader_spec.rb
@@ -124,6 +124,15 @@ describe FileUploader do
end
end
+ describe '.extract_dynamic_path' do
+ it 'works with hashed storage' do
+ path = 'export/4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a/test/uploads/72a497a02fe3ee09edae2ed06d390038/dummy.txt'
+
+ expect(described_class.extract_dynamic_path(path)[:identifier]).to eq('dummy.txt')
+ expect(described_class.extract_dynamic_path(path)[:secret]).to eq('72a497a02fe3ee09edae2ed06d390038')
+ end
+ end
+
describe '#secret' do
it 'generates a secret if none is provided' do
expect(described_class).to receive(:generate_secret).and_return('secret')