diff options
author | Z.J. van de Weg <git@zjvandeweg.nl> | 2017-06-01 10:31:33 +0200 |
---|---|---|
committer | Z.J. van de Weg <git@zjvandeweg.nl> | 2017-06-01 10:31:33 +0200 |
commit | 00b00f1edee71d236b0cd5b796bb68f15142911f (patch) | |
tree | 471ef31c0c455abe44f04dcd7d2ba84e87f22be1 /spec/models | |
parent | f4aa01053ed39a265ddfd9ee6e9618bd3406e59d (diff) | |
parent | dd0f8b8ccc3b5f61e31703f7391a919b702934a5 (diff) | |
download | gitlab-ce-00b00f1edee71d236b0cd5b796bb68f15142911f.tar.gz |
Merge branch 'master' into zj-realtime-env-list
Diffstat (limited to 'spec/models')
22 files changed, 481 insertions, 374 deletions
diff --git a/spec/models/ci/pipeline_schedule_spec.rb b/spec/models/ci/pipeline_schedule_spec.rb index 822b98c5f6c..b00e7a73571 100644 --- a/spec/models/ci/pipeline_schedule_spec.rb +++ b/spec/models/ci/pipeline_schedule_spec.rb @@ -25,6 +25,14 @@ describe Ci::PipelineSchedule, models: true do expect(pipeline_schedule).not_to be_valid end + + context 'when active is false' do + it 'does not allow nullified ref' do + pipeline_schedule = build(:ci_pipeline_schedule, :inactive, ref: nil) + + expect(pipeline_schedule).not_to be_valid + end + end end describe '#set_next_run_at' do diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 56b24ce62f3..ae1b01b76ab 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -21,13 +21,35 @@ describe Ci::Pipeline, models: true do it { is_expected.to have_many(:auto_canceled_pipelines) } it { is_expected.to have_many(:auto_canceled_jobs) } - it { is_expected.to validate_presence_of :sha } - it { is_expected.to validate_presence_of :status } + it { is_expected.to validate_presence_of(:sha) } + it { is_expected.to validate_presence_of(:status) } it { is_expected.to respond_to :git_author_name } it { is_expected.to respond_to :git_author_email } it { is_expected.to respond_to :short_sha } + describe '#source' do + context 'when creating new pipeline' do + let(:pipeline) do + build(:ci_empty_pipeline, status: :created, project: project, source: nil) + end + + it "prevents from creating an object" do + expect(pipeline).not_to be_valid + end + end + + context 'when updating existing pipeline' do + before do + pipeline.update_attribute(:source, nil) + end + + it "object is valid" do + expect(pipeline).to be_valid + end + end + end + describe '#block' do it 'changes pipeline status to manual' do expect(pipeline.block).to be true @@ -965,7 +987,7 @@ describe Ci::Pipeline, models: true do end before do - ProjectWebHookWorker.drain + WebHookWorker.drain end context 'with pipeline hooks enabled' do diff --git a/spec/models/concerns/routable_spec.rb b/spec/models/concerns/routable_spec.rb index 49a4132f763..0e10d91836d 100644 --- a/spec/models/concerns/routable_spec.rb +++ b/spec/models/concerns/routable_spec.rb @@ -115,123 +115,6 @@ describe Group, 'Routable' do end end - describe '.member_descendants' do - let!(:user) { create(:user) } - let!(:nested_group) { create(:group, parent: group) } - - before { group.add_owner(user) } - subject { described_class.member_descendants(user.id) } - - it { is_expected.to eq([nested_group]) } - end - - describe '.member_self_and_descendants' do - let!(:user) { create(:user) } - let!(:nested_group) { create(:group, parent: group) } - - before { group.add_owner(user) } - subject { described_class.member_self_and_descendants(user.id) } - - it { is_expected.to match_array [group, nested_group] } - end - - describe '.member_hierarchy' do - # foo/bar would also match foo/barbaz instead of just foo/bar and foo/bar/baz - let!(:user) { create(:user) } - - # group - # _______ (foo) _______ - # | | - # | | - # nested_group_1 nested_group_2 - # (bar) (barbaz) - # | | - # | | - # nested_group_1_1 nested_group_2_1 - # (baz) (baz) - # - let!(:nested_group_1) { create :group, parent: group, name: 'bar' } - let!(:nested_group_1_1) { create :group, parent: nested_group_1, name: 'baz' } - let!(:nested_group_2) { create :group, parent: group, name: 'barbaz' } - let!(:nested_group_2_1) { create :group, parent: nested_group_2, name: 'baz' } - - context 'user is not a member of any group' do - subject { described_class.member_hierarchy(user.id) } - - it 'returns an empty array' do - is_expected.to eq [] - end - end - - context 'user is member of all groups' do - before do - group.add_owner(user) - nested_group_1.add_owner(user) - nested_group_1_1.add_owner(user) - nested_group_2.add_owner(user) - nested_group_2_1.add_owner(user) - end - subject { described_class.member_hierarchy(user.id) } - - it 'returns all groups' do - is_expected.to match_array [ - group, - nested_group_1, nested_group_1_1, - nested_group_2, nested_group_2_1 - ] - end - end - - context 'user is member of the top group' do - before { group.add_owner(user) } - subject { described_class.member_hierarchy(user.id) } - - it 'returns all groups' do - is_expected.to match_array [ - group, - nested_group_1, nested_group_1_1, - nested_group_2, nested_group_2_1 - ] - end - end - - context 'user is member of the first child (internal node), branch 1' do - before { nested_group_1.add_owner(user) } - subject { described_class.member_hierarchy(user.id) } - - it 'returns the groups in the hierarchy' do - is_expected.to match_array [ - group, - nested_group_1, nested_group_1_1 - ] - end - end - - context 'user is member of the first child (internal node), branch 2' do - before { nested_group_2.add_owner(user) } - subject { described_class.member_hierarchy(user.id) } - - it 'returns the groups in the hierarchy' do - is_expected.to match_array [ - group, - nested_group_2, nested_group_2_1 - ] - end - end - - context 'user is member of the last child (leaf node)' do - before { nested_group_1_1.add_owner(user) } - subject { described_class.member_hierarchy(user.id) } - - it 'returns the groups in the hierarchy' do - is_expected.to match_array [ - group, - nested_group_1, nested_group_1_1 - ] - end - end - end - describe '#full_path' do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } diff --git a/spec/models/diff_note_spec.rb b/spec/models/diff_note_spec.rb index ab4c51a87b0..96f075d4f7d 100644 --- a/spec/models/diff_note_spec.rb +++ b/spec/models/diff_note_spec.rb @@ -145,7 +145,7 @@ describe DiffNote, models: true do context "when the merge request's diff refs don't match that of the diff note" do before do - allow(subject.noteable).to receive(:diff_sha_refs).and_return(commit.diff_refs) + allow(subject.noteable).to receive(:diff_refs).and_return(commit.diff_refs) end it "returns false" do @@ -194,7 +194,7 @@ describe DiffNote, models: true do context "when the note is outdated" do before do - allow(merge_request).to receive(:diff_sha_refs).and_return(commit.diff_refs) + allow(merge_request).to receive(:diff_refs).and_return(commit.diff_refs) end it "uses the DiffPositionUpdateService" do diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index b6162908e12..fe69c8e351d 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -247,7 +247,10 @@ describe Environment, models: true do context 'when user is allowed to stop environment' do before do - project.add_master(user) + project.add_developer(user) + + create(:protected_branch, :developers_can_merge, + name: 'master', project: project) end context 'when action did not yet finish' do diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 6ca1eb0374d..316bf153660 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -340,7 +340,7 @@ describe Group, models: true do it { expect(subject.parent).to be_kind_of(Group) } end - describe '#members_with_parents' do + describe '#members_with_parents', :nested_groups do let!(:group) { create(:group, :nested) } let!(:master) { group.parent.add_user(create(:user), GroupMember::MASTER) } let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) } diff --git a/spec/models/hooks/service_hook_spec.rb b/spec/models/hooks/service_hook_spec.rb index 1a83c836652..57454d2a773 100644 --- a/spec/models/hooks/service_hook_spec.rb +++ b/spec/models/hooks/service_hook_spec.rb @@ -1,36 +1,19 @@ -require "spec_helper" +require 'spec_helper' describe ServiceHook, models: true do - describe "Associations" do + describe 'associations' do it { is_expected.to belong_to :service } end - describe "execute" do - before(:each) do - @service_hook = create(:service_hook) - @data = { project_id: 1, data: {} } + describe 'execute' do + let(:hook) { build(:service_hook) } + let(:data) { { key: 'value' } } - WebMock.stub_request(:post, @service_hook.url) - end - - it "POSTs to the webhook URL" do - @service_hook.execute(@data) - expect(WebMock).to have_requested(:post, @service_hook.url).with( - headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Service Hook' } - ).once - end - - it "POSTs the data as JSON" do - @service_hook.execute(@data) - expect(WebMock).to have_requested(:post, @service_hook.url).with( - headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Service Hook' } - ).once - end - - it "catches exceptions" do - expect(WebHook).to receive(:post).and_raise("Some HTTP Post error") + it '#execute' do + expect(WebHookService).to receive(:new).with(hook, data, 'service_hook').and_call_original + expect_any_instance_of(WebHookService).to receive(:execute) - expect { @service_hook.execute(@data) }.to raise_error(RuntimeError) + hook.execute(data) end end end diff --git a/spec/models/hooks/system_hook_spec.rb b/spec/models/hooks/system_hook_spec.rb index 4340170888d..0d2b622132e 100644 --- a/spec/models/hooks/system_hook_spec.rb +++ b/spec/models/hooks/system_hook_spec.rb @@ -126,4 +126,26 @@ describe SystemHook, models: true do expect(SystemHook.repository_update_hooks).to eq([hook]) end end + + describe 'execute WebHookService' do + let(:hook) { build(:system_hook) } + let(:data) { { key: 'value' } } + let(:hook_name) { 'system_hook' } + + before do + expect(WebHookService).to receive(:new).with(hook, data, hook_name).and_call_original + end + + it '#execute' do + expect_any_instance_of(WebHookService).to receive(:execute) + + hook.execute(data, hook_name) + end + + it '#async_execute' do + expect_any_instance_of(WebHookService).to receive(:async_execute) + + hook.async_execute(data, hook_name) + end + end end diff --git a/spec/models/hooks/web_hook_log_spec.rb b/spec/models/hooks/web_hook_log_spec.rb new file mode 100644 index 00000000000..c649cf3b589 --- /dev/null +++ b/spec/models/hooks/web_hook_log_spec.rb @@ -0,0 +1,30 @@ +require 'rails_helper' + +describe WebHookLog, models: true do + it { is_expected.to belong_to(:web_hook) } + + it { is_expected.to serialize(:request_headers).as(Hash) } + it { is_expected.to serialize(:request_data).as(Hash) } + it { is_expected.to serialize(:response_headers).as(Hash) } + + it { is_expected.to validate_presence_of(:web_hook) } + + describe '#success?' do + let(:web_hook_log) { build(:web_hook_log, response_status: status) } + + describe '2xx' do + let(:status) { '200' } + it { expect(web_hook_log.success?).to be_truthy } + end + + describe 'not 2xx' do + let(:status) { '500' } + it { expect(web_hook_log.success?).to be_falsey } + end + + describe 'internal erorr' do + let(:status) { 'internal error' } + it { expect(web_hook_log.success?).to be_falsey } + end + end +end diff --git a/spec/models/hooks/web_hook_spec.rb b/spec/models/hooks/web_hook_spec.rb index 9d4db1bfb52..53157c24477 100644 --- a/spec/models/hooks/web_hook_spec.rb +++ b/spec/models/hooks/web_hook_spec.rb @@ -1,89 +1,54 @@ require 'spec_helper' describe WebHook, models: true do - describe "Validations" do + let(:hook) { build(:project_hook) } + + describe 'associations' do + it { is_expected.to have_many(:web_hook_logs).dependent(:destroy) } + end + + describe 'validations' do it { is_expected.to validate_presence_of(:url) } describe 'url' do - it { is_expected.to allow_value("http://example.com").for(:url) } - it { is_expected.to allow_value("https://example.com").for(:url) } - it { is_expected.to allow_value(" https://example.com ").for(:url) } - it { is_expected.to allow_value("http://test.com/api").for(:url) } - it { is_expected.to allow_value("http://test.com/api?key=abc").for(:url) } - it { is_expected.to allow_value("http://test.com/api?key=abc&type=def").for(:url) } + it { is_expected.to allow_value('http://example.com').for(:url) } + it { is_expected.to allow_value('https://example.com').for(:url) } + it { is_expected.to allow_value(' https://example.com ').for(:url) } + it { is_expected.to allow_value('http://test.com/api').for(:url) } + it { is_expected.to allow_value('http://test.com/api?key=abc').for(:url) } + it { is_expected.to allow_value('http://test.com/api?key=abc&type=def').for(:url) } - it { is_expected.not_to allow_value("example.com").for(:url) } - it { is_expected.not_to allow_value("ftp://example.com").for(:url) } - it { is_expected.not_to allow_value("herp-and-derp").for(:url) } + it { is_expected.not_to allow_value('example.com').for(:url) } + it { is_expected.not_to allow_value('ftp://example.com').for(:url) } + it { is_expected.not_to allow_value('herp-and-derp').for(:url) } it 'strips :url before saving it' do - hook = create(:project_hook, url: ' https://example.com ') + hook.url = ' https://example.com ' + hook.save expect(hook.url).to eq('https://example.com') end end end - describe "execute" do - let(:project) { create(:empty_project) } - let(:project_hook) { create(:project_hook) } - - before(:each) do - project.hooks << [project_hook] - @data = { before: 'oldrev', after: 'newrev', ref: 'ref' } - - WebMock.stub_request(:post, project_hook.url) - end - - context 'when token is defined' do - let(:project_hook) { create(:project_hook, :token) } - - it 'POSTs to the webhook URL' do - project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, project_hook.url).with( - headers: { 'Content-Type' => 'application/json', - 'X-Gitlab-Event' => 'Push Hook', - 'X-Gitlab-Token' => project_hook.token } - ).once - end - end - - it "POSTs to the webhook URL" do - project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, project_hook.url).with( - headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Push Hook' } - ).once - end - - it "POSTs the data as JSON" do - project_hook.execute(@data, 'push_hooks') - expect(WebMock).to have_requested(:post, project_hook.url).with( - headers: { 'Content-Type' => 'application/json', 'X-Gitlab-Event' => 'Push Hook' } - ).once - end - - it "catches exceptions" do - expect(WebHook).to receive(:post).and_raise("Some HTTP Post error") - - expect { project_hook.execute(@data, 'push_hooks') }.to raise_error(RuntimeError) - end - - it "handles SSL exceptions" do - expect(WebHook).to receive(:post).and_raise(OpenSSL::SSL::SSLError.new('SSL error')) + describe 'execute' do + let(:data) { { key: 'value' } } + let(:hook_name) { 'project hook' } - expect(project_hook.execute(@data, 'push_hooks')).to eq([false, 'SSL error']) + before do + expect(WebHookService).to receive(:new).with(hook, data, hook_name).and_call_original end - it "handles 200 status code" do - WebMock.stub_request(:post, project_hook.url).to_return(status: 200, body: "Success") + it '#execute' do + expect_any_instance_of(WebHookService).to receive(:execute) - expect(project_hook.execute(@data, 'push_hooks')).to eq([200, 'Success']) + hook.execute(data, hook_name) end - it "handles 2xx status codes" do - WebMock.stub_request(:post, project_hook.url).to_return(status: 201, body: "Success") + it '#async_execute' do + expect_any_instance_of(WebHookService).to receive(:async_execute) - expect(project_hook.execute(@data, 'push_hooks')).to eq([201, 'Success']) + hook.async_execute(data, hook_name) end end end diff --git a/spec/models/label_spec.rb b/spec/models/label_spec.rb index 80ca19acdda..84867e3d96b 100644 --- a/spec/models/label_spec.rb +++ b/spec/models/label_spec.rb @@ -49,6 +49,23 @@ describe Label, models: true do expect(label.color).to eq('#abcdef') end + + it 'uses default color if color is missing' do + label = described_class.new(color: nil) + + expect(label.color).to be(Label::DEFAULT_COLOR) + end + end + + describe '#text_color' do + it 'uses default color if color is missing' do + expect(LabelsHelper).to receive(:text_color_for_bg).with(Label::DEFAULT_COLOR). + and_return(spy) + + label = described_class.new(color: nil) + + label.text_color + end end describe '#title' do diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index 87ea2e70680..cf9c701e8c5 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -22,16 +22,15 @@ describe ProjectMember, models: true do end describe '.add_user' do - context 'when called with the project owner' do - it 'adds the user as a member' do - project = create(:empty_project) + it 'adds the user as a member' do + user = create(:user) + project = create(:empty_project) - expect(project.users).not_to include(project.owner) + expect(project.users).not_to include(user) - described_class.add_user(project, project.owner, :master, current_user: project.owner) + described_class.add_user(project, user, :master, current_user: project.owner) - expect(project.users.reload).to include(project.owner) - end + expect(project.users.reload).to include(user) end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index da915c49d3c..712470d6bf5 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1243,7 +1243,7 @@ describe MergeRequest, models: true do end end - describe "#diff_sha_refs" do + describe "#diff_refs" do context "with diffs" do subject { create(:merge_request, :with_diffs) } @@ -1252,7 +1252,7 @@ describe MergeRequest, models: true do expect_any_instance_of(Repository).not_to receive(:commit) - subject.diff_sha_refs + subject.diff_refs end it "returns expected diff_refs" do @@ -1262,7 +1262,7 @@ describe MergeRequest, models: true do head_sha: subject.merge_request_diff.head_commit_sha ) - expect(subject.diff_sha_refs).to eq(expected_diff_refs) + expect(subject.diff_refs).to eq(expected_diff_refs) end end end diff --git a/spec/models/milestone_spec.rb b/spec/models/milestone_spec.rb index e3e8e6d571c..aa1ce89ffd7 100644 --- a/spec/models/milestone_spec.rb +++ b/spec/models/milestone_spec.rb @@ -249,4 +249,17 @@ describe Milestone, models: true do expect(milestone.to_reference(another_project)).to eq "sample-project%1" end end + + describe '#participants' do + let(:project) { build(:empty_project, name: 'sample-project') } + let(:milestone) { build(:milestone, iid: 1, project: project) } + + it 'returns participants without duplicates' do + user = create :user + create :issue, project: project, milestone: milestone, assignees: [user] + create :issue, project: project, milestone: milestone, assignees: [user] + + expect(milestone.participants).to eq [user] + end + end end diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb index 312302afdbb..0e74f1ab1bd 100644 --- a/spec/models/namespace_spec.rb +++ b/spec/models/namespace_spec.rb @@ -238,8 +238,8 @@ describe Namespace, models: true do end context 'in sub-groups' do - let(:parent) { create(:namespace, path: 'parent') } - let(:child) { create(:namespace, parent: parent, path: 'child') } + let(:parent) { create(:group, path: 'parent') } + let(:child) { create(:group, parent: parent, path: 'child') } let!(:project) { create(:project_empty_repo, namespace: child) } let(:path_in_dir) { File.join(repository_storage_path, 'parent', 'child') } let(:deleted_path) { File.join('parent', "child+#{child.id}+deleted") } @@ -287,21 +287,21 @@ describe Namespace, models: true do end end - describe '#ancestors' do + describe '#ancestors', :nested_groups do let(:group) { create(:group) } let(:nested_group) { create(:group, parent: group) } let(:deep_nested_group) { create(:group, parent: nested_group) } let(:very_deep_nested_group) { create(:group, parent: deep_nested_group) } it 'returns the correct ancestors' do - expect(very_deep_nested_group.ancestors).to eq([group, nested_group, deep_nested_group]) - expect(deep_nested_group.ancestors).to eq([group, nested_group]) - expect(nested_group.ancestors).to eq([group]) + expect(very_deep_nested_group.ancestors).to include(group, nested_group, deep_nested_group) + expect(deep_nested_group.ancestors).to include(group, nested_group) + expect(nested_group.ancestors).to include(group) expect(group.ancestors).to eq([]) end end - describe '#descendants' do + describe '#descendants', :nested_groups do let!(:group) { create(:group, path: 'git_lab') } let!(:nested_group) { create(:group, parent: group) } let!(:deep_nested_group) { create(:group, parent: nested_group) } @@ -311,9 +311,9 @@ describe Namespace, models: true do it 'returns the correct descendants' do expect(very_deep_nested_group.descendants.to_a).to eq([]) - expect(deep_nested_group.descendants.to_a).to eq([very_deep_nested_group]) - expect(nested_group.descendants.to_a).to eq([deep_nested_group, very_deep_nested_group]) - expect(group.descendants.to_a).to eq([nested_group, deep_nested_group, very_deep_nested_group]) + expect(deep_nested_group.descendants.to_a).to include(very_deep_nested_group) + expect(nested_group.descendants.to_a).to include(deep_nested_group, very_deep_nested_group) + expect(group.descendants.to_a).to include(nested_group, deep_nested_group, very_deep_nested_group) end end diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb index 9b711bfc007..4161b9158b1 100644 --- a/spec/models/project_group_link_spec.rb +++ b/spec/models/project_group_link_spec.rb @@ -23,7 +23,7 @@ describe ProjectGroupLink do expect(project_group_link).not_to be_valid end - it "doesn't allow a project to be shared with an ancestor of the group it is in" do + it "doesn't allow a project to be shared with an ancestor of the group it is in", :nested_groups do project_group_link.group = parent_group expect(project_group_link).not_to be_valid diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb index 4bca0229e7a..1920b5bf42b 100644 --- a/spec/models/project_services/jira_service_spec.rb +++ b/spec/models/project_services/jira_service_spec.rb @@ -22,6 +22,42 @@ describe JiraService, models: true do it { is_expected.not_to validate_presence_of(:url) } end + + context 'validating urls' do + let(:service) do + described_class.new( + project: create(:empty_project), + active: true, + username: 'username', + password: 'test', + project_key: 'TEST', + jira_issue_transition_id: 24, + url: 'http://jira.test.com' + ) + end + + it 'is valid when all fields have required values' do + expect(service).to be_valid + end + + it 'is not valid when url is not a valid url' do + service.url = 'not valid' + + expect(service).not_to be_valid + end + + it 'is not valid when api url is not a valid url' do + service.api_url = 'not valid' + + expect(service).not_to be_valid + end + + it 'is valid when api url is a valid url' do + service.api_url = 'http://jira.test.com/api' + + expect(service).to be_valid + end + end end describe '#reference_pattern' do @@ -97,6 +133,7 @@ describe JiraService, models: true do allow(JIRA::Resource::Issue).to receive(:find).and_return(open_issue, closed_issue) allow_any_instance_of(JIRA::Resource::Issue).to receive(:key).and_return("JIRA-123") + allow(JIRA::Resource::Remotelink).to receive(:all).and_return([]) @jira_service.save @@ -187,22 +224,29 @@ describe JiraService, models: true do describe '#test_settings' do let(:jira_service) do described_class.new( + project: create(:project), url: 'http://jira.example.com', - username: 'gitlab_jira_username', - password: 'gitlab_jira_password', + username: 'jira_username', + password: 'jira_password', project_key: 'GitLabProject' ) end - let(:project_url) { 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/project/GitLabProject' } - before do + def test_settings(api_url) + project_url = "http://jira_username:jira_password@#{api_url}/rest/api/2/project/GitLabProject" + WebMock.stub_request(:get, project_url) - end - it 'tries to get JIRA project' do jira_service.test_settings + end + + it 'tries to get JIRA project with URL when API URL not set' do + test_settings('jira.example.com') + end - expect(WebMock).to have_requested(:get, project_url) + it 'tries to get JIRA project with API URL if set' do + jira_service.update(api_url: 'http://jira.api.com') + test_settings('jira.api.com') end end @@ -214,34 +258,75 @@ describe JiraService, models: true do @jira_service = JiraService.create!( project: project, properties: { - url: 'http://jira.example.com/rest/api/2', + url: 'http://jira.example.com/web', username: 'mic', password: "password" } ) end - it "reset password if url changed" do - @jira_service.url = 'http://jira_edited.example.com/rest/api/2' - @jira_service.save - expect(@jira_service.password).to be_nil + context 'when only web url present' do + it 'reset password if url changed' do + @jira_service.url = 'http://jira_edited.example.com/rest/api/2' + @jira_service.save + + expect(@jira_service.password).to be_nil + end + + it 'reset password if url not changed but api url added' do + @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2' + @jira_service.save + + expect(@jira_service.password).to be_nil + end end - it "does not reset password if username changed" do - @jira_service.username = "some_name" + context 'when both web and api url present' do + before do + @jira_service.api_url = 'http://jira.example.com/rest/api/2' + @jira_service.password = 'password' + + @jira_service.save + end + it 'reset password if api url changed' do + @jira_service.api_url = 'http://jira_edited.example.com/rest/api/2' + @jira_service.save + + expect(@jira_service.password).to be_nil + end + + it 'does not reset password if url changed' do + @jira_service.url = 'http://jira_edited.example.com/rweb' + @jira_service.save + + expect(@jira_service.password).to eq("password") + end + + it 'reset password if api url set to ""' do + @jira_service.api_url = '' + @jira_service.save + + expect(@jira_service.password).to be_nil + end + end + + it 'does not reset password if username changed' do + @jira_service.username = 'some_name' @jira_service.save - expect(@jira_service.password).to eq("password") + + expect(@jira_service.password).to eq('password') end - it "does not reset password if new url is set together with password, even if it's the same password" do + it 'does not reset password if new url is set together with password, even if it\'s the same password' do @jira_service.url = 'http://jira_edited.example.com/rest/api/2' @jira_service.password = 'password' @jira_service.save - expect(@jira_service.password).to eq("password") - expect(@jira_service.url).to eq("http://jira_edited.example.com/rest/api/2") + + expect(@jira_service.password).to eq('password') + expect(@jira_service.url).to eq('http://jira_edited.example.com/rest/api/2') end - it "resets password if url changed, even if setter called multiple times" do + it 'resets password if url changed, even if setter called multiple times' do @jira_service.url = 'http://jira1.example.com/rest/api/2' @jira_service.url = 'http://jira1.example.com/rest/api/2' @jira_service.save @@ -249,7 +334,7 @@ describe JiraService, models: true do end end - context "when no password was previously set" do + context 'when no password was previously set' do before do @jira_service = JiraService.create( project: project, @@ -260,26 +345,16 @@ describe JiraService, models: true do ) end - it "saves password if new url is set together with password" do + it 'saves password if new url is set together with password' do @jira_service.url = 'http://jira_edited.example.com/rest/api/2' @jira_service.password = 'password' @jira_service.save - expect(@jira_service.password).to eq("password") - expect(@jira_service.url).to eq("http://jira_edited.example.com/rest/api/2") + expect(@jira_service.password).to eq('password') + expect(@jira_service.url).to eq('http://jira_edited.example.com/rest/api/2') end end end - describe "Validations" do - context "active" do - before do - subject.active = true - end - - it { is_expected.to validate_presence_of :url } - end - end - describe 'description and title' do let(:project) { create(:empty_project) } @@ -321,9 +396,10 @@ describe JiraService, models: true do context 'when gitlab.yml was initialized' do before do settings = { - "jira" => { - "title" => "Jira", - "url" => "http://jira.sample/projects/project_a" + 'jira' => { + 'title' => 'Jira', + 'url' => 'http://jira.sample/projects/project_a', + 'api_url' => 'http://jira.sample/api' } } allow(Gitlab.config).to receive(:issues_tracker).and_return(settings) @@ -335,8 +411,9 @@ describe JiraService, models: true do end it 'is prepopulated with the settings' do - expect(@service.properties["title"]).to eq('Jira') - expect(@service.properties["url"]).to eq('http://jira.sample/projects/project_a') + expect(@service.properties['title']).to eq('Jira') + expect(@service.properties['url']).to eq('http://jira.sample/projects/project_a') + expect(@service.properties['api_url']).to eq('http://jira.sample/api') end end end diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index c1c2f2a7219..0dcf4a4b5d6 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -13,7 +13,7 @@ describe KubernetesService, models: true, caching: true do let(:discovery_url) { service.api_url + '/api/v1' } let(:discovery_response) { { body: kube_discovery_body.to_json } } - let(:pods_url) { service.api_url + "/api/v1/namespaces/#{service.namespace}/pods" } + let(:pods_url) { service.api_url + "/api/v1/namespaces/#{service.actual_namespace}/pods" } let(:pods_response) { { body: kube_pods_body(kube_pod).to_json } } def stub_kubeclient_discover @@ -100,7 +100,35 @@ describe KubernetesService, models: true, caching: true do it 'sets the namespace to the default' do expect(kube_namespace).not_to be_nil - expect(kube_namespace[:placeholder]).to match(/\A#{Gitlab::Regex::PATH_REGEX_STR}-\d+\z/) + expect(kube_namespace[:placeholder]).to match(/\A#{Gitlab::PathRegex::PATH_REGEX_STR}-\d+\z/) + end + end + end + + describe '#actual_namespace' do + subject { service.actual_namespace } + + it "returns the default namespace" do + is_expected.to eq(service.send(:default_namespace)) + end + + context 'when namespace is specified' do + before do + service.namespace = 'my-namespace' + end + + it "returns the user-namespace" do + is_expected.to eq('my-namespace') + end + end + + context 'when service is not assigned to project' do + before do + service.project = nil + end + + it "does not return namespace" do + is_expected.to be_nil end end end @@ -187,13 +215,14 @@ describe KubernetesService, models: true, caching: true do kube_namespace = subject.predefined_variables.find { |h| h[:key] == 'KUBE_NAMESPACE' } expect(kube_namespace).not_to be_nil - expect(kube_namespace[:value]).to match(/\A#{Gitlab::Regex::PATH_REGEX_STR}-\d+\z/) + expect(kube_namespace[:value]).to match(/\A#{Gitlab::PathRegex::PATH_REGEX_STR}-\d+\z/) end end end describe '#terminals' do let(:environment) { build(:environment, project: project, name: "env", slug: "env-000000") } + subject { service.terminals(environment) } context 'with invalid pods' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index f2b4e9070b4..da1b29a2bda 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -948,6 +948,20 @@ describe Project, models: true do end end + describe '.starred_by' do + it 'returns only projects starred by the given user' do + user1 = create(:user) + user2 = create(:user) + project1 = create(:empty_project) + project2 = create(:empty_project) + create(:empty_project) + user1.toggle_star(project1) + user2.toggle_star(project2) + + expect(Project.starred_by(user1)).to contain_exactly(project1) + end + end + describe '.visible_to_user' do let!(:project) { create(:empty_project, :private) } let!(:user) { create(:user) } @@ -1431,6 +1445,31 @@ describe Project, models: true do end end + describe 'Project import job' do + let(:project) { create(:empty_project) } + let(:mirror) { false } + + before do + allow_any_instance_of(Gitlab::Shell).to receive(:import_repository) + .with(project.repository_storage_path, project.path_with_namespace, project.import_url) + .and_return(true) + + allow(project).to receive(:repository_exists?).and_return(true) + + expect_any_instance_of(Repository).to receive(:after_import) + .and_call_original + end + + it 'imports a project' do + expect_any_instance_of(RepositoryImportWorker).to receive(:perform).and_call_original + + project.import_start + project.add_import_job + + expect(project.reload.import_status).to eq('finished') + end + end + describe '#latest_successful_builds_for' do def create_pipeline(status = 'success') create(:ci_pipeline, project: project, @@ -1884,19 +1923,9 @@ describe Project, models: true do describe '#http_url_to_repo' do let(:project) { create :empty_project } - context 'when no user is given' do - it 'returns the url to the repo without a username' do - expect(project.http_url_to_repo).to eq("#{project.web_url}.git") - expect(project.http_url_to_repo).not_to include('@') - end - end - - context 'when user is given' do - it 'returns the url to the repo with the username' do - user = build_stubbed(:user) - - expect(project.http_url_to_repo(user)).to start_with("http://#{user.username}@") - end + it 'returns the url to the repo without a username' do + expect(project.http_url_to_repo).to eq("#{project.web_url}.git") + expect(project.http_url_to_repo).not_to include('@') end end diff --git a/spec/models/project_team_spec.rb b/spec/models/project_team_spec.rb index 942eeab251d..fb2d5f60009 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -81,7 +81,7 @@ describe ProjectTeam, models: true do user = create(:user) project.add_guest(user) - expect(project.team.members).to contain_exactly(user) + expect(project.team.members).to contain_exactly(user, project.owner) end it 'returns project members of a specified level' do @@ -100,7 +100,8 @@ describe ProjectTeam, models: true do group_access: Gitlab::Access::GUEST ) - expect(project.team.members).to contain_exactly(group_member.user) + expect(project.team.members). + to contain_exactly(group_member.user, project.owner) end it 'returns invited members of a group of a specified level' do @@ -137,7 +138,10 @@ describe ProjectTeam, models: true do describe '#find_member' do context 'personal project' do - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) do + create(:empty_project, :public, :access_requestable) + end + let(:requester) { create(:user) } before do @@ -200,7 +204,9 @@ describe ProjectTeam, models: true do let(:requester) { create(:user) } context 'personal project' do - let(:project) { create(:empty_project, :public, :access_requestable) } + let(:project) do + create(:empty_project, :public, :access_requestable) + end context 'when project is not shared with group' do before do @@ -244,7 +250,9 @@ describe ProjectTeam, models: true do context 'group project' do let(:group) { create(:group, :access_requestable) } - let!(:project) { create(:empty_project, group: group) } + let!(:project) do + create(:empty_project, group: group) + end before do group.add_master(master) @@ -265,8 +273,15 @@ describe ProjectTeam, models: true do let(:group) { create(:group) } let(:developer) { create(:user) } let(:master) { create(:user) } - let(:personal_project) { create(:empty_project, namespace: developer.namespace) } - let(:group_project) { create(:empty_project, namespace: group) } + + let(:personal_project) do + create(:empty_project, namespace: developer.namespace) + end + + let(:group_project) do + create(:empty_project, namespace: group) + end + let(:members_project) { create(:empty_project) } let(:shared_project) { create(:empty_project) } diff --git a/spec/models/project_wiki_spec.rb b/spec/models/project_wiki_spec.rb index 969e9f7a130..224067f58dd 100644 --- a/spec/models/project_wiki_spec.rb +++ b/spec/models/project_wiki_spec.rb @@ -37,21 +37,11 @@ describe ProjectWiki, models: true do describe "#http_url_to_repo" do let(:project) { create :empty_project } - context 'when no user is given' do - it 'returns the url to the repo without a username' do - expected_url = "#{Gitlab.config.gitlab.url}/#{subject.path_with_namespace}.git" + it 'returns the full http url to the repo' do + expected_url = "#{Gitlab.config.gitlab.url}/#{subject.path_with_namespace}.git" - expect(project_wiki.http_url_to_repo).to eq(expected_url) - expect(project_wiki.http_url_to_repo).not_to include('@') - end - end - - context 'when user is given' do - it 'returns the url to the repo with the username' do - user = build_stubbed(:user) - - expect(project_wiki.http_url_to_repo(user)).to start_with("http://#{user.username}@") - end + expect(project_wiki.http_url_to_repo).to eq(expected_url) + expect(project_wiki.http_url_to_repo).not_to include('@') end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index aabdac4bb75..fe9df3360ff 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -627,16 +627,6 @@ describe User, models: true do it { expect(User.without_projects).to include user_without_project2 } end - describe '.not_in_project' do - before do - User.delete_all - @user = create :user - @project = create(:empty_project) - end - - it { expect(User.not_in_project(@project)).to include(@user, @project.owner) } - end - describe 'user creation' do describe 'normal user' do let(:user) { create(:user, name: 'John Smith') } @@ -1506,25 +1496,6 @@ describe User, models: true do end end - describe '#viewable_starred_projects' do - let(:user) { create(:user) } - let(:public_project) { create(:empty_project, :public) } - let(:private_project) { create(:empty_project, :private) } - let(:private_viewable_project) { create(:empty_project, :private) } - - before do - private_viewable_project.team << [user, Gitlab::Access::MASTER] - - [public_project, private_project, private_viewable_project].each do |project| - user.toggle_star(project) - end - end - - it 'returns only starred projects the user can view' do - expect(user.viewable_starred_projects).not_to include(private_project) - end - end - describe '#projects_with_reporter_access_limited_to' do let(:project1) { create(:empty_project) } let(:project2) { create(:empty_project) } @@ -1561,48 +1532,103 @@ describe User, models: true do end end - describe '#nested_groups' do + describe '#all_expanded_groups' do + # foo/bar would also match foo/barbaz instead of just foo/bar and foo/bar/baz let!(:user) { create(:user) } - let!(:group) { create(:group) } - let!(:nested_group) { create(:group, parent: group) } - before do - group.add_owner(user) + # group + # _______ (foo) _______ + # | | + # | | + # nested_group_1 nested_group_2 + # (bar) (barbaz) + # | | + # | | + # nested_group_1_1 nested_group_2_1 + # (baz) (baz) + # + let!(:group) { create :group } + let!(:nested_group_1) { create :group, parent: group, name: 'bar' } + let!(:nested_group_1_1) { create :group, parent: nested_group_1, name: 'baz' } + let!(:nested_group_2) { create :group, parent: group, name: 'barbaz' } + let!(:nested_group_2_1) { create :group, parent: nested_group_2, name: 'baz' } + + subject { user.all_expanded_groups } - # Add more data to ensure method does not include wrong groups - create(:group).add_owner(create(:user)) + context 'user is not a member of any group' do + it 'returns an empty array' do + is_expected.to eq([]) + end end - it { expect(user.nested_groups).to eq([nested_group]) } - end + context 'user is member of all groups' do + before do + group.add_owner(user) + nested_group_1.add_owner(user) + nested_group_1_1.add_owner(user) + nested_group_2.add_owner(user) + nested_group_2_1.add_owner(user) + end - describe '#all_expanded_groups' do - let!(:user) { create(:user) } - let!(:group) { create(:group) } - let!(:nested_group_1) { create(:group, parent: group) } - let!(:nested_group_2) { create(:group, parent: group) } + it 'returns all groups' do + is_expected.to match_array [ + group, + nested_group_1, nested_group_1_1, + nested_group_2, nested_group_2_1 + ] + end + end - before { nested_group_1.add_owner(user) } + context 'user is member of the top group' do + before { group.add_owner(user) } - it { expect(user.all_expanded_groups).to match_array [group, nested_group_1] } - end + if Group.supports_nested_groups? + it 'returns all groups' do + is_expected.to match_array [ + group, + nested_group_1, nested_group_1_1, + nested_group_2, nested_group_2_1 + ] + end + else + it 'returns the top-level groups' do + is_expected.to match_array [group] + end + end + end - describe '#nested_groups_projects' do - let!(:user) { create(:user) } - let!(:group) { create(:group) } - let!(:nested_group) { create(:group, parent: group) } - let!(:project) { create(:empty_project, namespace: group) } - let!(:nested_project) { create(:empty_project, namespace: nested_group) } + context 'user is member of the first child (internal node), branch 1', :nested_groups do + before { nested_group_1.add_owner(user) } - before do - group.add_owner(user) + it 'returns the groups in the hierarchy' do + is_expected.to match_array [ + group, + nested_group_1, nested_group_1_1 + ] + end + end + + context 'user is member of the first child (internal node), branch 2', :nested_groups do + before { nested_group_2.add_owner(user) } - # Add more data to ensure method does not include wrong projects - other_project = create(:empty_project, namespace: create(:group, :nested)) - other_project.add_developer(create(:user)) + it 'returns the groups in the hierarchy' do + is_expected.to match_array [ + group, + nested_group_2, nested_group_2_1 + ] + end end - it { expect(user.nested_groups_projects).to eq([nested_project]) } + context 'user is member of the last child (leaf node)', :nested_groups do + before { nested_group_1_1.add_owner(user) } + + it 'returns the groups in the hierarchy' do + is_expected.to match_array [ + group, + nested_group_1, nested_group_1_1 + ] + end + end end describe '#refresh_authorized_projects', redis: true do @@ -1622,10 +1648,6 @@ describe User, models: true do expect(user.project_authorizations.count).to eq(2) end - it 'sets the authorized_projects_populated column' do - expect(user.authorized_projects_populated).to eq(true) - end - it 'stores the correct access levels' do expect(user.project_authorizations.where(access_level: Gitlab::Access::GUEST).exists?).to eq(true) expect(user.project_authorizations.where(access_level: Gitlab::Access::REPORTER).exists?).to eq(true) @@ -1735,7 +1757,7 @@ describe User, models: true do end end - context 'with 2FA requirement on nested parent group' do + context 'with 2FA requirement on nested parent group', :nested_groups do let!(:group1) { create :group, require_two_factor_authentication: true } let!(:group1a) { create :group, require_two_factor_authentication: false, parent: group1 } @@ -1750,7 +1772,7 @@ describe User, models: true do end end - context 'with 2FA requirement on nested child group' do + context 'with 2FA requirement on nested child group', :nested_groups do let!(:group1) { create :group, require_two_factor_authentication: false } let!(:group1a) { create :group, require_two_factor_authentication: true, parent: group1 } |