From 429c9220f0ce49fa54ea640cbfc78e3591202138 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Mon, 12 Dec 2016 09:31:48 +0100 Subject: Setup mattermost session --- spec/lib/mattermost/mattermost_spec.rb | 42 ++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 spec/lib/mattermost/mattermost_spec.rb (limited to 'spec') diff --git a/spec/lib/mattermost/mattermost_spec.rb b/spec/lib/mattermost/mattermost_spec.rb new file mode 100644 index 00000000000..7c99b4df9f3 --- /dev/null +++ b/spec/lib/mattermost/mattermost_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Mattermost::Mattermost do + let(:user) { create(:user) } + + subject { described_class.new('http://localhost:8065', user) } + + # Needed for doorman to function + it { is_expected.to respond_to(:current_resource_owner) } + it { is_expected.to respond_to(:request) } + it { is_expected.to respond_to(:authorization) } + it { is_expected.to respond_to(:strategy) } + + describe '#with session' do + let!(:stub) do + WebMock.stub_request(:get, 'http://localhost:8065/api/v3/oauth/gitlab/login'). + to_return(headers: { 'location' => 'http://mylocation.com' }, status: 307) + end + + context 'without oauth uri' do + it 'makes a request to the oauth uri' do + expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) + end + + context 'with oauth_uri' do + let!(:doorkeeper) do + Doorkeeper::Application.create(name: "GitLab Mattermost", + redirect_uri: "http://localhost:8065/signup/gitlab/complete\nhttp://localhost:8065/login/gitlab/complete", + scopes: "") + end + + context 'without token_uri' do + it 'can not create a session' do + expect do + subject.with_session + end.to raise_error(Mattermost::NoSessionError) + end + end + end + end + end +end -- cgit v1.2.1 From e485b3f6ad3c220655e4aa909d93bca7a4ae6afc Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 15 Dec 2016 00:28:55 +0800 Subject: Give forbidden if project for the build was deleted Closes #25309 --- spec/requests/ci/api/builds_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'spec') diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 80652129928..d61a9afd12e 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -329,6 +329,25 @@ describe Ci::API::Builds do end end end + + context 'when project for the build has been deleted' do + let(:build) do + create(:ci_build, + :pending, + :trace, + runner_id: runner.id, + pipeline: pipeline) + end + + it 'responds with forbidden' do + expect(response.status).to eq 403 + end + + def initial_patch_the_trace + build.project.update(pending_delete: true) + super + end + end end context 'when Runner makes a force-patch' do -- cgit v1.2.1 From 4ae28cb31d9f0915aac647e1befa61067b6932f1 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 15 Dec 2016 17:30:49 +0000 Subject: Changes after review --- spec/features/projects/pipelines/pipeline_spec.rb | 91 +++++++++++++++-------- 1 file changed, 58 insertions(+), 33 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 80a596d34c9..9d43d264bdf 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -39,62 +39,87 @@ describe "Pipelines", feature: true, js: true do end context 'pipeline graph' do - it 'shows a running icon and a cancel action for the running build' do - title = "#{@running.name} - #{@running.status}" - - page.within("a[data-title='#{title}']") do - expect(page).to have_selector('.ci-status-icon-running') - expect(page).to have_content('deploy') + context 'running build' do + it 'shows a running icon and a cancel action for the running build' do + page.within('a[data-title="deploy - running"]') do + expect(page).to have_selector('.ci-status-icon-running') + expect(page).to have_content('deploy') + end + + page.within('a[data-title="deploy - running"] + .ci-action-icon-container') do + expect(page).to have_selector('.ci-action-icon-container .fa-ban') + end end - page.within("a[data-title='#{title}'] + .ci-action-icon-container") do - expect(page).to have_selector('.ci-action-icon-container .fa-ban') - end + it 'should be possible to cancel the running build' do + find('a[data-title="deploy - running"] + .ci-action-icon-container').trigger('click') + expect(page).not_to have_content('Cancel running') + end end - it 'shows the success icon and a retry action for the successfull build' do - title = "#{@success.name} - #{@success.status}" + context 'success build' do + it 'shows the success icon and a retry action for the successfull build' do + page.within('a[data-title="build - passed"]') do + expect(page).to have_selector('.ci-status-icon-success') + expect(page).to have_content('build') + end - page.within("a[data-title='#{title}']") do - expect(page).to have_selector('.ci-status-icon-success') - expect(page).to have_content('build') + page.within('a[data-title="build - passed"] + .ci-action-icon-container') do + expect(page).to have_selector('.ci-action-icon-container .fa-refresh') + end end - page.within("a[data-title='#{title}'] + .ci-action-icon-container") do - expect(page).to have_selector('.ci-action-icon-container .fa-refresh') + it 'should be possible to retry the success build' do + find('a[data-title="build - passed"] + .ci-action-icon-container').trigger('click') + + expect(page).not_to have_content('Retry build') end end - it 'shows the failed icon and a retry action for the failed build' do - title = "#{@failed.name} - #{@failed.status}" + context 'failed build' do + it 'shows the failed icon and a retry action for the failed build' do + page.within('a[data-title="test - failed"]') do + expect(page).to have_selector('.ci-status-icon-failed') + expect(page).to have_content('test') + end - page.within("a[data-title='#{title}']") do - expect(page).to have_selector('.ci-status-icon-failed') - expect(page).to have_content('test') + page.within('a[data-title="test - failed"] + .ci-action-icon-container') do + expect(page).to have_selector('.ci-action-icon-container .fa-refresh') + end end - page.within("a[data-title='#{title}'] + .ci-action-icon-container") do - expect(page).to have_selector('.ci-action-icon-container .fa-refresh') + it 'should be possible to retry the failed build' do + find('a[data-title="test - failed"] + .ci-action-icon-container').trigger('click') + + expect(page).not_to have_content('Retry build') end end - it 'shows the skipped icon and a play action for the manual build' do - title = "#{@manual.name} - #{@manual.status}" + context 'manual build' do + it 'shows the skipped icon and a play action for the manual build' do + page.within('a[data-title="manual build - manual play action"]') do + expect(page).to have_selector('.ci-status-icon-skipped') + expect(page).to have_content('manual') + end - page.within("a[data-title='#{title}']") do - expect(page).to have_selector('.ci-status-icon-skipped') - expect(page).to have_content('manual') + page.within('a[data-title="manual build - manual play action"] + .ci-action-icon-container') do + expect(page).to have_selector('.ci-action-icon-container .fa-play') + end end - page.within("a[data-title='#{title}'] + .ci-action-icon-container") do - expect(page).to have_selector('.ci-action-icon-container .fa-play') + it 'should be possible to play the manual build' do + find('a[data-title="manual build - manual play action"] + .ci-action-icon-container').trigger('click') + + expect(page).not_to have_content('Play build') end end - it 'shows the success icon and the generic comit status build' do - expect(page).to have_selector('.ci-status-icon-success') - expect(page).to have_content('jenkins') + context 'external build' do + it 'shows the success icon and the generic comit status build' do + expect(page).to have_selector('.ci-status-icon-success') + expect(page).to have_content('jenkins') + end end end -- cgit v1.2.1 From 4b23764da7622ae6bc40697c7c623df901cae01b Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Thu, 15 Dec 2016 14:32:50 +0100 Subject: Improve session tests --- spec/lib/mattermost/mattermost_spec.rb | 42 --------------------- spec/lib/mattermost/session_spec.rb | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 42 deletions(-) delete mode 100644 spec/lib/mattermost/mattermost_spec.rb create mode 100644 spec/lib/mattermost/session_spec.rb (limited to 'spec') diff --git a/spec/lib/mattermost/mattermost_spec.rb b/spec/lib/mattermost/mattermost_spec.rb deleted file mode 100644 index 7c99b4df9f3..00000000000 --- a/spec/lib/mattermost/mattermost_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'spec_helper' - -describe Mattermost::Mattermost do - let(:user) { create(:user) } - - subject { described_class.new('http://localhost:8065', user) } - - # Needed for doorman to function - it { is_expected.to respond_to(:current_resource_owner) } - it { is_expected.to respond_to(:request) } - it { is_expected.to respond_to(:authorization) } - it { is_expected.to respond_to(:strategy) } - - describe '#with session' do - let!(:stub) do - WebMock.stub_request(:get, 'http://localhost:8065/api/v3/oauth/gitlab/login'). - to_return(headers: { 'location' => 'http://mylocation.com' }, status: 307) - end - - context 'without oauth uri' do - it 'makes a request to the oauth uri' do - expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) - end - - context 'with oauth_uri' do - let!(:doorkeeper) do - Doorkeeper::Application.create(name: "GitLab Mattermost", - redirect_uri: "http://localhost:8065/signup/gitlab/complete\nhttp://localhost:8065/login/gitlab/complete", - scopes: "") - end - - context 'without token_uri' do - it 'can not create a session' do - expect do - subject.with_session - end.to raise_error(Mattermost::NoSessionError) - end - end - end - end - end -end diff --git a/spec/lib/mattermost/session_spec.rb b/spec/lib/mattermost/session_spec.rb new file mode 100644 index 00000000000..a93bab877da --- /dev/null +++ b/spec/lib/mattermost/session_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe Mattermost::Session do + let(:user) { create(:user) } + + subject { described_class.new('http://localhost:8065', user) } + + # Needed for doorkeeper to function + it { is_expected.to respond_to(:current_resource_owner) } + it { is_expected.to respond_to(:request) } + it { is_expected.to respond_to(:authorization) } + it { is_expected.to respond_to(:strategy) } + + describe '#with session' do + let(:location) { 'http://location.tld' } + let!(:stub) do + WebMock.stub_request(:get, 'http://localhost:8065/api/v3/oauth/gitlab/login'). + to_return(headers: { 'location' => location }, status: 307) + end + + context 'without oauth uri' do + it 'makes a request to the oauth uri' do + expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) + end + end + + context 'with oauth_uri' do + let!(:doorkeeper) do + Doorkeeper::Application.create(name: "GitLab Mattermost", + redirect_uri: "http://localhost:8065/signup/gitlab/complete\nhttp://localhost:8065/login/gitlab/complete", + scopes: "") + end + + context 'without token_uri' do + it 'can not create a session' do + expect do + subject.with_session + end.to raise_error(Mattermost::NoSessionError) + end + end + + context 'with token_uri' do + let(:state) { "eyJhY3Rpb24iOiJsb2dpbiIsImhhc2giOiIkMmEkMTAkVC9wYVlEaTdIUS8vcWdKRmdOOUllZUptaUNJWUlvNVNtNEcwU2NBMXFqelNOVmVPZ1cxWUsifQ%3D%3D" } + let(:location) { "http://locahost:8065/oauth/authorize?response_type=code&client_id=#{doorkeeper.uid}&redirect_uri=http%3A%2F%2Flocalhost:8065%2Fsignup%2Fgitlab%2Fcomplete&state=#{state}" } + + before do + WebMock.stub_request(:get, /http:\/\/localhost:8065\/signup\/gitlab\/complete*/). + to_return(headers: { 'token' => 'thisworksnow' }, status: 202) + end + + it 'can setup a session' do + expect(subject).to receive(:destroy) + + subject.with_session { 1 + 1 } + end + + it 'returns the value of the block' do + WebMock.stub_request(:post, "http://localhost:8065/api/v3/users/logout"). + to_return(headers: { 'token' => 'thisworksnow' }, status: 200) + + value = subject.with_session { 1 + 1 } + + expect(value).to be(2) + end + end + end + end +end -- cgit v1.2.1 From 178638c4b2fa6634dc0aaa0ef13fb5a14eb7021f Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Mon, 12 Dec 2016 09:31:48 +0100 Subject: Setup mattermost session --- spec/lib/mattermost/mattermost_spec.rb | 42 ++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 spec/lib/mattermost/mattermost_spec.rb (limited to 'spec') diff --git a/spec/lib/mattermost/mattermost_spec.rb b/spec/lib/mattermost/mattermost_spec.rb new file mode 100644 index 00000000000..7c99b4df9f3 --- /dev/null +++ b/spec/lib/mattermost/mattermost_spec.rb @@ -0,0 +1,42 @@ +require 'spec_helper' + +describe Mattermost::Mattermost do + let(:user) { create(:user) } + + subject { described_class.new('http://localhost:8065', user) } + + # Needed for doorman to function + it { is_expected.to respond_to(:current_resource_owner) } + it { is_expected.to respond_to(:request) } + it { is_expected.to respond_to(:authorization) } + it { is_expected.to respond_to(:strategy) } + + describe '#with session' do + let!(:stub) do + WebMock.stub_request(:get, 'http://localhost:8065/api/v3/oauth/gitlab/login'). + to_return(headers: { 'location' => 'http://mylocation.com' }, status: 307) + end + + context 'without oauth uri' do + it 'makes a request to the oauth uri' do + expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) + end + + context 'with oauth_uri' do + let!(:doorkeeper) do + Doorkeeper::Application.create(name: "GitLab Mattermost", + redirect_uri: "http://localhost:8065/signup/gitlab/complete\nhttp://localhost:8065/login/gitlab/complete", + scopes: "") + end + + context 'without token_uri' do + it 'can not create a session' do + expect do + subject.with_session + end.to raise_error(Mattermost::NoSessionError) + end + end + end + end + end +end -- cgit v1.2.1 From dd385c7c3d3046da18c6c251bce25afab1129662 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Thu, 15 Dec 2016 14:32:50 +0100 Subject: Improve session tests --- spec/lib/mattermost/mattermost_spec.rb | 42 --------------------- spec/lib/mattermost/session_spec.rb | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 42 deletions(-) delete mode 100644 spec/lib/mattermost/mattermost_spec.rb create mode 100644 spec/lib/mattermost/session_spec.rb (limited to 'spec') diff --git a/spec/lib/mattermost/mattermost_spec.rb b/spec/lib/mattermost/mattermost_spec.rb deleted file mode 100644 index 7c99b4df9f3..00000000000 --- a/spec/lib/mattermost/mattermost_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require 'spec_helper' - -describe Mattermost::Mattermost do - let(:user) { create(:user) } - - subject { described_class.new('http://localhost:8065', user) } - - # Needed for doorman to function - it { is_expected.to respond_to(:current_resource_owner) } - it { is_expected.to respond_to(:request) } - it { is_expected.to respond_to(:authorization) } - it { is_expected.to respond_to(:strategy) } - - describe '#with session' do - let!(:stub) do - WebMock.stub_request(:get, 'http://localhost:8065/api/v3/oauth/gitlab/login'). - to_return(headers: { 'location' => 'http://mylocation.com' }, status: 307) - end - - context 'without oauth uri' do - it 'makes a request to the oauth uri' do - expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) - end - - context 'with oauth_uri' do - let!(:doorkeeper) do - Doorkeeper::Application.create(name: "GitLab Mattermost", - redirect_uri: "http://localhost:8065/signup/gitlab/complete\nhttp://localhost:8065/login/gitlab/complete", - scopes: "") - end - - context 'without token_uri' do - it 'can not create a session' do - expect do - subject.with_session - end.to raise_error(Mattermost::NoSessionError) - end - end - end - end - end -end diff --git a/spec/lib/mattermost/session_spec.rb b/spec/lib/mattermost/session_spec.rb new file mode 100644 index 00000000000..aa56a56db81 --- /dev/null +++ b/spec/lib/mattermost/session_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe Mattermost::Session do + let(:user) { create(:user) } + + subject { described_class.new('http://localhost:8065', user) } + + # Needed for doorman to function + it { is_expected.to respond_to(:current_resource_owner) } + it { is_expected.to respond_to(:request) } + it { is_expected.to respond_to(:authorization) } + it { is_expected.to respond_to(:strategy) } + + describe '#with session' do + let(:location) { 'http://location.tld' } + let!(:stub) do + WebMock.stub_request(:get, 'http://localhost:8065/api/v3/oauth/gitlab/login'). + to_return(headers: { 'location' => location }, status: 307) + end + + context 'without oauth uri' do + it 'makes a request to the oauth uri' do + expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) + end + end + + context 'with oauth_uri' do + let!(:doorkeeper) do + Doorkeeper::Application.create(name: "GitLab Mattermost", + redirect_uri: "http://localhost:8065/signup/gitlab/complete\nhttp://localhost:8065/login/gitlab/complete", + scopes: "") + end + + context 'without token_uri' do + it 'can not create a session' do + expect do + subject.with_session + end.to raise_error(Mattermost::NoSessionError) + end + end + + context 'with token_uri' do + let(:state) { "eyJhY3Rpb24iOiJsb2dpbiIsImhhc2giOiIkMmEkMTAkVC9wYVlEaTdIUS8vcWdKRmdOOUllZUptaUNJWUlvNVNtNEcwU2NBMXFqelNOVmVPZ1cxWUsifQ%3D%3D" } + let(:location) { "http://locahost:8065/oauth/authorize?response_type=code&client_id=#{doorkeeper.uid}&redirect_uri=http%3A%2F%2Flocalhost:8065%2Fsignup%2Fgitlab%2Fcomplete&state=#{state}" } + + before do + WebMock.stub_request(:get, /http:\/\/localhost:8065\/signup\/gitlab\/complete*/). + to_return(headers: { 'token' => 'thisworksnow' }, status: 202) + end + + it 'can setup a session' do + expect(subject).to receive(:destroy) + + subject.with_session { 1 + 1 } + end + + it 'returns the value of the block' do + WebMock.stub_request(:post, "http://localhost:8065/api/v3/users/logout"). + to_return(headers: { 'token' => 'thisworksnow' }, status: 200) + + value = subject.with_session { 1 + 1 } + + expect(value).to be(2) + end + end + end + end +end -- cgit v1.2.1 From 0045996728308bcb7643618ab48efb7e04e7d4bf Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Thu, 15 Dec 2016 20:19:42 +0100 Subject: Add auto configure of commands --- spec/lib/mattermost/team_spec.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 spec/lib/mattermost/team_spec.rb (limited to 'spec') diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb new file mode 100644 index 00000000000..a3b0831659f --- /dev/null +++ b/spec/lib/mattermost/team_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe Mattermost::Team do + let(:session) { Mattermost::Session.new('http://localhost:8065/', nil) } + + describe '.all' do + let(:result) { {id: 'abc', display_name: 'team'} } + before do + WebMock.stub_request(:get, 'http://localhost:8065/api/v3/teams/all'). + and_return({ abc: result }.to_json) + end + + xit 'gets the teams' do + allow(session).to receive(:with_session) { yield } + + expect(described_class.all).to eq(result) + end + end +end -- cgit v1.2.1 From 7363a7d3b5804493f86531bebb1610afb91b5293 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Fri, 16 Dec 2016 15:45:56 +0100 Subject: Add tests for auto configure slash commands --- spec/fixtures/mattermost_initial_load.json | 1 + spec/fixtures/mattermost_new_command.json | 1 + spec/lib/mattermost/command_spec.rb | 17 ++++++++++++ spec/lib/mattermost/team_spec.rb | 19 +++++++------ .../mattermost_slash_commands_service_spec.rb | 31 ++++++++++++++++++++++ 5 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 spec/fixtures/mattermost_initial_load.json create mode 100644 spec/fixtures/mattermost_new_command.json create mode 100644 spec/lib/mattermost/command_spec.rb (limited to 'spec') diff --git a/spec/fixtures/mattermost_initial_load.json b/spec/fixtures/mattermost_initial_load.json new file mode 100644 index 00000000000..89e35f8ff15 --- /dev/null +++ b/spec/fixtures/mattermost_initial_load.json @@ -0,0 +1 @@ +{"user":{"id":"78nm4euoc7dypergdc13ekxgpo","create_at":1481826051672,"update_at":1481835484207,"delete_at":0,"username":"root","auth_data":"","auth_service":"gitlab","email":"admin@example.com","email_verified":true,"nickname":"","first_name":"Administrator","last_name":"","roles":"system_admin system_user","notify_props":{"channel":"true","desktop":"all","desktop_sound":"true","email":"true","first_name":"true","mention_keys":"root,@root","push":"mention"},"last_password_update":1481826051672,"locale":"en"},"team_members":[{"team_id":"w59qt5a817f69jkxdz6xe7y4ir","user_id":"78nm4euoc7dypergdc13ekxgpo","roles":"team_user team_admin","delete_at":0},{"team_id":"my9oujxf5jy1zqdgu9rihd66do","user_id":"78nm4euoc7dypergdc13ekxgpo","roles":"team_user team_admin","delete_at":0}],"teams":[{"id":"w59qt5a817f69jkxdz6xe7y4ir","create_at":1481835484179,"update_at":1481835484179,"delete_at":0,"display_name":"new_team","name":"new-team","email":"","type":"O","company_name":"","allowed_domains":"","invite_id":"mfgsqnmpiby18eepo6jd6pq3oh","allow_open_invite":false},{"id":"my9oujxf5jy1zqdgu9rihd66do","create_at":1481826062406,"update_at":1481826062406,"delete_at":0,"display_name":"chatops","name":"chatops","email":"","type":"O","company_name":"","allowed_domains":"","invite_id":"s7c1phenmi8udkybcyytc3pxuh","allow_open_invite":false}],"preferences":[{"user_id":"78nm4euoc7dypergdc13ekxgpo","category":"last","name":"channel","value":"u4j58zgjyt8zd8nwwhaqjkyqzw"},{"user_id":"78nm4euoc7dypergdc13ekxgpo","category":"tutorial_step","name":"78nm4euoc7dypergdc13ekxgpo","value":"999"}],"client_cfg":{"AboutLink":"/static/help/about.html","AndroidAppDownloadLink":"https://about.mattermost.com/mattermost-android-app/","AppDownloadLink":"https://about.mattermost.com/downloads/","AvailableLocales":"","BuildDate":"Wed Nov 23 19:43:58 UTC 2016","BuildEnterpriseReady":"false","BuildHash":"36f62c9e82350f58c902f64a5d3304872431ad41","BuildHashEnterprise":"none","BuildNumber":"3.5.1","DefaultClientLocale":"en","EnableCommands":"true","EnableCustomEmoji":"false","EnableDeveloper":"false","EnableDiagnostics":"true","EnableEmailBatching":"false","EnableIncomingWebhooks":"false","EnableOAuthServiceProvider":"false","EnableOnlyAdminIntegrations":"true","EnableOpenServer":"false","EnableOutgoingWebhooks":"false","EnablePostIconOverride":"true","EnablePostUsernameOverride":"true","EnablePublicLink":"true","EnableSignInWithEmail":"true","EnableSignInWithUsername":"false","EnableSignUpWithEmail":"false","EnableSignUpWithGitLab":"true","EnableTeamCreation":"true","EnableTesting":"false","EnableUserCreation":"true","EnableWebrtc":"false","GoogleDeveloperKey":"","HelpLink":"","IosAppDownloadLink":"https://about.mattermost.com/mattermost-ios-app/","MaxFileSize":"52428800","PrivacyPolicyLink":"/static/help/privacy.html","ProfileHeight":"128","ProfileWidth":"128","ReportAProblemLink":"/static/help/report_problem.html","RequireEmailVerification":"false","RestrictCustomEmojiCreation":"all","RestrictDirectMessage":"any","RestrictPrivateChannelManagement":"all","RestrictPublicChannelManagement":"all","RestrictTeamInvite":"all","SQLDriverName":"postgres","SegmentDeveloperKey":"","SendEmailNotifications":"false","SendPushNotifications":"false","ShowEmailAddress":"true","SiteName":"GitLab Mattermost","SiteURL":"","SupportEmail":"support@example.com","TermsOfServiceLink":"/static/help/terms.html","Version":"3.5.0","WebsocketPort":"80","WebsocketSecurePort":"443"},"license_cfg":{"IsLicensed":"false"},"no_accounts":false} diff --git a/spec/fixtures/mattermost_new_command.json b/spec/fixtures/mattermost_new_command.json new file mode 100644 index 00000000000..4b827f19926 --- /dev/null +++ b/spec/fixtures/mattermost_new_command.json @@ -0,0 +1 @@ +{"id":"y8j1nexrdirj5nubq5uzdwwidr","token":"pzajm5hfbtni3r49ujpt8betpc","create_at":1481897117122,"update_at":1481897117122,"delete_at":0,"creator_id":"78nm4euoc7dypergdc13ekxgpo","team_id":"w59qt5a817f69jkxdz6xe7y4ir","trigger":"display","method":"P","username":"GitLab","icon_url":"","auto_complete":false,"auto_complete_desc":"","auto_complete_hint":"","display_name":"Display name","description":"the description","url":"http://trigger.url/trigger"} diff --git a/spec/lib/mattermost/command_spec.rb b/spec/lib/mattermost/command_spec.rb new file mode 100644 index 00000000000..7c6457f639d --- /dev/null +++ b/spec/lib/mattermost/command_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Mattermost::Command do + describe '.create' do + let(:new_command) do + JSON.parse(File.read(Rails.root.join('spec/fixtures/', 'mattermost_new_command.json'))) + end + + it 'gets the teams' do + allow(described_class).to receive(:post_command).and_return(new_command) + + token = described_class.create('abc', url: 'http://trigger.url/trigger', icon_url: 'http://myicon.com/icon.png') + + expect(token).to eq('pzajm5hfbtni3r49ujpt8betpc') + end + end +end diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index a3b0831659f..0fe6163900d 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -1,19 +1,22 @@ require 'spec_helper' describe Mattermost::Team do - let(:session) { Mattermost::Session.new('http://localhost:8065/', nil) } + describe '.team_admin' do + let(:init_load) do + JSON.parse(File.read(Rails.root.join('spec/fixtures/', 'mattermost_initial_load.json'))) + end - describe '.all' do - let(:result) { {id: 'abc', display_name: 'team'} } before do - WebMock.stub_request(:get, 'http://localhost:8065/api/v3/teams/all'). - and_return({ abc: result }.to_json) + allow(described_class).to receive(:initial_load).and_return(init_load) end - xit 'gets the teams' do - allow(session).to receive(:with_session) { yield } + it 'gets the teams' do + expect(described_class.team_admin.count).to be(2) + end - expect(described_class.all).to eq(result) + it 'filters on being team admin' do + ids = described_class.team_admin.map { |team| team['id'] } + expect(ids).to include("w59qt5a817f69jkxdz6xe7y4ir", "my9oujxf5jy1zqdgu9rihd66do") end end end diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 4a1037e950b..43b2c2c1302 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -96,4 +96,35 @@ describe MattermostSlashCommandsService, models: true do end end end + + describe '#configure' do + let(:project) { create(:empty_project) } + let(:service) { project.build_mattermost_slash_commands_service } + + subject do + service.configure('http://localhost:8065', nil, team_id: 'abc', trigger: 'gitlab', url: 'http://trigger.url', icon_url: 'http://icon.url/icon.png') + end + + it 'creates a new Mattermost session' do + expect_any_instance_of(Mattermost::Session).to receive(:with_session) + + subject + end + + it 'saves the service' do + allow_any_instance_of(Mattermost::Session).to receive(:with_session). + and_return('mynewtoken') + + expect { subject }.to change { project.services.count }.by(1) + end + + it 'saves the token' do + allow_any_instance_of(Mattermost::Session).to receive(:with_session). + and_return('mynewtoken') + + subject + + expect(service.reload.token).to eq('mynewtoken') + end + end end -- cgit v1.2.1 From 0d3e24358b88ce41848c97f3ac37bc813074f260 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Wed, 30 Nov 2016 15:51:48 +0100 Subject: Create Slack Slash command service --- spec/lib/gitlab/chat_commands/command_spec.rb | 26 ++++++++++++++++++++-- .../chat_message/build_message_spec.rb | 8 +++---- .../chat_message/issue_message_spec.rb | 10 ++++----- .../chat_message/merge_message_spec.rb | 12 +++++----- .../chat_message/note_message_spec.rb | 22 +++++++++--------- .../chat_message/push_message_spec.rb | 26 +++++++++++----------- .../chat_message/wiki_page_message_spec.rb | 8 +++---- 7 files changed, 67 insertions(+), 45 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/chat_commands/command_spec.rb index bfc6818ac08..ed8d25a526a 100644 --- a/spec/lib/gitlab/chat_commands/command_spec.rb +++ b/spec/lib/gitlab/chat_commands/command_spec.rb @@ -64,7 +64,7 @@ describe Gitlab::ChatCommands::Command, service: true do context 'and user can not create deployment' do it 'returns action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Whoops! That action is not allowed') + expect(subject[:text]).to start_with('Whoops! This action is not allowed') end end @@ -74,7 +74,7 @@ describe Gitlab::ChatCommands::Command, service: true do end it 'returns action' do - expect(subject[:text]).to include('Deployment from staging to production started') + expect(subject[:text]).to include('Deployment started from staging to production') expect(subject[:response_type]).to be(:in_channel) end @@ -91,4 +91,26 @@ describe Gitlab::ChatCommands::Command, service: true do end end end + + describe '#match_command' do + subject { described_class.new(project, user, params).match_command.first } + + context 'IssueShow is triggered' do + let(:params) { { text: 'issue show 123' } } + + it { is_expected.to eq(Gitlab::ChatCommands::IssueShow) } + end + + context 'IssueCreate is triggered' do + let(:params) { { text: 'issue create my title' } } + + it { is_expected.to eq(Gitlab::ChatCommands::IssueCreate) } + end + + context 'IssueSearch is triggered' do + let(:params) { { text: 'issue search my query' } } + + it { is_expected.to eq(Gitlab::ChatCommands::IssueSearch) } + end + end end diff --git a/spec/models/project_services/chat_message/build_message_spec.rb b/spec/models/project_services/chat_message/build_message_spec.rb index b71d153f814..50ad5013df9 100644 --- a/spec/models/project_services/chat_message/build_message_spec.rb +++ b/spec/models/project_services/chat_message/build_message_spec.rb @@ -10,7 +10,7 @@ describe ChatMessage::BuildMessage do tag: false, project_name: 'project_name', - project_url: 'example.gitlab.com', + project_url: 'http://example.gitlab.com', commit: { status: status, @@ -48,10 +48,10 @@ describe ChatMessage::BuildMessage do end def build_message(status_text = status) - ":" \ - " Commit :" \ + " Commit " \ - " of branch" \ + " of branch" \ " by hacker #{status_text} in #{duration} #{'second'.pluralize(duration)}" end end diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb index ebe0ead4408..190ff4c535d 100644 --- a/spec/models/project_services/chat_message/issue_message_spec.rb +++ b/spec/models/project_services/chat_message/issue_message_spec.rb @@ -10,14 +10,14 @@ describe ChatMessage::IssueMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', object_attributes: { title: 'Issue title', id: 10, iid: 100, assignee_id: 1, - url: 'url', + url: 'http://url.com', action: 'open', state: 'opened', description: 'issue description' @@ -40,11 +40,11 @@ describe ChatMessage::IssueMessage, models: true do context 'open' do it 'returns a message regarding opening of issues' do expect(subject.pretext).to eq( - '] Issue opened by test.user') + '[] Issue opened by test.user') expect(subject.attachments).to eq([ { title: "#100 Issue title", - title_link: "url", + title_link: "http://url.com", text: "issue description", color: color, } @@ -60,7 +60,7 @@ describe ChatMessage::IssueMessage, models: true do it 'returns a message regarding closing of issues' do expect(subject.pretext). to eq( - '] Issue closed by test.user') + '[] Issue closed by test.user') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb index 07c414c6ca4..cc154112e90 100644 --- a/spec/models/project_services/chat_message/merge_message_spec.rb +++ b/spec/models/project_services/chat_message/merge_message_spec.rb @@ -10,14 +10,14 @@ describe ChatMessage::MergeMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', object_attributes: { title: "Issue title\nSecond line", id: 10, iid: 100, assignee_id: 1, - url: 'url', + url: 'http://url.com', state: 'opened', description: 'issue description', source_branch: 'source_branch', @@ -31,8 +31,8 @@ describe ChatMessage::MergeMessage, models: true do context 'open' do it 'returns a message regarding opening of merge requests' do expect(subject.pretext).to eq( - 'test.user opened '\ - 'in : *Issue title*') + 'test.user opened '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end @@ -43,8 +43,8 @@ describe ChatMessage::MergeMessage, models: true do end it 'returns a message regarding closing of merge requests' do expect(subject.pretext).to eq( - 'test.user closed '\ - 'in : *Issue title*') + 'test.user closed '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/chat_message/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb index 31936da40a2..da700a08e57 100644 --- a/spec/models/project_services/chat_message/note_message_spec.rb +++ b/spec/models/project_services/chat_message/note_message_spec.rb @@ -11,15 +11,15 @@ describe ChatMessage::NoteMessage, models: true do avatar_url: 'http://fakeavatar' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', repository: { name: 'project_name', - url: 'somewhere.com', + url: 'http://somewhere.com', }, object_attributes: { id: 10, note: 'comment on a commit', - url: 'url', + url: 'http://url.com', noteable_type: 'Commit' } } @@ -37,8 +37,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on commits' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*Added a commit message*") expected_attachments = [ { @@ -63,8 +63,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on a merge request' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*merge request title*") expected_attachments = [ { @@ -90,8 +90,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on an issue' do message = described_class.new(@args) expect(message.pretext).to eq( - "test.user in : " \ + "test.user in : " \ "*issue title*") expected_attachments = [ { @@ -115,8 +115,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on a project snippet' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*snippet title*") expected_attachments = [ { diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb index b781c4505db..24928873bad 100644 --- a/spec/models/project_services/chat_message/push_message_spec.rb +++ b/spec/models/project_services/chat_message/push_message_spec.rb @@ -10,7 +10,7 @@ describe ChatMessage::PushMessage, models: true do project_name: 'project_name', ref: 'refs/heads/master', user_name: 'test.user', - project_url: 'url' + project_url: 'http://url.com' } end @@ -19,20 +19,20 @@ describe ChatMessage::PushMessage, models: true do context 'push' do before do args[:commits] = [ - { message: 'message1', url: 'url1', id: 'abcdefghijkl', author: { name: 'author1' } }, - { message: 'message2', url: 'url2', id: '123456789012', author: { name: 'author2' } }, + { message: 'message1', url: 'http://url1.com', id: 'abcdefghijkl', author: { name: 'author1' } }, + { message: 'message2', url: 'http://url2.com', id: '123456789012', author: { name: 'author2' } }, ] end it 'returns a message regarding pushes' do expect(subject.pretext).to eq( - 'test.user pushed to branch of '\ - ' ()' + 'test.user pushed to branch of '\ + ' ()' ) expect(subject.attachments).to eq([ { - text: ": message1 - author1\n"\ - ": message2 - author2", + text: ": message1 - author1\n"\ + ": message2 - author2", color: color, } ]) @@ -47,14 +47,14 @@ describe ChatMessage::PushMessage, models: true do project_name: 'project_name', ref: 'refs/tags/new_tag', user_name: 'test.user', - project_url: 'url' + project_url: 'http://url.com' } end it 'returns a message regarding pushes' do expect(subject.pretext).to eq('test.user pushed new tag ' \ - ' to ' \ - '') + ' to ' \ + '') expect(subject.attachments).to be_empty end end @@ -66,8 +66,8 @@ describe ChatMessage::PushMessage, models: true do it 'returns a message regarding a new branch' do expect(subject.pretext).to eq( - 'test.user pushed new branch to '\ - '' + 'test.user pushed new branch to '\ + '' ) expect(subject.attachments).to be_empty end @@ -80,7 +80,7 @@ describe ChatMessage::PushMessage, models: true do it 'returns a message regarding a removed branch' do expect(subject.pretext).to eq( - 'test.user removed branch master from ' + 'test.user removed branch master from ' ) expect(subject.attachments).to be_empty end diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb index 94c04dc0865..a2ad61e38e7 100644 --- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb +++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb @@ -10,10 +10,10 @@ describe ChatMessage::WikiPageMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', object_attributes: { title: 'Wiki page title', - url: 'url', + url: 'http://url.com', content: 'Wiki page description' } } @@ -25,7 +25,7 @@ describe ChatMessage::WikiPageMessage, models: true do it 'returns a message that a new wiki page was created' do expect(subject.pretext).to eq( - 'test.user created in : '\ + 'test.user created in : '\ '*Wiki page title*') end end @@ -35,7 +35,7 @@ describe ChatMessage::WikiPageMessage, models: true do it 'returns a message that a wiki page was updated' do expect(subject.pretext).to eq( - 'test.user edited in : '\ + 'test.user edited in : '\ '*Wiki page title*') end end -- cgit v1.2.1 From f9f1a508c6a4bdb2fcee98d18394e28e1cc663c3 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 16 Dec 2016 14:21:06 +0100 Subject: Fix SlackSlashCommands tests --- spec/lib/gitlab/chat_commands/command_spec.rb | 20 +++- spec/models/project_services/chat_service_spec.rb | 15 --- .../chat_slash_commands_service_spec.rb | 103 +++++++++++++++++++++ .../mattermost_slash_commands_service_spec.rb | 96 +------------------ .../slack_slash_commands_service.rb | 5 + 5 files changed, 124 insertions(+), 115 deletions(-) delete mode 100644 spec/models/project_services/chat_service_spec.rb create mode 100644 spec/models/project_services/chat_slash_commands_service_spec.rb create mode 100644 spec/models/project_services/slack_slash_commands_service.rb (limited to 'spec') diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/chat_commands/command_spec.rb index ed8d25a526a..dec98d990b2 100644 --- a/spec/lib/gitlab/chat_commands/command_spec.rb +++ b/spec/lib/gitlab/chat_commands/command_spec.rb @@ -3,9 +3,13 @@ require 'spec_helper' describe Gitlab::ChatCommands::Command, service: true do let(:project) { create(:empty_project) } let(:user) { create(:user) } + let(:format) { nil } describe '#execute' do - subject { described_class.new(project, user, params).execute } + subject do + described_class.new(project, user, + params.merge(presenter_format: format)).execute + end context 'when no command is available' do let(:params) { { text: 'issue show 1' } } @@ -47,8 +51,14 @@ describe Gitlab::ChatCommands::Command, service: true do expect(subject[:text]).to match("my new issue") end - it 'shows a link to the new issue' do - expect(subject[:text]).to match(/\/issues\/\d+/) + %w(slack mattermost).each do |format| + context "for #{format}" do + let(:format) { format } + + it 'shows a link to the new issue' do + expect(subject[:text]).to match(/\/issues\/\d+/) + end + end end end @@ -64,7 +74,7 @@ describe Gitlab::ChatCommands::Command, service: true do context 'and user can not create deployment' do it 'returns action' do expect(subject[:response_type]).to be(:ephemeral) - expect(subject[:text]).to start_with('Whoops! This action is not allowed') + expect(subject[:text]).to start_with('Whoops! That action is not allowed') end end @@ -74,7 +84,7 @@ describe Gitlab::ChatCommands::Command, service: true do end it 'returns action' do - expect(subject[:text]).to include('Deployment started from staging to production') + expect(subject[:text]).to include('Deployment from staging to production started.') expect(subject[:response_type]).to be(:in_channel) end diff --git a/spec/models/project_services/chat_service_spec.rb b/spec/models/project_services/chat_service_spec.rb deleted file mode 100644 index c6a45a3e1be..00000000000 --- a/spec/models/project_services/chat_service_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require 'spec_helper' - -describe ChatService, models: true do - describe "Associations" do - it { is_expected.to have_many :chat_names } - end - - describe '#valid_token?' do - subject { described_class.new } - - it 'is false as it has no token' do - expect(subject.valid_token?('wer')).to be_falsey - end - end -end diff --git a/spec/models/project_services/chat_slash_commands_service_spec.rb b/spec/models/project_services/chat_slash_commands_service_spec.rb new file mode 100644 index 00000000000..64fdd4d570b --- /dev/null +++ b/spec/models/project_services/chat_slash_commands_service_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' + +describe ChatSlashCommandsService, models: true do + describe "Associations" do + it { is_expected.to respond_to :token } + it { is_expected.to have_many :chat_names } + end + + describe '#valid_token?' do + subject { described_class.new } + + context 'when the token is empty' do + it 'is false' do + expect(subject.valid_token?('wer')).to be_falsey + end + end + + context 'when there is a token' do + before do + subject.token = '123' + end + + it 'accepts equal tokens' do + expect(subject.valid_token?('123')).to be_truthy + end + end + end + + describe '#trigger' do + subject { described_class.new } + + before do + allow(subject).to receive(:presenter_format).and_return('unknown') + end + + context 'no token is passed' do + let(:params) { Hash.new } + + it 'returns nil' do + expect(subject.trigger(params)).to be_nil + end + end + + context 'with a token passed' do + let(:project) { create(:empty_project) } + let(:params) { { token: 'token' } } + + before do + allow(subject).to receive(:token).and_return('token') + end + + context 'no user can be found' do + context 'when no url can be generated' do + it 'responds with the authorize url' do + response = subject.trigger(params) + + expect(response[:response_type]).to eq :ephemeral + expect(response[:text]).to start_with ":sweat_smile: Couldn't identify you" + end + end + + context 'when an auth url can be generated' do + let(:params) do + { + team_domain: 'http://domain.tld', + team_id: 'T3423423', + user_id: 'U234234', + user_name: 'mepmep', + token: 'token' + } + end + + let(:service) do + project.create_mattermost_slash_commands_service( + properties: { token: 'token' } + ) + end + + it 'generates the url' do + response = service.trigger(params) + + expect(response[:text]).to start_with(':wave: Hi there!') + end + end + end + + context 'when the user is authenticated' do + let!(:chat_name) { create(:chat_name, service: subject) } + let(:params) { { token: 'token', team_id: chat_name.team_id, user_id: chat_name.chat_id } } + + subject do + described_class.create(project: project, properties: { token: 'token' }) + end + + it 'triggers the command' do + expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute) + + subject.trigger(params) + end + end + end + end +end diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 4a1037e950b..b9deb0201e1 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -1,99 +1,5 @@ require 'spec_helper' describe MattermostSlashCommandsService, models: true do - describe "Associations" do - it { is_expected.to respond_to :token } - end - - describe '#valid_token?' do - subject { described_class.new } - - context 'when the token is empty' do - it 'is false' do - expect(subject.valid_token?('wer')).to be_falsey - end - end - - context 'when there is a token' do - before do - subject.token = '123' - end - - it 'accepts equal tokens' do - expect(subject.valid_token?('123')).to be_truthy - end - end - end - - describe '#trigger' do - subject { described_class.new } - - context 'no token is passed' do - let(:params) { Hash.new } - - it 'returns nil' do - expect(subject.trigger(params)).to be_nil - end - end - - context 'with a token passed' do - let(:project) { create(:empty_project) } - let(:params) { { token: 'token' } } - - before do - allow(subject).to receive(:token).and_return('token') - end - - context 'no user can be found' do - context 'when no url can be generated' do - it 'responds with the authorize url' do - response = subject.trigger(params) - - expect(response[:response_type]).to eq :ephemeral - expect(response[:text]).to start_with ":sweat_smile: Couldn't identify you" - end - end - - context 'when an auth url can be generated' do - let(:params) do - { - team_domain: 'http://domain.tld', - team_id: 'T3423423', - user_id: 'U234234', - user_name: 'mepmep', - token: 'token' - } - end - - let(:service) do - project.create_mattermost_slash_commands_service( - properties: { token: 'token' } - ) - end - - it 'generates the url' do - response = service.trigger(params) - - expect(response[:text]).to start_with(':wave: Hi there!') - end - end - end - - context 'when the user is authenticated' do - let!(:chat_name) { create(:chat_name, service: service) } - let(:service) do - project.create_mattermost_slash_commands_service( - properties: { token: 'token' } - ) - end - let(:params) { { token: 'token', team_id: chat_name.team_id, user_id: chat_name.chat_id } } - - it 'triggers the command' do - expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute) - - service.trigger(params) - end - end - end - end + it { is_expected.to respond_to :presenter_format } end diff --git a/spec/models/project_services/slack_slash_commands_service.rb b/spec/models/project_services/slack_slash_commands_service.rb new file mode 100644 index 00000000000..5ef97b9a2ed --- /dev/null +++ b/spec/models/project_services/slack_slash_commands_service.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe SlackSlashCommandsService, models: true do + it { is_expected.to respond_to :presenter_format } +end -- cgit v1.2.1 From 0f2776287a7d9b0fde9ff54ef8d9f74e2f844a09 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Fri, 16 Dec 2016 15:08:10 +0100 Subject: Use Slack::Notifier::LinkFormatter to convert markdown links to slack compat --- spec/lib/gitlab/chat_commands/command_spec.rb | 14 +- .../chat_slash_commands_service_spec.rb | 103 ------- .../mattermost_notification_service_spec.rb | 2 +- .../mattermost_slash_commands_service_spec.rb | 2 +- .../slack_notification_service_spec.rb | 2 +- .../slack_slash_commands_service.rb | 35 ++- .../support/chat_slash_commands_shared_examples.rb | 97 ++++++ ...ack_mattermost_notifications_shared_examples.rb | 328 +++++++++++++++++++++ spec/support/slack_mattermost_shared_examples.rb | 328 --------------------- 9 files changed, 465 insertions(+), 446 deletions(-) delete mode 100644 spec/models/project_services/chat_slash_commands_service_spec.rb create mode 100644 spec/support/chat_slash_commands_shared_examples.rb create mode 100644 spec/support/slack_mattermost_notifications_shared_examples.rb delete mode 100644 spec/support/slack_mattermost_shared_examples.rb (limited to 'spec') diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/chat_commands/command_spec.rb index dec98d990b2..a0ec8884635 100644 --- a/spec/lib/gitlab/chat_commands/command_spec.rb +++ b/spec/lib/gitlab/chat_commands/command_spec.rb @@ -3,12 +3,10 @@ require 'spec_helper' describe Gitlab::ChatCommands::Command, service: true do let(:project) { create(:empty_project) } let(:user) { create(:user) } - let(:format) { nil } describe '#execute' do subject do - described_class.new(project, user, - params.merge(presenter_format: format)).execute + described_class.new(project, user, params).execute end context 'when no command is available' do @@ -51,14 +49,8 @@ describe Gitlab::ChatCommands::Command, service: true do expect(subject[:text]).to match("my new issue") end - %w(slack mattermost).each do |format| - context "for #{format}" do - let(:format) { format } - - it 'shows a link to the new issue' do - expect(subject[:text]).to match(/\/issues\/\d+/) - end - end + it 'shows a link to the new issue' do + expect(subject[:text]).to match(/\/issues\/\d+/) end end diff --git a/spec/models/project_services/chat_slash_commands_service_spec.rb b/spec/models/project_services/chat_slash_commands_service_spec.rb deleted file mode 100644 index 64fdd4d570b..00000000000 --- a/spec/models/project_services/chat_slash_commands_service_spec.rb +++ /dev/null @@ -1,103 +0,0 @@ -require 'spec_helper' - -describe ChatSlashCommandsService, models: true do - describe "Associations" do - it { is_expected.to respond_to :token } - it { is_expected.to have_many :chat_names } - end - - describe '#valid_token?' do - subject { described_class.new } - - context 'when the token is empty' do - it 'is false' do - expect(subject.valid_token?('wer')).to be_falsey - end - end - - context 'when there is a token' do - before do - subject.token = '123' - end - - it 'accepts equal tokens' do - expect(subject.valid_token?('123')).to be_truthy - end - end - end - - describe '#trigger' do - subject { described_class.new } - - before do - allow(subject).to receive(:presenter_format).and_return('unknown') - end - - context 'no token is passed' do - let(:params) { Hash.new } - - it 'returns nil' do - expect(subject.trigger(params)).to be_nil - end - end - - context 'with a token passed' do - let(:project) { create(:empty_project) } - let(:params) { { token: 'token' } } - - before do - allow(subject).to receive(:token).and_return('token') - end - - context 'no user can be found' do - context 'when no url can be generated' do - it 'responds with the authorize url' do - response = subject.trigger(params) - - expect(response[:response_type]).to eq :ephemeral - expect(response[:text]).to start_with ":sweat_smile: Couldn't identify you" - end - end - - context 'when an auth url can be generated' do - let(:params) do - { - team_domain: 'http://domain.tld', - team_id: 'T3423423', - user_id: 'U234234', - user_name: 'mepmep', - token: 'token' - } - end - - let(:service) do - project.create_mattermost_slash_commands_service( - properties: { token: 'token' } - ) - end - - it 'generates the url' do - response = service.trigger(params) - - expect(response[:text]).to start_with(':wave: Hi there!') - end - end - end - - context 'when the user is authenticated' do - let!(:chat_name) { create(:chat_name, service: subject) } - let(:params) { { token: 'token', team_id: chat_name.team_id, user_id: chat_name.chat_id } } - - subject do - described_class.create(project: project, properties: { token: 'token' }) - end - - it 'triggers the command' do - expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute) - - subject.trigger(params) - end - end - end - end -end diff --git a/spec/models/project_services/mattermost_notification_service_spec.rb b/spec/models/project_services/mattermost_notification_service_spec.rb index c01e64b4c8e..7832d6f50cf 100644 --- a/spec/models/project_services/mattermost_notification_service_spec.rb +++ b/spec/models/project_services/mattermost_notification_service_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' describe MattermostNotificationService, models: true do - it_behaves_like "slack or mattermost" + it_behaves_like "slack or mattermost notifications" end diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index b9deb0201e1..5c34cb6b4cf 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' describe MattermostSlashCommandsService, models: true do - it { is_expected.to respond_to :presenter_format } + it_behaves_like "chat slash commands" end diff --git a/spec/models/project_services/slack_notification_service_spec.rb b/spec/models/project_services/slack_notification_service_spec.rb index 59ddddf7454..110b5bf2115 100644 --- a/spec/models/project_services/slack_notification_service_spec.rb +++ b/spec/models/project_services/slack_notification_service_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' describe SlackNotificationService, models: true do - it_behaves_like "slack or mattermost" + it_behaves_like "slack or mattermost notifications" end diff --git a/spec/models/project_services/slack_slash_commands_service.rb b/spec/models/project_services/slack_slash_commands_service.rb index 5ef97b9a2ed..c3fa80caebe 100644 --- a/spec/models/project_services/slack_slash_commands_service.rb +++ b/spec/models/project_services/slack_slash_commands_service.rb @@ -1,5 +1,38 @@ require 'spec_helper' describe SlackSlashCommandsService, models: true do - it { is_expected.to respond_to :presenter_format } + it_behaves_like "chat slash commands" + + describe '#trigger' do + context 'when an auth url is generated' do + let(:project) { create(:empty_project) } + let(:params) do + { + team_domain: 'http://domain.tld', + team_id: 'T3423423', + user_id: 'U234234', + user_name: 'mepmep', + token: 'token' + } + end + let(:service) do + project.create_slack_slash_commands_service( + properties: { token: 'token' } + ) + end + let(:authorize_url) do + 'http://authorize.example.com/' + end + + before do + allow(service).to receive(:authorize_chat_name_url).and_return(authorize_url) + end + + it 'uses slack compatible links' do + response = service.trigger(params) + + expect(response[:text]).to include("<#{authorize_url}|connect your GitLab account>") + end + end + end end diff --git a/spec/support/chat_slash_commands_shared_examples.rb b/spec/support/chat_slash_commands_shared_examples.rb new file mode 100644 index 00000000000..96130b45235 --- /dev/null +++ b/spec/support/chat_slash_commands_shared_examples.rb @@ -0,0 +1,97 @@ +RSpec.shared_examples 'chat slash commands' do + describe "Associations" do + it { is_expected.to respond_to :token } + it { is_expected.to have_many :chat_names } + end + + describe '#valid_token?' do + subject { described_class.new } + + context 'when the token is empty' do + it 'is false' do + expect(subject.valid_token?('wer')).to be_falsey + end + end + + context 'when there is a token' do + before do + subject.token = '123' + end + + it 'accepts equal tokens' do + expect(subject.valid_token?('123')).to be_truthy + end + end + end + + describe '#trigger' do + subject { described_class.new } + + context 'no token is passed' do + let(:params) { Hash.new } + + it 'returns nil' do + expect(subject.trigger(params)).to be_nil + end + end + + context 'with a token passed' do + let(:project) { create(:empty_project) } + let(:params) { { token: 'token' } } + + before do + allow(subject).to receive(:token).and_return('token') + end + + context 'no user can be found' do + context 'when no url can be generated' do + it 'responds with the authorize url' do + response = subject.trigger(params) + + expect(response[:response_type]).to eq :ephemeral + expect(response[:text]).to start_with ":sweat_smile: Couldn't identify you" + end + end + + context 'when an auth url can be generated' do + let(:params) do + { + team_domain: 'http://domain.tld', + team_id: 'T3423423', + user_id: 'U234234', + user_name: 'mepmep', + token: 'token' + } + end + + let(:service) do + project.create_mattermost_slash_commands_service( + properties: { token: 'token' } + ) + end + + it 'generates the url' do + response = service.trigger(params) + + expect(response[:text]).to start_with(':wave: Hi there!') + end + end + end + + context 'when the user is authenticated' do + let!(:chat_name) { create(:chat_name, service: subject) } + let(:params) { { token: 'token', team_id: chat_name.team_id, user_id: chat_name.chat_id } } + + subject do + described_class.create(project: project, properties: { token: 'token' }) + end + + it 'triggers the command' do + expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute) + + subject.trigger(params) + end + end + end + end +end diff --git a/spec/support/slack_mattermost_notifications_shared_examples.rb b/spec/support/slack_mattermost_notifications_shared_examples.rb new file mode 100644 index 00000000000..8582aea5fe5 --- /dev/null +++ b/spec/support/slack_mattermost_notifications_shared_examples.rb @@ -0,0 +1,328 @@ +Dir[Rails.root.join("app/models/project_services/chat_message/*.rb")].each { |f| require f } + +RSpec.shared_examples 'slack or mattermost notifications' do + let(:chat_service) { described_class.new } + let(:webhook_url) { 'https://example.gitlab.com/' } + + describe "Associations" do + it { is_expected.to belong_to :project } + it { is_expected.to have_one :service_hook } + end + + describe 'Validations' do + context 'when service is active' do + before { subject.active = true } + + it { is_expected.to validate_presence_of(:webhook) } + it_behaves_like 'issue tracker service URL attribute', :webhook + end + + context 'when service is inactive' do + before { subject.active = false } + + it { is_expected.not_to validate_presence_of(:webhook) } + end + end + + describe "#execute" do + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:username) { 'slack_username' } + let(:channel) { 'slack_channel' } + + let(:push_sample_data) do + Gitlab::DataBuilder::Push.build_sample(project, user) + end + + before do + allow(chat_service).to receive_messages( + project: project, + project_id: project.id, + service_hook: true, + webhook: webhook_url + ) + + WebMock.stub_request(:post, webhook_url) + + opts = { + title: 'Awesome issue', + description: 'please fix' + } + + issue_service = Issues::CreateService.new(project, user, opts) + @issue = issue_service.execute + @issues_sample_data = issue_service.hook_data(@issue, 'open') + + opts = { + title: 'Awesome merge_request', + description: 'please fix', + source_branch: 'feature', + target_branch: 'master' + } + merge_service = MergeRequests::CreateService.new(project, + user, opts) + @merge_request = merge_service.execute + @merge_sample_data = merge_service.hook_data(@merge_request, + 'open') + + opts = { + title: "Awesome wiki_page", + content: "Some text describing some thing or another", + format: "md", + message: "user created page: Awesome wiki_page" + } + + wiki_page_service = WikiPages::CreateService.new(project, user, opts) + @wiki_page = wiki_page_service.execute + @wiki_page_sample_data = wiki_page_service.hook_data(@wiki_page, 'create') + end + + it "calls Slack/Mattermost API for push events" do + chat_service.execute(push_sample_data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + + it "calls Slack/Mattermost API for issue events" do + chat_service.execute(@issues_sample_data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + + it "calls Slack/Mattermost API for merge requests events" do + chat_service.execute(@merge_sample_data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + + it "calls Slack/Mattermost API for wiki page events" do + chat_service.execute(@wiki_page_sample_data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + + it 'uses the username as an option for slack when configured' do + allow(chat_service).to receive(:username).and_return(username) + + expect(Slack::Notifier).to receive(:new). + with(webhook_url, username: username, channel: chat_service.default_channel). + and_return( + double(:slack_service).as_null_object + ) + + chat_service.execute(push_sample_data) + end + + it 'uses the channel as an option when it is configured' do + allow(chat_service).to receive(:channel).and_return(channel) + expect(Slack::Notifier).to receive(:new). + with(webhook_url, channel: channel). + and_return( + double(:slack_service).as_null_object + ) + chat_service.execute(push_sample_data) + end + + context "event channels" do + it "uses the right channel for push event" do + chat_service.update_attributes(push_channel: "random") + + expect(Slack::Notifier).to receive(:new). + with(webhook_url, channel: "random"). + and_return( + double(:slack_service).as_null_object + ) + + chat_service.execute(push_sample_data) + end + + it "uses the right channel for merge request event" do + chat_service.update_attributes(merge_request_channel: "random") + + expect(Slack::Notifier).to receive(:new). + with(webhook_url, channel: "random"). + and_return( + double(:slack_service).as_null_object + ) + + chat_service.execute(@merge_sample_data) + end + + it "uses the right channel for issue event" do + chat_service.update_attributes(issue_channel: "random") + + expect(Slack::Notifier).to receive(:new). + with(webhook_url, channel: "random"). + and_return( + double(:slack_service).as_null_object + ) + + chat_service.execute(@issues_sample_data) + end + + it "uses the right channel for wiki event" do + chat_service.update_attributes(wiki_page_channel: "random") + + expect(Slack::Notifier).to receive(:new). + with(webhook_url, channel: "random"). + and_return( + double(:slack_service).as_null_object + ) + + chat_service.execute(@wiki_page_sample_data) + end + + context "note event" do + let(:issue_note) do + create(:note_on_issue, project: project, note: "issue note") + end + + it "uses the right channel" do + chat_service.update_attributes(note_channel: "random") + + note_data = Gitlab::DataBuilder::Note.build(issue_note, user) + + expect(Slack::Notifier).to receive(:new). + with(webhook_url, channel: "random"). + and_return( + double(:slack_service).as_null_object + ) + + chat_service.execute(note_data) + end + end + end + end + + describe "Note events" do + let(:user) { create(:user) } + let(:project) { create(:project, creator_id: user.id) } + + before do + allow(chat_service).to receive_messages( + project: project, + project_id: project.id, + service_hook: true, + webhook: webhook_url + ) + + WebMock.stub_request(:post, webhook_url) + end + + context 'when commit comment event executed' do + let(:commit_note) do + create(:note_on_commit, author: user, + project: project, + commit_id: project.repository.commit.id, + note: 'a comment on a commit') + end + + it "calls Slack/Mattermost API for commit comment events" do + data = Gitlab::DataBuilder::Note.build(commit_note, user) + chat_service.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + end + + context 'when merge request comment event executed' do + let(:merge_request_note) do + create(:note_on_merge_request, project: project, + note: "merge request note") + end + + it "calls Slack API for merge request comment events" do + data = Gitlab::DataBuilder::Note.build(merge_request_note, user) + chat_service.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + end + + context 'when issue comment event executed' do + let(:issue_note) do + create(:note_on_issue, project: project, note: "issue note") + end + + it "calls Slack API for issue comment events" do + data = Gitlab::DataBuilder::Note.build(issue_note, user) + chat_service.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + end + + context 'when snippet comment event executed' do + let(:snippet_note) do + create(:note_on_project_snippet, project: project, + note: "snippet note") + end + + it "calls Slack API for snippet comment events" do + data = Gitlab::DataBuilder::Note.build(snippet_note, user) + chat_service.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + end + end + + describe 'Pipeline events' do + let(:user) { create(:user) } + let(:project) { create(:project) } + + let(:pipeline) do + create(:ci_pipeline, + project: project, status: status, + sha: project.commit.sha, ref: project.default_branch) + end + + before do + allow(chat_service).to receive_messages( + project: project, + service_hook: true, + webhook: webhook_url + ) + end + + shared_examples 'call Slack/Mattermost API' do + before do + WebMock.stub_request(:post, webhook_url) + end + + it 'calls Slack/Mattermost API for pipeline events' do + data = Gitlab::DataBuilder::Pipeline.build(pipeline) + chat_service.execute(data) + + expect(WebMock).to have_requested(:post, webhook_url).once + end + end + + context 'with failed pipeline' do + let(:status) { 'failed' } + + it_behaves_like 'call Slack/Mattermost API' + end + + context 'with succeeded pipeline' do + let(:status) { 'success' } + + context 'with default to notify_only_broken_pipelines' do + it 'does not call Slack/Mattermost API for pipeline events' do + data = Gitlab::DataBuilder::Pipeline.build(pipeline) + result = chat_service.execute(data) + + expect(result).to be_falsy + end + end + + context 'with setting notify_only_broken_pipelines to false' do + before do + chat_service.notify_only_broken_pipelines = false + end + + it_behaves_like 'call Slack/Mattermost API' + end + end + end +end diff --git a/spec/support/slack_mattermost_shared_examples.rb b/spec/support/slack_mattermost_shared_examples.rb deleted file mode 100644 index 56d4965f74d..00000000000 --- a/spec/support/slack_mattermost_shared_examples.rb +++ /dev/null @@ -1,328 +0,0 @@ -Dir[Rails.root.join("app/models/project_services/chat_message/*.rb")].each { |f| require f } - -RSpec.shared_examples 'slack or mattermost' do - let(:chat_service) { described_class.new } - let(:webhook_url) { 'https://example.gitlab.com/' } - - describe "Associations" do - it { is_expected.to belong_to :project } - it { is_expected.to have_one :service_hook } - end - - describe 'Validations' do - context 'when service is active' do - before { subject.active = true } - - it { is_expected.to validate_presence_of(:webhook) } - it_behaves_like 'issue tracker service URL attribute', :webhook - end - - context 'when service is inactive' do - before { subject.active = false } - - it { is_expected.not_to validate_presence_of(:webhook) } - end - end - - describe "#execute" do - let(:user) { create(:user) } - let(:project) { create(:project) } - let(:username) { 'slack_username' } - let(:channel) { 'slack_channel' } - - let(:push_sample_data) do - Gitlab::DataBuilder::Push.build_sample(project, user) - end - - before do - allow(chat_service).to receive_messages( - project: project, - project_id: project.id, - service_hook: true, - webhook: webhook_url - ) - - WebMock.stub_request(:post, webhook_url) - - opts = { - title: 'Awesome issue', - description: 'please fix' - } - - issue_service = Issues::CreateService.new(project, user, opts) - @issue = issue_service.execute - @issues_sample_data = issue_service.hook_data(@issue, 'open') - - opts = { - title: 'Awesome merge_request', - description: 'please fix', - source_branch: 'feature', - target_branch: 'master' - } - merge_service = MergeRequests::CreateService.new(project, - user, opts) - @merge_request = merge_service.execute - @merge_sample_data = merge_service.hook_data(@merge_request, - 'open') - - opts = { - title: "Awesome wiki_page", - content: "Some text describing some thing or another", - format: "md", - message: "user created page: Awesome wiki_page" - } - - wiki_page_service = WikiPages::CreateService.new(project, user, opts) - @wiki_page = wiki_page_service.execute - @wiki_page_sample_data = wiki_page_service.hook_data(@wiki_page, 'create') - end - - it "calls Slack/Mattermost API for push events" do - chat_service.execute(push_sample_data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - - it "calls Slack/Mattermost API for issue events" do - chat_service.execute(@issues_sample_data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - - it "calls Slack/Mattermost API for merge requests events" do - chat_service.execute(@merge_sample_data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - - it "calls Slack/Mattermost API for wiki page events" do - chat_service.execute(@wiki_page_sample_data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - - it 'uses the username as an option for slack when configured' do - allow(chat_service).to receive(:username).and_return(username) - - expect(Slack::Notifier).to receive(:new). - with(webhook_url, username: username, channel: chat_service.default_channel). - and_return( - double(:slack_service).as_null_object - ) - - chat_service.execute(push_sample_data) - end - - it 'uses the channel as an option when it is configured' do - allow(chat_service).to receive(:channel).and_return(channel) - expect(Slack::Notifier).to receive(:new). - with(webhook_url, channel: channel). - and_return( - double(:slack_service).as_null_object - ) - chat_service.execute(push_sample_data) - end - - context "event channels" do - it "uses the right channel for push event" do - chat_service.update_attributes(push_channel: "random") - - expect(Slack::Notifier).to receive(:new). - with(webhook_url, channel: "random"). - and_return( - double(:slack_service).as_null_object - ) - - chat_service.execute(push_sample_data) - end - - it "uses the right channel for merge request event" do - chat_service.update_attributes(merge_request_channel: "random") - - expect(Slack::Notifier).to receive(:new). - with(webhook_url, channel: "random"). - and_return( - double(:slack_service).as_null_object - ) - - chat_service.execute(@merge_sample_data) - end - - it "uses the right channel for issue event" do - chat_service.update_attributes(issue_channel: "random") - - expect(Slack::Notifier).to receive(:new). - with(webhook_url, channel: "random"). - and_return( - double(:slack_service).as_null_object - ) - - chat_service.execute(@issues_sample_data) - end - - it "uses the right channel for wiki event" do - chat_service.update_attributes(wiki_page_channel: "random") - - expect(Slack::Notifier).to receive(:new). - with(webhook_url, channel: "random"). - and_return( - double(:slack_service).as_null_object - ) - - chat_service.execute(@wiki_page_sample_data) - end - - context "note event" do - let(:issue_note) do - create(:note_on_issue, project: project, note: "issue note") - end - - it "uses the right channel" do - chat_service.update_attributes(note_channel: "random") - - note_data = Gitlab::DataBuilder::Note.build(issue_note, user) - - expect(Slack::Notifier).to receive(:new). - with(webhook_url, channel: "random"). - and_return( - double(:slack_service).as_null_object - ) - - chat_service.execute(note_data) - end - end - end - end - - describe "Note events" do - let(:user) { create(:user) } - let(:project) { create(:project, creator_id: user.id) } - - before do - allow(chat_service).to receive_messages( - project: project, - project_id: project.id, - service_hook: true, - webhook: webhook_url - ) - - WebMock.stub_request(:post, webhook_url) - end - - context 'when commit comment event executed' do - let(:commit_note) do - create(:note_on_commit, author: user, - project: project, - commit_id: project.repository.commit.id, - note: 'a comment on a commit') - end - - it "calls Slack/Mattermost API for commit comment events" do - data = Gitlab::DataBuilder::Note.build(commit_note, user) - chat_service.execute(data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - end - - context 'when merge request comment event executed' do - let(:merge_request_note) do - create(:note_on_merge_request, project: project, - note: "merge request note") - end - - it "calls Slack API for merge request comment events" do - data = Gitlab::DataBuilder::Note.build(merge_request_note, user) - chat_service.execute(data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - end - - context 'when issue comment event executed' do - let(:issue_note) do - create(:note_on_issue, project: project, note: "issue note") - end - - it "calls Slack API for issue comment events" do - data = Gitlab::DataBuilder::Note.build(issue_note, user) - chat_service.execute(data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - end - - context 'when snippet comment event executed' do - let(:snippet_note) do - create(:note_on_project_snippet, project: project, - note: "snippet note") - end - - it "calls Slack API for snippet comment events" do - data = Gitlab::DataBuilder::Note.build(snippet_note, user) - chat_service.execute(data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - end - end - - describe 'Pipeline events' do - let(:user) { create(:user) } - let(:project) { create(:project) } - - let(:pipeline) do - create(:ci_pipeline, - project: project, status: status, - sha: project.commit.sha, ref: project.default_branch) - end - - before do - allow(chat_service).to receive_messages( - project: project, - service_hook: true, - webhook: webhook_url - ) - end - - shared_examples 'call Slack/Mattermost API' do - before do - WebMock.stub_request(:post, webhook_url) - end - - it 'calls Slack/Mattermost API for pipeline events' do - data = Gitlab::DataBuilder::Pipeline.build(pipeline) - chat_service.execute(data) - - expect(WebMock).to have_requested(:post, webhook_url).once - end - end - - context 'with failed pipeline' do - let(:status) { 'failed' } - - it_behaves_like 'call Slack/Mattermost API' - end - - context 'with succeeded pipeline' do - let(:status) { 'success' } - - context 'with default to notify_only_broken_pipelines' do - it 'does not call Slack/Mattermost API for pipeline events' do - data = Gitlab::DataBuilder::Pipeline.build(pipeline) - result = chat_service.execute(data) - - expect(result).to be_falsy - end - end - - context 'with setting notify_only_broken_pipelines to false' do - before do - chat_service.notify_only_broken_pipelines = false - end - - it_behaves_like 'call Slack/Mattermost API' - end - end - end -end -- cgit v1.2.1 From 3f60a276fc36fc7d1c5323c38b33fdbc774cfbbf Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 13 Dec 2016 16:53:01 +0000 Subject: Added slack slash commands frontend help well Added tests --- .../projects/services/slack_slash_command_spec.rb | 48 ++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 spec/features/projects/services/slack_slash_command_spec.rb (limited to 'spec') diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb new file mode 100644 index 00000000000..dee43d69895 --- /dev/null +++ b/spec/features/projects/services/slack_slash_command_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +feature 'Setup Slack slash commands', feature: true do + include WaitForAjax + + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:service) { project.create_slack_slash_commands_service } + + before do + project.team << [user, :master] + login_as(user) + end + + describe 'user visits the slack slash command config page', js: true do + it 'shows a help message' do + visit edit_namespace_project_service_path(project.namespace, project, service) + + wait_for_ajax + + expect(page).to have_content('This service allows GitLab users to perform common') + end + end + + describe 'saving a token' do + let(:token) { ('a'..'z').to_a.join } + + it 'shows the token after saving' do + visit edit_namespace_project_service_path(project.namespace, project, service) + + fill_in 'service_token', with: token + click_on 'Save' + + value = find_field('service_token').value + + expect(value).to eq(token) + end + end + + describe 'the trigger url' do + it 'shows the correct url' do + visit edit_namespace_project_service_path(project.namespace, project, service) + + value = find_field('url').value + expect(value).to match("api/v3/projects/#{project.id}/services/slack_slash_commands/trigger") + end + end +end -- cgit v1.2.1 From 9e3153dbf556b9b9397806bedcf0a195e8ee3fa4 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 18 Dec 2016 23:30:48 +0100 Subject: Remove not related spec changes --- .../chat_message/build_message_spec.rb | 8 +++---- .../chat_message/issue_message_spec.rb | 10 ++++----- .../chat_message/merge_message_spec.rb | 12 +++++----- .../chat_message/note_message_spec.rb | 22 +++++++++--------- .../chat_message/push_message_spec.rb | 26 +++++++++++----------- .../chat_message/wiki_page_message_spec.rb | 8 +++---- 6 files changed, 43 insertions(+), 43 deletions(-) (limited to 'spec') diff --git a/spec/models/project_services/chat_message/build_message_spec.rb b/spec/models/project_services/chat_message/build_message_spec.rb index 50ad5013df9..b71d153f814 100644 --- a/spec/models/project_services/chat_message/build_message_spec.rb +++ b/spec/models/project_services/chat_message/build_message_spec.rb @@ -10,7 +10,7 @@ describe ChatMessage::BuildMessage do tag: false, project_name: 'project_name', - project_url: 'http://example.gitlab.com', + project_url: 'example.gitlab.com', commit: { status: status, @@ -48,10 +48,10 @@ describe ChatMessage::BuildMessage do end def build_message(status_text = status) - ":" \ - " Commit :" \ + " Commit " \ - " of branch" \ + " of branch" \ " by hacker #{status_text} in #{duration} #{'second'.pluralize(duration)}" end end diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb index 190ff4c535d..ebe0ead4408 100644 --- a/spec/models/project_services/chat_message/issue_message_spec.rb +++ b/spec/models/project_services/chat_message/issue_message_spec.rb @@ -10,14 +10,14 @@ describe ChatMessage::IssueMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'http://somewhere.com', + project_url: 'somewhere.com', object_attributes: { title: 'Issue title', id: 10, iid: 100, assignee_id: 1, - url: 'http://url.com', + url: 'url', action: 'open', state: 'opened', description: 'issue description' @@ -40,11 +40,11 @@ describe ChatMessage::IssueMessage, models: true do context 'open' do it 'returns a message regarding opening of issues' do expect(subject.pretext).to eq( - '[] Issue opened by test.user') + '] Issue opened by test.user') expect(subject.attachments).to eq([ { title: "#100 Issue title", - title_link: "http://url.com", + title_link: "url", text: "issue description", color: color, } @@ -60,7 +60,7 @@ describe ChatMessage::IssueMessage, models: true do it 'returns a message regarding closing of issues' do expect(subject.pretext). to eq( - '[] Issue closed by test.user') + '] Issue closed by test.user') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb index cc154112e90..07c414c6ca4 100644 --- a/spec/models/project_services/chat_message/merge_message_spec.rb +++ b/spec/models/project_services/chat_message/merge_message_spec.rb @@ -10,14 +10,14 @@ describe ChatMessage::MergeMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'http://somewhere.com', + project_url: 'somewhere.com', object_attributes: { title: "Issue title\nSecond line", id: 10, iid: 100, assignee_id: 1, - url: 'http://url.com', + url: 'url', state: 'opened', description: 'issue description', source_branch: 'source_branch', @@ -31,8 +31,8 @@ describe ChatMessage::MergeMessage, models: true do context 'open' do it 'returns a message regarding opening of merge requests' do expect(subject.pretext).to eq( - 'test.user opened '\ - 'in : *Issue title*') + 'test.user opened '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end @@ -43,8 +43,8 @@ describe ChatMessage::MergeMessage, models: true do end it 'returns a message regarding closing of merge requests' do expect(subject.pretext).to eq( - 'test.user closed '\ - 'in : *Issue title*') + 'test.user closed '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/chat_message/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb index da700a08e57..31936da40a2 100644 --- a/spec/models/project_services/chat_message/note_message_spec.rb +++ b/spec/models/project_services/chat_message/note_message_spec.rb @@ -11,15 +11,15 @@ describe ChatMessage::NoteMessage, models: true do avatar_url: 'http://fakeavatar' }, project_name: 'project_name', - project_url: 'http://somewhere.com', + project_url: 'somewhere.com', repository: { name: 'project_name', - url: 'http://somewhere.com', + url: 'somewhere.com', }, object_attributes: { id: 10, note: 'comment on a commit', - url: 'http://url.com', + url: 'url', noteable_type: 'Commit' } } @@ -37,8 +37,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on commits' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*Added a commit message*") expected_attachments = [ { @@ -63,8 +63,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on a merge request' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*merge request title*") expected_attachments = [ { @@ -90,8 +90,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on an issue' do message = described_class.new(@args) expect(message.pretext).to eq( - "test.user in : " \ + "test.user in : " \ "*issue title*") expected_attachments = [ { @@ -115,8 +115,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on a project snippet' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*snippet title*") expected_attachments = [ { diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb index 24928873bad..b781c4505db 100644 --- a/spec/models/project_services/chat_message/push_message_spec.rb +++ b/spec/models/project_services/chat_message/push_message_spec.rb @@ -10,7 +10,7 @@ describe ChatMessage::PushMessage, models: true do project_name: 'project_name', ref: 'refs/heads/master', user_name: 'test.user', - project_url: 'http://url.com' + project_url: 'url' } end @@ -19,20 +19,20 @@ describe ChatMessage::PushMessage, models: true do context 'push' do before do args[:commits] = [ - { message: 'message1', url: 'http://url1.com', id: 'abcdefghijkl', author: { name: 'author1' } }, - { message: 'message2', url: 'http://url2.com', id: '123456789012', author: { name: 'author2' } }, + { message: 'message1', url: 'url1', id: 'abcdefghijkl', author: { name: 'author1' } }, + { message: 'message2', url: 'url2', id: '123456789012', author: { name: 'author2' } }, ] end it 'returns a message regarding pushes' do expect(subject.pretext).to eq( - 'test.user pushed to branch of '\ - ' ()' + 'test.user pushed to branch of '\ + ' ()' ) expect(subject.attachments).to eq([ { - text: ": message1 - author1\n"\ - ": message2 - author2", + text: ": message1 - author1\n"\ + ": message2 - author2", color: color, } ]) @@ -47,14 +47,14 @@ describe ChatMessage::PushMessage, models: true do project_name: 'project_name', ref: 'refs/tags/new_tag', user_name: 'test.user', - project_url: 'http://url.com' + project_url: 'url' } end it 'returns a message regarding pushes' do expect(subject.pretext).to eq('test.user pushed new tag ' \ - ' to ' \ - '') + ' to ' \ + '') expect(subject.attachments).to be_empty end end @@ -66,8 +66,8 @@ describe ChatMessage::PushMessage, models: true do it 'returns a message regarding a new branch' do expect(subject.pretext).to eq( - 'test.user pushed new branch to '\ - '' + 'test.user pushed new branch to '\ + '' ) expect(subject.attachments).to be_empty end @@ -80,7 +80,7 @@ describe ChatMessage::PushMessage, models: true do it 'returns a message regarding a removed branch' do expect(subject.pretext).to eq( - 'test.user removed branch master from ' + 'test.user removed branch master from ' ) expect(subject.attachments).to be_empty end diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb index a2ad61e38e7..94c04dc0865 100644 --- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb +++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb @@ -10,10 +10,10 @@ describe ChatMessage::WikiPageMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'http://somewhere.com', + project_url: 'somewhere.com', object_attributes: { title: 'Wiki page title', - url: 'http://url.com', + url: 'url', content: 'Wiki page description' } } @@ -25,7 +25,7 @@ describe ChatMessage::WikiPageMessage, models: true do it 'returns a message that a new wiki page was created' do expect(subject.pretext).to eq( - 'test.user created in : '\ + 'test.user created in : '\ '*Wiki page title*') end end @@ -35,7 +35,7 @@ describe ChatMessage::WikiPageMessage, models: true do it 'returns a message that a wiki page was updated' do expect(subject.pretext).to eq( - 'test.user edited in : '\ + 'test.user edited in : '\ '*Wiki page title*') end end -- cgit v1.2.1 From f9023adbad4939ba597d509e319105659e61734b Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 18 Dec 2016 23:32:53 +0100 Subject: Fix spec failures --- spec/features/admin/admin_settings_spec.rb | 4 ++-- spec/lib/gitlab/import_export/all_models.yml | 1 + spec/models/project_spec.rb | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index 8cd66f189be..e7a23746244 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -17,9 +17,9 @@ feature 'Admin updates settings', feature: true do expect(page).to have_content "Application settings saved successfully" end - scenario 'Change Slack Service template settings' do + scenario 'Change Slack Notifications Service template settings' do click_link 'Service Templates' - click_link 'Slack' + click_link 'Slack notifications' fill_in 'Webhook', with: 'http://localhost' fill_in 'Username', with: 'test_user' fill_in 'service_push_channel', with: '#test_channel' diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 9b49d6837c3..7e618e2fcf5 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -129,6 +129,7 @@ project: - builds_email_service - pipelines_email_service - mattermost_slash_commands_service +- slack_slash_commands_service - irker_service - pivotaltracker_service - hipchat_service diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index bab3c3dbb02..4b39dc77f29 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -20,7 +20,6 @@ describe Project, models: true do it { is_expected.to have_many(:deploy_keys) } it { is_expected.to have_many(:hooks).dependent(:destroy) } it { is_expected.to have_many(:protected_branches).dependent(:destroy) } - it { is_expected.to have_many(:chat_services) } it { is_expected.to have_one(:forked_project_link).dependent(:destroy) } it { is_expected.to have_one(:slack_notification_service).dependent(:destroy) } it { is_expected.to have_one(:mattermost_notification_service).dependent(:destroy) } @@ -37,6 +36,7 @@ describe Project, models: true do it { is_expected.to have_one(:hipchat_service).dependent(:destroy) } it { is_expected.to have_one(:flowdock_service).dependent(:destroy) } it { is_expected.to have_one(:assembla_service).dependent(:destroy) } + it { is_expected.to have_one(:slack_slash_commands_service).dependent(:destroy) } it { is_expected.to have_one(:mattermost_slash_commands_service).dependent(:destroy) } it { is_expected.to have_one(:gemnasium_service).dependent(:destroy) } it { is_expected.to have_one(:buildkite_service).dependent(:destroy) } -- cgit v1.2.1 From f5ff372140d066d7bcedc0ad0799c723a9012bb0 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Sun, 18 Dec 2016 23:34:40 +0100 Subject: Fix failures --- spec/features/admin/admin_settings_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/admin/admin_settings_spec.rb b/spec/features/admin/admin_settings_spec.rb index e7a23746244..47fa2f14307 100644 --- a/spec/features/admin/admin_settings_spec.rb +++ b/spec/features/admin/admin_settings_spec.rb @@ -30,7 +30,7 @@ feature 'Admin updates settings', feature: true do expect(page).to have_content 'Application settings saved successfully' - click_link 'Slack' + click_link 'Slack notifications' page.all('input[type=checkbox]').each do |checkbox| expect(checkbox).to be_checked -- cgit v1.2.1 From fb23153343f274a29cba1023759f675aaf64251a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 19 Dec 2016 18:50:01 +0800 Subject: Delete the project when building the build Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8091#note_20222756 --- spec/requests/ci/api/builds_spec.rb | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index d61a9afd12e..2963fe85478 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -332,21 +332,18 @@ describe Ci::API::Builds do context 'when project for the build has been deleted' do let(:build) do - create(:ci_build, - :pending, - :trace, - runner_id: runner.id, - pipeline: pipeline) + result = create(:ci_build, + :pending, + :trace, + runner_id: runner.id, + pipeline: pipeline) + result.project.update(pending_delete: true) + result end it 'responds with forbidden' do expect(response.status).to eq 403 end - - def initial_patch_the_trace - build.project.update(pending_delete: true) - super - end end end -- cgit v1.2.1 From b1ccf99e87605216f7d5733d6a4ffb4530d4cfc9 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 19 Dec 2016 13:34:03 +0100 Subject: Fix previously reverted spec failures --- .../chat_message/build_message_spec.rb | 8 +++---- .../chat_message/issue_message_spec.rb | 10 ++++----- .../chat_message/merge_message_spec.rb | 12 +++++----- .../chat_message/note_message_spec.rb | 22 +++++++++--------- .../chat_message/pipeline_message_spec.rb | 8 +++---- .../chat_message/push_message_spec.rb | 26 +++++++++++----------- .../chat_message/wiki_page_message_spec.rb | 8 +++---- 7 files changed, 47 insertions(+), 47 deletions(-) (limited to 'spec') diff --git a/spec/models/project_services/chat_message/build_message_spec.rb b/spec/models/project_services/chat_message/build_message_spec.rb index b71d153f814..50ad5013df9 100644 --- a/spec/models/project_services/chat_message/build_message_spec.rb +++ b/spec/models/project_services/chat_message/build_message_spec.rb @@ -10,7 +10,7 @@ describe ChatMessage::BuildMessage do tag: false, project_name: 'project_name', - project_url: 'example.gitlab.com', + project_url: 'http://example.gitlab.com', commit: { status: status, @@ -48,10 +48,10 @@ describe ChatMessage::BuildMessage do end def build_message(status_text = status) - ":" \ - " Commit :" \ + " Commit " \ - " of branch" \ + " of branch" \ " by hacker #{status_text} in #{duration} #{'second'.pluralize(duration)}" end end diff --git a/spec/models/project_services/chat_message/issue_message_spec.rb b/spec/models/project_services/chat_message/issue_message_spec.rb index ebe0ead4408..190ff4c535d 100644 --- a/spec/models/project_services/chat_message/issue_message_spec.rb +++ b/spec/models/project_services/chat_message/issue_message_spec.rb @@ -10,14 +10,14 @@ describe ChatMessage::IssueMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', object_attributes: { title: 'Issue title', id: 10, iid: 100, assignee_id: 1, - url: 'url', + url: 'http://url.com', action: 'open', state: 'opened', description: 'issue description' @@ -40,11 +40,11 @@ describe ChatMessage::IssueMessage, models: true do context 'open' do it 'returns a message regarding opening of issues' do expect(subject.pretext).to eq( - '] Issue opened by test.user') + '[] Issue opened by test.user') expect(subject.attachments).to eq([ { title: "#100 Issue title", - title_link: "url", + title_link: "http://url.com", text: "issue description", color: color, } @@ -60,7 +60,7 @@ describe ChatMessage::IssueMessage, models: true do it 'returns a message regarding closing of issues' do expect(subject.pretext). to eq( - '] Issue closed by test.user') + '[] Issue closed by test.user') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/chat_message/merge_message_spec.rb b/spec/models/project_services/chat_message/merge_message_spec.rb index 07c414c6ca4..cc154112e90 100644 --- a/spec/models/project_services/chat_message/merge_message_spec.rb +++ b/spec/models/project_services/chat_message/merge_message_spec.rb @@ -10,14 +10,14 @@ describe ChatMessage::MergeMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', object_attributes: { title: "Issue title\nSecond line", id: 10, iid: 100, assignee_id: 1, - url: 'url', + url: 'http://url.com', state: 'opened', description: 'issue description', source_branch: 'source_branch', @@ -31,8 +31,8 @@ describe ChatMessage::MergeMessage, models: true do context 'open' do it 'returns a message regarding opening of merge requests' do expect(subject.pretext).to eq( - 'test.user opened '\ - 'in : *Issue title*') + 'test.user opened '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end @@ -43,8 +43,8 @@ describe ChatMessage::MergeMessage, models: true do end it 'returns a message regarding closing of merge requests' do expect(subject.pretext).to eq( - 'test.user closed '\ - 'in : *Issue title*') + 'test.user closed '\ + 'in : *Issue title*') expect(subject.attachments).to be_empty end end diff --git a/spec/models/project_services/chat_message/note_message_spec.rb b/spec/models/project_services/chat_message/note_message_spec.rb index 31936da40a2..da700a08e57 100644 --- a/spec/models/project_services/chat_message/note_message_spec.rb +++ b/spec/models/project_services/chat_message/note_message_spec.rb @@ -11,15 +11,15 @@ describe ChatMessage::NoteMessage, models: true do avatar_url: 'http://fakeavatar' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', repository: { name: 'project_name', - url: 'somewhere.com', + url: 'http://somewhere.com', }, object_attributes: { id: 10, note: 'comment on a commit', - url: 'url', + url: 'http://url.com', noteable_type: 'Commit' } } @@ -37,8 +37,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on commits' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*Added a commit message*") expected_attachments = [ { @@ -63,8 +63,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on a merge request' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*merge request title*") expected_attachments = [ { @@ -90,8 +90,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on an issue' do message = described_class.new(@args) expect(message.pretext).to eq( - "test.user in : " \ + "test.user in : " \ "*issue title*") expected_attachments = [ { @@ -115,8 +115,8 @@ describe ChatMessage::NoteMessage, models: true do it 'returns a message regarding notes on a project snippet' do message = described_class.new(@args) - expect(message.pretext).to eq("test.user in : " \ + expect(message.pretext).to eq("test.user in : " \ "*snippet title*") expected_attachments = [ { diff --git a/spec/models/project_services/chat_message/pipeline_message_spec.rb b/spec/models/project_services/chat_message/pipeline_message_spec.rb index eca71db07b6..bf2a9616455 100644 --- a/spec/models/project_services/chat_message/pipeline_message_spec.rb +++ b/spec/models/project_services/chat_message/pipeline_message_spec.rb @@ -15,7 +15,7 @@ describe ChatMessage::PipelineMessage do duration: duration }, project: { path_with_namespace: 'project_name', - web_url: 'example.gitlab.com' }, + web_url: 'http://example.gitlab.com' }, user: user } end @@ -59,9 +59,9 @@ describe ChatMessage::PipelineMessage do end def build_message(status_text = status, name = user[:name]) - ":" \ - " Pipeline " \ - " of branch" \ + ":" \ + " Pipeline " \ + " of branch" \ " by #{name} #{status_text} in #{duration} #{'second'.pluralize(duration)}" end end diff --git a/spec/models/project_services/chat_message/push_message_spec.rb b/spec/models/project_services/chat_message/push_message_spec.rb index b781c4505db..24928873bad 100644 --- a/spec/models/project_services/chat_message/push_message_spec.rb +++ b/spec/models/project_services/chat_message/push_message_spec.rb @@ -10,7 +10,7 @@ describe ChatMessage::PushMessage, models: true do project_name: 'project_name', ref: 'refs/heads/master', user_name: 'test.user', - project_url: 'url' + project_url: 'http://url.com' } end @@ -19,20 +19,20 @@ describe ChatMessage::PushMessage, models: true do context 'push' do before do args[:commits] = [ - { message: 'message1', url: 'url1', id: 'abcdefghijkl', author: { name: 'author1' } }, - { message: 'message2', url: 'url2', id: '123456789012', author: { name: 'author2' } }, + { message: 'message1', url: 'http://url1.com', id: 'abcdefghijkl', author: { name: 'author1' } }, + { message: 'message2', url: 'http://url2.com', id: '123456789012', author: { name: 'author2' } }, ] end it 'returns a message regarding pushes' do expect(subject.pretext).to eq( - 'test.user pushed to branch of '\ - ' ()' + 'test.user pushed to branch of '\ + ' ()' ) expect(subject.attachments).to eq([ { - text: ": message1 - author1\n"\ - ": message2 - author2", + text: ": message1 - author1\n"\ + ": message2 - author2", color: color, } ]) @@ -47,14 +47,14 @@ describe ChatMessage::PushMessage, models: true do project_name: 'project_name', ref: 'refs/tags/new_tag', user_name: 'test.user', - project_url: 'url' + project_url: 'http://url.com' } end it 'returns a message regarding pushes' do expect(subject.pretext).to eq('test.user pushed new tag ' \ - ' to ' \ - '') + ' to ' \ + '') expect(subject.attachments).to be_empty end end @@ -66,8 +66,8 @@ describe ChatMessage::PushMessage, models: true do it 'returns a message regarding a new branch' do expect(subject.pretext).to eq( - 'test.user pushed new branch to '\ - '' + 'test.user pushed new branch to '\ + '' ) expect(subject.attachments).to be_empty end @@ -80,7 +80,7 @@ describe ChatMessage::PushMessage, models: true do it 'returns a message regarding a removed branch' do expect(subject.pretext).to eq( - 'test.user removed branch master from ' + 'test.user removed branch master from ' ) expect(subject.attachments).to be_empty end diff --git a/spec/models/project_services/chat_message/wiki_page_message_spec.rb b/spec/models/project_services/chat_message/wiki_page_message_spec.rb index 94c04dc0865..a2ad61e38e7 100644 --- a/spec/models/project_services/chat_message/wiki_page_message_spec.rb +++ b/spec/models/project_services/chat_message/wiki_page_message_spec.rb @@ -10,10 +10,10 @@ describe ChatMessage::WikiPageMessage, models: true do username: 'test.user' }, project_name: 'project_name', - project_url: 'somewhere.com', + project_url: 'http://somewhere.com', object_attributes: { title: 'Wiki page title', - url: 'url', + url: 'http://url.com', content: 'Wiki page description' } } @@ -25,7 +25,7 @@ describe ChatMessage::WikiPageMessage, models: true do it 'returns a message that a new wiki page was created' do expect(subject.pretext).to eq( - 'test.user created in : '\ + 'test.user created in : '\ '*Wiki page title*') end end @@ -35,7 +35,7 @@ describe ChatMessage::WikiPageMessage, models: true do it 'returns a message that a wiki page was updated' do expect(subject.pretext).to eq( - 'test.user edited in : '\ + 'test.user edited in : '\ '*Wiki page title*') end end -- cgit v1.2.1 From 6d14a6640f89893792ad6c66b7f4362ef4ff9007 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Mon, 19 Dec 2016 14:14:09 +0100 Subject: Minor adjustments API Mattermost [ci skip] --- spec/fixtures/mattermost_new_command.json | 1 - spec/lib/mattermost/command_spec.rb | 13 +++++-------- spec/lib/mattermost/session_spec.rb | 2 +- spec/lib/mattermost/team_spec.rb | 15 +++++++++------ 4 files changed, 15 insertions(+), 16 deletions(-) delete mode 100644 spec/fixtures/mattermost_new_command.json (limited to 'spec') diff --git a/spec/fixtures/mattermost_new_command.json b/spec/fixtures/mattermost_new_command.json deleted file mode 100644 index 4b827f19926..00000000000 --- a/spec/fixtures/mattermost_new_command.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"y8j1nexrdirj5nubq5uzdwwidr","token":"pzajm5hfbtni3r49ujpt8betpc","create_at":1481897117122,"update_at":1481897117122,"delete_at":0,"creator_id":"78nm4euoc7dypergdc13ekxgpo","team_id":"w59qt5a817f69jkxdz6xe7y4ir","trigger":"display","method":"P","username":"GitLab","icon_url":"","auto_complete":false,"auto_complete_desc":"","auto_complete_hint":"","display_name":"Display name","description":"the description","url":"http://trigger.url/trigger"} diff --git a/spec/lib/mattermost/command_spec.rb b/spec/lib/mattermost/command_spec.rb index 7c6457f639d..8c4b12c4d03 100644 --- a/spec/lib/mattermost/command_spec.rb +++ b/spec/lib/mattermost/command_spec.rb @@ -1,17 +1,14 @@ require 'spec_helper' describe Mattermost::Command do - describe '.create' do - let(:new_command) do - JSON.parse(File.read(Rails.root.join('spec/fixtures/', 'mattermost_new_command.json'))) - end + let(:session) { double("session") } + describe '.create' do it 'gets the teams' do - allow(described_class).to receive(:post_command).and_return(new_command) - - token = described_class.create('abc', url: 'http://trigger.url/trigger', icon_url: 'http://myicon.com/icon.png') + allow(session).to receive(:post).and_return('token' => 'token') + expect(session).to receive(:post) - expect(token).to eq('pzajm5hfbtni3r49ujpt8betpc') + described_class.create(session, 'abc', url: 'http://trigger.com') end end end diff --git a/spec/lib/mattermost/session_spec.rb b/spec/lib/mattermost/session_spec.rb index 752ac796b1c..3c2eddbd221 100644 --- a/spec/lib/mattermost/session_spec.rb +++ b/spec/lib/mattermost/session_spec.rb @@ -96,4 +96,4 @@ describe Mattermost::Session, type: :request do end end end -end \ No newline at end of file +end diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index 0fe6163900d..b3db2999070 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -2,20 +2,23 @@ require 'spec_helper' describe Mattermost::Team do describe '.team_admin' do - let(:init_load) do - JSON.parse(File.read(Rails.root.join('spec/fixtures/', 'mattermost_initial_load.json'))) - end + let(:session) { double("session") } + let(:json) { File.read(Rails.root.join('spec/fixtures/', 'mattermost_initial_load.json')) } + let(:parsed_response) { JSON.parse(json) } before do - allow(described_class).to receive(:initial_load).and_return(init_load) + allow(session).to receive(:get).with('/api/v3/users/initial_load'). + and_return(json) + allow(json).to receive(:parsed_response).and_return(parsed_response) end it 'gets the teams' do - expect(described_class.team_admin.count).to be(2) + expect(described_class.team_admin(session).count).to be(2) end it 'filters on being team admin' do - ids = described_class.team_admin.map { |team| team['id'] } + ids = described_class.team_admin(session).map { |team| team['id'] } + expect(ids).to include("w59qt5a817f69jkxdz6xe7y4ir", "my9oujxf5jy1zqdgu9rihd66do") end end -- cgit v1.2.1 From 1e2e0de9441a2f9777bb989e8a8c275c2b103ca7 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 19 Dec 2016 22:01:37 +0800 Subject: Define actions in let so that it could be overridden Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8091/diffs#note_20236356 --- spec/requests/ci/api/builds_spec.rb | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 2963fe85478..fdb2234d32b 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -249,7 +249,13 @@ describe Ci::API::Builds do end describe 'PATCH /builds/:id/trace.txt' do - let(:build) { create(:ci_build, :pending, :trace, runner_id: runner.id) } + let(:build) do + attributes = {runner_id: runner.id, pipeline: pipeline} + create(:ci_build, :pending, :trace, attributes) do |build| + build.run + end + end + let(:headers) { { Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token, 'Content-Type' => 'text/plain' } } let(:headers_with_range) { headers.merge({ 'Content-Range' => '11-20' }) } let(:update_interval) { 10.seconds.to_i } @@ -276,7 +282,6 @@ describe Ci::API::Builds do end before do - build.run! initial_patch_the_trace end @@ -332,17 +337,15 @@ describe Ci::API::Builds do context 'when project for the build has been deleted' do let(:build) do - result = create(:ci_build, - :pending, - :trace, - runner_id: runner.id, - pipeline: pipeline) - result.project.update(pending_delete: true) - result + attributes = {runner_id: runner.id, pipeline: pipeline} + create(:ci_build, :pending, :trace, attributes) do |build| + build.run + build.project.update(pending_delete: true) + end end it 'responds with forbidden' do - expect(response.status).to eq 403 + expect(response.status).to eq(403) end end end -- cgit v1.2.1 From e6c83b1c1f3db5cea9730ae320f3a6525fd6fe2a Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 19 Dec 2016 22:19:03 +0800 Subject: Just set the status rather than calling event Feedback: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8091#note_20239558 --- spec/requests/ci/api/builds_spec.rb | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index fdb2234d32b..5acda0fd729 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -251,9 +251,7 @@ describe Ci::API::Builds do describe 'PATCH /builds/:id/trace.txt' do let(:build) do attributes = {runner_id: runner.id, pipeline: pipeline} - create(:ci_build, :pending, :trace, attributes) do |build| - build.run - end + create(:ci_build, :running, :trace, attributes) end let(:headers) { { Ci::API::Helpers::BUILD_TOKEN_HEADER => build.token, 'Content-Type' => 'text/plain' } } @@ -338,8 +336,7 @@ describe Ci::API::Builds do context 'when project for the build has been deleted' do let(:build) do attributes = {runner_id: runner.id, pipeline: pipeline} - create(:ci_build, :pending, :trace, attributes) do |build| - build.run + create(:ci_build, :running, :trace, attributes) do |build| build.project.update(pending_delete: true) end end -- cgit v1.2.1 From ad39831049a5d645da2df62de4f9a618fa6f80d7 Mon Sep 17 00:00:00 2001 From: Semyon Pupkov Date: Mon, 19 Dec 2016 16:29:58 +0500 Subject: Move admin projects spinach tests to rspec https://gitlab.com/gitlab-org/gitlab-ce/issues/23036 --- spec/features/admin/admin_projects_spec.rb | 99 +++++++++++++++++++++++++++--- 1 file changed, 91 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/features/admin/admin_projects_spec.rb b/spec/features/admin/admin_projects_spec.rb index a36bfd574cb..a5b88812b75 100644 --- a/spec/features/admin/admin_projects_spec.rb +++ b/spec/features/admin/admin_projects_spec.rb @@ -1,12 +1,17 @@ require 'spec_helper' describe "Admin::Projects", feature: true do - before do - @project = create(:project) + include Select2Helper + + let(:user) { create :user } + let!(:project) { create(:project) } + let!(:current_user) do login_as :admin end describe "GET /admin/projects" do + let!(:archived_project) { create :project, :public, archived: true } + before do visit admin_projects_path end @@ -15,20 +20,98 @@ describe "Admin::Projects", feature: true do expect(current_path).to eq(admin_projects_path) end - it "has projects list" do - expect(page).to have_content(@project.name) + it 'renders projects list without archived project' do + expect(page).to have_content(project.name) + expect(page).not_to have_content(archived_project.name) + end + + it 'renders all projects', js: true do + find(:css, '#sort-projects-dropdown').click + click_link 'Show archived projects' + + expect(page).to have_content(project.name) + expect(page).to have_content(archived_project.name) + expect(page).to have_xpath("//span[@class='label label-warning']", text: 'archived') end end - describe "GET /admin/projects/:id" do + describe "GET /admin/projects/:namespace_id/:id" do before do visit admin_projects_path - click_link "#{@project.name}" + click_link "#{project.name}" + end + + it do + expect(current_path).to eq admin_namespace_project_path(project.namespace, project) end it "has project info" do - expect(page).to have_content(@project.path) - expect(page).to have_content(@project.name) + expect(page).to have_content(project.path) + expect(page).to have_content(project.name) + expect(page).to have_content(project.name_with_namespace) + expect(page).to have_content(project.creator.name) + end + end + + describe 'transfer project' do + before do + create(:group, name: 'Web') + + allow_any_instance_of(Projects::TransferService). + to receive(:move_uploads_to_new_namespace).and_return(true) + end + + it 'transfers project to group web', js: true do + visit admin_namespace_project_path(project.namespace, project) + + click_button 'Search for Namespace' + click_link 'group: web' + click_button 'Transfer' + + expect(page).to have_content("Web / #{project.name}") + expect(page).to have_content('Namespace: Web') + end + end + + describe 'add admin himself to a project' do + before do + project.team << [user, :master] + end + + it 'adds admin a to a project as developer', js: true do + visit namespace_project_project_members_path(project.namespace, project) + + page.within '.users-project-form' do + select2(current_user.id, from: '#user_ids', multiple: true) + select 'Developer', from: 'access_level' + end + + click_button 'Add to project' + + page.within '.content-list' do + expect(page).to have_content(current_user.name) + expect(page).to have_content('Developer') + end + end + end + + describe 'admin remove himself from a project' do + before do + project.team << [user, :master] + project.team << [current_user, :developer] + end + + it 'removes admin from the project' do + visit namespace_project_project_members_path(project.namespace, project) + + page.within '.content-list' do + expect(page).to have_content(current_user.name) + expect(page).to have_content('Developer') + end + + find(:css, 'li', text: current_user.name).find(:css, 'a.btn-remove').click + + expect(page).not_to have_selector(:css, '.content-list') end end end -- cgit v1.2.1 From 298d05a5c3cc3c2f1daa4d77c45f9c90b53248df Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 19 Dec 2016 15:40:06 +0100 Subject: Improve after feedback --- .../projects/services/slack_slash_command_spec.rb | 18 +++++++++--------- .../mattermost_slash_commands_service_spec.rb | 4 ++-- .../project_services/slack_slash_commands_service.rb | 6 ++++-- spec/support/chat_slash_commands_shared_examples.rb | 2 +- 4 files changed, 16 insertions(+), 14 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb index dee43d69895..70e203efcf5 100644 --- a/spec/features/projects/services/slack_slash_command_spec.rb +++ b/spec/features/projects/services/slack_slash_command_spec.rb @@ -1,18 +1,18 @@ require 'spec_helper' -feature 'Setup Slack slash commands', feature: true do +feature 'Slack slash commands', feature: true do include WaitForAjax - let(:user) { create(:user) } - let(:project) { create(:project) } - let(:service) { project.create_slack_slash_commands_service } + given(:user) { create(:user) } + given(:project) { create(:project) } + given(:service) { project.create_slack_slash_commands_service } - before do + background do project.team << [user, :master] login_as(user) end - describe 'user visits the slack slash command config page', js: true do + scenario 'user visits the slack slash command config page', js: true do it 'shows a help message' do visit edit_namespace_project_service_path(project.namespace, project, service) @@ -22,8 +22,8 @@ feature 'Setup Slack slash commands', feature: true do end end - describe 'saving a token' do - let(:token) { ('a'..'z').to_a.join } + scenario 'saving a token' do + given(:token) { ('a'..'z').to_a.join } it 'shows the token after saving' do visit edit_namespace_project_service_path(project.namespace, project, service) @@ -37,7 +37,7 @@ feature 'Setup Slack slash commands', feature: true do end end - describe 'the trigger url' do + scenario 'the trigger url' do it 'shows the correct url' do visit edit_namespace_project_service_path(project.namespace, project, service) diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 5c34cb6b4cf..1ae1483e2a4 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -1,5 +1,5 @@ require 'spec_helper' -describe MattermostSlashCommandsService, models: true do - it_behaves_like "chat slash commands" +describe MattermostSlashCommandsService, :models do + it_behaves_like "chat slash commands service" end diff --git a/spec/models/project_services/slack_slash_commands_service.rb b/spec/models/project_services/slack_slash_commands_service.rb index c3fa80caebe..5775e439906 100644 --- a/spec/models/project_services/slack_slash_commands_service.rb +++ b/spec/models/project_services/slack_slash_commands_service.rb @@ -1,7 +1,7 @@ require 'spec_helper' -describe SlackSlashCommandsService, models: true do - it_behaves_like "chat slash commands" +describe SlackSlashCommandsService, :models do + it_behaves_like "chat slash commands service" describe '#trigger' do context 'when an auth url is generated' do @@ -15,11 +15,13 @@ describe SlackSlashCommandsService, models: true do token: 'token' } end + let(:service) do project.create_slack_slash_commands_service( properties: { token: 'token' } ) end + let(:authorize_url) do 'http://authorize.example.com/' end diff --git a/spec/support/chat_slash_commands_shared_examples.rb b/spec/support/chat_slash_commands_shared_examples.rb index 96130b45235..4dfa29849ee 100644 --- a/spec/support/chat_slash_commands_shared_examples.rb +++ b/spec/support/chat_slash_commands_shared_examples.rb @@ -1,4 +1,4 @@ -RSpec.shared_examples 'chat slash commands' do +RSpec.shared_examples 'chat slash commands service' do describe "Associations" do it { is_expected.to respond_to :token } it { is_expected.to have_many :chat_names } -- cgit v1.2.1 From a0690c4c01fceccef9efca70a9256f5790fba9c7 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Mon, 19 Dec 2016 23:20:22 +0800 Subject: Spaces around literal hash Feedback: https://gitlab.com/gitlab-org/gitlab-ce/builds/7617209 --- spec/requests/ci/api/builds_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 5acda0fd729..79f12ace999 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -250,7 +250,7 @@ describe Ci::API::Builds do describe 'PATCH /builds/:id/trace.txt' do let(:build) do - attributes = {runner_id: runner.id, pipeline: pipeline} + attributes = { runner_id: runner.id, pipeline: pipeline } create(:ci_build, :running, :trace, attributes) end @@ -335,7 +335,7 @@ describe Ci::API::Builds do context 'when project for the build has been deleted' do let(:build) do - attributes = {runner_id: runner.id, pipeline: pipeline} + attributes = { runner_id: runner.id, pipeline: pipeline } create(:ci_build, :running, :trace, attributes) do |build| build.project.update(pending_delete: true) end -- cgit v1.2.1 From f73193c328b871a9a3af803012c10d9bc1bd0904 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 6 Dec 2016 17:31:58 +0100 Subject: Smarter refreshing of authorized projects Prior to this commit the refreshing of authorized projects was done in two steps: 1. Remove existing authorizations 2. Insert a new list of all authorizations This can lead to a high amount of dead tuples as every time all rows are being replaced. For example, if a user with 100 authorizations is given access to a new project this would lead to: * 100 rows being removed * 101 new rows being inserted This commit changes the way this system works so it only removes/inserts what is necessary. Using the above example this would lead to only 1 new row being inserted, with the initial 100 being left untouched. Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/25257 --- spec/models/project_authorization_spec.rb | 25 +++ .../refresh_authorized_projects_service_spec.rb | 185 +++++++++++++++++++++ spec/workers/authorized_projects_worker_spec.rb | 14 +- 3 files changed, 212 insertions(+), 12 deletions(-) create mode 100644 spec/models/project_authorization_spec.rb create mode 100644 spec/services/users/refresh_authorized_projects_service_spec.rb (limited to 'spec') diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb new file mode 100644 index 00000000000..33ef67f97a7 --- /dev/null +++ b/spec/models/project_authorization_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe ProjectAuthorization do + let(:user) { create(:user) } + let(:project1) { create(:empty_project) } + let(:project2) { create(:empty_project) } + + describe '.insert_authorizations' do + it 'inserts the authorizations' do + described_class. + insert_authorizations([[user.id, project1.id, Gitlab::Access::MASTER]]) + + expect(user.project_authorizations.count).to eq(1) + end + + it 'inserts rows in batches' do + described_class.insert_authorizations([ + [user.id, project1.id, Gitlab::Access::MASTER], + [user.id, project2.id, Gitlab::Access::MASTER], + ], 1) + + expect(user.project_authorizations.count).to eq(2) + end + end +end diff --git a/spec/services/users/refresh_authorized_projects_service_spec.rb b/spec/services/users/refresh_authorized_projects_service_spec.rb new file mode 100644 index 00000000000..72c8f7cd8ec --- /dev/null +++ b/spec/services/users/refresh_authorized_projects_service_spec.rb @@ -0,0 +1,185 @@ +require 'spec_helper' + +describe Users::RefreshAuthorizedProjectsService do + let(:project) { create(:empty_project) } + let(:user) { project.namespace.owner } + let(:service) { described_class.new(user) } + + def create_authorization(project, user, access_level = Gitlab::Access::MASTER) + ProjectAuthorization. + create!(project: project, user: user, access_level: access_level) + end + + describe '#execute' do + before do + user.project_authorizations.delete_all + end + + it 'updates the authorized projects of the user' do + project2 = create(:empty_project) + to_remove = create_authorization(project2, user) + + expect(service).to receive(:update_with_lease). + with([to_remove.id], [[user.id, project.id, Gitlab::Access::MASTER]]) + + service.execute + end + + it 'sets the access level of a project to the highest available level' do + to_remove = create_authorization(project, user, Gitlab::Access::DEVELOPER) + + expect(service).to receive(:update_with_lease). + with([to_remove.id], [[user.id, project.id, Gitlab::Access::MASTER]]) + + service.execute + end + + it 'returns a User' do + expect(service.execute).to be_an_instance_of(User) + end + end + + describe '#update_with_lease', :redis do + it 'refreshes the authorizations using a lease' do + expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain). + and_return('foo') + + expect(Gitlab::ExclusiveLease).to receive(:cancel). + with(an_instance_of(String), 'foo') + + expect(service).to receive(:update_authorizations).with([1], []) + + service.update_with_lease([1]) + end + end + + describe '#update_authorizations' do + it 'does nothing when there are no rows to add and remove' do + expect(user).not_to receive(:remove_project_authorizations) + expect(ProjectAuthorization).not_to receive(:insert_authorizations) + expect(user).not_to receive(:set_authorized_projects_column) + + service.update_authorizations([], []) + end + + it 'removes authorizations that should be removed' do + authorization = create_authorization(project, user) + + service.update_authorizations([authorization.id]) + + expect(user.project_authorizations).to be_empty + end + + it 'inserts authorizations that should be added' do + service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MASTER]]) + + authorizations = user.project_authorizations + + expect(authorizations.length).to eq(1) + expect(authorizations[0].user_id).to eq(user.id) + expect(authorizations[0].project_id).to eq(project.id) + expect(authorizations[0].access_level).to eq(Gitlab::Access::MASTER) + end + + it 'populates the authorized projects column' do + # make sure we start with a nil value no matter what the default in the + # factory may be. + user.update(authorized_projects_populated: nil) + + service.update_authorizations([], [[user.id, project.id, Gitlab::Access::MASTER]]) + + expect(user.authorized_projects_populated).to eq(true) + end + end + + describe '#fresh_access_levels_per_project' do + let(:hash) { service.fresh_access_levels_per_project } + + it 'returns a Hash' do + expect(hash).to be_an_instance_of(Hash) + end + + it 'sets the keys to the project IDs' do + expect(hash.keys).to eq([project.id]) + end + + it 'sets the values to the access levels' do + expect(hash.values).to eq([Gitlab::Access::MASTER]) + end + end + + describe '#current_authorizations_per_project' do + before { create_authorization(project, user) } + + let(:hash) { service.current_authorizations_per_project } + + it 'returns a Hash' do + expect(hash).to be_an_instance_of(Hash) + end + + it 'sets the keys to the project IDs' do + expect(hash.keys).to eq([project.id]) + end + + it 'sets the values to the project authorization rows' do + expect(hash.values).to eq([ProjectAuthorization.first]) + end + end + + describe '#current_authorizations' do + context 'without authorizations' do + it 'returns an empty list' do + expect(service.current_authorizations.empty?).to eq(true) + end + end + + context 'with an authorization' do + before { create_authorization(project, user) } + + let(:row) { service.current_authorizations.take } + + it 'returns the currently authorized projects' do + expect(service.current_authorizations.length).to eq(1) + end + + it 'includes the row ID for every row' do + expect(row.id).to be_a_kind_of(Numeric) + end + + it 'includes the project ID for every row' do + expect(row.project_id).to eq(project.id) + end + + it 'includes the access level for every row' do + expect(row.access_level).to eq(Gitlab::Access::MASTER) + end + end + end + + describe '#fresh_authorizations' do + it 'returns the new authorized projects' do + expect(service.fresh_authorizations.length).to eq(1) + end + + it 'returns the highest access level' do + project.team.add_guest(user) + + rows = service.fresh_authorizations.to_a + + expect(rows.length).to eq(1) + expect(rows.first.access_level).to eq(Gitlab::Access::MASTER) + end + + context 'every returned row' do + let(:row) { service.fresh_authorizations.take } + + it 'includes the project ID' do + expect(row.project_id).to eq(project.id) + end + + it 'includes the access level' do + expect(row.access_level).to eq(Gitlab::Access::MASTER) + end + end + end +end diff --git a/spec/workers/authorized_projects_worker_spec.rb b/spec/workers/authorized_projects_worker_spec.rb index 95e2458da35..b6591f272f6 100644 --- a/spec/workers/authorized_projects_worker_spec.rb +++ b/spec/workers/authorized_projects_worker_spec.rb @@ -7,27 +7,17 @@ describe AuthorizedProjectsWorker do it "refreshes user's authorized projects" do user = create(:user) - expect(worker).to receive(:refresh).with(an_instance_of(User)) + expect_any_instance_of(User).to receive(:refresh_authorized_projects) worker.perform(user.id) end context "when the user is not found" do it "does nothing" do - expect(worker).not_to receive(:refresh) + expect_any_instance_of(User).not_to receive(:refresh_authorized_projects) described_class.new.perform(-1) end end end - - describe '#refresh', redis: true do - it 'refreshes the authorized projects of the user' do - user = create(:user) - - expect(user).to receive(:refresh_authorized_projects) - - worker.refresh(user) - end - end end -- cgit v1.2.1 From 103114e3d73819f76bed9d8ad1bbdb8964875579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 15 Dec 2016 17:31:14 +0100 Subject: Rename Gogs to Gitea, DRY the controller and improve views MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/controllers/import/gitea_controller_spec.rb | 43 ++++ spec/controllers/import/github_controller_spec.rb | 218 +------------------- spec/routing/import_routing_spec.rb | 166 +++++++++++++++ .../githubish_import_controller_shared_context.rb | 10 + .../githubish_import_controller_shared_examples.rb | 228 +++++++++++++++++++++ spec/support/import_spec_helper.rb | 4 + 6 files changed, 461 insertions(+), 208 deletions(-) create mode 100644 spec/controllers/import/gitea_controller_spec.rb create mode 100644 spec/routing/import_routing_spec.rb create mode 100644 spec/support/githubish_import_controller_shared_context.rb create mode 100644 spec/support/githubish_import_controller_shared_examples.rb (limited to 'spec') diff --git a/spec/controllers/import/gitea_controller_spec.rb b/spec/controllers/import/gitea_controller_spec.rb new file mode 100644 index 00000000000..3064d1dd58a --- /dev/null +++ b/spec/controllers/import/gitea_controller_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe Import::GiteaController do + include ImportSpecHelper + + let(:provider) { :gitea } + let(:host_url) { 'https://try.gitea.io' } + + include_context 'a GitHub-ish import controller' + + def assign_host_url + session[:host_url] = host_url + end + + describe "GET new" do + it_behaves_like 'a GitHub-ish import controller: GET new' do + before do + assign_host_url + end + end + end + + describe "POST personal_access_token" do + it_behaves_like 'a GitHub-ish import controller: POST personal_access_token' + end + + describe "GET status" do + it_behaves_like 'a GitHub-ish import controller: GET status' do + before do + assign_host_url + end + let(:extra_assign_expectations) { { gitea_root_url: host_url } } + end + end + + describe 'POST create' do + it_behaves_like 'a GitHub-ish import controller: POST create' do + before do + assign_host_url + end + end + end +end diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index 4f96567192d..55820a7cc65 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -3,34 +3,18 @@ require 'spec_helper' describe Import::GithubController do include ImportSpecHelper - let(:user) { create(:user) } - let(:token) { "asdasd12345" } - let(:access_params) { { github_access_token: token } } + let(:provider) { :github } - def assign_session_token - session[:github_access_token] = token - end - - before do - sign_in(user) - allow(controller).to receive(:github_import_enabled?).and_return(true) - end + include_context 'a GitHub-ish import controller' describe "GET new" do - it "redirects to GitHub for an access token if logged in with GitHub" do - allow(controller).to receive(:logged_in_with_github?).and_return(true) - expect(controller).to receive(:go_to_github_for_permissions) + it_behaves_like 'a GitHub-ish import controller: GET new' - get :new - end - - it "redirects to status if we already have a token" do - assign_session_token - allow(controller).to receive(:logged_in_with_github?).and_return(false) + it "redirects to GitHub for an access token if logged in with GitHub" do + allow(controller).to receive(:logged_in_with_provider?).and_return(true) + expect(controller).to receive(:go_to_provider_for_permissions) get :new - - expect(controller).to redirect_to(status_import_github_url) end end @@ -45,202 +29,20 @@ describe Import::GithubController do get :callback - expect(session[:github_access_token]).to eq(token) + expect(session[:access_token]).to eq(token) expect(controller).to redirect_to(status_import_github_url) end end describe "POST personal_access_token" do - it "updates access token" do - token = "asdfasdf9876" - - allow_any_instance_of(Gitlab::GithubImport::Client). - to receive(:user).and_return(true) - - post :personal_access_token, personal_access_token: token - - expect(session[:github_access_token]).to eq(token) - expect(controller).to redirect_to(status_import_github_url) - end + it_behaves_like 'a GitHub-ish import controller: POST personal_access_token' end describe "GET status" do - before do - @repo = OpenStruct.new(login: 'vim', full_name: 'asd/vim') - @org = OpenStruct.new(login: 'company') - @org_repo = OpenStruct.new(login: 'company', full_name: 'company/repo') - assign_session_token - end - - it "assigns variables" do - @project = create(:project, import_type: 'github', creator_id: user.id) - stub_client(repos: [@repo, @org_repo], orgs: [@org], org_repos: [@org_repo]) - - get :status - - expect(assigns(:already_added_projects)).to eq([@project]) - expect(assigns(:repos)).to eq([@repo, @org_repo]) - end - - it "does not show already added project" do - @project = create(:project, import_type: 'github', creator_id: user.id, import_source: 'asd/vim') - stub_client(repos: [@repo], orgs: []) - - get :status - - expect(assigns(:already_added_projects)).to eq([@project]) - expect(assigns(:repos)).to eq([]) - end - - it "handles an invalid access token" do - allow_any_instance_of(Gitlab::GithubImport::Client). - to receive(:repos).and_raise(Octokit::Unauthorized) - - get :status - - expect(session[:github_access_token]).to eq(nil) - expect(controller).to redirect_to(new_import_github_url) - expect(flash[:alert]).to eq('Access denied to your GitHub account.') - end + it_behaves_like 'a GitHub-ish import controller: GET status' end describe "POST create" do - let(:github_username) { user.username } - let(:github_user) { OpenStruct.new(login: github_username) } - let(:github_repo) do - OpenStruct.new( - name: 'vim', - full_name: "#{github_username}/vim", - owner: OpenStruct.new(login: github_username) - ) - end - - before do - stub_client(user: github_user, repo: github_repo) - assign_session_token - end - - context "when the repository owner is the GitHub user" do - context "when the GitHub user and GitLab user's usernames match" do - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - - context "when the GitHub user and GitLab user's usernames don't match" do - let(:github_username) { "someone_else" } - - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context "when the repository owner is not the GitHub user" do - let(:other_username) { "someone_else" } - - before do - github_repo.owner = OpenStruct.new(login: other_username) - assign_session_token - end - - context "when a namespace with the GitHub user's username already exists" do - let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) } - - context "when the namespace is owned by the GitLab user" do - it "takes the existing namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, existing_namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - - context "when the namespace is not owned by the GitLab user" do - before do - existing_namespace.owner = create(:user) - existing_namespace.save - end - - it "creates a project using user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context "when a namespace with the GitHub user's username doesn't exist" do - context "when current user can create namespaces" do - it "creates the namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).and_return(double(execute: true)) - - expect { post :create, target_namespace: github_repo.name, format: :js }.to change(Namespace, :count).by(1) - end - - it "takes the new namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, an_instance_of(Group), user, access_params). - and_return(double(execute: true)) - - post :create, target_namespace: github_repo.name, format: :js - end - end - - context "when current user can't create namespaces" do - before do - user.update_attribute(:can_create_group, false) - end - - it "doesn't create the namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).and_return(double(execute: true)) - - expect { post :create, format: :js }.not_to change(Namespace, :count) - end - - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, github_repo.name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context 'user has chosen a namespace and name for the project' do - let(:test_namespace) { create(:namespace, name: 'test_namespace', owner: user) } - let(:test_name) { 'test_name' } - - it 'takes the selected namespace and name' do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, test_name, test_namespace, user, access_params). - and_return(double(execute: true)) - - post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :js } - end - - it 'takes the selected name and default namespace' do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(github_repo, test_name, user.namespace, user, access_params). - and_return(double(execute: true)) - - post :create, { new_name: test_name, format: :js } - end - end - end + it_behaves_like 'a GitHub-ish import controller: POST create' end end diff --git a/spec/routing/import_routing_spec.rb b/spec/routing/import_routing_spec.rb new file mode 100644 index 00000000000..f1234ff470b --- /dev/null +++ b/spec/routing/import_routing_spec.rb @@ -0,0 +1,166 @@ +require 'spec_helper' + +# Shared examples for a resource inside a Project +# +# By default it tests all the default REST actions: index, create, new, edit, +# show, update, and destroy. You can remove actions by customizing the +# `actions` variable. +# +# It also expects a `controller` variable to be available which defines both +# the path to the resource as well as the controller name. +# +# Examples +# +# # Default behavior +# it_behaves_like 'RESTful project resources' do +# let(:controller) { 'issues' } +# end +# +# # Customizing actions +# it_behaves_like 'RESTful project resources' do +# let(:actions) { [:index] } +# let(:controller) { 'issues' } +# end +shared_examples 'importer routing' do + let(:except_actions) { [] } + + it 'to #create' do + expect(post("/import/#{provider}")).to route_to("import/#{provider}#create") unless except_actions.include?(:create) + end + + it 'to #new' do + expect(get("/import/#{provider}/new")).to route_to("import/#{provider}#new") unless except_actions.include?(:new) + end + + it 'to #status' do + expect(get("/import/#{provider}/status")).to route_to("import/#{provider}#status") unless except_actions.include?(:status) + end + + it 'to #callback' do + expect(get("/import/#{provider}/callback")).to route_to("import/#{provider}#callback") unless except_actions.include?(:callback) + end + + it 'to #jobs' do + expect(get("/import/#{provider}/jobs")).to route_to("import/#{provider}#jobs") unless except_actions.include?(:jobs) + end +end + +# personal_access_token_import_github POST /import/github/personal_access_token(.:format) import/github#personal_access_token +# status_import_github GET /import/github/status(.:format) import/github#status +# callback_import_github GET /import/github/callback(.:format) import/github#callback +# jobs_import_github GET /import/github/jobs(.:format) import/github#jobs +# import_github POST /import/github(.:format) import/github#create +# new_import_github GET /import/github/new(.:format) import/github#new +describe Import::GithubController, 'routing' do + it_behaves_like 'importer routing' do + let(:provider) { 'github' } + end + + it 'to #personal_access_token' do + expect(post('/import/github/personal_access_token')).to route_to('import/github#personal_access_token') + end +end + +# personal_access_token_import_gitea POST /import/gitea/personal_access_token(.:format) import/gitea#personal_access_token +# status_import_gitea GET /import/gitea/status(.:format) import/gitea#status +# jobs_import_gitea GET /import/gitea/jobs(.:format) import/gitea#jobs +# import_gitea POST /import/gitea(.:format) import/gitea#create +# new_import_gitea GET /import/gitea/new(.:format) import/gitea#new +describe Import::GiteaController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:callback] } + let(:provider) { 'gitea' } + end + + it 'to #personal_access_token' do + expect(post('/import/gitea/personal_access_token')).to route_to('import/gitea#personal_access_token') + end + +end + +# status_import_gitlab GET /import/gitlab/status(.:format) import/gitlab#status +# callback_import_gitlab GET /import/gitlab/callback(.:format) import/gitlab#callback +# jobs_import_gitlab GET /import/gitlab/jobs(.:format) import/gitlab#jobs +# import_gitlab POST /import/gitlab(.:format) import/gitlab#create +describe Import::GitlabController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:new] } + let(:provider) { 'gitlab' } + end +end + +# status_import_bitbucket GET /import/bitbucket/status(.:format) import/bitbucket#status +# callback_import_bitbucket GET /import/bitbucket/callback(.:format) import/bitbucket#callback +# jobs_import_bitbucket GET /import/bitbucket/jobs(.:format) import/bitbucket#jobs +# import_bitbucket POST /import/bitbucket(.:format) import/bitbucket#create +describe Import::BitbucketController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:new] } + let(:provider) { 'bitbucket' } + end +end + +# status_import_google_code GET /import/google_code/status(.:format) import/google_code#status +# callback_import_google_code POST /import/google_code/callback(.:format) import/google_code#callback +# jobs_import_google_code GET /import/google_code/jobs(.:format) import/google_code#jobs +# new_user_map_import_google_code GET /import/google_code/user_map(.:format) import/google_code#new_user_map +# create_user_map_import_google_code POST /import/google_code/user_map(.:format) import/google_code#create_user_map +# import_google_code POST /import/google_code(.:format) import/google_code#create +# new_import_google_code GET /import/google_code/new(.:format) import/google_code#new +describe Import::GoogleCodeController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:callback] } + let(:provider) { 'google_code' } + end + + it 'to #callback' do + expect(post("/import/google_code/callback")).to route_to("import/google_code#callback") + end + + it 'to #new_user_map' do + expect(get('/import/google_code/user_map')).to route_to('import/google_code#new_user_map') + end + + it 'to #create_user_map' do + expect(post('/import/google_code/user_map')).to route_to('import/google_code#create_user_map') + end +end + +# status_import_fogbugz GET /import/fogbugz/status(.:format) import/fogbugz#status +# callback_import_fogbugz POST /import/fogbugz/callback(.:format) import/fogbugz#callback +# jobs_import_fogbugz GET /import/fogbugz/jobs(.:format) import/fogbugz#jobs +# new_user_map_import_fogbugz GET /import/fogbugz/user_map(.:format) import/fogbugz#new_user_map +# create_user_map_import_fogbugz POST /import/fogbugz/user_map(.:format) import/fogbugz#create_user_map +# import_fogbugz POST /import/fogbugz(.:format) import/fogbugz#create +# new_import_fogbugz GET /import/fogbugz/new(.:format) import/fogbugz#new +describe Import::FogbugzController, 'routing' do + it_behaves_like 'importer routing' do + let(:except_actions) { [:callback] } + let(:provider) { 'fogbugz' } + end + + it 'to #callback' do + expect(post("/import/fogbugz/callback")).to route_to("import/fogbugz#callback") + end + + it 'to #new_user_map' do + expect(get('/import/fogbugz/user_map')).to route_to('import/fogbugz#new_user_map') + end + + it 'to #create_user_map' do + expect(post('/import/fogbugz/user_map')).to route_to('import/fogbugz#create_user_map') + end +end + +# import_gitlab_project POST /import/gitlab_project(.:format) import/gitlab_projects#create +# POST /import/gitlab_project(.:format) import/gitlab_projects#create +# new_import_gitlab_project GET /import/gitlab_project/new(.:format) import/gitlab_projects#new +describe Import::GitlabProjectsController, 'routing' do + it 'to #create' do + expect(post('/import/gitlab_project')).to route_to('import/gitlab_projects#create') + end + + it 'to #new' do + expect(get('/import/gitlab_project/new')).to route_to('import/gitlab_projects#new') + end +end diff --git a/spec/support/githubish_import_controller_shared_context.rb b/spec/support/githubish_import_controller_shared_context.rb new file mode 100644 index 00000000000..e71994edec6 --- /dev/null +++ b/spec/support/githubish_import_controller_shared_context.rb @@ -0,0 +1,10 @@ +shared_context 'a GitHub-ish import controller' do + let(:user) { create(:user) } + let(:token) { "asdasd12345" } + let(:access_params) { { github_access_token: token } } + + before do + sign_in(user) + allow(controller).to receive(:"#{provider}_import_enabled?").and_return(true) + end +end diff --git a/spec/support/githubish_import_controller_shared_examples.rb b/spec/support/githubish_import_controller_shared_examples.rb new file mode 100644 index 00000000000..aa2d8aed0bd --- /dev/null +++ b/spec/support/githubish_import_controller_shared_examples.rb @@ -0,0 +1,228 @@ +# Specifications for behavior common to all objects with an email attribute. +# Takes a list of email-format attributes and requires: +# - subject { "the object with a attribute= setter" } +# Note: You have access to `email_value` which is the email address value +# being currently tested). + +shared_examples 'a GitHub-ish import controller: POST personal_access_token' do + let(:status_import_url) { public_send("status_import_#{provider}_url") } + + it "updates access token" do + token = 'asdfasdf9876' + + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:user).and_return(true) + + post :personal_access_token, personal_access_token: token + + expect(session[:access_token]).to eq(token) + expect(controller).to redirect_to(status_import_url) + end +end + +shared_examples 'a GitHub-ish import controller: GET new' do + let(:status_import_url) { public_send("status_import_#{provider}_url") } + + it "redirects to status if we already have a token" do + assign_session_token + allow(controller).to receive(:logged_in_with_provider?).and_return(false) + + get :new + + expect(controller).to redirect_to(status_import_url) + end + + it "renders the :new page if no token is present in session" do + get :new + + expect(response).to render_template(:new) + end +end + +shared_examples 'a GitHub-ish import controller: GET status' do + let(:new_import_url) { public_send("new_import_#{provider}_url") } + let(:user) { create(:user) } + let(:repo) { OpenStruct.new(login: 'vim', full_name: 'asd/vim') } + let(:org) { OpenStruct.new(login: 'company') } + let(:org_repo) { OpenStruct.new(login: 'company', full_name: 'company/repo') } + let(:extra_assign_expectations) { {} } + + before do + assign_session_token + end + + it "assigns variables" do + project = create(:empty_project, import_type: provider, creator_id: user.id) + stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo]) + + get :status + + expect(assigns(:already_added_projects)).to eq([project]) + expect(assigns(:repos)).to eq([repo, org_repo]) + extra_assign_expectations.each do |key, value| + expect(assigns(key)).to eq(value) + end + end + + it "does not show already added project" do + project = create(:empty_project, import_type: provider, creator_id: user.id, import_source: 'asd/vim') + stub_client(repos: [repo], orgs: []) + + get :status + + expect(assigns(:already_added_projects)).to eq([project]) + expect(assigns(:repos)).to eq([]) + end + + it "handles an invalid access token" do + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:repos).and_raise(Octokit::Unauthorized) + + get :status + + expect(session[:access_token]).to eq(nil) + expect(controller).to redirect_to(new_import_url) + expect(flash[:alert]).to eq("Access denied to your #{Gitlab::ImportSources.options.key(provider.to_s)} account.") + end +end + +shared_examples 'a GitHub-ish import controller: POST create' do + let(:user) { create(:user) } + let(:provider_username) { user.username } + let(:provider_user) { OpenStruct.new(login: provider_username) } + let(:provider_repo) do + OpenStruct.new( + name: 'vim', + full_name: "#{provider_username}/vim", + owner: OpenStruct.new(login: provider_username) + ) + end + + before do + stub_client(user: provider_user, repo: provider_repo) + assign_session_token + end + + context "when the repository owner is the Gitea user" do + context "when the Gitea user and GitLab user's usernames match" do + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + + context "when the Gitea user and GitLab user's usernames don't match" do + let(:provider_username) { "someone_else" } + + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context "when the repository owner is not the Gitea user" do + let(:other_username) { "someone_else" } + + before do + provider_repo.owner = OpenStruct.new(login: other_username) + assign_session_token + end + + context "when a namespace with the Gitea user's username already exists" do + let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) } + + context "when the namespace is owned by the GitLab user" do + it "takes the existing namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, existing_namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + + context "when the namespace is not owned by the GitLab user" do + before do + existing_namespace.owner = create(:user) + existing_namespace.save + end + + it "creates a project using user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context "when a namespace with the Gitea user's username doesn't exist" do + context "when current user can create namespaces" do + it "creates the namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).and_return(double(execute: true)) + + expect { post :create, target_namespace: provider_repo.name, format: :js }.to change(Namespace, :count).by(1) + end + + it "takes the new namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, target_namespace: provider_repo.name, format: :js + end + end + + context "when current user can't create namespaces" do + before do + user.update_attribute(:can_create_group, false) + end + + it "doesn't create the namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).and_return(double(execute: true)) + + expect { post :create, format: :js }.not_to change(Namespace, :count) + end + + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context 'user has chosen a namespace and name for the project' do + let(:test_namespace) { create(:namespace, name: 'test_namespace', owner: user) } + let(:test_name) { 'test_name' } + + it 'takes the selected namespace and name' do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :js } + end + + it 'takes the selected name and default namespace' do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, { new_name: test_name, format: :js } + end + end + end +end diff --git a/spec/support/import_spec_helper.rb b/spec/support/import_spec_helper.rb index 6710962f082..cd25e05ac4b 100644 --- a/spec/support/import_spec_helper.rb +++ b/spec/support/import_spec_helper.rb @@ -30,4 +30,8 @@ module ImportSpecHelper ) allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider]) end + + def assign_session_token + session[:access_token] = 'asdasd12345' + end end -- cgit v1.2.1 From 99ddd1dcbed35b642d7bd8a52cc6e5e5453b9f8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 15 Dec 2016 17:36:53 +0100 Subject: Modify GithubImport to support Gitea MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reason is that Gitea plan to be GitHub-compatible so it makes sense to just modify GitHubImport a bit for now, and hopefully we can change it to GitHubishImport once Gitea is 100%-compatible. Signed-off-by: Rémy Coutable --- spec/controllers/import/gitea_controller_spec.rb | 2 +- spec/lib/gitlab/github_import/client_spec.rb | 46 ++- spec/lib/gitlab/github_import/importer_spec.rb | 370 +++++++++++++-------- .../github_import/issuable_formatter_spec.rb | 21 ++ .../gitlab/github_import/issue_formatter_spec.rb | 38 ++- .../github_import/milestone_formatter_spec.rb | 27 +- .../github_import/pull_request_formatter_spec.rb | 34 +- spec/routing/import_routing_spec.rb | 1 - .../githubish_import_controller_shared_context.rb | 10 + .../githubish_import_controller_shared_examples.rb | 228 +++++++++++++ .../githubish_import_controller_shared_context.rb | 10 - .../githubish_import_controller_shared_examples.rb | 228 ------------- 12 files changed, 595 insertions(+), 420 deletions(-) create mode 100644 spec/lib/gitlab/github_import/issuable_formatter_spec.rb create mode 100644 spec/support/controllers/githubish_import_controller_shared_context.rb create mode 100644 spec/support/controllers/githubish_import_controller_shared_examples.rb delete mode 100644 spec/support/githubish_import_controller_shared_context.rb delete mode 100644 spec/support/githubish_import_controller_shared_examples.rb (limited to 'spec') diff --git a/spec/controllers/import/gitea_controller_spec.rb b/spec/controllers/import/gitea_controller_spec.rb index 3064d1dd58a..3643386ffbc 100644 --- a/spec/controllers/import/gitea_controller_spec.rb +++ b/spec/controllers/import/gitea_controller_spec.rb @@ -29,7 +29,7 @@ describe Import::GiteaController do before do assign_host_url end - let(:extra_assign_expectations) { { gitea_root_url: host_url } } + let(:extra_assign_expectations) { { gitea_host_url: host_url } } end end diff --git a/spec/lib/gitlab/github_import/client_spec.rb b/spec/lib/gitlab/github_import/client_spec.rb index e829b936343..21f2a9e225b 100644 --- a/spec/lib/gitlab/github_import/client_spec.rb +++ b/spec/lib/gitlab/github_import/client_spec.rb @@ -45,20 +45,46 @@ describe Gitlab::GithubImport::Client, lib: true do end end - context 'when provider does not specity an API endpoint' do - it 'uses GitHub root API endpoint' do - expect(client.api.api_endpoint).to eq 'https://api.github.com/' + describe '#api_endpoint' do + context 'when provider does not specity an API endpoint' do + it 'uses GitHub root API endpoint' do + expect(client.api.api_endpoint).to eq 'https://api.github.com/' + end end - end - context 'when provider specify a custom API endpoint' do - before do - github_provider['args']['client_options']['site'] = 'https://github.company.com/' + context 'when provider specify a custom API endpoint' do + before do + github_provider['args']['client_options']['site'] = 'https://github.company.com/' + end + + it 'uses the custom API endpoint' do + expect(OmniAuth::Strategies::GitHub).not_to receive(:default_options) + expect(client.api.api_endpoint).to eq 'https://github.company.com/' + end + end + + context 'when given a host' do + subject(:client) { described_class.new(token, host: 'https://try.gitea.io/') } + + it 'builds a endpoint with the given host and the default API version' do + expect(client.api.api_endpoint).to eq 'https://try.gitea.io/api/v3/' + end end - it 'uses the custom API endpoint' do - expect(OmniAuth::Strategies::GitHub).not_to receive(:default_options) - expect(client.api.api_endpoint).to eq 'https://github.company.com/' + context 'when given an API version' do + subject(:client) { described_class.new(token, api_version: 'v3') } + + it 'does not use the API version without a host' do + expect(client.api.api_endpoint).to eq 'https://api.github.com/' + end + end + + context 'when given a host and version' do + subject(:client) { described_class.new(token, host: 'https://try.gitea.io/', api_version: 'v3') } + + it 'builds a endpoint with the given options' do + expect(client.api.api_endpoint).to eq 'https://try.gitea.io/api/v3/' + end end end diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb index 9e027839f59..0a03b7353f6 100644 --- a/spec/lib/gitlab/github_import/importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -1,169 +1,251 @@ require 'spec_helper' describe Gitlab::GithubImport::Importer, lib: true do - describe '#execute' do + shared_examples 'Gitlab::GithubImport::Importer#execute' do + let(:expected_not_called) { [] } + before do - allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new) + allow(project).to receive(:import_data).and_return(double.as_null_object) end - context 'when an error occurs' do - let(:project) { create(:project, import_url: 'https://github.com/octocat/Hello-World.git', wiki_access_level: ProjectFeature::DISABLED) } - let(:octocat) { double(id: 123456, login: 'octocat') } - let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } - let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } - let(:repository) { double(id: 1, fork: false) } - let(:source_sha) { create(:commit, project: project).id } - let(:source_branch) { double(ref: 'feature', repo: repository, sha: source_sha) } - let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id } - let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) } - - let(:label1) do - double( - name: 'Bug', - color: 'ff0000', - url: 'https://api.github.com/repos/octocat/Hello-World/labels/bug' - ) - end + it 'calls import methods' do + importer = described_class.new(project) - let(:label2) do - double( - name: nil, - color: 'ff0000', - url: 'https://api.github.com/repos/octocat/Hello-World/labels/bug' - ) - end + expected_called = [ + :import_labels, :import_milestones, :import_pull_requests, :import_issues, + :import_wiki, :import_releases, :handle_errors + ] - let(:milestone) do - double( - number: 1347, - state: 'open', - title: '1.0', - description: 'Version 1.0', - due_on: nil, - created_at: created_at, - updated_at: updated_at, - closed_at: nil, - url: 'https://api.github.com/repos/octocat/Hello-World/milestones/1' - ) - end + expected_called -= expected_not_called - let(:issue1) do - double( - number: 1347, - milestone: nil, - state: 'open', - title: 'Found a bug', - body: "I'm having a problem with this.", - assignee: nil, - user: octocat, - comments: 0, - pull_request: nil, - created_at: created_at, - updated_at: updated_at, - closed_at: nil, - url: 'https://api.github.com/repos/octocat/Hello-World/issues/1347', - labels: [double(name: 'Label #1')], - ) - end + aggregate_failures do + expected_called.each do |method_name| + expect(importer).to receive(method_name) + end - let(:issue2) do - double( - number: 1348, - milestone: nil, - state: 'open', - title: nil, - body: "I'm having a problem with this.", - assignee: nil, - user: octocat, - comments: 0, - pull_request: nil, - created_at: created_at, - updated_at: updated_at, - closed_at: nil, - url: 'https://api.github.com/repos/octocat/Hello-World/issues/1348', - labels: [double(name: 'Label #2')], - ) - end + expect(importer).to receive(:import_comments).with(:issues) + expect(importer).to receive(:import_comments).with(:pull_requests) - let(:pull_request) do - double( - number: 1347, - milestone: nil, - state: 'open', - title: 'New feature', - body: 'Please pull these awesome changes', - head: source_branch, - base: target_branch, - assignee: nil, - user: octocat, - created_at: created_at, - updated_at: updated_at, - closed_at: nil, - merged_at: nil, - url: 'https://api.github.com/repos/octocat/Hello-World/pulls/1347', - ) + expected_not_called.each do |method_name| + expect(importer).not_to receive(method_name) + end end - let(:release1) do - double( - tag_name: 'v1.0.0', - name: 'First release', - body: 'Release v1.0.0', - draft: false, - created_at: created_at, - updated_at: updated_at, - url: 'https://api.github.com/repos/octocat/Hello-World/releases/1' - ) - end + importer.execute + end + end - let(:release2) do - double( - tag_name: 'v2.0.0', - name: 'Second release', - body: nil, - draft: false, - created_at: created_at, - updated_at: updated_at, - url: 'https://api.github.com/repos/octocat/Hello-World/releases/2' - ) - end + shared_examples 'Gitlab::GithubImport::Importer#execute an error occurs' do + before do + allow(project).to receive(:import_data).and_return(double.as_null_object) - before do - allow(project).to receive(:import_data).and_return(double.as_null_object) - allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound) - allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label1, label2]) - allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone]) - allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2]) - allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request]) - allow_any_instance_of(Octokit::Client).to receive(:issues_comments).and_return([]) - allow_any_instance_of(Octokit::Client).to receive(:pull_requests_comments).and_return([]) - allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil })) - allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2]) - allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error) - end + allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new) + + allow_any_instance_of(Octokit::Client).to receive(:rate_limit!).and_raise(Octokit::NotFound) + allow_any_instance_of(Gitlab::Shell).to receive(:import_repository).and_raise(Gitlab::Shell::Error) + + allow_any_instance_of(Octokit::Client).to receive(:labels).and_return([label1, label2]) + allow_any_instance_of(Octokit::Client).to receive(:milestones).and_return([milestone, milestone]) + allow_any_instance_of(Octokit::Client).to receive(:issues).and_return([issue1, issue2]) + allow_any_instance_of(Octokit::Client).to receive(:pull_requests).and_return([pull_request, pull_request]) + allow_any_instance_of(Octokit::Client).to receive(:issues_comments).and_return([]) + allow_any_instance_of(Octokit::Client).to receive(:pull_requests_comments).and_return([]) + allow_any_instance_of(Octokit::Client).to receive(:last_response).and_return(double(rels: { next: nil })) + allow_any_instance_of(Octokit::Client).to receive(:releases).and_return([release1, release2]) + end + let(:octocat) { double(id: 123456, login: 'octocat') } + let(:created_at) { DateTime.strptime('2011-01-26T19:01:12Z') } + let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } + let(:label1) do + double( + name: 'Bug', + color: 'ff0000', + url: "#{api_root}/repos/octocat/Hello-World/labels/bug" + ) + end + + let(:label2) do + double( + name: nil, + color: 'ff0000', + url: "#{api_root}/repos/octocat/Hello-World/labels/bug" + ) + end + + let(:milestone) do + double( + id: 1347, # For Gitea + number: 1347, + state: 'open', + title: '1.0', + description: 'Version 1.0', + due_on: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + url: "#{api_root}/repos/octocat/Hello-World/milestones/1" + ) + end - it 'returns true' do - expect(described_class.new(project).execute).to eq true + let(:issue1) do + double( + number: 1347, + milestone: nil, + state: 'open', + title: 'Found a bug', + body: "I'm having a problem with this.", + assignee: nil, + user: octocat, + comments: 0, + pull_request: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + url: "#{api_root}/repos/octocat/Hello-World/issues/1347", + labels: [double(name: 'Label #1')] + ) + end + + let(:issue2) do + double( + number: 1348, + milestone: nil, + state: 'open', + title: nil, + body: "I'm having a problem with this.", + assignee: nil, + user: octocat, + comments: 0, + pull_request: nil, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + url: "#{api_root}/repos/octocat/Hello-World/issues/1348", + labels: [double(name: 'Label #2')] + ) + end + + let(:repository) { double(id: 1, fork: false) } + let(:source_sha) { create(:commit, project: project).id } + let(:source_branch) { double(ref: 'feature', repo: repository, sha: source_sha) } + let(:target_sha) { create(:commit, project: project, git_commit: RepoHelpers.another_sample_commit).id } + let(:target_branch) { double(ref: 'master', repo: repository, sha: target_sha) } + let(:pull_request) do + double( + number: 1347, + milestone: nil, + state: 'open', + title: 'New feature', + body: 'Please pull these awesome changes', + head: source_branch, + base: target_branch, + assignee: nil, + user: octocat, + created_at: created_at, + updated_at: updated_at, + closed_at: nil, + merged_at: nil, + url: "#{api_root}/repos/octocat/Hello-World/pulls/1347", + labels: [double(name: 'Label #2')] + ) + end + + let(:release1) do + double( + tag_name: 'v1.0.0', + name: 'First release', + body: 'Release v1.0.0', + draft: false, + created_at: created_at, + updated_at: updated_at, + url: "#{api_root}/repos/octocat/Hello-World/releases/1" + ) + end + + let(:release2) do + double( + tag_name: 'v2.0.0', + name: 'Second release', + body: nil, + draft: false, + created_at: created_at, + updated_at: updated_at, + url: "#{api_root}/repos/octocat/Hello-World/releases/2" + ) + end + + it 'returns true' do + expect(described_class.new(project).execute).to eq true + end + + it 'does not raise an error' do + expect { described_class.new(project).execute }.not_to raise_error + end + + it 'stores error messages' do + error = { + message: 'The remote data could not be fully imported.', + errors: [ + { type: :label, url: "#{api_root}/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title can't be blank, Title is invalid" }, + { type: :issue, url: "#{api_root}/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank" }, + { type: :wiki, errors: "Gitlab::Shell::Error" } + ] + } + + unless project.import_type == 'gitea' + error[:errors] << { type: :release, url: "#{api_root}/repos/octocat/Hello-World/releases/2", errors: "Validation failed: Description can't be blank" } end - it 'does not raise an error' do - expect { described_class.new(project).execute }.not_to raise_error + described_class.new(project).execute + + expect(project.import_error).to eq error.to_json + end + end + + let(:project) { create(:project, import_url: "#{repo_root}/octocat/Hello-World.git", wiki_access_level: ProjectFeature::DISABLED) } + let(:credentials) { { user: 'joe' } } + + context 'when importing a GitHub project' do + let(:api_root) { 'https://api.github.com' } + let(:repo_root) { 'https://github.com' } + + it_behaves_like 'Gitlab::GithubImport::Importer#execute' + it_behaves_like 'Gitlab::GithubImport::Importer#execute an error occurs' + + describe '#client' do + it 'instantiates a Client' do + allow(project).to receive(:import_data).and_return(double(credentials: credentials)) + expect(Gitlab::GithubImport::Client).to receive(:new).with( + credentials[:user], + {} + ) + + described_class.new(project).client end + end + end - it 'stores error messages' do - error = { - message: 'The remote data could not be fully imported.', - errors: [ - { type: :label, url: "https://api.github.com/repos/octocat/Hello-World/labels/bug", errors: "Validation failed: Title can't be blank, Title is invalid" }, - { type: :issue, url: "https://api.github.com/repos/octocat/Hello-World/issues/1348", errors: "Validation failed: Title can't be blank" }, - { type: :wiki, errors: "Gitlab::Shell::Error" }, - { type: :release, url: 'https://api.github.com/repos/octocat/Hello-World/releases/2', errors: "Validation failed: Description can't be blank" } - ] - } + context 'when importing a Gitea project' do + let(:api_root) { 'https://try.gitea.io/api/v1' } + let(:repo_root) { 'https://try.gitea.io' } + before do + project.update(import_type: 'gitea', import_url: "#{repo_root}/foo/group/project.git") + end - described_class.new(project).execute + it_behaves_like 'Gitlab::GithubImport::Importer#execute' do + let(:expected_not_called) { [:import_releases] } + end + it_behaves_like 'Gitlab::GithubImport::Importer#execute an error occurs' + + describe '#client' do + it 'instantiates a Client' do + allow(project).to receive(:import_data).and_return(double(credentials: credentials)) + expect(Gitlab::GithubImport::Client).to receive(:new).with( + credentials[:user], + { host: "#{repo_root}:443/foo", api_version: 'v1' } + ) - expect(project.import_error).to eq error.to_json + described_class.new(project).client end end end diff --git a/spec/lib/gitlab/github_import/issuable_formatter_spec.rb b/spec/lib/gitlab/github_import/issuable_formatter_spec.rb new file mode 100644 index 00000000000..6bc5f98ed2c --- /dev/null +++ b/spec/lib/gitlab/github_import/issuable_formatter_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe Gitlab::GithubImport::IssuableFormatter, lib: true do + let(:raw_data) do + double(number: 42) + end + let(:project) { double(import_type: 'github') } + let(:issuable_formatter) { described_class.new(project, raw_data) } + + describe '#project_association' do + it { expect { issuable_formatter.project_association }.to raise_error(NotImplementedError) } + end + + describe '#number' do + it { expect(issuable_formatter.number).to eq(42) } + end + + describe '#find_condition' do + it { expect(issuable_formatter.find_condition).to eq({ iid: 42 }) } + end +end diff --git a/spec/lib/gitlab/github_import/issue_formatter_spec.rb b/spec/lib/gitlab/github_import/issue_formatter_spec.rb index 95339e2f128..e31ed9c1fa0 100644 --- a/spec/lib/gitlab/github_import/issue_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/issue_formatter_spec.rb @@ -23,9 +23,9 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do } end - subject(:issue) { described_class.new(project, raw_data)} + subject(:issue) { described_class.new(project, raw_data) } - describe '#attributes' do + shared_examples 'Gitlab::GithubImport::IssueFormatter#attributes' do context 'when issue is open' do let(:raw_data) { double(base_data.merge(state: 'open')) } @@ -83,7 +83,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end context 'when it has a milestone' do - let(:milestone) { double(number: 45) } + let(:milestone) { double(id: 42, number: 42) } let(:raw_data) { double(base_data.merge(milestone: milestone)) } it 'returns nil when milestone does not exist' do @@ -91,7 +91,7 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end it 'returns milestone when it exists' do - milestone = create(:milestone, project: project, iid: 45) + milestone = create(:milestone, project: project, iid: 42) expect(issue.attributes.fetch(:milestone)).to eq milestone end @@ -118,6 +118,28 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end end + shared_examples 'Gitlab::GithubImport::IssueFormatter#number' do + let(:raw_data) { double(base_data.merge(number: 1347)) } + + it 'returns issue number' do + expect(issue.number).to eq 1347 + end + end + + context 'when importing a GitHub project' do + it_behaves_like 'Gitlab::GithubImport::IssueFormatter#attributes' + it_behaves_like 'Gitlab::GithubImport::IssueFormatter#number' + end + + context 'when importing a Gitea project' do + before do + project.update(import_type: 'gitea') + end + + it_behaves_like 'Gitlab::GithubImport::IssueFormatter#attributes' + it_behaves_like 'Gitlab::GithubImport::IssueFormatter#number' + end + describe '#has_comments?' do context 'when number of comments is greater than zero' do let(:raw_data) { double(base_data.merge(comments: 1)) } @@ -136,14 +158,6 @@ describe Gitlab::GithubImport::IssueFormatter, lib: true do end end - describe '#number' do - let(:raw_data) { double(base_data.merge(number: 1347)) } - - it 'returns pull request number' do - expect(issue.number).to eq 1347 - end - end - describe '#pull_request?' do context 'when mention a pull request' do let(:raw_data) { double(base_data.merge(pull_request: double)) } diff --git a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb index 09337c99a07..6d38041c468 100644 --- a/spec/lib/gitlab/github_import/milestone_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/milestone_formatter_spec.rb @@ -6,7 +6,6 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do let(:updated_at) { DateTime.strptime('2011-01-27T19:01:12Z') } let(:base_data) do { - number: 1347, state: 'open', title: '1.0', description: 'Version 1.0', @@ -16,12 +15,15 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do closed_at: nil } end + let(:iid_attr) { :number } - subject(:formatter) { described_class.new(project, raw_data)} + subject(:formatter) { described_class.new(project, raw_data) } + + shared_examples 'Gitlab::GithubImport::MilestoneFormatter#attributes' do + let(:data) { base_data.merge(iid_attr => 1347) } - describe '#attributes' do context 'when milestone is open' do - let(:raw_data) { double(base_data.merge(state: 'open')) } + let(:raw_data) { double(data.merge(state: 'open')) } it 'returns formatted attributes' do expected = { @@ -40,7 +42,7 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do end context 'when milestone is closed' do - let(:raw_data) { double(base_data.merge(state: 'closed')) } + let(:raw_data) { double(data.merge(state: 'closed')) } it 'returns formatted attributes' do expected = { @@ -60,7 +62,7 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do context 'when milestone has a due date' do let(:due_date) { DateTime.strptime('2011-01-28T19:01:12Z') } - let(:raw_data) { double(base_data.merge(due_on: due_date)) } + let(:raw_data) { double(data.merge(due_on: due_date)) } it 'returns formatted attributes' do expected = { @@ -78,4 +80,17 @@ describe Gitlab::GithubImport::MilestoneFormatter, lib: true do end end end + + context 'when importing a GitHub project' do + it_behaves_like 'Gitlab::GithubImport::MilestoneFormatter#attributes' + end + + context 'when importing a Gitea project' do + let(:iid_attr) { :id } + before do + project.update(import_type: 'gitea') + end + + it_behaves_like 'Gitlab::GithubImport::MilestoneFormatter#attributes' + end end diff --git a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb index 302f0fc0623..2b3256edcb2 100644 --- a/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb +++ b/spec/lib/gitlab/github_import/pull_request_formatter_spec.rb @@ -32,9 +32,9 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do } end - subject(:pull_request) { described_class.new(project, raw_data)} + subject(:pull_request) { described_class.new(project, raw_data) } - describe '#attributes' do + shared_examples 'Gitlab::GithubImport::PullRequestFormatter#attributes' do context 'when pull request is open' do let(:raw_data) { double(base_data.merge(state: 'open')) } @@ -149,7 +149,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end context 'when it has a milestone' do - let(:milestone) { double(number: 45) } + let(:milestone) { double(id: 42, number: 42) } let(:raw_data) { double(base_data.merge(milestone: milestone)) } it 'returns nil when milestone does not exist' do @@ -157,22 +157,22 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end it 'returns milestone when it exists' do - milestone = create(:milestone, project: project, iid: 45) + milestone = create(:milestone, project: project, iid: 42) expect(pull_request.attributes.fetch(:milestone)).to eq milestone end end end - describe '#number' do - let(:raw_data) { double(base_data.merge(number: 1347)) } + shared_examples 'Gitlab::GithubImport::PullRequestFormatter#number' do + let(:raw_data) { double(base_data) } it 'returns pull request number' do expect(pull_request.number).to eq 1347 end end - describe '#source_branch_name' do + shared_examples 'Gitlab::GithubImport::PullRequestFormatter#source_branch_name' do context 'when source branch exists' do let(:raw_data) { double(base_data) } @@ -190,7 +190,7 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end end - describe '#target_branch_name' do + shared_examples 'Gitlab::GithubImport::PullRequestFormatter#target_branch_name' do context 'when source branch exists' do let(:raw_data) { double(base_data) } @@ -208,6 +208,24 @@ describe Gitlab::GithubImport::PullRequestFormatter, lib: true do end end + context 'when importing a GitHub project' do + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#attributes' + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#number' + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#source_branch_name' + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#target_branch_name' + end + + context 'when importing a Gitea project' do + before do + project.update(import_type: 'gitea') + end + + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#attributes' + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#number' + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#source_branch_name' + it_behaves_like 'Gitlab::GithubImport::PullRequestFormatter#target_branch_name' + end + describe '#valid?' do context 'when source, and target repos are not a fork' do let(:raw_data) { double(base_data) } diff --git a/spec/routing/import_routing_spec.rb b/spec/routing/import_routing_spec.rb index f1234ff470b..78ff9c6e6fd 100644 --- a/spec/routing/import_routing_spec.rb +++ b/spec/routing/import_routing_spec.rb @@ -75,7 +75,6 @@ describe Import::GiteaController, 'routing' do it 'to #personal_access_token' do expect(post('/import/gitea/personal_access_token')).to route_to('import/gitea#personal_access_token') end - end # status_import_gitlab GET /import/gitlab/status(.:format) import/gitlab#status diff --git a/spec/support/controllers/githubish_import_controller_shared_context.rb b/spec/support/controllers/githubish_import_controller_shared_context.rb new file mode 100644 index 00000000000..e71994edec6 --- /dev/null +++ b/spec/support/controllers/githubish_import_controller_shared_context.rb @@ -0,0 +1,10 @@ +shared_context 'a GitHub-ish import controller' do + let(:user) { create(:user) } + let(:token) { "asdasd12345" } + let(:access_params) { { github_access_token: token } } + + before do + sign_in(user) + allow(controller).to receive(:"#{provider}_import_enabled?").and_return(true) + end +end diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb new file mode 100644 index 00000000000..e11ab802095 --- /dev/null +++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb @@ -0,0 +1,228 @@ +# Specifications for behavior common to all objects with an email attribute. +# Takes a list of email-format attributes and requires: +# - subject { "the object with a attribute= setter" } +# Note: You have access to `email_value` which is the email address value +# being currently tested). + +shared_examples 'a GitHub-ish import controller: POST personal_access_token' do + let(:status_import_url) { public_send("status_import_#{provider}_url") } + + it "updates access token" do + token = 'asdfasdf9876' + + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:user).and_return(true) + + post :personal_access_token, personal_access_token: token + + expect(session[:access_token]).to eq(token) + expect(controller).to redirect_to(status_import_url) + end +end + +shared_examples 'a GitHub-ish import controller: GET new' do + let(:status_import_url) { public_send("status_import_#{provider}_url") } + + it "redirects to status if we already have a token" do + assign_session_token + allow(controller).to receive(:logged_in_with_provider?).and_return(false) + + get :new + + expect(controller).to redirect_to(status_import_url) + end + + it "renders the :new page if no token is present in session" do + get :new + + expect(response).to render_template(:new) + end +end + +shared_examples 'a GitHub-ish import controller: GET status' do + let(:new_import_url) { public_send("new_import_#{provider}_url") } + let(:user) { create(:user) } + let(:repo) { OpenStruct.new(login: 'vim', full_name: 'asd/vim') } + let(:org) { OpenStruct.new(login: 'company') } + let(:org_repo) { OpenStruct.new(login: 'company', full_name: 'company/repo') } + let(:extra_assign_expectations) { {} } + + before do + assign_session_token + end + + it "assigns variables" do + project = create(:empty_project, import_type: provider, creator_id: user.id) + stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo]) + + get :status + + expect(assigns(:already_added_projects)).to eq([project]) + expect(assigns(:repos)).to eq([repo, org_repo]) + extra_assign_expectations.each do |key, value| + expect(assigns(key)).to eq(value) + end + end + + it "does not show already added project" do + project = create(:empty_project, import_type: provider, creator_id: user.id, import_source: 'asd/vim') + stub_client(repos: [repo], orgs: []) + + get :status + + expect(assigns(:already_added_projects)).to eq([project]) + expect(assigns(:repos)).to eq([]) + end + + it "handles an invalid access token" do + allow_any_instance_of(Gitlab::GithubImport::Client). + to receive(:repos).and_raise(Octokit::Unauthorized) + + get :status + + expect(session[:access_token]).to eq(nil) + expect(controller).to redirect_to(new_import_url) + expect(flash[:alert]).to eq("Access denied to your #{Gitlab::ImportSources.title(provider.to_s)} account.") + end +end + +shared_examples 'a GitHub-ish import controller: POST create' do + let(:user) { create(:user) } + let(:provider_username) { user.username } + let(:provider_user) { OpenStruct.new(login: provider_username) } + let(:provider_repo) do + OpenStruct.new( + name: 'vim', + full_name: "#{provider_username}/vim", + owner: OpenStruct.new(login: provider_username) + ) + end + + before do + stub_client(user: provider_user, repo: provider_repo) + assign_session_token + end + + context "when the repository owner is the Gitea user" do + context "when the Gitea user and GitLab user's usernames match" do + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + + context "when the Gitea user and GitLab user's usernames don't match" do + let(:provider_username) { "someone_else" } + + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context "when the repository owner is not the Gitea user" do + let(:other_username) { "someone_else" } + + before do + provider_repo.owner = OpenStruct.new(login: other_username) + assign_session_token + end + + context "when a namespace with the Gitea user's username already exists" do + let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) } + + context "when the namespace is owned by the GitLab user" do + it "takes the existing namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, existing_namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + + context "when the namespace is not owned by the GitLab user" do + before do + existing_namespace.owner = create(:user) + existing_namespace.save + end + + it "creates a project using user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context "when a namespace with the Gitea user's username doesn't exist" do + context "when current user can create namespaces" do + it "creates the namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).and_return(double(execute: true)) + + expect { post :create, target_namespace: provider_repo.name, format: :js }.to change(Namespace, :count).by(1) + end + + it "takes the new namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, target_namespace: provider_repo.name, format: :js + end + end + + context "when current user can't create namespaces" do + before do + user.update_attribute(:can_create_group, false) + end + + it "doesn't create the namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).and_return(double(execute: true)) + + expect { post :create, format: :js }.not_to change(Namespace, :count) + end + + it "takes the current user's namespace" do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, format: :js + end + end + end + + context 'user has chosen a namespace and name for the project' do + let(:test_namespace) { create(:namespace, name: 'test_namespace', owner: user) } + let(:test_name) { 'test_name' } + + it 'takes the selected namespace and name' do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :js } + end + + it 'takes the selected name and default namespace' do + expect(Gitlab::GithubImport::ProjectCreator). + to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider). + and_return(double(execute: true)) + + post :create, { new_name: test_name, format: :js } + end + end + end +end diff --git a/spec/support/githubish_import_controller_shared_context.rb b/spec/support/githubish_import_controller_shared_context.rb deleted file mode 100644 index e71994edec6..00000000000 --- a/spec/support/githubish_import_controller_shared_context.rb +++ /dev/null @@ -1,10 +0,0 @@ -shared_context 'a GitHub-ish import controller' do - let(:user) { create(:user) } - let(:token) { "asdasd12345" } - let(:access_params) { { github_access_token: token } } - - before do - sign_in(user) - allow(controller).to receive(:"#{provider}_import_enabled?").and_return(true) - end -end diff --git a/spec/support/githubish_import_controller_shared_examples.rb b/spec/support/githubish_import_controller_shared_examples.rb deleted file mode 100644 index aa2d8aed0bd..00000000000 --- a/spec/support/githubish_import_controller_shared_examples.rb +++ /dev/null @@ -1,228 +0,0 @@ -# Specifications for behavior common to all objects with an email attribute. -# Takes a list of email-format attributes and requires: -# - subject { "the object with a attribute= setter" } -# Note: You have access to `email_value` which is the email address value -# being currently tested). - -shared_examples 'a GitHub-ish import controller: POST personal_access_token' do - let(:status_import_url) { public_send("status_import_#{provider}_url") } - - it "updates access token" do - token = 'asdfasdf9876' - - allow_any_instance_of(Gitlab::GithubImport::Client). - to receive(:user).and_return(true) - - post :personal_access_token, personal_access_token: token - - expect(session[:access_token]).to eq(token) - expect(controller).to redirect_to(status_import_url) - end -end - -shared_examples 'a GitHub-ish import controller: GET new' do - let(:status_import_url) { public_send("status_import_#{provider}_url") } - - it "redirects to status if we already have a token" do - assign_session_token - allow(controller).to receive(:logged_in_with_provider?).and_return(false) - - get :new - - expect(controller).to redirect_to(status_import_url) - end - - it "renders the :new page if no token is present in session" do - get :new - - expect(response).to render_template(:new) - end -end - -shared_examples 'a GitHub-ish import controller: GET status' do - let(:new_import_url) { public_send("new_import_#{provider}_url") } - let(:user) { create(:user) } - let(:repo) { OpenStruct.new(login: 'vim', full_name: 'asd/vim') } - let(:org) { OpenStruct.new(login: 'company') } - let(:org_repo) { OpenStruct.new(login: 'company', full_name: 'company/repo') } - let(:extra_assign_expectations) { {} } - - before do - assign_session_token - end - - it "assigns variables" do - project = create(:empty_project, import_type: provider, creator_id: user.id) - stub_client(repos: [repo, org_repo], orgs: [org], org_repos: [org_repo]) - - get :status - - expect(assigns(:already_added_projects)).to eq([project]) - expect(assigns(:repos)).to eq([repo, org_repo]) - extra_assign_expectations.each do |key, value| - expect(assigns(key)).to eq(value) - end - end - - it "does not show already added project" do - project = create(:empty_project, import_type: provider, creator_id: user.id, import_source: 'asd/vim') - stub_client(repos: [repo], orgs: []) - - get :status - - expect(assigns(:already_added_projects)).to eq([project]) - expect(assigns(:repos)).to eq([]) - end - - it "handles an invalid access token" do - allow_any_instance_of(Gitlab::GithubImport::Client). - to receive(:repos).and_raise(Octokit::Unauthorized) - - get :status - - expect(session[:access_token]).to eq(nil) - expect(controller).to redirect_to(new_import_url) - expect(flash[:alert]).to eq("Access denied to your #{Gitlab::ImportSources.options.key(provider.to_s)} account.") - end -end - -shared_examples 'a GitHub-ish import controller: POST create' do - let(:user) { create(:user) } - let(:provider_username) { user.username } - let(:provider_user) { OpenStruct.new(login: provider_username) } - let(:provider_repo) do - OpenStruct.new( - name: 'vim', - full_name: "#{provider_username}/vim", - owner: OpenStruct.new(login: provider_username) - ) - end - - before do - stub_client(user: provider_user, repo: provider_repo) - assign_session_token - end - - context "when the repository owner is the Gitea user" do - context "when the Gitea user and GitLab user's usernames match" do - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, format: :js - end - end - - context "when the Gitea user and GitLab user's usernames don't match" do - let(:provider_username) { "someone_else" } - - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context "when the repository owner is not the Gitea user" do - let(:other_username) { "someone_else" } - - before do - provider_repo.owner = OpenStruct.new(login: other_username) - assign_session_token - end - - context "when a namespace with the Gitea user's username already exists" do - let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) } - - context "when the namespace is owned by the GitLab user" do - it "takes the existing namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, provider_repo.name, existing_namespace, user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, format: :js - end - end - - context "when the namespace is not owned by the GitLab user" do - before do - existing_namespace.owner = create(:user) - existing_namespace.save - end - - it "creates a project using user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context "when a namespace with the Gitea user's username doesn't exist" do - context "when current user can create namespaces" do - it "creates the namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).and_return(double(execute: true)) - - expect { post :create, target_namespace: provider_repo.name, format: :js }.to change(Namespace, :count).by(1) - end - - it "takes the new namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, provider_repo.name, an_instance_of(Group), user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, target_namespace: provider_repo.name, format: :js - end - end - - context "when current user can't create namespaces" do - before do - user.update_attribute(:can_create_group, false) - end - - it "doesn't create the namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).and_return(double(execute: true)) - - expect { post :create, format: :js }.not_to change(Namespace, :count) - end - - it "takes the current user's namespace" do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, format: :js - end - end - end - - context 'user has chosen a namespace and name for the project' do - let(:test_namespace) { create(:namespace, name: 'test_namespace', owner: user) } - let(:test_name) { 'test_name' } - - it 'takes the selected namespace and name' do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, test_name, test_namespace, user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, { target_namespace: test_namespace.name, new_name: test_name, format: :js } - end - - it 'takes the selected name and default namespace' do - expect(Gitlab::GithubImport::ProjectCreator). - to receive(:new).with(provider_repo, test_name, user.namespace, user, access_params, type: provider). - and_return(double(execute: true)) - - post :create, { new_name: test_name, format: :js } - end - end - end -end -- cgit v1.2.1 From 8fc63d1f648fa38eac9e5422dd42667d8e7f1b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 16 Dec 2016 09:15:30 +0100 Subject: Improve Gitlab::ImportSources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/lib/gitlab/import_sources_spec.rb | 94 ++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 spec/lib/gitlab/import_sources_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/import_sources_spec.rb b/spec/lib/gitlab/import_sources_spec.rb new file mode 100644 index 00000000000..8cea38e9ff8 --- /dev/null +++ b/spec/lib/gitlab/import_sources_spec.rb @@ -0,0 +1,94 @@ +require 'spec_helper' + +describe Gitlab::ImportSources do + describe '.options' do + it 'returns a hash' do + expected = + { + 'GitHub' => 'github', + 'Bitbucket' => 'bitbucket', + 'GitLab.com' => 'gitlab', + 'Google Code' => 'google_code', + 'FogBugz' => 'fogbugz', + 'Repo by URL' => 'git', + 'GitLab export' => 'gitlab_project', + 'Gitea' => 'gitea' + } + + expect(described_class.options).to eq(expected) + end + end + + describe '.values' do + it 'returns an array' do + expected = + [ + 'github', + 'bitbucket', + 'gitlab', + 'google_code', + 'fogbugz', + 'git', + 'gitlab_project', + 'gitea' + ] + + expect(described_class.values).to eq(expected) + end + end + + describe '.importer_names' do + it 'returns an array of importer names' do + expected = + [ + 'github', + 'bitbucket', + 'gitlab', + 'google_code', + 'fogbugz', + 'gitlab_project', + 'gitea' + ] + + expect(described_class.importer_names).to eq(expected) + end + end + + describe '.importer' do + import_sources = { + 'github' => Gitlab::GithubImport::Importer, + 'bitbucket' => Gitlab::BitbucketImport::Importer, + 'gitlab' => Gitlab::GitlabImport::Importer, + 'google_code' => Gitlab::GoogleCodeImport::Importer, + 'fogbugz' => Gitlab::FogbugzImport::Importer, + 'git' => nil, + 'gitlab_project' => Gitlab::ImportExport::Importer, + 'gitea' => Gitlab::GithubImport::Importer + } + + import_sources.each do |name, klass| + it "returns #{klass} when given #{name}" do + expect(described_class.importer(name)).to eq(klass) + end + end + end + + describe '.title' do + import_sources = { + 'github' => 'GitHub', + 'bitbucket' => 'Bitbucket', + 'gitlab' => 'GitLab.com', + 'google_code' => 'Google Code', + 'fogbugz' => 'FogBugz', + 'git' => 'Repo by URL', + 'gitlab_project' => 'GitLab export', + 'gitea' => 'Gitea' + } + + import_sources.each do |name, title| + it "returns #{title} when given #{name}" do + expect(described_class.title(name)).to eq(title) + end + end + end +end -- cgit v1.2.1 From 20aff5cd2b782fa47fe6c15aad07a547179ee147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 16 Dec 2016 10:47:26 +0100 Subject: Reduce duplication for GitHubish import status view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/helpers/import_helper_spec.rb | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'spec') diff --git a/spec/helpers/import_helper_spec.rb b/spec/helpers/import_helper_spec.rb index 187b891b927..10f293cddf5 100644 --- a/spec/helpers/import_helper_spec.rb +++ b/spec/helpers/import_helper_spec.rb @@ -25,24 +25,37 @@ describe ImportHelper do end end - describe '#github_project_link' do - context 'when provider does not specify a custom URL' do - it 'uses default GitHub URL' do - allow(Gitlab.config.omniauth).to receive(:providers). + describe '#provider_project_link' do + context 'when provider is "github"' do + context 'when provider does not specify a custom URL' do + it 'uses default GitHub URL' do + allow(Gitlab.config.omniauth).to receive(:providers). and_return([Settingslogic.new('name' => 'github')]) - expect(helper.github_project_link('octocat/Hello-World')). + expect(helper.provider_project_link('github', 'octocat/Hello-World')). to include('href="https://github.com/octocat/Hello-World"') + end end - end - context 'when provider specify a custom URL' do - it 'uses custom URL' do - allow(Gitlab.config.omniauth).to receive(:providers). + context 'when provider specify a custom URL' do + it 'uses custom URL' do + allow(Gitlab.config.omniauth).to receive(:providers). and_return([Settingslogic.new('name' => 'github', 'url' => 'https://github.company.com')]) - expect(helper.github_project_link('octocat/Hello-World')). + expect(helper.provider_project_link('github', 'octocat/Hello-World')). to include('href="https://github.company.com/octocat/Hello-World"') + end + end + end + + context 'when provider is "gitea"' do + before do + assign(:gitea_host_url, 'https://try.gitea.io/') + end + + it 'uses given host' do + expect(helper.provider_project_link('gitea', 'octocat/Hello-World')). + to include('href="https://try.gitea.io/octocat/Hello-World"') end end end -- cgit v1.2.1 From e046e4c14d06a19cc30a679f4943c77b56ee6d0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 16 Dec 2016 17:43:34 +0100 Subject: Namespace access token session key in `Import::GithubController` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/controllers/import/gitea_controller_spec.rb | 2 +- spec/controllers/import/github_controller_spec.rb | 2 +- .../githubish_import_controller_shared_examples.rb | 28 ++++++++++++---------- spec/support/import_spec_helper.rb | 4 ---- 4 files changed, 18 insertions(+), 18 deletions(-) (limited to 'spec') diff --git a/spec/controllers/import/gitea_controller_spec.rb b/spec/controllers/import/gitea_controller_spec.rb index 3643386ffbc..5ba64ab3eed 100644 --- a/spec/controllers/import/gitea_controller_spec.rb +++ b/spec/controllers/import/gitea_controller_spec.rb @@ -9,7 +9,7 @@ describe Import::GiteaController do include_context 'a GitHub-ish import controller' def assign_host_url - session[:host_url] = host_url + session[:gitea_host_url] = host_url end describe "GET new" do diff --git a/spec/controllers/import/github_controller_spec.rb b/spec/controllers/import/github_controller_spec.rb index 55820a7cc65..95696e14b6c 100644 --- a/spec/controllers/import/github_controller_spec.rb +++ b/spec/controllers/import/github_controller_spec.rb @@ -29,7 +29,7 @@ describe Import::GithubController do get :callback - expect(session[:access_token]).to eq(token) + expect(session[:github_access_token]).to eq(token) expect(controller).to redirect_to(status_import_github_url) end end diff --git a/spec/support/controllers/githubish_import_controller_shared_examples.rb b/spec/support/controllers/githubish_import_controller_shared_examples.rb index e11ab802095..d0fd2d52004 100644 --- a/spec/support/controllers/githubish_import_controller_shared_examples.rb +++ b/spec/support/controllers/githubish_import_controller_shared_examples.rb @@ -4,6 +4,10 @@ # Note: You have access to `email_value` which is the email address value # being currently tested). +def assign_session_token(provider) + session[:"#{provider}_access_token"] = 'asdasd12345' +end + shared_examples 'a GitHub-ish import controller: POST personal_access_token' do let(:status_import_url) { public_send("status_import_#{provider}_url") } @@ -15,7 +19,7 @@ shared_examples 'a GitHub-ish import controller: POST personal_access_token' do post :personal_access_token, personal_access_token: token - expect(session[:access_token]).to eq(token) + expect(session[:"#{provider}_access_token"]).to eq(token) expect(controller).to redirect_to(status_import_url) end end @@ -24,7 +28,7 @@ shared_examples 'a GitHub-ish import controller: GET new' do let(:status_import_url) { public_send("status_import_#{provider}_url") } it "redirects to status if we already have a token" do - assign_session_token + assign_session_token(provider) allow(controller).to receive(:logged_in_with_provider?).and_return(false) get :new @@ -48,7 +52,7 @@ shared_examples 'a GitHub-ish import controller: GET status' do let(:extra_assign_expectations) { {} } before do - assign_session_token + assign_session_token(provider) end it "assigns variables" do @@ -80,7 +84,7 @@ shared_examples 'a GitHub-ish import controller: GET status' do get :status - expect(session[:access_token]).to eq(nil) + expect(session[:"#{provider}_access_token"]).to be_nil expect(controller).to redirect_to(new_import_url) expect(flash[:alert]).to eq("Access denied to your #{Gitlab::ImportSources.title(provider.to_s)} account.") end @@ -100,11 +104,11 @@ shared_examples 'a GitHub-ish import controller: POST create' do before do stub_client(user: provider_user, repo: provider_repo) - assign_session_token + assign_session_token(provider) end - context "when the repository owner is the Gitea user" do - context "when the Gitea user and GitLab user's usernames match" do + context "when the repository owner is the provider user" do + context "when the provider user and GitLab user's usernames match" do it "takes the current user's namespace" do expect(Gitlab::GithubImport::ProjectCreator). to receive(:new).with(provider_repo, provider_repo.name, user.namespace, user, access_params, type: provider). @@ -114,7 +118,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do end end - context "when the Gitea user and GitLab user's usernames don't match" do + context "when the provider user and GitLab user's usernames don't match" do let(:provider_username) { "someone_else" } it "takes the current user's namespace" do @@ -127,15 +131,15 @@ shared_examples 'a GitHub-ish import controller: POST create' do end end - context "when the repository owner is not the Gitea user" do + context "when the repository owner is not the provider user" do let(:other_username) { "someone_else" } before do provider_repo.owner = OpenStruct.new(login: other_username) - assign_session_token + assign_session_token(provider) end - context "when a namespace with the Gitea user's username already exists" do + context "when a namespace with the provider user's username already exists" do let!(:existing_namespace) { create(:namespace, name: other_username, owner: user) } context "when the namespace is owned by the GitLab user" do @@ -164,7 +168,7 @@ shared_examples 'a GitHub-ish import controller: POST create' do end end - context "when a namespace with the Gitea user's username doesn't exist" do + context "when a namespace with the provider user's username doesn't exist" do context "when current user can create namespaces" do it "creates the namespace" do expect(Gitlab::GithubImport::ProjectCreator). diff --git a/spec/support/import_spec_helper.rb b/spec/support/import_spec_helper.rb index cd25e05ac4b..6710962f082 100644 --- a/spec/support/import_spec_helper.rb +++ b/spec/support/import_spec_helper.rb @@ -30,8 +30,4 @@ module ImportSpecHelper ) allow(Gitlab.config.omniauth).to receive(:providers).and_return([provider]) end - - def assign_session_token - session[:access_token] = 'asdasd12345' - end end -- cgit v1.2.1 From ab06313c36fc5856b2472d3dfcb966a8c6341d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 16 Dec 2016 17:44:22 +0100 Subject: Add Project#gitea_import? MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/lib/gitlab/github_import/importer_spec.rb | 2 +- spec/models/project_spec.rb | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/lib/gitlab/github_import/importer_spec.rb b/spec/lib/gitlab/github_import/importer_spec.rb index 0a03b7353f6..72421832ffc 100644 --- a/spec/lib/gitlab/github_import/importer_spec.rb +++ b/spec/lib/gitlab/github_import/importer_spec.rb @@ -192,7 +192,7 @@ describe Gitlab::GithubImport::Importer, lib: true do ] } - unless project.import_type == 'gitea' + unless project.gitea_import? error[:errors] << { type: :release, url: "#{api_root}/repos/octocat/Hello-World/releases/2", errors: "Validation failed: Description can't be blank" } end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index ed6b2c6a22b..8779b399344 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1458,6 +1458,18 @@ describe Project, models: true do end end + describe '#gitlab_project_import?' do + subject(:project) { build(:project, import_type: 'gitlab_project') } + + it { expect(project.gitlab_project_import?).to be true } + end + + describe '#gitea_import?' do + subject(:project) { build(:project, import_type: 'gitea') } + + it { expect(project.gitea_import?).to be true } + end + describe '#lfs_enabled?' do let(:project) { create(:project) } -- cgit v1.2.1 From b67ad2db8717a0f9b673f828f9bea5732e7d258a Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Mon, 19 Dec 2016 16:54:14 +0000 Subject: Added integration tests --- .../services/mattermost_slash_command_spec.rb | 67 +++++++++++++++++----- 1 file changed, 53 insertions(+), 14 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index f474e7e891b..4c08d1e6e65 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -10,23 +10,18 @@ feature 'Setup Mattermost slash commands', feature: true do before do project.team << [user, :master] login_as(user) + visit edit_namespace_project_service_path(project.namespace, project, service) end - describe 'user visites the mattermost slash command config page', js: true do + describe 'user visits the mattermost slash command config page', js: true do it 'shows a help message' do - visit edit_namespace_project_service_path(project.namespace, project, service) - wait_for_ajax expect(page).to have_content("This service allows GitLab users to perform common") end - end - - describe 'saving a token' do - let(:token) { ('a'..'z').to_a.join } it 'shows the token after saving' do - visit edit_namespace_project_service_path(project.namespace, project, service) + token = ('a'..'z').to_a.join fill_in 'service_token', with: token click_on 'Save' @@ -35,14 +30,58 @@ feature 'Setup Mattermost slash commands', feature: true do expect(value).to eq(token) end - end - describe 'the trigger url' do - it 'shows the correct url' do - visit edit_namespace_project_service_path(project.namespace, project, service) + describe 'mattermost service is enabled' do + let(:info) { find('.services-installation-info') } + + before do + Gitlab.config.mattermost.enabled = true + end + + it 'shows the correct mattermost url' do + expect(page).to have_content Gitlab.config.mattermost.host + end + + describe 'mattermost service is active' do + before do + service.active = true + end + + it 'shows that mattermost is active' do + expect(info).to have_content 'Installed' + expect(info).not_to have_content 'Not installed' + end + + it 'shows the edit mattermost button' do + expect(info).to have_button 'Edit Mattermost' + end + end + + describe 'mattermost service is not active' do + before do + service.active = false + end + + it 'shows that mattermost is not active' do + expect(info).to have_content 'Not installed' + end + + it 'shows the add to mattermost button' do + expect(info).to have_button 'Add to Mattermost' + end + end + end + + describe 'mattermost service is not enabled' do + before do + Gitlab.config.mattermost.enabled = false + end + + it 'shows the correct trigger url' do + value = find_field('request_url').value - value = find_field('request_url').value - expect(value).to match("api/v3/projects/#{project.id}/services/mattermost_slash_commands/trigger") + expect(value).to match("api/v3/projects/#{project.id}/services/mattermost_slash_commands/trigger") + end end end end -- cgit v1.2.1 From 2e6c1720ead0f2843abb0d03f0c01b92fa063980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 16 Dec 2016 18:21:58 +0100 Subject: Allow Repositories API GET endpoints to be requested anonymously MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/requests/api/repositories_spec.rb | 276 +++++++++++++++++++++++---------- 1 file changed, 194 insertions(+), 82 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index c90b69e8ebb..67f0bc537fe 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -16,15 +16,32 @@ describe API::Repositories, api: true do context "authorized user" do before { project.team << [user2, :reporter] } - it "returns project commits" do - get api("/projects/#{project.id}/repository/tree", user) + shared_examples_for 'repository tree' do + it 'returns the repository tree' do + get api("/projects/#{project.id}/repository/tree", current_user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.first['name']).to eq('bar') - expect(json_response.first['type']).to eq('tree') - expect(json_response.first['mode']).to eq('040000') + first_commit = json_response.first + + expect(json_response).to be_an Array + expect(first_commit['name']).to eq('bar') + expect(first_commit['type']).to eq('tree') + expect(first_commit['mode']).to eq('040000') + end + end + + context 'when unauthenticated' do + it_behaves_like 'repository tree' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end + end + + context 'when authenticated' do + it_behaves_like 'repository tree' do + let(:current_user) { user } + end end it 'returns a 404 for unknown ref' do @@ -39,7 +56,8 @@ describe API::Repositories, api: true do context "unauthorized user" do it "does not return project commits" do get api("/projects/#{project.id}/repository/tree") - expect(response).to have_http_status(401) + + expect(response).to have_http_status(404) end end end @@ -72,15 +90,38 @@ describe API::Repositories, api: true do context "unauthorized user" do it "does not return project commits" do get api("/projects/#{project.id}/repository/tree?recursive=1") - expect(response).to have_http_status(401) + + expect(response).to have_http_status(404) end end end - describe "GET /projects/:id/repository/blobs/:sha" do - it "gets the raw file contents" do - get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", user) - expect(response).to have_http_status(200) + describe "GET /projects/:id/repository/blobs/:sha & /projects/:id/repository/commits/:sha" do + shared_examples_for 'repository blob' do + it 'returns the repository blob for /repository/blobs/master' do + get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", current_user) + + expect(response).to have_http_status(200) + end + + it 'returns the repository blob for /repository/commits/master' do + get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", current_user) + + expect(response).to have_http_status(200) + end + end + + context 'when unauthenticated' do + it_behaves_like 'repository blob' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end + end + + context 'when authenticated' do + it_behaves_like 'repository blob' do + let(:current_user) { user } + end end it "returns 404 for invalid branch_name" do @@ -99,17 +140,26 @@ describe API::Repositories, api: true do end end - describe "GET /projects/:id/repository/commits/:sha/blob" do - it "gets the raw file contents" do - get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", user) - expect(response).to have_http_status(200) + describe "GET /projects/:id/repository/raw_blobs/:sha" do + shared_examples_for 'repository raw blob' do + it 'returns the repository raw blob' do + get api("/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}", current_user) + + expect(response).to have_http_status(200) + end end - end - describe "GET /projects/:id/repository/raw_blobs/:sha" do - it "gets the raw file contents" do - get api("/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}", user) - expect(response).to have_http_status(200) + context 'when unauthenticated' do + it_behaves_like 'repository raw blob' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end + end + + context 'when authenticated' do + it_behaves_like 'repository raw blob' do + let(:current_user) { user } + end end it 'returns a 404 for unknown blob' do @@ -122,31 +172,55 @@ describe API::Repositories, api: true do end describe "GET /projects/:id/repository/archive(.:format)?:sha" do - it "gets the archive" do - get api("/projects/#{project.id}/repository/archive", user) - repo_name = project.repository.name.gsub("\.git", "") - expect(response).to have_http_status(200) - type, params = workhorse_send_data - expect(type).to eq('git-archive') - expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/) + shared_examples_for 'repository archive' do + it 'returns the repository archive' do + get api("/projects/#{project.id}/repository/archive", current_user) + + expect(response).to have_http_status(200) + + repo_name = project.repository.name.gsub("\.git", "") + type, params = workhorse_send_data + + expect(type).to eq('git-archive') + expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.gz/) + end + + it 'returns the repository archive archive.zip' do + get api("/projects/#{project.id}/repository/archive.zip", user) + + expect(response).to have_http_status(200) + + repo_name = project.repository.name.gsub("\.git", "") + type, params = workhorse_send_data + + expect(type).to eq('git-archive') + expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/) + end + + it 'returns the repository archive archive.tar.bz2' do + get api("/projects/#{project.id}/repository/archive.tar.bz2", user) + + expect(response).to have_http_status(200) + + repo_name = project.repository.name.gsub("\.git", "") + type, params = workhorse_send_data + + expect(type).to eq('git-archive') + expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/) + end end - it "gets the archive.zip" do - get api("/projects/#{project.id}/repository/archive.zip", user) - repo_name = project.repository.name.gsub("\.git", "") - expect(response).to have_http_status(200) - type, params = workhorse_send_data - expect(type).to eq('git-archive') - expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.zip/) + context 'when unauthenticated' do + it_behaves_like 'repository archive' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end end - it "gets the archive.tar.bz2" do - get api("/projects/#{project.id}/repository/archive.tar.bz2", user) - repo_name = project.repository.name.gsub("\.git", "") - expect(response).to have_http_status(200) - type, params = workhorse_send_data - expect(type).to eq('git-archive') - expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/) + context 'when authenticated' do + it_behaves_like 'repository archive' do + let(:current_user) { user } + end end it "returns 404 for invalid sha" do @@ -156,55 +230,93 @@ describe API::Repositories, api: true do end describe 'GET /projects/:id/repository/compare' do - it "compares branches" do - get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'feature' - expect(response).to have_http_status(200) - expect(json_response['commits']).to be_present - expect(json_response['diffs']).to be_present - end + shared_examples_for 'repository compare' do + it "compares branches" do + get api("/projects/#{project.id}/repository/compare", current_user), from: 'master', to: 'feature' - it "compares tags" do - get api("/projects/#{project.id}/repository/compare", user), from: 'v1.0.0', to: 'v1.1.0' - expect(response).to have_http_status(200) - expect(json_response['commits']).to be_present - expect(json_response['diffs']).to be_present - end + expect(response).to have_http_status(200) + expect(json_response['commits']).to be_present + expect(json_response['diffs']).to be_present + end + + it "compares tags" do + get api("/projects/#{project.id}/repository/compare", current_user), from: 'v1.0.0', to: 'v1.1.0' + + expect(response).to have_http_status(200) + expect(json_response['commits']).to be_present + expect(json_response['diffs']).to be_present + end + + it "compares commits" do + get api("/projects/#{project.id}/repository/compare", current_user), from: sample_commit.id, to: sample_commit.parent_id + + expect(response).to have_http_status(200) + expect(json_response['commits']).to be_empty + expect(json_response['diffs']).to be_empty + expect(json_response['compare_same_ref']).to be_falsey + end - it "compares commits" do - get api("/projects/#{project.id}/repository/compare", user), from: sample_commit.id, to: sample_commit.parent_id - expect(response).to have_http_status(200) - expect(json_response['commits']).to be_empty - expect(json_response['diffs']).to be_empty - expect(json_response['compare_same_ref']).to be_falsey + it "compares commits in reverse order" do + get api("/projects/#{project.id}/repository/compare", current_user), from: sample_commit.parent_id, to: sample_commit.id + + expect(response).to have_http_status(200) + expect(json_response['commits']).to be_present + expect(json_response['diffs']).to be_present + end + + it "compares same refs" do + get api("/projects/#{project.id}/repository/compare", current_user), from: 'master', to: 'master' + + expect(response).to have_http_status(200) + expect(json_response['commits']).to be_empty + expect(json_response['diffs']).to be_empty + expect(json_response['compare_same_ref']).to be_truthy + end end - it "compares commits in reverse order" do - get api("/projects/#{project.id}/repository/compare", user), from: sample_commit.parent_id, to: sample_commit.id - expect(response).to have_http_status(200) - expect(json_response['commits']).to be_present - expect(json_response['diffs']).to be_present + context 'when unauthenticated' do + it_behaves_like 'repository compare' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end end - it "compares same refs" do - get api("/projects/#{project.id}/repository/compare", user), from: 'master', to: 'master' - expect(response).to have_http_status(200) - expect(json_response['commits']).to be_empty - expect(json_response['diffs']).to be_empty - expect(json_response['compare_same_ref']).to be_truthy + context 'when authenticated' do + it_behaves_like 'repository compare' do + let(:current_user) { user } + end end end describe 'GET /projects/:id/repository/contributors' do - it 'returns valid data' do - get api("/projects/#{project.id}/repository/contributors", user) - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - contributor = json_response.first - expect(contributor['email']).to eq('tiagonbotelho@hotmail.com') - expect(contributor['name']).to eq('tiagonbotelho') - expect(contributor['commits']).to eq(1) - expect(contributor['additions']).to eq(0) - expect(contributor['deletions']).to eq(0) + shared_examples_for 'repository contributors' do + it 'returns valid data' do + get api("/projects/#{project.id}/repository/contributors", user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + + first_contributor = json_response.first + + expect(first_contributor['email']).to eq('tiagonbotelho@hotmail.com') + expect(first_contributor['name']).to eq('tiagonbotelho') + expect(first_contributor['commits']).to eq(1) + expect(first_contributor['additions']).to eq(0) + expect(first_contributor['deletions']).to eq(0) + end + end + + context 'when unauthenticated' do + it_behaves_like 'repository contributors' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end + end + + context 'when authenticated' do + it_behaves_like 'repository contributors' do + let(:current_user) { user } + end end end end -- cgit v1.2.1 From 5378302763e1a461bab5213aa379d5b9e6dc322c Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Sat, 17 Dec 2016 04:09:50 +0000 Subject: Add a ReactiveCaching concern for use in the KubernetesService --- spec/models/concerns/reactive_caching_spec.rb | 145 ++++++++++++++++++++++++++ spec/support/reactive_caching_helpers.rb | 38 +++++++ spec/workers/reactive_caching_worker_spec.rb | 15 +++ 3 files changed, 198 insertions(+) create mode 100644 spec/models/concerns/reactive_caching_spec.rb create mode 100644 spec/support/reactive_caching_helpers.rb create mode 100644 spec/workers/reactive_caching_worker_spec.rb (limited to 'spec') diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb new file mode 100644 index 00000000000..a0765a264cf --- /dev/null +++ b/spec/models/concerns/reactive_caching_spec.rb @@ -0,0 +1,145 @@ +require 'spec_helper' + +describe ReactiveCaching, caching: true do + include ReactiveCachingHelpers + + class CacheTest + include ReactiveCaching + + self.reactive_cache_key = ->(thing) { ["foo", thing.id] } + + self.reactive_cache_lifetime = 5.minutes + self.reactive_cache_refresh_interval = 15.seconds + + attr_reader :id + + def initialize(id, &blk) + @id = id + @calculator = blk + end + + def calculate_reactive_cache + @calculator.call + end + + def result + with_reactive_cache do |data| + data / 2 + end + end + end + + let(:now) { Time.now.utc } + + around(:each) do |example| + Timecop.freeze(now) { example.run } + end + + let(:calculation) { -> { 2 + 2 } } + let(:cache_key) { "foo:666" } + let(:instance) { CacheTest.new(666, &calculation) } + + describe '#with_reactive_cache' do + before { stub_reactive_cache } + subject(:go!) { instance.result } + + context 'when cache is empty' do + it { is_expected.to be_nil } + + it 'queues a background worker' do + expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666) + + go! + end + + it 'updates the cache lifespan' do + go! + + expect(reactive_cache_alive?(instance)).to be_truthy + end + end + + context 'when the cache is full' do + before { stub_reactive_cache(instance, 4) } + + it { is_expected.to eq(2) } + + context 'and expired' do + before { invalidate_reactive_cache(instance) } + it { is_expected.to be_nil } + end + end + end + + describe '#clear_reactive_cache!' do + before do + stub_reactive_cache(instance, 4) + instance.clear_reactive_cache! + end + + it { expect(instance.result).to be_nil } + end + + describe '#exclusively_update_reactive_cache!' do + subject(:go!) { instance.exclusively_update_reactive_cache! } + + context 'when the lease is free and lifetime is not exceeded' do + before { stub_reactive_cache(instance, "preexisting") } + + it 'takes and releases the lease' do + expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return("000000") + expect(Gitlab::ExclusiveLease).to receive(:cancel).with(cache_key, "000000") + + go! + end + + it 'caches the result of #calculate_reactive_cache' do + go! + + expect(read_reactive_cache(instance)).to eq(calculation.call) + end + + it "enqueues a repeat worker" do + expect_reactive_cache_update_queued(instance) + + go! + end + + context 'and #calculate_reactive_cache raises an exception' do + before { stub_reactive_cache(instance, "preexisting") } + let(:calculation) { -> { raise "foo"} } + + it 'leaves the cache untouched' do + expect { go! }.to raise_error("foo") + expect(read_reactive_cache(instance)).to eq("preexisting") + end + + it 'enqueues a repeat worker' do + expect_reactive_cache_update_queued(instance) + + expect { go! }.to raise_error("foo") + end + end + end + + context 'when lifetime is exceeded' do + it 'skips the calculation' do + expect(instance).to receive(:calculate_reactive_cache).never + + go! + end + end + + context 'when the lease is already taken' do + before do + expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(nil) + end + + it 'skips the calculation' do + expect(instance).to receive(:calculate_reactive_cache).never + + go! + end + end + end +end diff --git a/spec/support/reactive_caching_helpers.rb b/spec/support/reactive_caching_helpers.rb new file mode 100644 index 00000000000..279db3c5748 --- /dev/null +++ b/spec/support/reactive_caching_helpers.rb @@ -0,0 +1,38 @@ +module ReactiveCachingHelpers + def reactive_cache_key(subject, *qualifiers) + ([subject.class.reactive_cache_key.call(subject)].flatten + qualifiers).join(':') + end + + def stub_reactive_cache(subject = nil, data = nil) + allow(ReactiveCachingWorker).to receive(:perform_async) + allow(ReactiveCachingWorker).to receive(:perform_in) + write_reactive_cache(subject, data) if data + end + + def read_reactive_cache(subject) + Rails.cache.read(reactive_cache_key(subject)) + end + + def write_reactive_cache(subject, data) + start_reactive_cache_lifetime(subject) + Rails.cache.write(reactive_cache_key(subject), data) + end + + def reactive_cache_alive?(subject) + Rails.cache.read(reactive_cache_key(subject, 'alive')) + end + + def invalidate_reactive_cache(subject) + Rails.cache.delete(reactive_cache_key(subject, 'alive')) + end + + def start_reactive_cache_lifetime(subject) + Rails.cache.write(reactive_cache_key(subject, 'alive'), true) + end + + def expect_reactive_cache_update_queued(subject) + expect(ReactiveCachingWorker). + to receive(:perform_in). + with(subject.class.reactive_cache_refresh_interval, subject.class, subject.id) + end +end diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb new file mode 100644 index 00000000000..5f4453c15d6 --- /dev/null +++ b/spec/workers/reactive_caching_worker_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe ReactiveCachingWorker do + let(:project) { create(:kubernetes_project) } + let(:service) { project.deployment_service } + subject { described_class.new.perform("KubernetesService", service.id) } + + describe '#perform' do + it 'calls #exclusively_update_reactive_cache!' do + expect_any_instance_of(KubernetesService).to receive(:exclusively_update_reactive_cache!) + + subject + end + end +end -- cgit v1.2.1 From c3d972f4e861059312c2708dacb57999416fcc70 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Tue, 22 Nov 2016 19:55:56 +0000 Subject: Add terminals to the Kubernetes deployment service --- .../projects/environments_controller_spec.rb | 68 +++++++++++++ spec/factories/projects.rb | 2 +- spec/lib/gitlab/kubernetes_spec.rb | 39 ++++++++ spec/lib/gitlab/workhorse_spec.rb | 36 +++++++ spec/models/environment_spec.rb | 60 +++++++++++- .../project_services/kubernetes_service_spec.rb | 109 ++++++++++++++++----- spec/support/kubernetes_helpers.rb | 52 ++++++++++ 7 files changed, 335 insertions(+), 31 deletions(-) create mode 100644 spec/lib/gitlab/kubernetes_spec.rb create mode 100644 spec/support/kubernetes_helpers.rb (limited to 'spec') diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index bc5e2711125..7afa8b1bc28 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -71,6 +71,74 @@ describe Projects::EnvironmentsController do end end + describe 'GET #terminal' do + context 'with valid id' do + it 'responds with a status code 200' do + get :terminal, environment_params + + expect(response).to have_http_status(200) + end + + it 'loads the terminals for the enviroment' do + expect_any_instance_of(Environment).to receive(:terminals) + + get :terminal, environment_params + end + end + + context 'with invalid id' do + it 'responds with a status code 404' do + get :terminal, environment_params(id: 666) + + expect(response).to have_http_status(404) + end + end + end + + describe 'GET #terminal_websocket_authorize' do + context 'with valid workhorse signature' do + before do + allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_return(nil) + end + + context 'and valid id' do + it 'returns the first terminal for the environment' do + expect_any_instance_of(Environment). + to receive(:terminals). + and_return([:fake_terminal]) + + expect(Gitlab::Workhorse). + to receive(:terminal_websocket). + with(:fake_terminal). + and_return(workhorse: :response) + + get :terminal_websocket_authorize, environment_params + + expect(response).to have_http_status(200) + expect(response.headers["Content-Type"]).to eq(Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE) + expect(response.body).to eq('{"workhorse":"response"}') + end + end + + context 'and invalid id' do + it 'returns 404' do + get :terminal_websocket_authorize, environment_params(id: 666) + expect(response).to have_http_status(404) + end + end + end + + context 'with invalid workhorse signature' do + it 'aborts with an exception' do + allow(Gitlab::Workhorse).to receive(:verify_api_request!).and_raise(JWT::DecodeError) + + expect { get :terminal_websocket_authorize, environment_params }.to raise_error(JWT::DecodeError) + # controller tests don't set the response status correctly. It's enough + # to check that the action raised an exception + end + end + end + def environment_params(opts = {}) opts.reverse_merge(namespace_id: project.namespace, project_id: project, diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index 0d072d6a690..c941fb5ef4b 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -140,7 +140,7 @@ FactoryGirl.define do active: true, properties: { namespace: project.path, - api_url: 'https://kubernetes.example.com/api', + api_url: 'https://kubernetes.example.com', token: 'a' * 40, } ) diff --git a/spec/lib/gitlab/kubernetes_spec.rb b/spec/lib/gitlab/kubernetes_spec.rb new file mode 100644 index 00000000000..c9bd52a3b8f --- /dev/null +++ b/spec/lib/gitlab/kubernetes_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe Gitlab::Kubernetes do + include described_class + + describe '#container_exec_url' do + let(:api_url) { 'https://example.com' } + let(:namespace) { 'default' } + let(:pod_name) { 'pod1' } + let(:container_name) { 'container1' } + + subject(:result) { URI::parse(container_exec_url(api_url, namespace, pod_name, container_name)) } + + it { expect(result.scheme).to eq('wss') } + it { expect(result.host).to eq('example.com') } + it { expect(result.path).to eq('/api/v1/namespaces/default/pods/pod1/exec') } + it { expect(result.query).to eq('container=container1&stderr=true&stdin=true&stdout=true&tty=true&command=sh&command=-c&command=bash+%7C%7C+sh') } + + context 'with a HTTP API URL' do + let(:api_url) { 'http://example.com' } + + it { expect(result.scheme).to eq('ws') } + end + + context 'with a path prefix in the API URL' do + let(:api_url) { 'https://example.com/prefix/' } + it { expect(result.path).to eq('/prefix/api/v1/namespaces/default/pods/pod1/exec') } + end + + context 'with arguments that need urlencoding' do + let(:namespace) { 'default namespace' } + let(:pod_name) { 'pod 1' } + let(:container_name) { 'container 1' } + + it { expect(result.path).to eq('/api/v1/namespaces/default%20namespace/pods/pod%201/exec') } + it { expect(result.query).to match(/\Acontainer=container\+1&/) } + end + end +end diff --git a/spec/lib/gitlab/workhorse_spec.rb b/spec/lib/gitlab/workhorse_spec.rb index b5b685da904..61da91dcbd3 100644 --- a/spec/lib/gitlab/workhorse_spec.rb +++ b/spec/lib/gitlab/workhorse_spec.rb @@ -37,6 +37,42 @@ describe Gitlab::Workhorse, lib: true do end end + describe '.terminal_websocket' do + def terminal(ca_pem: nil) + out = { + subprotocols: ['foo'], + url: 'wss://example.com/terminal.ws', + headers: { 'Authorization' => ['Token x'] } + } + out[:ca_pem] = ca_pem if ca_pem + out + end + + def workhorse(ca_pem: nil) + out = { + 'Terminal' => { + 'Subprotocols' => ['foo'], + 'Url' => 'wss://example.com/terminal.ws', + 'Header' => { 'Authorization' => ['Token x'] } + } + } + out['Terminal']['CAPem'] = ca_pem if ca_pem + out + end + + context 'without ca_pem' do + subject { Gitlab::Workhorse.terminal_websocket(terminal) } + + it { is_expected.to eq(workhorse) } + end + + context 'with ca_pem' do + subject { Gitlab::Workhorse.terminal_websocket(terminal(ca_pem: "foo")) } + + it { is_expected.to eq(workhorse(ca_pem: "foo")) } + end + end + describe '.send_git_diff' do let(:diff_refs) { double(base_sha: "base", head_sha: "head") } subject { described_class.send_git_patch(repository, diff_refs) } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 97cbb093ed2..93eb402e060 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -1,7 +1,8 @@ require 'spec_helper' describe Environment, models: true do - subject(:environment) { create(:environment) } + let(:project) { create(:empty_project) } + subject(:environment) { create(:environment, project: project) } it { is_expected.to belong_to(:project) } it { is_expected.to have_many(:deployments) } @@ -31,6 +32,8 @@ describe Environment, models: true do end describe '#includes_commit?' do + let(:project) { create(:project) } + context 'without a last deployment' do it "returns false" do expect(environment.includes_commit?('HEAD')).to be false @@ -38,9 +41,6 @@ describe Environment, models: true do end context 'with a last deployment' do - let(:project) { create(:project) } - let(:environment) { create(:environment, project: project) } - let!(:deployment) do create(:deployment, environment: environment, sha: project.commit('master').id) end @@ -65,7 +65,6 @@ describe Environment, models: true do describe '#first_deployment_for' do let(:project) { create(:project) } - let!(:environment) { create(:environment, project: project) } let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } let(:head_commit) { project.commit } @@ -196,6 +195,57 @@ describe Environment, models: true do end end + describe '#has_terminals?' do + subject { environment.has_terminals? } + + context 'when the enviroment is available' do + context 'with a deployment service' do + let(:project) { create(:kubernetes_project) } + + context 'and a deployment' do + let!(:deployment) { create(:deployment, environment: environment) } + it { is_expected.to be_truthy } + end + + context 'but no deployments' do + it { is_expected.to be_falsy } + end + end + + context 'without a deployment service' do + it { is_expected.to be_falsy } + end + end + + context 'when the environment is unavailable' do + let(:project) { create(:kubernetes_project) } + before { environment.stop } + it { is_expected.to be_falsy } + end + end + + describe '#terminals' do + let(:project) { create(:kubernetes_project) } + subject { environment.terminals } + + context 'when the environment has terminals' do + before { allow(environment).to receive(:has_terminals?).and_return(true) } + + it 'returns the terminals from the deployment service' do + expect(project.deployment_service). + to receive(:terminals).with(environment). + and_return(:fake_terminals) + + is_expected.to eq(:fake_terminals) + end + end + + context 'when the environment does not have terminals' do + before { allow(environment).to receive(:has_terminals?).and_return(false) } + it { is_expected.to eq(nil) } + end + end + describe '#slug' do it "is automatically generated" do expect(environment.slug).not_to be_nil diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 3603602e41d..4f3cd14e941 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -1,7 +1,29 @@ require 'spec_helper' -describe KubernetesService, models: true do - let(:project) { create(:empty_project) } +describe KubernetesService, models: true, caching: true do + include KubernetesHelpers + include ReactiveCachingHelpers + + let(:project) { create(:kubernetes_project) } + let(:service) { project.kubernetes_service } + + # We use Kubeclient to interactive with the Kubernetes API. It will + # GET /api/v1 for a list of resources the API supports. This must be stubbed + # in addition to any other HTTP requests we expect it to perform. + 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_response) { { body: kube_pods_body(kube_pod).to_json } } + + def stub_kubeclient_discover + WebMock.stub_request(:get, discovery_url).to_return(discovery_response) + end + + def stub_kubeclient_pods + stub_kubeclient_discover + WebMock.stub_request(:get, pods_url).to_return(pods_response) + end describe "Associations" do it { is_expected.to belong_to :project } @@ -65,22 +87,15 @@ describe KubernetesService, models: true do end describe '#test' do - let(:project) { create(:kubernetes_project) } - let(:service) { project.kubernetes_service } - let(:discovery_url) { service.api_url + '/api/v1' } - - # JSON response body from Kubernetes GET /api/v1 request - let(:discovery_response) { { "kind" => "APIResourceList", "groupVersion" => "v1", "resources" => [] }.to_json } + before do + stub_kubeclient_discover + end context 'with path prefix in api_url' do let(:discovery_url) { 'https://kubernetes.example.com/prefix/api/v1' } - before do - service.api_url = 'https://kubernetes.example.com/prefix/' - end - it 'tests with the prefix' do - WebMock.stub_request(:get, discovery_url).to_return(body: discovery_response) + service.api_url = 'https://kubernetes.example.com/prefix/' expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once @@ -88,17 +103,12 @@ describe KubernetesService, models: true do end context 'with custom CA certificate' do - let(:certificate) { "CA PEM DATA" } - before do - service.update_attributes!(ca_pem: certificate) - end - it 'is added to the certificate store' do - cert = double("certificate") + service.ca_pem = "CA PEM DATA" - expect(OpenSSL::X509::Certificate).to receive(:new).with(certificate).and_return(cert) + cert = double("certificate") + expect(OpenSSL::X509::Certificate).to receive(:new).with(service.ca_pem).and_return(cert) expect_any_instance_of(OpenSSL::X509::Store).to receive(:add_cert).with(cert) - WebMock.stub_request(:get, discovery_url).to_return(body: discovery_response) expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once @@ -107,17 +117,15 @@ describe KubernetesService, models: true do context 'success' do it 'reads the discovery endpoint' do - WebMock.stub_request(:get, discovery_url).to_return(body: discovery_response) - expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once end end context 'failure' do - it 'fails to read the discovery endpoint' do - WebMock.stub_request(:get, discovery_url).to_return(status: 404) + let(:discovery_response) { { status: 404 } } + it 'fails to read the discovery endpoint' do expect(service.test[:success]).to be_falsy expect(WebMock).to have_requested(:get, discovery_url).once end @@ -156,4 +164,55 @@ describe KubernetesService, models: true do ) 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 + it 'returns no terminals' do + stub_reactive_cache(service, pods: [ { "bad" => "pod" } ]) + + is_expected.to be_empty + end + end + + context 'with valid pods' do + let(:pod) { kube_pod(app: environment.slug) } + let(:terminals) { kube_terminals(service, pod) } + + it 'returns terminals' do + stub_reactive_cache(service, pods: [ pod, pod, kube_pod(app: "should-be-filtered-out") ]) + + is_expected.to eq(terminals + terminals) + end + end + end + + describe '#calculate_reactive_cache' do + before { stub_kubeclient_pods } + subject { service.calculate_reactive_cache } + + context 'when service is inactive' do + before { service.active = false } + + it { is_expected.to be_nil } + end + + context 'when kubernetes responds with valid pods' do + it { is_expected.to eq(pods: [kube_pod]) } + end + + context 'when kubernetes responds with 500' do + let(:pods_response) { { status: 500 } } + + it { expect { subject }.to raise_error(KubeException) } + end + + context 'when kubernetes responds with 404' do + let(:pods_response) { { status: 404 } } + + it { is_expected.to eq(pods: []) } + end + end end diff --git a/spec/support/kubernetes_helpers.rb b/spec/support/kubernetes_helpers.rb new file mode 100644 index 00000000000..6c4c246a68b --- /dev/null +++ b/spec/support/kubernetes_helpers.rb @@ -0,0 +1,52 @@ +module KubernetesHelpers + include Gitlab::Kubernetes + + def kube_discovery_body + { "kind" => "APIResourceList", + "resources" => [ + { "name" => "pods", "namespaced" => true, "kind" => "Pod" }, + ], + } + end + + def kube_pods_body(*pods) + { "kind" => "PodList", + "items" => [ kube_pod ], + } + end + + # This is a partial response, it will have many more elements in reality but + # these are the ones we care about at the moment + def kube_pod(app: "valid-pod-label") + { "metadata" => { + "name" => "kube-pod", + "creationTimestamp" => "2016-11-25T19:55:19Z", + "labels" => { "app" => app }, + }, + "spec" => { + "containers" => [ + { "name" => "container-0" }, + { "name" => "container-1" }, + ], + }, + "status" => { "phase" => "Running" }, + } + end + + def kube_terminals(service, pod) + pod_name = pod['metadata']['name'] + containers = pod['spec']['containers'] + + containers.map do |container| + terminal = { + selectors: { pod: pod_name, container: container['name'] }, + url: container_exec_url(service.api_url, service.namespace, pod_name, container['name']), + subprotocols: ['channel.k8s.io'], + headers: { 'Authorization' => ["Bearer #{service.token}"] }, + created_at: DateTime.parse(pod['metadata']['creationTimestamp']) + } + terminal[:ca_pem] = service.ca_pem if service.ca_pem.present? + terminal + end + end +end -- cgit v1.2.1 From 95e0fac59ae8174d11873e95a3ef579af476f215 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Mon, 19 Dec 2016 22:36:47 +0200 Subject: Fix Route#rename_children behavior Given group `gitlab` and `gitlab-org` exists. When rename `gitlab` it will rename `gitlab-org` group route too. This commit fixes it Signed-off-by: Dmitriy Zaporozhets --- spec/models/route_spec.rb | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/models/route_spec.rb b/spec/models/route_spec.rb index 6f491fdf9a0..8481a9bef16 100644 --- a/spec/models/route_spec.rb +++ b/spec/models/route_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Route, models: true do - let!(:group) { create(:group) } + let!(:group) { create(:group, path: 'gitlab') } let!(:route) { group.route } describe 'relationships' do @@ -17,13 +17,15 @@ describe Route, models: true do describe '#rename_children' do let!(:nested_group) { create(:group, path: "test", parent: group) } let!(:deep_nested_group) { create(:group, path: "foo", parent: nested_group) } + let!(:similar_group) { create(:group, path: 'gitlab-org') } - it "updates children routes with new path" do - route.update_attributes(path: 'bar') + before { route.update_attributes(path: 'bar') } + it "updates children routes with new path" do expect(described_class.exists?(path: 'bar')).to be_truthy expect(described_class.exists?(path: 'bar/test')).to be_truthy expect(described_class.exists?(path: 'bar/test/foo')).to be_truthy + expect(described_class.exists?(path: 'gitlab-org')).to be_truthy end end end -- cgit v1.2.1 From d21535602b30316646772b1cd74d7069254076df Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Mon, 19 Dec 2016 14:14:09 +0100 Subject: Minor adjustments API Mattermost [ci skip] --- spec/fixtures/mattermost_new_command.json | 1 - spec/lib/mattermost/command_spec.rb | 20 +++++++++---- spec/lib/mattermost/session_spec.rb | 2 +- spec/lib/mattermost/team_spec.rb | 18 ++++++----- .../mattermost_slash_commands_service_spec.rb | 35 ++++++++++++---------- 5 files changed, 45 insertions(+), 31 deletions(-) delete mode 100644 spec/fixtures/mattermost_new_command.json (limited to 'spec') diff --git a/spec/fixtures/mattermost_new_command.json b/spec/fixtures/mattermost_new_command.json deleted file mode 100644 index 4b827f19926..00000000000 --- a/spec/fixtures/mattermost_new_command.json +++ /dev/null @@ -1 +0,0 @@ -{"id":"y8j1nexrdirj5nubq5uzdwwidr","token":"pzajm5hfbtni3r49ujpt8betpc","create_at":1481897117122,"update_at":1481897117122,"delete_at":0,"creator_id":"78nm4euoc7dypergdc13ekxgpo","team_id":"w59qt5a817f69jkxdz6xe7y4ir","trigger":"display","method":"P","username":"GitLab","icon_url":"","auto_complete":false,"auto_complete_desc":"","auto_complete_hint":"","display_name":"Display name","description":"the description","url":"http://trigger.url/trigger"} diff --git a/spec/lib/mattermost/command_spec.rb b/spec/lib/mattermost/command_spec.rb index 7c6457f639d..bc2e47ebbc9 100644 --- a/spec/lib/mattermost/command_spec.rb +++ b/spec/lib/mattermost/command_spec.rb @@ -1,17 +1,25 @@ require 'spec_helper' describe Mattermost::Command do + let(:session) { double("session") } + let(:hash) { { 'token' => 'token' } } + describe '.create' do - let(:new_command) do - JSON.parse(File.read(Rails.root.join('spec/fixtures/', 'mattermost_new_command.json'))) + before do + allow(session).to receive(:post).and_return(hash) + allow(hash).to receive(:parsed_response).and_return(hash) end - it 'gets the teams' do - allow(described_class).to receive(:post_command).and_return(new_command) + context 'with access' do + it 'gets the teams' do + expect(session).to receive(:post) + + described_class.create(session, 'abc', url: 'http://trigger.com') + end + end - token = described_class.create('abc', url: 'http://trigger.url/trigger', icon_url: 'http://myicon.com/icon.png') + context 'on an error' do - expect(token).to eq('pzajm5hfbtni3r49ujpt8betpc') end end end diff --git a/spec/lib/mattermost/session_spec.rb b/spec/lib/mattermost/session_spec.rb index 752ac796b1c..3c2eddbd221 100644 --- a/spec/lib/mattermost/session_spec.rb +++ b/spec/lib/mattermost/session_spec.rb @@ -96,4 +96,4 @@ describe Mattermost::Session, type: :request do end end end -end \ No newline at end of file +end diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index 0fe6163900d..32a0dbf42ec 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -2,20 +2,22 @@ require 'spec_helper' describe Mattermost::Team do describe '.team_admin' do - let(:init_load) do - JSON.parse(File.read(Rails.root.join('spec/fixtures/', 'mattermost_initial_load.json'))) - end + let(:session) { double("session") } + # TODO fix fixture + let(:json) { File.read(Rails.root.join('spec/fixtures/', 'mattermost_initial_load.json')) } + let(:parsed_response) { JSON.parse(json) } before do - allow(described_class).to receive(:initial_load).and_return(init_load) + allow(session).to receive(:get).with('/api/v3/teams/all'). + and_return(json) + allow(json).to receive(:parsed_response).and_return(parsed_response) end - it 'gets the teams' do - expect(described_class.team_admin.count).to be(2) + xit 'gets the teams' do + expect(described_class.all(session).count).to be(2) end - it 'filters on being team admin' do - ids = described_class.team_admin.map { |team| team['id'] } + xit 'filters on being team admin' do expect(ids).to include("w59qt5a817f69jkxdz6xe7y4ir", "my9oujxf5jy1zqdgu9rihd66do") end end diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 43b2c2c1302..00018624d96 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -102,29 +102,34 @@ describe MattermostSlashCommandsService, models: true do let(:service) { project.build_mattermost_slash_commands_service } subject do - service.configure('http://localhost:8065', nil, team_id: 'abc', trigger: 'gitlab', url: 'http://trigger.url', icon_url: 'http://icon.url/icon.png') + service.configure('http://localhost:8065', team_id: 'abc', trigger: 'gitlab', url: 'http://trigger.url', icon_url: 'http://icon.url/icon.png') end - it 'creates a new Mattermost session' do - expect_any_instance_of(Mattermost::Session).to receive(:with_session) + context 'the requests succeeds' do + before do + allow_any_instance_of(Mattermost::Session).to receive(:with_session). + and_return('token' => 'mynewtoken') + end - subject - end + it 'saves the service' do + expect_any_instance_of(Mattermost::Session).to receive(:with_session) + expect { subject }.to change { project.services.count }.by(1) + end - it 'saves the service' do - allow_any_instance_of(Mattermost::Session).to receive(:with_session). - and_return('mynewtoken') + it 'saves the token' do + subject - expect { subject }.to change { project.services.count }.by(1) + expect(service.reload.token).to eq('mynewtoken') + end end - it 'saves the token' do - allow_any_instance_of(Mattermost::Session).to receive(:with_session). - and_return('mynewtoken') - - subject + context 'an error is received' do + it 'shows error messages' do + allow_any_instance_of(Mattermost::Session).to receive(:with_session). + and_return('token' => 'mynewtoken', 'message' => "Error") - expect(service.reload.token).to eq('mynewtoken') + expect(subject).to eq("Error") + end end end end -- cgit v1.2.1 From e06f88effa842c73d3827593f8d28846207bfca0 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Mon, 19 Dec 2016 22:12:30 +0100 Subject: Fix specs --- .../projects/services/slack_slash_command_spec.rb | 36 +++++++++------------- 1 file changed, 14 insertions(+), 22 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/services/slack_slash_command_spec.rb b/spec/features/projects/services/slack_slash_command_spec.rb index 70e203efcf5..32b32f7ae8e 100644 --- a/spec/features/projects/services/slack_slash_command_spec.rb +++ b/spec/features/projects/services/slack_slash_command_spec.rb @@ -12,37 +12,29 @@ feature 'Slack slash commands', feature: true do login_as(user) end - scenario 'user visits the slack slash command config page', js: true do - it 'shows a help message' do - visit edit_namespace_project_service_path(project.namespace, project, service) + scenario 'user visits the slack slash command config page and shows a help message', js: true do + visit edit_namespace_project_service_path(project.namespace, project, service) - wait_for_ajax + wait_for_ajax - expect(page).to have_content('This service allows GitLab users to perform common') - end + expect(page).to have_content('This service allows GitLab users to perform common') end - scenario 'saving a token' do - given(:token) { ('a'..'z').to_a.join } + scenario 'shows the token after saving' do + visit edit_namespace_project_service_path(project.namespace, project, service) - it 'shows the token after saving' do - visit edit_namespace_project_service_path(project.namespace, project, service) + fill_in 'service_token', with: 'token' + click_on 'Save' - fill_in 'service_token', with: token - click_on 'Save' + value = find_field('service_token').value - value = find_field('service_token').value - - expect(value).to eq(token) - end + expect(value).to eq('token') end - scenario 'the trigger url' do - it 'shows the correct url' do - visit edit_namespace_project_service_path(project.namespace, project, service) + scenario 'shows the correct trigger url' do + visit edit_namespace_project_service_path(project.namespace, project, service) - value = find_field('url').value - expect(value).to match("api/v3/projects/#{project.id}/services/slack_slash_commands/trigger") - end + value = find_field('url').value + expect(value).to match("api/v3/projects/#{project.id}/services/slack_slash_commands/trigger") end end -- cgit v1.2.1 From 3db5b7033b13c21b904a21f751bc0f19156ea155 Mon Sep 17 00:00:00 2001 From: Fatih Acet Date: Thu, 15 Dec 2016 00:59:04 +0000 Subject: Add terminal UI and controller actions --- .../projects/environments_controller_spec.rb | 1 + spec/factories/projects.rb | 10 +++++-- spec/features/environment_spec.rb | 32 ++++++++++++++++++++++ spec/features/environments_spec.rb | 28 +++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/environments_controller_spec.rb b/spec/controllers/projects/environments_controller_spec.rb index 7afa8b1bc28..7ac1d62d1b1 100644 --- a/spec/controllers/projects/environments_controller_spec.rb +++ b/spec/controllers/projects/environments_controller_spec.rb @@ -123,6 +123,7 @@ describe Projects::EnvironmentsController do context 'and invalid id' do it 'returns 404' do get :terminal_websocket_authorize, environment_params(id: 666) + expect(response).to have_http_status(404) end end diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index c941fb5ef4b..f7fa834d7a2 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -42,6 +42,12 @@ FactoryGirl.define do end end + trait :test_repo do + after :create do |project| + TestEnv.copy_repo(project) + end + end + # Nest Project Feature attributes transient do wiki_access_level ProjectFeature::ENABLED @@ -91,9 +97,7 @@ FactoryGirl.define do factory :project, parent: :empty_project do path { 'gitlabhq' } - after :create do |project| - TestEnv.copy_repo(project) - end + test_repo end factory :forked_project_with_submodules, parent: :empty_project do diff --git a/spec/features/environment_spec.rb b/spec/features/environment_spec.rb index 0c1939fd885..56f6cd2e095 100644 --- a/spec/features/environment_spec.rb +++ b/spec/features/environment_spec.rb @@ -38,6 +38,10 @@ feature 'Environment', :feature do scenario 'does not show a re-deploy button for deployment without build' do expect(page).not_to have_link('Re-deploy') end + + scenario 'does not show terminal button' do + expect(page).not_to have_terminal_button + end end context 'with related deployable present' do @@ -60,6 +64,10 @@ feature 'Environment', :feature do expect(page).not_to have_link('Stop') end + scenario 'does not show terminal button' do + expect(page).not_to have_terminal_button + end + context 'with manual action' do given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'deploy to production') } @@ -84,6 +92,26 @@ feature 'Environment', :feature do end end + context 'with terminal' do + let(:project) { create(:kubernetes_project, :test_repo) } + + context 'for project master' do + let(:role) { :master } + + scenario 'it shows the terminal button' do + expect(page).to have_terminal_button + end + end + + context 'for developer' do + let(:role) { :developer } + + scenario 'does not show terminal button' do + expect(page).not_to have_terminal_button + end + end + end + context 'with stop action' do given(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'close_app') } given(:deployment) { create(:deployment, environment: environment, deployable: build, on_stop: 'close_app') } @@ -158,4 +186,8 @@ feature 'Environment', :feature do environment.project, environment) end + + def have_terminal_button + have_link(nil, href: terminal_namespace_project_environment_path(project.namespace, project, environment)) + end end diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index e1b97b31e5d..72b984cfab8 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -113,6 +113,10 @@ feature 'Environments page', :feature, :js do expect(page).not_to have_css('external-url') end + scenario 'does not show terminal button' do + expect(page).not_to have_terminal_button + end + context 'with external_url' do given(:environment) { create(:environment, project: project, external_url: 'https://git.gitlab.com') } given(:build) { create(:ci_build, pipeline: pipeline) } @@ -145,6 +149,26 @@ feature 'Environments page', :feature, :js do end end end + + context 'with terminal' do + let(:project) { create(:kubernetes_project, :test_repo) } + + context 'for project master' do + let(:role) { :master } + + scenario 'it shows the terminal button' do + expect(page).to have_terminal_button + end + end + + context 'for developer' do + let(:role) { :developer } + + scenario 'does not show terminal button' do + expect(page).not_to have_terminal_button + end + end + end end end end @@ -195,6 +219,10 @@ feature 'Environments page', :feature, :js do end end + def have_terminal_button + have_link(nil, href: terminal_namespace_project_environment_path(project.namespace, project, environment)) + end + def visit_environments(project) visit namespace_project_environments_path(project.namespace, project) end -- cgit v1.2.1 From 921f411a41d92ff6b3fdea2560adbd861d97be57 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Mon, 19 Dec 2016 23:50:42 +0100 Subject: Last fixes --- spec/lib/mattermost/team_spec.rb | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'spec') diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index d4fe63fcd8b..c208be3912b 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -6,18 +6,18 @@ describe Mattermost::Team do let(:response) do [{ - "id"=>"xiyro8huptfhdndadpz8r3wnbo", - "create_at"=>1482174222155, - "update_at"=>1482174222155, - "delete_at"=>0, - "display_name"=>"chatops", - "name"=>"chatops", - "email"=>"admin@example.com", - "type"=>"O", - "company_name"=>"", - "allowed_domains"=>"", - "invite_id"=>"o4utakb9jtb7imctdfzbf9r5ro", - "allow_open_invite"=>false}] + "id" => "xiyro8huptfhdndadpz8r3wnbo", + "create_at" => 1482174222155, + "update_at" => 1482174222155, + "delete_at" => 0, + "display_name" => "chatops", + "name" => "chatops", + "email" => "admin@example.com", + "type" => "O", + "company_name" => "", + "allowed_domains" => "", + "invite_id" => "o4utakb9jtb7imctdfzbf9r5ro", + "allow_open_invite" => false }] end let(:json) { nil } -- cgit v1.2.1 From 8275efa36bd51ad0d46495341d524b215c01bfff Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Mon, 19 Dec 2016 19:48:49 -0200 Subject: Fix member with expiration date feature spec --- .../projects/members/master_adds_member_with_expiration_date_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb index 27a83fdcd1f..b7273021c95 100644 --- a/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb +++ b/spec/features/projects/members/master_adds_member_with_expiration_date_spec.rb @@ -24,7 +24,7 @@ feature 'Projects > Members > Master adds member with expiration date', feature: click_on 'Add to project' end - page.within '.project_member:first-child' do + page.within "#project_member_#{new_member.project_members.first.id}" do expect(page).to have_content('Expires in 4 days') end end @@ -35,7 +35,7 @@ feature 'Projects > Members > Master adds member with expiration date', feature: project.team.add_users([new_member.id], :developer, expires_at: '2016-09-06') visit namespace_project_project_members_path(project.namespace, project) - page.within '.project_member:first-child' do + page.within "#project_member_#{new_member.project_members.first.id}" do find('.js-access-expiration-date').set '2016-08-09' wait_for_ajax expect(page).to have_content('Expires in 3 days') -- cgit v1.2.1 From 212967aefb55e0792a36e67a881b66c8bd871e9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 20 Dec 2016 09:45:37 +0100 Subject: Reject blank environment vcariables in Gitlab::Git::RevList MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/lib/gitlab/git/rev_list_spec.rb | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/git/rev_list_spec.rb b/spec/lib/gitlab/git/rev_list_spec.rb index 444639acbaa..1f9c987be0b 100644 --- a/spec/lib/gitlab/git/rev_list_spec.rb +++ b/spec/lib/gitlab/git/rev_list_spec.rb @@ -26,6 +26,13 @@ describe Gitlab::Git::RevList, lib: true do expect(rev_list).not_to be_valid end + + it "ignores nil values" do + env = { var => nil } + rev_list = described_class.new('oldrev', 'newrev', project: project, env: env) + + expect(rev_list).to be_valid + end end end end -- cgit v1.2.1 From 2b0b53cddd7d57ca5dd93437fdffefd7a07af91e Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 20 Dec 2016 11:00:56 +0100 Subject: Add tests for stage API endpoint --- spec/features/projects/pipelines/pipelines_spec.rb | 29 ++++++++++++++++++++++ spec/models/ci/pipeline_spec.rb | 20 +++++++++++++++ spec/models/ci/stage_spec.rb | 11 ++++++++ 3 files changed, 60 insertions(+) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index f3731698a18..e1c6b4c115c 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -152,6 +152,35 @@ describe "Pipelines" do end end + describe 'GET /:project/pipelines/stage?name=stage' do + let!(:pipeline) do + create(:ci_empty_pipeline, project: project, ref: 'master', + status: 'running') + end + + context 'when accessing existing stage' do + let!(:build) do + create(:ci_build, pipeline: pipeline, stage: 'build') + end + + before do + visit stage_namespace_project_pipeline_path( + project.namespace, project, pipeline, format: :json, stage: 'build') + end + + it { expect(page).to have_http_status(:ok) } + end + + context 'when accessing unknown stage' do + before do + visit stage_namespace_project_pipeline_path( + project.namespace, project, pipeline, format: :json, stage: 'test') + end + + it { expect(page).to have_http_status(:not_found) } + end + end + describe 'POST /:project/pipelines' do let(:project) { create(:project) } diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 52dd41065e9..67cc3e6be68 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -175,6 +175,26 @@ describe Ci::Pipeline, models: true do end end + describe '#stage' do + subject { pipeline.stage('test') } + + context 'with status in stage' do + let!(:status) { create(:commit_status, pipeline: pipeline, stage: 'test') } + + it 'return stage object' do + is_expected.to be_a(Ci::Stage) + end + end + + context 'without status in stage' do + let!(:status) { create(:commit_status, pipeline: pipeline, stage: 'build') } + + it 'return stage object' do + is_expected.to be_nil + end + end + end + describe 'state machine' do let(:current) { Time.now.change(usec: 0) } let(:build) { create_build('build1', 0) } diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index 8fff38f7cda..d8dce0f1cc6 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -28,6 +28,17 @@ describe Ci::Stage, models: true do end end + describe '#statuses_count' do + let!(:stage_build) { create_job(:ci_build) } + let!(:other_build) { create_job(:ci_build, stage: 'other stage') } + + subject { stage.statuses_count } + + it "statuses only from current stage" do + is_expected.to eq(1) + end + end + describe '#builds' do let!(:stage_build) { create_job(:ci_build) } let!(:commit_status) { create_job(:commit_status) } -- cgit v1.2.1 From 5ec1c140d991b37d665c47e52dba4a453cc305a4 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 20 Dec 2016 11:26:24 +0100 Subject: Improve specs --- spec/features/projects/pipelines/pipelines_spec.rb | 7 +++++-- spec/models/ci/pipeline_spec.rb | 14 +++++++++----- spec/models/ci/stage_spec.rb | 6 ++++-- 3 files changed, 18 insertions(+), 9 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index e1c6b4c115c..24e501b0151 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -152,7 +152,7 @@ describe "Pipelines" do end end - describe 'GET /:project/pipelines/stage?name=stage' do + describe 'GET /:project/pipelines/stage.json?name=stage' do let!(:pipeline) do create(:ci_empty_pipeline, project: project, ref: 'master', status: 'running') @@ -168,7 +168,10 @@ describe "Pipelines" do project.namespace, project, pipeline, format: :json, stage: 'build') end - it { expect(page).to have_http_status(:ok) } + it do + expect(page).to have_http_status(:ok) + expect(JSON.parse(page.source)).to include("html") + end end context 'when accessing unknown stage' do diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 67cc3e6be68..5e1a9fa8dd8 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -179,15 +179,19 @@ describe Ci::Pipeline, models: true do subject { pipeline.stage('test') } context 'with status in stage' do - let!(:status) { create(:commit_status, pipeline: pipeline, stage: 'test') } - - it 'return stage object' do - is_expected.to be_a(Ci::Stage) + before do + create(:commit_status, pipeline: pipeline, stage: 'test') end + + it { expect(subject).to be_a(Ci::Stage) } + it { expect(subject.name).to eq('stage') } + it { expect(subject.statues).not_to be_empty } end context 'without status in stage' do - let!(:status) { create(:commit_status, pipeline: pipeline, stage: 'build') } + before do + create(:commit_status, pipeline: pipeline, stage: 'build') + end it 'return stage object' do is_expected.to be_nil diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index d8dce0f1cc6..65a302e9d9b 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -29,8 +29,10 @@ describe Ci::Stage, models: true do end describe '#statuses_count' do - let!(:stage_build) { create_job(:ci_build) } - let!(:other_build) { create_job(:ci_build, stage: 'other stage') } + before do + create_job(:ci_build) } + create_job(:ci_build, stage: 'other stage') + end subject { stage.statuses_count } -- cgit v1.2.1 From 0cf23fde7c666b64e6c18a92d29e632f51b00059 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 20 Dec 2016 12:02:37 +0100 Subject: Work on tests for mattermost --- .../mattermost_slash_commands_service_spec.rb | 35 ++++++++++++++++++++++ 1 file changed, 35 insertions(+) (limited to 'spec') diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 1ae1483e2a4..9fb6132d171 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -2,4 +2,39 @@ require 'spec_helper' describe MattermostSlashCommandsService, :models do it_behaves_like "chat slash commands service" + + describe '#configure!' do + let(:project) { create(:empty_project) } + let(:service) { project.build_mattermost_slash_commands_service } + let(:user) { create(:user)} + + before do + allow_any_instance_of(Mattermost::Session).to + receive(:with_session).and_yield + end + + subject do + service.configure!(user, team_id: 'abc', + trigger: 'gitlab', url: 'http://trigger.url', + icon_url: 'http://icon.url/icon.png') + end + + context 'the requests succeeds' do + it 'saves the service' do + expect { subject }.to change { project.services.count }.by(1) + end + + it 'saves the token' do + subject + + expect(service.reload.token).to eq('mynewtoken') + end + end + + context 'an error is received' do + it 'shows error messages' do + expect(subject).to raise_error("Error") + end + end + end end -- cgit v1.2.1 From 11040589c803410837d67fb481221e9d6ef1d969 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 20 Dec 2016 10:08:15 +0000 Subject: Adds tests for the MiniPipelineGraph class --- .../fixtures/mini_dropdown_graph.html.haml | 8 ++++ .../mini_pipeline_graph_dropdown_spec.js.es6 | 51 ++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 spec/javascripts/fixtures/mini_dropdown_graph.html.haml create mode 100644 spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 (limited to 'spec') diff --git a/spec/javascripts/fixtures/mini_dropdown_graph.html.haml b/spec/javascripts/fixtures/mini_dropdown_graph.html.haml new file mode 100644 index 00000000000..e9bf7568e95 --- /dev/null +++ b/spec/javascripts/fixtures/mini_dropdown_graph.html.haml @@ -0,0 +1,8 @@ +%div.js-builds-dropdown-tests + %button.dropdown.js-builds-dropdown-button{'data-stage-endpoint' => 'foobar'} + Dropdown + %div.js-builds-dropdown-container + %div.js-builds-dropdown-list + + %div.js-builds-dropdown-loading.builds-dropdown-loading.hidden + %span.fa.fa-spinner.fa-spin diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 new file mode 100644 index 00000000000..d1793e9308e --- /dev/null +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 @@ -0,0 +1,51 @@ +/* eslint-disable no-new */ + +//= require flash +//= require mini_pipeline_graph_dropdown + +(() => { + describe('Mini Pipeline Graph Dropdown', () => { + fixture.preload('mini_dropdown_graph'); + + beforeEach(() => { + fixture.load('mini_dropdown_graph'); + }); + + describe('When is initialized', () => { + it('should initialize without errors when no options are given', () => { + const miniPipelineGraph = new window.gl.MiniPipelineGraph(); + + expect(miniPipelineGraph.dropdownListSelector).toEqual('.js-builds-dropdown-container'); + }); + + it('should set the container as the given prop', () => { + const container = '.foo'; + + const miniPipelineGraph = new window.gl.MiniPipelineGraph({ container }); + + expect(miniPipelineGraph.container).toEqual(container); + }); + }); + + describe('When dropdown is clicked', () => { + it('should call getBuildsList', () => { + const getBuildsListSpy = spyOn(gl.MiniPipelineGraph.prototype, 'getBuildsList').and.callFake(function () {}); + + new gl.MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }); + + document.querySelector('.js-builds-dropdown-button').click(); + + expect(getBuildsListSpy).toHaveBeenCalled(); + }); + + it('should make a request to the endpoint provided in the html', () => { + const ajaxSpy = spyOn($, 'ajax').and.callFake(function () {}); + + new gl.MiniPipelineGraph({ container: '.js-builds-dropdown-tests' }); + + document.querySelector('.js-builds-dropdown-button').click(); + expect(ajaxSpy.calls.allArgs()[0][0].url).toEqual('foobar'); + }); + }); + }); +})(); -- cgit v1.2.1 From c87d93d462bb83caebd22bd759d8a1ead845d6a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Mon, 19 Dec 2016 16:26:59 +0100 Subject: Improve specs for Repositories API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/requests/api/repositories_spec.rb | 336 +++++++++++++++++++---------- spec/support/api/status_shared_examples.rb | 42 ++++ 2 files changed, 265 insertions(+), 113 deletions(-) create mode 100644 spec/support/api/status_shared_examples.rb (limited to 'spec') diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 67f0bc537fe..fe28ad1d1a1 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -7,174 +7,239 @@ describe API::Repositories, api: true do include WorkhorseHelpers let(:user) { create(:user) } - let(:user2) { create(:user) } + let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } } let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:project_member, :master, user: user, project: project) } - let!(:guest) { create(:project_member, :guest, user: user2, project: project) } + + shared_context 'disabled repository' do + before do + project.project_feature.update_attributes!( + repository_access_level: ProjectFeature::DISABLED, + merge_requests_access_level: ProjectFeature::DISABLED, + builds_access_level: ProjectFeature::DISABLED + ) + expect(project.feature_available?(:repository, current_user)).to be false + end + end describe "GET /projects/:id/repository/tree" do - context "authorized user" do - before { project.team << [user2, :reporter] } + let(:route) { "/projects/#{project.id}/repository/tree" } - shared_examples_for 'repository tree' do - it 'returns the repository tree' do - get api("/projects/#{project.id}/repository/tree", current_user) + shared_examples_for 'repository tree' do + it 'returns the repository tree' do + get api(route, current_user) - expect(response).to have_http_status(200) + expect(response).to have_http_status(200) - first_commit = json_response.first + first_commit = json_response.first - expect(json_response).to be_an Array - expect(first_commit['name']).to eq('bar') - expect(first_commit['type']).to eq('tree') - expect(first_commit['mode']).to eq('040000') - end + expect(json_response).to be_an Array + expect(first_commit['name']).to eq('bar') + expect(first_commit['type']).to eq('tree') + expect(first_commit['mode']).to eq('040000') end - context 'when unauthenticated' do - it_behaves_like 'repository tree' do - let(:project) { create(:project, :public) } - let(:current_user) { nil } + context 'when ref does not exist' do + it_behaves_like '404 response' do + let(:request) { get api("#{route}?ref_name=foo", current_user) } + let(:message) { '404 Tree Not Found' } end end - context 'when authenticated' do - it_behaves_like 'repository tree' do - let(:current_user) { user } + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } end end - it 'returns a 404 for unknown ref' do - get api("/projects/#{project.id}/repository/tree?ref_name=foo", user) - expect(response).to have_http_status(404) + context 'with recursive=1' do + it 'returns recursive project paths tree' do + get api("#{route}?recursive=1", current_user) - expect(json_response).to be_an Object - json_response['message'] == '404 Tree Not Found' - end - end + expect(response.status).to eq(200) + expect(json_response).to be_an Array + expect(json_response[4]['name']).to eq('html') + expect(json_response[4]['path']).to eq('files/html') + expect(json_response[4]['type']).to eq('tree') + expect(json_response[4]['mode']).to eq('040000') + end - context "unauthorized user" do - it "does not return project commits" do - get api("/projects/#{project.id}/repository/tree") + context 'when repository is disabled' do + include_context 'disabled repository' - expect(response).to have_http_status(404) + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end + end + + context 'when ref does not exist' do + it_behaves_like '404 response' do + let(:request) { get api("#{route}?recursive=1&ref_name=foo", current_user) } + let(:message) { '404 Tree Not Found' } + end + end end end - end - - describe 'GET /projects/:id/repository/tree?recursive=1' do - context 'authorized user' do - before { project.team << [user2, :reporter] } - - it 'should return recursive project paths tree' do - get api("/projects/#{project.id}/repository/tree?recursive=1", user) - expect(response.status).to eq(200) - - expect(json_response).to be_an Array - expect(json_response[4]['name']).to eq('html') - expect(json_response[4]['path']).to eq('files/html') - expect(json_response[4]['type']).to eq('tree') - expect(json_response[4]['mode']).to eq('040000') + context 'when unauthenticated', 'and project is public' do + it_behaves_like 'repository tree' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } end + end - it 'returns a 404 for unknown ref' do - get api("/projects/#{project.id}/repository/tree?ref_name=foo&recursive=1", user) - expect(response).to have_http_status(404) - - expect(json_response).to be_an Object - json_response['message'] == '404 Tree Not Found' + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } end end - context "unauthorized user" do - it "does not return project commits" do - get api("/projects/#{project.id}/repository/tree?recursive=1") + context 'when authenticated', 'as a developer' do + it_behaves_like 'repository tree' do + let(:current_user) { user } + end + end - expect(response).to have_http_status(404) + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } end end end - describe "GET /projects/:id/repository/blobs/:sha & /projects/:id/repository/commits/:sha" do - shared_examples_for 'repository blob' do - it 'returns the repository blob for /repository/blobs/master' do - get api("/projects/#{project.id}/repository/blobs/master?filepath=README.md", current_user) + { + 'blobs/:sha' => 'blobs/master', + 'commits/:sha/blob' => 'commits/master/blob' + }.each do |desc_path, example_path| + describe "GET /projects/:id/repository/#{desc_path}" do + let(:route) { "/projects/#{project.id}/repository/#{example_path}?filepath=README.md" } - expect(response).to have_http_status(200) - end + shared_examples_for 'repository blob' do + it 'returns the repository blob' do + get api(route, current_user) - it 'returns the repository blob for /repository/commits/master' do - get api("/projects/#{project.id}/repository/commits/master/blob?filepath=README.md", current_user) + expect(response).to have_http_status(200) + end - expect(response).to have_http_status(200) - end - end + context 'when sha does not exist' do + it_behaves_like '404 response' do + let(:request) { get api(route.sub('master', 'invalid_branch_name'), current_user) } + let(:message) { '404 Commit Not Found' } + end + end - context 'when unauthenticated' do - it_behaves_like 'repository blob' do - let(:project) { create(:project, :public) } - let(:current_user) { nil } + context 'when filepath does not exist' do + it_behaves_like '404 response' do + let(:request) { get api(route.sub('README.md', 'README.invalid'), current_user) } + let(:message) { '404 File Not Found' } + end + end + + context 'when no filepath is given' do + it_behaves_like '400 response' do + let(:request) { get api(route.sub('?filepath=README.md', ''), current_user) } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end + end end - end - context 'when authenticated' do - it_behaves_like 'repository blob' do - let(:current_user) { user } + context 'when unauthenticated', 'and project is public' do + it_behaves_like 'repository blob' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end end - end - it "returns 404 for invalid branch_name" do - get api("/projects/#{project.id}/repository/blobs/invalid_branch_name?filepath=README.md", user) - expect(response).to have_http_status(404) - end + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } + end + end - it "returns 404 for invalid file" do - get api("/projects/#{project.id}/repository/blobs/master?filepath=README.invalid", user) - expect(response).to have_http_status(404) - end + context 'when authenticated', 'as a developer' do + it_behaves_like 'repository blob' do + let(:current_user) { user } + end + end - it "returns a 400 error if filepath is missing" do - get api("/projects/#{project.id}/repository/blobs/master", user) - expect(response).to have_http_status(400) + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } + end + end end end describe "GET /projects/:id/repository/raw_blobs/:sha" do + let(:route) { "/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}" } + shared_examples_for 'repository raw blob' do it 'returns the repository raw blob' do - get api("/projects/#{project.id}/repository/raw_blobs/#{sample_blob.oid}", current_user) + get api(route, current_user) expect(response).to have_http_status(200) end + + context 'when sha does not exist' do + it_behaves_like '404 response' do + let(:request) { get api(route.sub(sample_blob.oid, '123456'), current_user) } + let(:message) { '404 Blob Not Found' } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user) } + end + end end - context 'when unauthenticated' do + context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository raw blob' do let(:project) { create(:project, :public) } let(:current_user) { nil } end end - context 'when authenticated' do + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } + end + end + + context 'when authenticated', 'as a developer' do it_behaves_like 'repository raw blob' do let(:current_user) { user } end end - it 'returns a 404 for unknown blob' do - get api("/projects/#{project.id}/repository/raw_blobs/123456", user) - expect(response).to have_http_status(404) - - expect(json_response).to be_an Object - json_response['message'] == '404 Blob Not Found' + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } + end end end describe "GET /projects/:id/repository/archive(.:format)?:sha" do + let(:route) { "/projects/#{project.id}/repository/archive" } + shared_examples_for 'repository archive' do it 'returns the repository archive' do - get api("/projects/#{project.id}/repository/archive", current_user) + get api(route, current_user) expect(response).to have_http_status(200) @@ -208,31 +273,48 @@ describe API::Repositories, api: true do expect(type).to eq('git-archive') expect(params['ArchivePath']).to match(/#{repo_name}\-[^\.]+\.tar.bz2/) end + + context 'when sha does not exist' do + it_behaves_like '404 response' do + let(:request) { get api("#{route}?sha=xxx", current_user) } + let(:message) { '404 File Not Found' } + end + end end - context 'when unauthenticated' do + context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository archive' do let(:project) { create(:project, :public) } let(:current_user) { nil } end end - context 'when authenticated' do + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } + end + end + + context 'when authenticated', 'as a developer' do it_behaves_like 'repository archive' do let(:current_user) { user } end end - it "returns 404 for invalid sha" do - get api("/projects/#{project.id}/repository/archive/?sha=xxx", user) - expect(response).to have_http_status(404) + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } + end end end describe 'GET /projects/:id/repository/compare' do + let(:route) { "/projects/#{project.id}/repository/compare" } + shared_examples_for 'repository compare' do it "compares branches" do - get api("/projects/#{project.id}/repository/compare", current_user), from: 'master', to: 'feature' + get api(route, current_user), from: 'master', to: 'feature' expect(response).to have_http_status(200) expect(json_response['commits']).to be_present @@ -240,7 +322,7 @@ describe API::Repositories, api: true do end it "compares tags" do - get api("/projects/#{project.id}/repository/compare", current_user), from: 'v1.0.0', to: 'v1.1.0' + get api(route, current_user), from: 'v1.0.0', to: 'v1.1.0' expect(response).to have_http_status(200) expect(json_response['commits']).to be_present @@ -248,7 +330,7 @@ describe API::Repositories, api: true do end it "compares commits" do - get api("/projects/#{project.id}/repository/compare", current_user), from: sample_commit.id, to: sample_commit.parent_id + get api(route, current_user), from: sample_commit.id, to: sample_commit.parent_id expect(response).to have_http_status(200) expect(json_response['commits']).to be_empty @@ -257,7 +339,7 @@ describe API::Repositories, api: true do end it "compares commits in reverse order" do - get api("/projects/#{project.id}/repository/compare", current_user), from: sample_commit.parent_id, to: sample_commit.id + get api(route, current_user), from: sample_commit.parent_id, to: sample_commit.id expect(response).to have_http_status(200) expect(json_response['commits']).to be_present @@ -265,7 +347,7 @@ describe API::Repositories, api: true do end it "compares same refs" do - get api("/projects/#{project.id}/repository/compare", current_user), from: 'master', to: 'master' + get api(route, current_user), from: 'master', to: 'master' expect(response).to have_http_status(200) expect(json_response['commits']).to be_empty @@ -274,24 +356,39 @@ describe API::Repositories, api: true do end end - context 'when unauthenticated' do + context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository compare' do let(:project) { create(:project, :public) } let(:current_user) { nil } end end - context 'when authenticated' do + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } + end + end + + context 'when authenticated', 'as a developer' do it_behaves_like 'repository compare' do let(:current_user) { user } end end + + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } + end + end end describe 'GET /projects/:id/repository/contributors' do + let(:route) { "/projects/#{project.id}/repository/contributors" } + shared_examples_for 'repository contributors' do it 'returns valid data' do - get api("/projects/#{project.id}/repository/contributors", user) + get api(route, current_user) expect(response).to have_http_status(200) expect(json_response).to be_an Array @@ -306,17 +403,30 @@ describe API::Repositories, api: true do end end - context 'when unauthenticated' do + context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository contributors' do let(:project) { create(:project, :public) } let(:current_user) { nil } end end - context 'when authenticated' do + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route) } + let(:message) { '404 Project Not Found' } + end + end + + context 'when authenticated', 'as a developer' do it_behaves_like 'repository contributors' do let(:current_user) { user } end end + + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest) } + end + end end end diff --git a/spec/support/api/status_shared_examples.rb b/spec/support/api/status_shared_examples.rb new file mode 100644 index 00000000000..3481749a7f0 --- /dev/null +++ b/spec/support/api/status_shared_examples.rb @@ -0,0 +1,42 @@ +# Specs for status checking. +# +# Requires an API request: +# let(:request) { get api("/projects/#{project.id}/repository/branches", user) } +shared_examples_for '400 response' do + before do + # Fires the request + request + end + + it 'returns 400' do + expect(response).to have_http_status(400) + end +end + +shared_examples_for '403 response' do + before do + # Fires the request + request + end + + it 'returns 403' do + expect(response).to have_http_status(403) + end +end + +shared_examples_for '404 response' do + let(:message) { nil } + before do + # Fires the request + request + end + + it 'returns 404' do + expect(response).to have_http_status(404) + expect(json_response).to be_an Object + + if message.present? + expect(json_response['message']).to eq(message) + end + end +end -- cgit v1.2.1 From 4b9bd188433d77fbaec8ae445716de8084b6a145 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 20 Dec 2016 13:22:31 +0000 Subject: Adds tests for the mini pipeline graph --- spec/features/projects/pipelines/pipelines_spec.rb | 50 ++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 24e501b0151..d1ebb12715f 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -1,7 +1,8 @@ require 'spec_helper' -describe "Pipelines" do +describe "Pipelines", feature: true, js:true do include GitlabRoutingHelper + include WaitForAjax let(:project) { create(:empty_project) } let(:user) { create(:user) } @@ -76,7 +77,11 @@ describe "Pipelines" do it { expect(page).to have_link('Manual build') } context 'when playing' do - before { click_link('Manual build') } + + before do + find('.js-pipeline-dropdown-manual-actions').click + click_link('Manual build') + end it { expect(manual.reload).to be_pending } end @@ -131,7 +136,10 @@ describe "Pipelines" do before { visit namespace_project_pipelines_path(project.namespace, project) } it { expect(page).to have_selector('.build-artifacts') } - it { expect(page).to have_link(with_artifacts.name) } + it do + find('.js-pipeline-dropdown-download').click + expect(page).to have_link(with_artifacts.name) + end end context 'with artifacts expired' do @@ -150,6 +158,42 @@ describe "Pipelines" do it { expect(page).not_to have_selector('.build-artifacts') } end end + + context 'mini pipleine graph' do + let!(:build) do + create(:ci_build, pipeline: pipeline, stage: 'build', name: 'build') + end + + before do + visit namespace_project_pipelines_path(project.namespace, project) + end + + it 'should render a mini pipeline graph' do + endpoint = stage_namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline, stage: build.name) + + expect(page).to have_selector('.mini-pipeline-graph') + expect(page).to have_selector(".js-builds-dropdown-button[data-stage-endpoint='#{endpoint}']") + end + + context 'when clicking a graph stage' do + it 'should open a dropdown' do + find('.js-builds-dropdown-button').trigger('click') + + wait_for_ajax + + expect(page).to have_link build.name + end + + it 'should be possible to retry the failed build' do + find('.js-builds-dropdown-button').trigger('click') + + wait_for_ajax + + find('a.ci-action-icon-container').trigger('click') + expect(page).not_to have_content('Cancel running') + end + end + end end describe 'GET /:project/pipelines/stage.json?name=stage' do -- cgit v1.2.1 From ccfbbf7dfac61557159d743b776f145fe380527a Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 20 Dec 2016 13:53:24 +0000 Subject: Fix tests --- .../services/mattermost_slash_command_spec.rb | 40 +++------------------- 1 file changed, 5 insertions(+), 35 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index 4c08d1e6e65..521eedeae9e 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -32,49 +32,19 @@ feature 'Setup Mattermost slash commands', feature: true do end describe 'mattermost service is enabled' do - let(:info) { find('.services-installation-info') } - before do - Gitlab.config.mattermost.enabled = true - end - - it 'shows the correct mattermost url' do - expect(page).to have_content Gitlab.config.mattermost.host - end - - describe 'mattermost service is active' do - before do - service.active = true - end - - it 'shows that mattermost is active' do - expect(info).to have_content 'Installed' - expect(info).not_to have_content 'Not installed' - end - - it 'shows the edit mattermost button' do - expect(info).to have_button 'Edit Mattermost' - end + allow(Gitlab.config.mattermost).to receive(:enabled).and_return(true) end - describe 'mattermost service is not active' do - before do - service.active = false - end - - it 'shows that mattermost is not active' do - expect(info).to have_content 'Not installed' - end - - it 'shows the add to mattermost button' do - expect(info).to have_button 'Add to Mattermost' - end + it 'shows the add to mattermost button' do + expect(page).to have_link 'Add to Mattermost' end end + describe 'mattermost service is not enabled' do before do - Gitlab.config.mattermost.enabled = false + allow(Gitlab.config.mattermost).to receive(:enabled).and_return(false) end it 'shows the correct trigger url' do -- cgit v1.2.1 From 3ef1e76659d0d583a2fd72d86309c2ba6816a316 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 20 Dec 2016 13:25:58 +0000 Subject: Fix broken test Changes after review --- spec/features/projects/pipelines/pipelines_spec.rb | 5 ++++- spec/models/ci/stage_spec.rb | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index d1ebb12715f..5a4d14d2f95 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -74,7 +74,10 @@ describe "Pipelines", feature: true, js:true do before { visit namespace_project_pipelines_path(project.namespace, project) } - it { expect(page).to have_link('Manual build') } + it do + find('.js-pipeline-dropdown-manual-actions').click + expect(page).to have_link('Manual build') + end context 'when playing' do diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index 65a302e9d9b..786091a577d 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -36,7 +36,7 @@ describe Ci::Stage, models: true do subject { stage.statuses_count } - it "statuses only from current stage" do + it "counts statuses only from current stage" do is_expected.to eq(1) end end -- cgit v1.2.1 From b2daf9f16892f362f57a4a0f7990dbc2f6ab8429 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 20 Dec 2016 14:17:21 +0000 Subject: Fix broken test --- spec/features/projects/pipelines/pipelines_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'spec') diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 5a4d14d2f95..57abbf5d7a4 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -217,7 +217,7 @@ describe "Pipelines", feature: true, js:true do it do expect(page).to have_http_status(:ok) - expect(JSON.parse(page.source)).to include("html") + expect(page.source).to include("html") end end -- cgit v1.2.1 From 9c6480db8993ee6f1d8d1fac29e044dd00d66465 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 20 Dec 2016 15:53:53 +0100 Subject: Move test for HTML stage endpoint to controller specs --- .../projects/pipelines_controller_spec.rb | 46 ++++++++++++++++++++++ spec/features/projects/pipelines/pipeline_spec.rb | 2 +- spec/features/projects/pipelines/pipelines_spec.rb | 32 --------------- 3 files changed, 47 insertions(+), 33 deletions(-) create mode 100644 spec/controllers/projects/pipelines_controller_spec.rb (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb new file mode 100644 index 00000000000..94113250c9f --- /dev/null +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe Projects::PipelinesController do + include ApiHelpers + + let(:user) { create(:user) } + let(:project) { create(:empty_project, :public) } + let(:pipeline) { create(:ci_pipeline, project: project) } + + before do + sign_in(user) + end + + describe 'GET stages.json' do + def get_stage(name) + get :stage, namespace_id: project.namespace.path, + project_id: project.path, + id: pipeline.id, + stage: name, + format: :json + end + + context 'when accessing existing stage' do + before do + create(:ci_build, pipeline: pipeline, stage: 'build') + + get_stage('build') + end + + it 'returns html source for stage dropdown' do + expect(response).to have_http_status(:ok) + expect(response).to render_template('projects/pipelines/_stage') + expect(json_response).to include('html') + end + end + + context 'when accessing unknown stage' do + before do + get_stage('test') + end + + it { expect(response).to have_http_status(:not_found) } + end + + end +end diff --git a/spec/features/projects/pipelines/pipeline_spec.rb b/spec/features/projects/pipelines/pipeline_spec.rb index 1210e2745db..14e009daba8 100644 --- a/spec/features/projects/pipelines/pipeline_spec.rb +++ b/spec/features/projects/pipelines/pipeline_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Pipelines", feature: true, js: true do +describe 'Pipeline', :feature, :js do include GitlabRoutingHelper let(:project) { create(:empty_project) } diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index 57abbf5d7a4..fa8ba21b389 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -199,38 +199,6 @@ describe "Pipelines", feature: true, js:true do end end - describe 'GET /:project/pipelines/stage.json?name=stage' do - let!(:pipeline) do - create(:ci_empty_pipeline, project: project, ref: 'master', - status: 'running') - end - - context 'when accessing existing stage' do - let!(:build) do - create(:ci_build, pipeline: pipeline, stage: 'build') - end - - before do - visit stage_namespace_project_pipeline_path( - project.namespace, project, pipeline, format: :json, stage: 'build') - end - - it do - expect(page).to have_http_status(:ok) - expect(page.source).to include("html") - end - end - - context 'when accessing unknown stage' do - before do - visit stage_namespace_project_pipeline_path( - project.namespace, project, pipeline, format: :json, stage: 'test') - end - - it { expect(page).to have_http_status(:not_found) } - end - end - describe 'POST /:project/pipelines' do let(:project) { create(:project) } -- cgit v1.2.1 From ec4b1bc7556848c6683546559290a6576301c05d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 20 Dec 2016 16:06:01 +0100 Subject: Add isolated view spec for pipeline stage partial --- .../projects/pipelines/_stage.html.haml_spec.rb | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 spec/views/projects/pipelines/_stage.html.haml_spec.rb (limited to 'spec') diff --git a/spec/views/projects/pipelines/_stage.html.haml_spec.rb b/spec/views/projects/pipelines/_stage.html.haml_spec.rb new file mode 100644 index 00000000000..eb7f7ca4a1a --- /dev/null +++ b/spec/views/projects/pipelines/_stage.html.haml_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe 'projects/pipelines/_stage', :view do + let(:project) { create(:project) } + let(:pipeline) { create(:ci_pipeline, project: project) } + let(:stage) { build(:ci_stage, pipeline: pipeline) } + + before do + assign :stage, stage + + create(:ci_build, name: 'test:build', + stage: stage.name, + pipeline: pipeline) + end + + it 'shows the builds in the stage' do + render + + expect(rendered).to have_text 'test:build' + end +end -- cgit v1.2.1 From 5652da8bb4ea26acd35a241683e242439fefdd33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Fri, 16 Dec 2016 18:58:24 +0100 Subject: Allow unauthenticated access to Repositories Files API GET endpoints MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/requests/api/files_spec.rb | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 2081f80ccc1..4dd312e2852 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -24,19 +24,34 @@ describe API::Files, api: true do before { project.team << [user, :developer] } describe "GET /projects/:id/repository/files" do - it "returns file info" do - params = { - file_path: file_path, - ref: 'master', - } + shared_examples_for 'repository files' do + it "returns file info" do + params = { + file_path: file_path, + ref: 'master', + } - get api("/projects/#{project.id}/repository/files", user), params + get api("/projects/#{project.id}/repository/files", current_user), params - expect(response).to have_http_status(200) - expect(json_response['file_path']).to eq(file_path) - expect(json_response['file_name']).to eq('popen.rb') - expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') - expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n") + expect(response).to have_http_status(200) + expect(json_response['file_path']).to eq(file_path) + expect(json_response['file_name']).to eq('popen.rb') + expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') + expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n") + end + end + + context 'when unauthenticated' do + it_behaves_like 'repository files' do + let(:project) { create(:project, :public) } + let(:current_user) { nil } + end + end + + context 'when authenticated' do + it_behaves_like 'repository files' do + let(:current_user) { user } + end end it "returns a 400 bad request if no params given" do -- cgit v1.2.1 From 0349e83aa74b42c3f564fd1bc34104300a41ddf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 20 Dec 2016 15:05:57 +0100 Subject: Improve specs for Files API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/requests/api/files_spec.rb | 74 +++++++++++++++++-------- spec/requests/api/repositories_spec.rb | 11 ---- spec/support/api/repositories_shared_context.rb | 10 ++++ 3 files changed, 61 insertions(+), 34 deletions(-) create mode 100644 spec/support/api/repositories_shared_context.rb (limited to 'spec') diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb index 4dd312e2852..685da28c673 100644 --- a/spec/requests/api/files_spec.rb +++ b/spec/requests/api/files_spec.rb @@ -4,7 +4,14 @@ describe API::Files, api: true do include ApiHelpers let(:user) { create(:user) } let!(:project) { create(:project, namespace: user.namespace ) } + let(:guest) { create(:user).tap { |u| create(:project_member, :guest, user: u, project: project) } } let(:file_path) { 'files/ruby/popen.rb' } + let(:params) do + { + file_path: file_path, + ref: 'master' + } + end let(:author_email) { FFaker::Internet.email } # I have to remove periods from the end of the name @@ -24,14 +31,11 @@ describe API::Files, api: true do before { project.team << [user, :developer] } describe "GET /projects/:id/repository/files" do + let(:route) { "/projects/#{project.id}/repository/files" } + shared_examples_for 'repository files' do it "returns file info" do - params = { - file_path: file_path, - ref: 'master', - } - - get api("/projects/#{project.id}/repository/files", current_user), params + get api(route, current_user), params expect(response).to have_http_status(200) expect(json_response['file_path']).to eq(file_path) @@ -39,36 +43,60 @@ describe API::Files, api: true do expect(json_response['last_commit_id']).to eq('570e7b2abdd848b95f2f578043fc23bd6f6fd24d') expect(Base64.decode64(json_response['content']).lines.first).to eq("require 'fileutils'\n") end + + context 'when no params are given' do + it_behaves_like '400 response' do + let(:request) { get api(route, current_user) } + end + end + + context 'when file_path does not exist' do + let(:params) do + { + file_path: 'app/models/application.rb', + ref: 'master', + } + end + + it_behaves_like '404 response' do + let(:request) { get api(route, current_user), params } + let(:message) { '404 File Not Found' } + end + end + + context 'when repository is disabled' do + include_context 'disabled repository' + + it_behaves_like '403 response' do + let(:request) { get api(route, current_user), params } + end + end end - context 'when unauthenticated' do + context 'when unauthenticated', 'and project is public' do it_behaves_like 'repository files' do let(:project) { create(:project, :public) } let(:current_user) { nil } end end - context 'when authenticated' do - it_behaves_like 'repository files' do - let(:current_user) { user } + context 'when unauthenticated', 'and project is private' do + it_behaves_like '404 response' do + let(:request) { get api(route), params } + let(:message) { '404 Project Not Found' } end end - it "returns a 400 bad request if no params given" do - get api("/projects/#{project.id}/repository/files", user) - - expect(response).to have_http_status(400) + context 'when authenticated', 'as a developer' do + it_behaves_like 'repository files' do + let(:current_user) { user } + end end - it "returns a 404 if such file does not exist" do - params = { - file_path: 'app/models/application.rb', - ref: 'master', - } - - get api("/projects/#{project.id}/repository/files", user), params - - expect(response).to have_http_status(404) + context 'when authenticated', 'as a guest' do + it_behaves_like '403 response' do + let(:request) { get api(route, guest), params } + end end end diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index fe28ad1d1a1..0b19fa38c55 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -11,17 +11,6 @@ describe API::Repositories, api: true do let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:project_member, :master, user: user, project: project) } - shared_context 'disabled repository' do - before do - project.project_feature.update_attributes!( - repository_access_level: ProjectFeature::DISABLED, - merge_requests_access_level: ProjectFeature::DISABLED, - builds_access_level: ProjectFeature::DISABLED - ) - expect(project.feature_available?(:repository, current_user)).to be false - end - end - describe "GET /projects/:id/repository/tree" do let(:route) { "/projects/#{project.id}/repository/tree" } diff --git a/spec/support/api/repositories_shared_context.rb b/spec/support/api/repositories_shared_context.rb new file mode 100644 index 00000000000..ea38fe4f5b8 --- /dev/null +++ b/spec/support/api/repositories_shared_context.rb @@ -0,0 +1,10 @@ +shared_context 'disabled repository' do + before do + project.project_feature.update_attributes!( + repository_access_level: ProjectFeature::DISABLED, + merge_requests_access_level: ProjectFeature::DISABLED, + builds_access_level: ProjectFeature::DISABLED + ) + expect(project.feature_available?(:repository, current_user)).to be false + end +end -- cgit v1.2.1 From b82fdf6257255b720526ccef716759892e88de09 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Tue, 20 Dec 2016 17:52:27 +0100 Subject: Fix error 500 renaming group. Also added specs and changelog. --- spec/controllers/groups_controller_spec.rb | 21 +++++++++++++ spec/services/groups/update_service_spec.rb | 49 ++++++++++++++++++++++++----- 2 files changed, 63 insertions(+), 7 deletions(-) (limited to 'spec') diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index a763e2c5ba8..4bb37bc52ee 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -105,4 +105,25 @@ describe GroupsController do end end end + + describe 'PUT update' do + before do + sign_in(user) + end + + it 'updates the path succesfully' do + post :update, id: group.to_param, group: { path: 'new_path' } + + expect(response).to have_http_status(302) + expect(controller).to set_flash[:notice] + end + + it 'does not update the path on error' do + allow_any_instance_of(Group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError) + post :update, id: group.to_param, group: { path: 'new_path' } + + expect(response).to have_http_status(302) + expect(controller).to set_flash[:alert] + end + end end diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index 9c2331144a0..8ac5736cbb3 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -1,15 +1,15 @@ require 'spec_helper' describe Groups::UpdateService, services: true do - let!(:user) { create(:user) } - let!(:private_group) { create(:group, :private) } - let!(:internal_group) { create(:group, :internal) } - let!(:public_group) { create(:group, :public) } + let!(:user) { create(:user) } + let!(:private_group) { create(:group, :private) } + let!(:internal_group) { create(:group, :internal) } + let!(:public_group) { create(:group, :public) } describe "#execute" do context "project visibility_level validation" do context "public group with public projects" do - let!(:service) { described_class.new(public_group, user, visibility_level: Gitlab::VisibilityLevel::INTERNAL ) } + let!(:service) { described_class.new(public_group, user, visibility_level: Gitlab::VisibilityLevel::INTERNAL) } before do public_group.add_user(user, Gitlab::Access::MASTER) @@ -23,7 +23,7 @@ describe Groups::UpdateService, services: true do end context "internal group with internal project" do - let!(:service) { described_class.new(internal_group, user, visibility_level: Gitlab::VisibilityLevel::PRIVATE ) } + let!(:service) { described_class.new(internal_group, user, visibility_level: Gitlab::VisibilityLevel::PRIVATE) } before do internal_group.add_user(user, Gitlab::Access::MASTER) @@ -39,7 +39,7 @@ describe Groups::UpdateService, services: true do end context "unauthorized visibility_level validation" do - let!(:service) { described_class.new(internal_group, user, visibility_level: 99 ) } + let!(:service) { described_class.new(internal_group, user, visibility_level: 99) } before do internal_group.add_user(user, Gitlab::Access::MASTER) end @@ -49,4 +49,39 @@ describe Groups::UpdateService, services: true do expect(internal_group.errors.count).to eq(1) end end + + context 'rename group' do + let!(:service) { described_class.new(internal_group, user, path: 'new_path') } + + before do + internal_group.add_user(user, Gitlab::Access::MASTER) + create(:project, :internal, group: internal_group) + end + + it 'returns true' do + puts internal_group.errors.full_messages + + expect(service.execute).to eq(true) + end + + context 'error moving group' do + before do + allow(internal_group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError) + end + + it 'does not raise an error' do + expect { service.execute }.not_to raise_error + end + + it 'returns false' do + expect(service.execute).to eq(false) + end + + it 'has the right error' do + service.execute + + expect(internal_group.errors.full_messages.first).to eq('Gitlab::UpdatePathError') + end + end + end end -- cgit v1.2.1 From 9c623e3e5d7434f2e30f7c389d13e5af4ede770a Mon Sep 17 00:00:00 2001 From: James Edwards-Jones Date: Tue, 20 Dec 2016 14:48:04 +0000 Subject: Added QueryRecorder to test N+1 fix on Milestone#show --- spec/features/milestones/show_spec.rb | 26 +++++++++++++++++++++++ spec/support/query_recorder.rb | 40 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 spec/features/milestones/show_spec.rb create mode 100644 spec/support/query_recorder.rb (limited to 'spec') diff --git a/spec/features/milestones/show_spec.rb b/spec/features/milestones/show_spec.rb new file mode 100644 index 00000000000..40b4dc63697 --- /dev/null +++ b/spec/features/milestones/show_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +describe 'Milestone show', feature: true do + let(:user) { create(:user) } + let(:project) { create(:empty_project) } + let(:milestone) { create(:milestone, project: project) } + let(:labels) { create_list(:label, 2, project: project) } + let(:issue_params) { { project: project, assignee: user, author: user, milestone: milestone, labels: labels } } + + before do + project.add_user(user, :developer) + login_as(user) + end + + def visit_milestone + visit namespace_project_milestone_path(project.namespace, project, milestone) + end + + it 'avoids N+1 database queries' do + create(:labeled_issue, issue_params) + control_count = ActiveRecord::QueryRecorder.new { visit_milestone }.count + create_list(:labeled_issue, 10, issue_params) + + expect { visit_milestone }.not_to exceed_query_limit(control_count) + end +end diff --git a/spec/support/query_recorder.rb b/spec/support/query_recorder.rb new file mode 100644 index 00000000000..e40d5ebd9a8 --- /dev/null +++ b/spec/support/query_recorder.rb @@ -0,0 +1,40 @@ +module ActiveRecord + class QueryRecorder + attr_reader :log + + def initialize(&block) + @log = [] + ActiveSupport::Notifications.subscribed(method(:callback), 'sql.active_record', &block) + end + + def callback(name, start, finish, message_id, values) + return if %w(CACHE SCHEMA).include?(values[:name]) + @log << values[:sql] + end + + def count + @log.count + end + + def log_message + @log.join("\n\n") + end + end +end + +RSpec::Matchers.define :exceed_query_limit do |expected| + supports_block_expectations + + match do |block| + query_count(&block) > expected + end + + failure_message_when_negated do |actual| + "Expected a maximum of #{expected} queries, got #{@recorder.count}:\n\n#{@recorder.log_message}" + end + + def query_count(&block) + @recorder = ActiveRecord::QueryRecorder.new(&block) + @recorder.count + end +end -- cgit v1.2.1 From 61d09a7b15ef9ae2e23359f1afb87b0adbda4dd4 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 20 Dec 2016 19:11:53 +0100 Subject: WIP --- spec/lib/mattermost/command_spec.rb | 18 ++++++++---------- spec/lib/mattermost/team_spec.rb | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/lib/mattermost/command_spec.rb b/spec/lib/mattermost/command_spec.rb index f38bb273e7d..ecf336e3199 100644 --- a/spec/lib/mattermost/command_spec.rb +++ b/spec/lib/mattermost/command_spec.rb @@ -1,19 +1,17 @@ require 'spec_helper' describe Mattermost::Command do - let(:session) { double("session") } let(:hash) { { 'token' => 'token' } } + let(:user) { create(:user) } - describe '.create' do - before do - allow(session).to receive(:post).and_return(hash) - allow(hash).to receive(:parsed_response).and_return(hash) - end - - it 'gets the teams' do - expect(session).to receive(:post) + before do + Mattermost::Session.base_uri("http://mattermost.example.com") + end - described_class.create(session, 'abc', url: 'http://trigger.com') + describe '#create' do + it 'creates a command' do + described_class.new(user). + create(team_id: 'abc', url: 'http://trigger.com') end end end diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index c208be3912b..5d1fc6fc603 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Mattermost::Team do - describe '.team_admin' do + describe '#all' do let(:session) { double("session") } let(:response) do -- cgit v1.2.1 From 2b486c2bb27087e4eb306821b9fca95ff8ac74d3 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Tue, 20 Dec 2016 20:07:34 +0100 Subject: Fix stage and pipeline specs and rubocop offenses --- .../projects/pipelines_controller_spec.rb | 19 ++++++++-------- spec/features/projects/pipelines/pipelines_spec.rb | 25 +++++++++++++++------- spec/models/ci/pipeline_spec.rb | 6 +++--- spec/models/ci/stage_spec.rb | 2 +- 4 files changed, 31 insertions(+), 21 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/pipelines_controller_spec.rb b/spec/controllers/projects/pipelines_controller_spec.rb index 94113250c9f..5fe7e6407cc 100644 --- a/spec/controllers/projects/pipelines_controller_spec.rb +++ b/spec/controllers/projects/pipelines_controller_spec.rb @@ -12,14 +12,6 @@ describe Projects::PipelinesController do end describe 'GET stages.json' do - def get_stage(name) - get :stage, namespace_id: project.namespace.path, - project_id: project.path, - id: pipeline.id, - stage: name, - format: :json - end - context 'when accessing existing stage' do before do create(:ci_build, pipeline: pipeline, stage: 'build') @@ -39,8 +31,17 @@ describe Projects::PipelinesController do get_stage('test') end - it { expect(response).to have_http_status(:not_found) } + it 'responds with not found' do + expect(response).to have_http_status(:not_found) + end end + def get_stage(name) + get :stage, namespace_id: project.namespace.path, + project_id: project.path, + id: pipeline.id, + stage: name, + format: :json + end end end diff --git a/spec/features/projects/pipelines/pipelines_spec.rb b/spec/features/projects/pipelines/pipelines_spec.rb index fa8ba21b389..1ff57f92c4c 100644 --- a/spec/features/projects/pipelines/pipelines_spec.rb +++ b/spec/features/projects/pipelines/pipelines_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe "Pipelines", feature: true, js:true do +describe 'Pipelines', :feature, :js do include GitlabRoutingHelper include WaitForAjax @@ -70,23 +70,32 @@ describe "Pipelines", feature: true, js:true do end context 'with manual actions' do - let!(:manual) { create(:ci_build, :manual, pipeline: pipeline, name: 'manual build', stage: 'test', commands: 'test') } + let!(:manual) do + create(:ci_build, :manual, pipeline: pipeline, + name: 'manual build', + stage: 'test', + commands: 'test') + end - before { visit namespace_project_pipelines_path(project.namespace, project) } + before do + visit namespace_project_pipelines_path(project.namespace, project) + end - it do + it 'has link to the manual action' do find('.js-pipeline-dropdown-manual-actions').click - expect(page).to have_link('Manual build') - end - context 'when playing' do + expect(page).to have_link('Manual build') + end + context 'when manual action was played' do before do find('.js-pipeline-dropdown-manual-actions').click click_link('Manual build') end - it { expect(manual.reload).to be_pending } + it 'enqueues manual action job' do + expect(manual.reload).to be_pending + end end end diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 5e1a9fa8dd8..dc377d15f15 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -183,9 +183,9 @@ describe Ci::Pipeline, models: true do create(:commit_status, pipeline: pipeline, stage: 'test') end - it { expect(subject).to be_a(Ci::Stage) } - it { expect(subject.name).to eq('stage') } - it { expect(subject.statues).not_to be_empty } + it { expect(subject).to be_a Ci::Stage } + it { expect(subject.name).to eq 'test' } + it { expect(subject.statuses).not_to be_empty } end context 'without status in stage' do diff --git a/spec/models/ci/stage_spec.rb b/spec/models/ci/stage_spec.rb index 786091a577d..742bedb37e4 100644 --- a/spec/models/ci/stage_spec.rb +++ b/spec/models/ci/stage_spec.rb @@ -30,7 +30,7 @@ describe Ci::Stage, models: true do describe '#statuses_count' do before do - create_job(:ci_build) } + create_job(:ci_build) create_job(:ci_build, stage: 'other stage') end -- cgit v1.2.1 From 2393d30da232db04faa8da9e1a958cec22ffb6e8 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 20 Dec 2016 20:11:02 +0100 Subject: Fix rubocop errors [ci skip] --- spec/features/projects/services/mattermost_slash_command_spec.rb | 1 - .../project_services/mattermost_slash_commands_service_spec.rb | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index 521eedeae9e..73ecf86aded 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -41,7 +41,6 @@ feature 'Setup Mattermost slash commands', feature: true do end end - describe 'mattermost service is not enabled' do before do allow(Gitlab.config.mattermost).to receive(:enabled).and_return(false) diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 9fb6132d171..07662d2d89a 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -10,13 +10,13 @@ describe MattermostSlashCommandsService, :models do before do allow_any_instance_of(Mattermost::Session).to - receive(:with_session).and_yield + receive(:with_session).and_yield end subject do service.configure!(user, team_id: 'abc', - trigger: 'gitlab', url: 'http://trigger.url', - icon_url: 'http://icon.url/icon.png') + trigger: 'gitlab', url: 'http://trigger.url', + icon_url: 'http://icon.url/icon.png') end context 'the requests succeeds' do -- cgit v1.2.1 From 4a03fae930a58b485ee610ce9e6058a2c2dd3d6e Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 20 Dec 2016 20:56:46 +0100 Subject: Fix rspec tests due to different API [ci skip] --- .../services/mattermost_slash_command_spec.rb | 12 ++++-------- spec/lib/mattermost/command_spec.rb | 15 ++++++++++----- spec/lib/mattermost/team_spec.rb | 17 +++++------------ .../mattermost_slash_commands_service_spec.rb | 21 ++++++++++++--------- 4 files changed, 31 insertions(+), 34 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/services/mattermost_slash_command_spec.rb b/spec/features/projects/services/mattermost_slash_command_spec.rb index 73ecf86aded..274d50e7ce4 100644 --- a/spec/features/projects/services/mattermost_slash_command_spec.rb +++ b/spec/features/projects/services/mattermost_slash_command_spec.rb @@ -4,10 +4,12 @@ feature 'Setup Mattermost slash commands', feature: true do include WaitForAjax let(:user) { create(:user) } - let(:project) { create(:project) } + let(:project) { create(:empty_project) } let(:service) { project.create_mattermost_slash_commands_service } + let(:mattermost_enabled) { true } before do + Settings.mattermost['enabled'] = mattermost_enabled project.team << [user, :master] login_as(user) visit edit_namespace_project_service_path(project.namespace, project, service) @@ -32,19 +34,13 @@ feature 'Setup Mattermost slash commands', feature: true do end describe 'mattermost service is enabled' do - before do - allow(Gitlab.config.mattermost).to receive(:enabled).and_return(true) - end - it 'shows the add to mattermost button' do expect(page).to have_link 'Add to Mattermost' end end describe 'mattermost service is not enabled' do - before do - allow(Gitlab.config.mattermost).to receive(:enabled).and_return(false) - end + let(:mattermost_enabled) { false } it 'shows the correct trigger url' do value = find_field('request_url').value diff --git a/spec/lib/mattermost/command_spec.rb b/spec/lib/mattermost/command_spec.rb index ecf336e3199..f70aee7f3e5 100644 --- a/spec/lib/mattermost/command_spec.rb +++ b/spec/lib/mattermost/command_spec.rb @@ -1,17 +1,22 @@ require 'spec_helper' describe Mattermost::Command do - let(:hash) { { 'token' => 'token' } } - let(:user) { create(:user) } + let(:params) { { 'token' => 'token', team_id: 'abc' } } + let(:user) { build(:user) } before do Mattermost::Session.base_uri("http://mattermost.example.com") end + subject { described_class.new(user) } + describe '#create' do - it 'creates a command' do - described_class.new(user). - create(team_id: 'abc', url: 'http://trigger.com') + it 'interpolates the team id' do + allow(subject).to receive(:json_post). + with('/api/v3/teams/abc/commands/create', body: params.to_json). + and_return('token' => 'token') + + subject.create(params) end end end diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index 5d1fc6fc603..ef39c456d5f 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -2,7 +2,9 @@ require 'spec_helper' describe Mattermost::Team do describe '#all' do - let(:session) { double("session") } + let(:user) { build(:user) } + + subject { described_class.new(user) } let(:response) do [{ @@ -20,22 +22,13 @@ describe Mattermost::Team do "allow_open_invite" => false }] end - let(:json) { nil } before do - allow(session).to receive(:get).with('/api/v3/teams/all'). - and_return(json) - allow(json).to receive(:parsed_response).and_return(response) + allow(subject).to receive(:json_get).and_return(response) end it 'gets the teams' do - expect(described_class.all(session).count).to be(1) - end - - it 'filters on being team admin' do - ids = described_class.all(session).map { |team| team['id'] } - - expect(ids).to include("xiyro8huptfhdndadpz8r3wnbo") + expect(subject.all.count).to be(1) end end end diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 07662d2d89a..850ca45ddd8 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -3,23 +3,23 @@ require 'spec_helper' describe MattermostSlashCommandsService, :models do it_behaves_like "chat slash commands service" - describe '#configure!' do + describe '#configure' do let(:project) { create(:empty_project) } let(:service) { project.build_mattermost_slash_commands_service } let(:user) { create(:user)} - before do - allow_any_instance_of(Mattermost::Session).to - receive(:with_session).and_yield - end - subject do - service.configure!(user, team_id: 'abc', + service.configure(user, team_id: 'abc', trigger: 'gitlab', url: 'http://trigger.url', icon_url: 'http://icon.url/icon.png') end context 'the requests succeeds' do + before do + allow_any_instance_of(Mattermost::Command). + to receive(:json_post).and_return('token' => 'token') + end + it 'saves the service' do expect { subject }.to change { project.services.count }.by(1) end @@ -27,13 +27,16 @@ describe MattermostSlashCommandsService, :models do it 'saves the token' do subject - expect(service.reload.token).to eq('mynewtoken') + expect(service.reload.token).to eq('token') end end context 'an error is received' do it 'shows error messages' do - expect(subject).to raise_error("Error") + succeeded, message = subject + + expect(succeeded).to be(false) + expect(message).to start_with("Failed to open TCP connection to") end end end -- cgit v1.2.1 From 36eed726dcf7e4bf062265cb665ad798be774f89 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 20 Dec 2016 22:30:06 +0100 Subject: Add controller test --- .../projects/mattermosts_controller_spec.rb | 53 ++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 spec/controllers/projects/mattermosts_controller_spec.rb (limited to 'spec') diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb new file mode 100644 index 00000000000..3f9482b0cde --- /dev/null +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe Projects::MattermostsController do + let!(:project) { create(:empty_project) } + let!(:user) { create(:user) } + + before do + project.team << [user, :master] + sign_in(user) + end + + describe 'GET #new' do + before do + get(:new, + namespace_id: project.namespace.to_param, + project_id: project.to_param) + end + + it 'accepts the request' do + expect(response).to have_http_status(200) + end + end + + describe 'POST #create' do + let(:mattermost_params) { { trigger: 'http://localhost:3000/trigger', team_id: 'abc' } } + + subject do + post(:create, + namespace_id: project.namespace.to_param, + project_id: project.to_param, + mattermost: mattermost_params) + end + + context 'no request can be made to mattermost' do + it 'shows the error' do + expect(controller).to set_flash[:alert].to /\AFailed to open TCP connection to/ + end + end + + context 'the request is succesull' do + before do + allow_any_instance_of(Mattermost::Command).to receive(:create).and_return('token') + end + + it 'redirects to the new page' do + subject + service = project.services.last + + expect(subject).to redirect_to(edit_namespace_project_service_url(project.namespace, project, service)) + end + end + end +end -- cgit v1.2.1 From fed29117de6f30055d88daaa497ec18f85397ad6 Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 20 Dec 2016 19:14:33 -0200 Subject: Rename SlackNotificationService back to SlackService --- .../import_export/test_project_export.tar.gz | Bin 679415 -> 682154 bytes .../projects/services/slack_service_spec.rb | 4 ++-- spec/lib/gitlab/import_export/all_models.yml | 2 +- .../slack_notification_service_spec.rb | 5 ----- spec/models/project_services/slack_service_spec.rb | 5 +++++ spec/models/project_spec.rb | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) delete mode 100644 spec/models/project_services/slack_notification_service_spec.rb create mode 100644 spec/models/project_services/slack_service_spec.rb (limited to 'spec') diff --git a/spec/features/projects/import_export/test_project_export.tar.gz b/spec/features/projects/import_export/test_project_export.tar.gz index d3165d07d7b..7655c2b351f 100644 Binary files a/spec/features/projects/import_export/test_project_export.tar.gz and b/spec/features/projects/import_export/test_project_export.tar.gz differ diff --git a/spec/features/projects/services/slack_service_spec.rb b/spec/features/projects/services/slack_service_spec.rb index 320ed13a01d..16541f51d98 100644 --- a/spec/features/projects/services/slack_service_spec.rb +++ b/spec/features/projects/services/slack_service_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' feature 'Projects > Slack service > Setup events', feature: true do let(:user) { create(:user) } - let(:service) { SlackNotificationService.new } - let(:project) { create(:project, slack_notification_service: service) } + let(:service) { SlackService.new } + let(:project) { create(:project, slack_service: service) } background do service.fields diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 7e618e2fcf5..155cf8565b5 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -137,7 +137,7 @@ project: - assembla_service - asana_service - gemnasium_service -- slack_notification_service +- slack_service - mattermost_notification_service - buildkite_service - bamboo_service diff --git a/spec/models/project_services/slack_notification_service_spec.rb b/spec/models/project_services/slack_notification_service_spec.rb deleted file mode 100644 index 110b5bf2115..00000000000 --- a/spec/models/project_services/slack_notification_service_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe SlackNotificationService, models: true do - it_behaves_like "slack or mattermost notifications" -end diff --git a/spec/models/project_services/slack_service_spec.rb b/spec/models/project_services/slack_service_spec.rb new file mode 100644 index 00000000000..9a3ecc66d83 --- /dev/null +++ b/spec/models/project_services/slack_service_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe SlackService, models: true do + it_behaves_like "slack or mattermost notifications" +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 0455cd2fe49..569071c0418 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -21,7 +21,7 @@ describe Project, models: true do it { is_expected.to have_many(:hooks).dependent(:destroy) } it { is_expected.to have_many(:protected_branches).dependent(:destroy) } it { is_expected.to have_one(:forked_project_link).dependent(:destroy) } - it { is_expected.to have_one(:slack_notification_service).dependent(:destroy) } + it { is_expected.to have_one(:slack_service).dependent(:destroy) } it { is_expected.to have_one(:mattermost_notification_service).dependent(:destroy) } it { is_expected.to have_one(:pushover_service).dependent(:destroy) } it { is_expected.to have_one(:asana_service).dependent(:destroy) } -- cgit v1.2.1 From d1bf557aacb5dd789ccc88786b47ec174ed1de2b Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Tue, 20 Dec 2016 19:29:39 -0200 Subject: Rename MattermostNotificationService back to MattermostService --- spec/lib/gitlab/import_export/all_models.yml | 2 +- spec/models/project_services/mattermost_notification_service_spec.rb | 5 ----- spec/models/project_services/mattermost_service_spec.rb | 5 +++++ spec/models/project_spec.rb | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 spec/models/project_services/mattermost_notification_service_spec.rb create mode 100644 spec/models/project_services/mattermost_service_spec.rb (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 155cf8565b5..f420d71dee2 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -138,7 +138,7 @@ project: - asana_service - gemnasium_service - slack_service -- mattermost_notification_service +- mattermost_service - buildkite_service - bamboo_service - teamcity_service diff --git a/spec/models/project_services/mattermost_notification_service_spec.rb b/spec/models/project_services/mattermost_notification_service_spec.rb deleted file mode 100644 index 7832d6f50cf..00000000000 --- a/spec/models/project_services/mattermost_notification_service_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'spec_helper' - -describe MattermostNotificationService, models: true do - it_behaves_like "slack or mattermost notifications" -end diff --git a/spec/models/project_services/mattermost_service_spec.rb b/spec/models/project_services/mattermost_service_spec.rb new file mode 100644 index 00000000000..490d6aedffc --- /dev/null +++ b/spec/models/project_services/mattermost_service_spec.rb @@ -0,0 +1,5 @@ +require 'spec_helper' + +describe MattermostService, models: true do + it_behaves_like "slack or mattermost notifications" +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 569071c0418..88d5d14f855 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -22,7 +22,7 @@ describe Project, models: true do it { is_expected.to have_many(:protected_branches).dependent(:destroy) } it { is_expected.to have_one(:forked_project_link).dependent(:destroy) } it { is_expected.to have_one(:slack_service).dependent(:destroy) } - it { is_expected.to have_one(:mattermost_notification_service).dependent(:destroy) } + it { is_expected.to have_one(:mattermost_service).dependent(:destroy) } it { is_expected.to have_one(:pushover_service).dependent(:destroy) } it { is_expected.to have_one(:asana_service).dependent(:destroy) } it { is_expected.to have_many(:boards).dependent(:destroy) } -- cgit v1.2.1 From 22a0567823e792bd760ced79539a0b2c4bfd8f5e Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Tue, 20 Dec 2016 23:17:32 +0100 Subject: Fix a few error messages --- spec/lib/mattermost/team_spec.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index ef39c456d5f..704579f0f48 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -3,9 +3,6 @@ require 'spec_helper' describe Mattermost::Team do describe '#all' do let(:user) { build(:user) } - - subject { described_class.new(user) } - let(:response) do [{ "id" => "xiyro8huptfhdndadpz8r3wnbo", @@ -22,6 +19,7 @@ describe Mattermost::Team do "allow_open_invite" => false }] end + subject { described_class.new(user) } before do allow(subject).to receive(:json_get).and_return(response) -- cgit v1.2.1 From 5452747729d30733a51a85ff1212d0724af1d1ff Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 21 Dec 2016 10:33:20 +0100 Subject: Fix error importing label priorities and added relevant spec --- spec/lib/gitlab/import_export/project.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'spec') diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json index 931d426c87f..2c0750c3377 100644 --- a/spec/lib/gitlab/import_export/project.json +++ b/spec/lib/gitlab/import_export/project.json @@ -15,6 +15,28 @@ "type": "ProjectLabel", "priorities": [ ] + }, + { + "id": 3, + "title": "test3", + "color": "#428bca", + "group_id": 8, + "created_at": "2016-07-22T08:55:44.161Z", + "updated_at": "2016-07-22T08:55:44.161Z", + "template": false, + "description": "", + "project_id": null, + "type": "GroupLabel", + "priorities": [ + { + "id": 1, + "project_id": 5, + "label_id": 1, + "priority": 1, + "created_at": "2016-10-18T09:35:43.338Z", + "updated_at": "2016-10-18T09:35:43.338Z" + } + ] } ], "issues": [ -- cgit v1.2.1 From 359718603eb880bffc5688c16ceed170823b665a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 21 Dec 2016 11:45:28 +0100 Subject: Ensure nil User-Agent doesn't break the CI API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/requests/ci/api/builds_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'spec') diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb index 79f12ace999..3b5dc98e4d5 100644 --- a/spec/requests/ci/api/builds_spec.rb +++ b/spec/requests/ci/api/builds_spec.rb @@ -37,6 +37,11 @@ describe Ci::API::Builds do let(:user_agent) { 'Go-http-client/1.1' } it { expect(response).to have_http_status(404) } end + + context "when runner doesn't have a User-Agent" do + let(:user_agent) { nil } + it { expect(response).to have_http_status(404) } + end end context 'when there is a pending build' do -- cgit v1.2.1 From 55c61d2e412733b0feefcb5fa33a96e584ffe2bc Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 21 Dec 2016 11:53:44 +0100 Subject: Improve API specs --- spec/lib/mattermost/command_spec.rb | 57 ++++++++-- spec/lib/mattermost/team_spec.rb | 76 +++++++++---- .../mattermost_slash_commands_service_spec.rb | 119 +++++++++++++++++---- 3 files changed, 203 insertions(+), 49 deletions(-) (limited to 'spec') diff --git a/spec/lib/mattermost/command_spec.rb b/spec/lib/mattermost/command_spec.rb index f70aee7f3e5..5ccf1100898 100644 --- a/spec/lib/mattermost/command_spec.rb +++ b/spec/lib/mattermost/command_spec.rb @@ -2,21 +2,60 @@ require 'spec_helper' describe Mattermost::Command do let(:params) { { 'token' => 'token', team_id: 'abc' } } - let(:user) { build(:user) } before do - Mattermost::Session.base_uri("http://mattermost.example.com") - end + Mattermost::Session.base_uri('http://mattermost.example.com') - subject { described_class.new(user) } + allow_any_instance_of(Mattermost::Client).to receive(:with_session). + and_yield(Mattermost::Session.new(nil)) + end describe '#create' do - it 'interpolates the team id' do - allow(subject).to receive(:json_post). - with('/api/v3/teams/abc/commands/create', body: params.to_json). - and_return('token' => 'token') + let(:params) do + { team_id: 'abc', + trigger: 'gitlab' + } + end + + subject { described_class.new(nil).create(params) } + + context 'for valid trigger word' do + before do + stub_request(:post, 'http://mattermost.example.com/api/v3/teams/abc/commands/create'). + with(body: { + team_id: 'abc', + trigger: 'gitlab' }.to_json). + to_return( + status: 200, + headers: { 'Content-Type' => 'application/json' }, + body: { token: 'token' }.to_json + ) + end + + it 'returns a token' do + is_expected.to eq('token') + end + end + + context 'for error message' do + before do + stub_request(:post, 'http://mattermost.example.com/api/v3/teams/abc/commands/create'). + to_return( + status: 500, + headers: { 'Content-Type' => 'application/json' }, + body: { + id: 'api.command.duplicate_trigger.app_error', + message: 'This trigger word is already in use. Please choose another word.', + detailed_error: '', + request_id: 'obc374man7bx5r3dbc1q5qhf3r', + status_code: 500 + }.to_json + ) + end - subject.create(params) + it 'raises an error with message' do + expect { subject }.to raise_error(Mattermost::Error, 'This trigger word is already in use. Please choose another word.') + end end end end diff --git a/spec/lib/mattermost/team_spec.rb b/spec/lib/mattermost/team_spec.rb index 704579f0f48..2d14be6bcc2 100644 --- a/spec/lib/mattermost/team_spec.rb +++ b/spec/lib/mattermost/team_spec.rb @@ -1,32 +1,66 @@ require 'spec_helper' describe Mattermost::Team do + before do + Mattermost::Session.base_uri('http://mattermost.example.com') + + allow_any_instance_of(Mattermost::Client).to receive(:with_session). + and_yield(Mattermost::Session.new(nil)) + end + describe '#all' do - let(:user) { build(:user) } - let(:response) do - [{ - "id" => "xiyro8huptfhdndadpz8r3wnbo", - "create_at" => 1482174222155, - "update_at" => 1482174222155, - "delete_at" => 0, - "display_name" => "chatops", - "name" => "chatops", - "email" => "admin@example.com", - "type" => "O", - "company_name" => "", - "allowed_domains" => "", - "invite_id" => "o4utakb9jtb7imctdfzbf9r5ro", - "allow_open_invite" => false }] - end + subject { described_class.new(nil).all } + + context 'for valid request' do + let(:response) do + [{ + "id" => "xiyro8huptfhdndadpz8r3wnbo", + "create_at" => 1482174222155, + "update_at" => 1482174222155, + "delete_at" => 0, + "display_name" => "chatops", + "name" => "chatops", + "email" => "admin@example.com", + "type" => "O", + "company_name" => "", + "allowed_domains" => "", + "invite_id" => "o4utakb9jtb7imctdfzbf9r5ro", + "allow_open_invite" => false }] + end - subject { described_class.new(user) } + before do + stub_request(:get, 'http://mattermost.example.com/api/v3/teams/all'). + to_return( + status: 200, + headers: { 'Content-Type' => 'application/json' }, + body: response.to_json + ) + end - before do - allow(subject).to receive(:json_get).and_return(response) + it 'returns a token' do + is_expected.to eq(response) + end end - it 'gets the teams' do - expect(subject.all.count).to be(1) + context 'for error message' do + before do + stub_request(:get, 'http://mattermost.example.com/api/v3/teams/all'). + to_return( + status: 500, + headers: { 'Content-Type' => 'application/json' }, + body: { + id: 'api.team.list.app_error', + message: 'Cannot list teams.', + detailed_error: '', + request_id: 'obc374man7bx5r3dbc1q5qhf3r', + status_code: 500 + }.to_json + ) + end + + it 'raises an error with message' do + expect { subject }.to raise_error(Mattermost::Error, 'Cannot list teams.') + end end end end diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb index 850ca45ddd8..d6f4fbd7265 100644 --- a/spec/models/project_services/mattermost_slash_commands_service_spec.rb +++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb @@ -3,40 +3,121 @@ require 'spec_helper' describe MattermostSlashCommandsService, :models do it_behaves_like "chat slash commands service" - describe '#configure' do + context 'Mattermost API' do let(:project) { create(:empty_project) } let(:service) { project.build_mattermost_slash_commands_service } let(:user) { create(:user)} - subject do - service.configure(user, team_id: 'abc', - trigger: 'gitlab', url: 'http://trigger.url', - icon_url: 'http://icon.url/icon.png') + before do + Mattermost::Session.base_uri("http://mattermost.example.com") + + allow_any_instance_of(Mattermost::Client).to receive(:with_session). + and_yield(Mattermost::Session.new(nil)) end - context 'the requests succeeds' do - before do - allow_any_instance_of(Mattermost::Command). - to receive(:json_post).and_return('token' => 'token') + describe '#configure' do + subject do + service.configure(user, team_id: 'abc', + trigger: 'gitlab', url: 'http://trigger.url', + icon_url: 'http://icon.url/icon.png') end - it 'saves the service' do - expect { subject }.to change { project.services.count }.by(1) + context 'the requests succeeds' do + before do + stub_request(:post, 'http://mattermost.example.com/api/v3/teams/abc/commands/create'). + with(body: { + team_id: 'abc', + trigger: 'gitlab', + url: 'http://trigger.url', + icon_url: 'http://icon.url/icon.png', + auto_complete: true, + auto_complete_desc: "Perform common operations on: #{project.name_with_namespace}", + auto_complete_hint: '[help]', + description: "Perform common operations on: #{project.name_with_namespace}", + display_name: "GitLab / #{project.name_with_namespace}", + method: 'P', + user_name: 'GitLab' }.to_json). + to_return( + status: 200, + headers: { 'Content-Type' => 'application/json' }, + body: { token: 'token' }.to_json + ) + end + + it 'saves the service' do + expect { subject }.to change { project.services.count }.by(1) + end + + it 'saves the token' do + subject + + expect(service.reload.token).to eq('token') + end end - it 'saves the token' do - subject + context 'an error is received' do + before do + stub_request(:post, 'http://mattermost.example.com/api/v3/teams/abc/commands/create'). + to_return( + status: 500, + headers: { 'Content-Type' => 'application/json' }, + body: { + id: 'api.command.duplicate_trigger.app_error', + message: 'This trigger word is already in use. Please choose another word.', + detailed_error: '', + request_id: 'obc374man7bx5r3dbc1q5qhf3r', + status_code: 500 + }.to_json + ) + end + + it 'shows error messages' do + succeeded, message = subject - expect(service.reload.token).to eq('token') + expect(succeeded).to be(false) + expect(message).to eq('This trigger word is already in use. Please choose another word.') + end end end - context 'an error is received' do - it 'shows error messages' do - succeeded, message = subject + describe '#list_teams' do + subject do + service.list_teams(user) + end + + context 'the requests succeeds' do + before do + stub_request(:get, 'http://mattermost.example.com/api/v3/teams/all'). + to_return( + status: 200, + headers: { 'Content-Type' => 'application/json' }, + body: ['list'].to_json + ) + end + + it 'returns a list of teams' do + expect(subject).not_to be_empty + end + end + + context 'an error is received' do + before do + stub_request(:get, 'http://mattermost.example.com/api/v3/teams/all'). + to_return( + status: 500, + headers: { 'Content-Type' => 'application/json' }, + body: { + message: 'Failed to get team list.' + }.to_json + ) + end + + it 'shows error messages' do + teams, message = subject - expect(succeeded).to be(false) - expect(message).to start_with("Failed to open TCP connection to") + expect(teams).to be_empty + expect(message).to eq('Failed to get team list.') + end end end end -- cgit v1.2.1 From dfa842ce1de5b93bca2f336f3cf8c8769a555853 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 24 Nov 2016 15:45:34 +0000 Subject: Removes builds tab from merge request Fix specs --- spec/controllers/projects/merge_requests_controller_spec.rb | 4 ---- spec/features/merge_requests/created_from_fork_spec.rb | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'spec') diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 9e0b80205d8..440b897ddc6 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -649,10 +649,6 @@ describe Projects::MergeRequestsController do end end - describe 'GET builds' do - it_behaves_like "loads labels", :builds - end - describe 'GET pipelines' do it_behaves_like "loads labels", :pipelines end diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb index 142649297cc..73c5ef31edc 100644 --- a/spec/features/merge_requests/created_from_fork_spec.rb +++ b/spec/features/merge_requests/created_from_fork_spec.rb @@ -54,14 +54,14 @@ feature 'Merge request created from fork' do scenario 'user visits a pipelines page', js: true do visit_merge_request(merge_request) - page.within('.merge-request-tabs') { click_link 'Builds' } + page.within('.merge-request-tabs') { click_link 'Pipelines' } page.within('table.ci-table') do - expect(page).to have_content 'rspec' - expect(page).to have_content 'spinach' + expect(page).to have_content pipeline.status + expect(page).to have_content pipeline.id end - expect(find_link('Cancel running')[:href]) + expect(page.find('a.btn-remove')[:href]) .to include fork_project.path_with_namespace end end -- cgit v1.2.1 From 7086dac42fff6e32bc38b389ffa104d9c21a159c Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 29 Nov 2016 13:02:28 +0000 Subject: Changes after review Fix broken test Remove spinach tests for the builds tab --- spec/features/projects/commit/builds_spec.rb | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'spec') diff --git a/spec/features/projects/commit/builds_spec.rb b/spec/features/projects/commit/builds_spec.rb index fcdf7870f34..33f1c323af1 100644 --- a/spec/features/projects/commit/builds_spec.rb +++ b/spec/features/projects/commit/builds_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -feature 'project commit builds' do +feature 'project commit pipelines' do given(:project) { create(:project) } background do @@ -16,11 +16,13 @@ feature 'project commit builds' do ref: 'master') end - scenario 'user views commit builds page' do - visit builds_namespace_project_commit_path(project.namespace, - project, project.commit.sha) + scenario 'user views commit pipelines page' do + visit pipelines_namespace_project_commit_path(project.namespace, project, project.commit.sha) - expect(page).to have_content('Builds') + page.within('.table-holder') do + expect(page).to have_content project.pipelines[0].status # pipeline status + expect(page).to have_content project.pipelines[0].id # pipeline ids + end end end end -- cgit v1.2.1 From 4ec259fd36fe57aa95446c10a47d784dae2c8f00 Mon Sep 17 00:00:00 2001 From: Jacob Vosmaer Date: Wed, 21 Dec 2016 11:44:47 +0100 Subject: Inject ::UploadedFile from Multipart middleware I mistakenly concluded Rack::Multipart injects File instances into the params. These should be UploadedFile instances. This reuses a mock UploadedFile class we already had in GitLab. --- spec/lib/gitlab/middleware/multipart_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/middleware/multipart_spec.rb b/spec/lib/gitlab/middleware/multipart_spec.rb index ab1ab22795c..8d925460f01 100644 --- a/spec/lib/gitlab/middleware/multipart_spec.rb +++ b/spec/lib/gitlab/middleware/multipart_spec.rb @@ -12,7 +12,7 @@ describe Gitlab::Middleware::Multipart do expect(app).to receive(:call) do |env| file = Rack::Request.new(env).params['file'] - expect(file).to be_a(File) + expect(file).to be_a(::UploadedFile) expect(file.path).to eq(tempfile.path) end @@ -39,7 +39,7 @@ describe Gitlab::Middleware::Multipart do expect(app).to receive(:call) do |env| file = Rack::Request.new(env).params['user']['avatar'] - expect(file).to be_a(File) + expect(file).to be_a(::UploadedFile) expect(file.path).to eq(tempfile.path) end @@ -54,7 +54,7 @@ describe Gitlab::Middleware::Multipart do expect(app).to receive(:call) do |env| file = Rack::Request.new(env).params['project']['milestone']['themesong'] - expect(file).to be_a(File) + expect(file).to be_a(::UploadedFile) expect(file.path).to eq(tempfile.path) end -- cgit v1.2.1 From 4c3ec579e5660daab23d48bd4b3e21050735f726 Mon Sep 17 00:00:00 2001 From: James Lopez Date: Wed, 21 Dec 2016 13:29:27 +0100 Subject: added more specs --- spec/controllers/groups_controller_spec.rb | 4 ++-- spec/services/groups/update_service_spec.rb | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'spec') diff --git a/spec/controllers/groups_controller_spec.rb b/spec/controllers/groups_controller_spec.rb index 4bb37bc52ee..98dfb3e5216 100644 --- a/spec/controllers/groups_controller_spec.rb +++ b/spec/controllers/groups_controller_spec.rb @@ -122,8 +122,8 @@ describe GroupsController do allow_any_instance_of(Group).to receive(:move_dir).and_raise(Gitlab::UpdatePathError) post :update, id: group.to_param, group: { path: 'new_path' } - expect(response).to have_http_status(302) - expect(controller).to set_flash[:alert] + expect(assigns(:group).errors).not_to be_empty + expect(assigns(:group).path).not_to eq('new_path') end end end diff --git a/spec/services/groups/update_service_spec.rb b/spec/services/groups/update_service_spec.rb index 8ac5736cbb3..531180e48a1 100644 --- a/spec/services/groups/update_service_spec.rb +++ b/spec/services/groups/update_service_spec.rb @@ -59,8 +59,6 @@ describe Groups::UpdateService, services: true do end it 'returns true' do - puts internal_group.errors.full_messages - expect(service.execute).to eq(true) end @@ -82,6 +80,10 @@ describe Groups::UpdateService, services: true do expect(internal_group.errors.full_messages.first).to eq('Gitlab::UpdatePathError') end + + it "hasn't changed the path" do + expect { service.execute}.not_to change { internal_group.reload.path} + end end end end -- cgit v1.2.1 From a9f85d11a584a5a9ad99aaf6366f22fd6f6d0957 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 21 Dec 2016 11:03:52 +0000 Subject: Fix space issue and add test --- spec/features/issues/gfm_autocomplete_spec.rb | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'spec') diff --git a/spec/features/issues/gfm_autocomplete_spec.rb b/spec/features/issues/gfm_autocomplete_spec.rb index da64827b377..df3a467cbb7 100644 --- a/spec/features/issues/gfm_autocomplete_spec.rb +++ b/spec/features/issues/gfm_autocomplete_spec.rb @@ -39,7 +39,6 @@ feature 'GFM autocomplete', feature: true, js: true do page.within '.timeline-content-form' do note.native.send_keys('') note.native.send_keys("~#{label.title[0]}") - sleep 1 note.click end @@ -53,7 +52,6 @@ feature 'GFM autocomplete', feature: true, js: true do page.within '.timeline-content-form' do note.native.send_keys('') note.native.send_keys("@#{user.username[0]}") - sleep 1 note.click end @@ -67,7 +65,6 @@ feature 'GFM autocomplete', feature: true, js: true do page.within '.timeline-content-form' do note.native.send_keys('') note.native.send_keys(":cartwheel") - sleep 1 note.click end @@ -76,6 +73,22 @@ feature 'GFM autocomplete', feature: true, js: true do expect_to_wrap(false, emoji_item, note, 'cartwheel_tone1') end + it 'doesn\'t open autocomplete after non-word character' do + page.within '.timeline-content-form' do + find('#note_note').native.send_keys("@#{user.username[0..2]}!") + end + + expect(page).not_to have_selector('.atwho-view') + end + + it 'doesn\'t open autocomplete if there is no space before' do + page.within '.timeline-content-form' do + find('#note_note').native.send_keys("hello:#{user.username[0..2]}") + end + + expect(page).not_to have_selector('.atwho-view') + end + def expect_to_wrap(should_wrap, item, note, value) expect(item).to have_content(value) expect(item).not_to have_content("\"#{value}\"") @@ -89,12 +102,4 @@ feature 'GFM autocomplete', feature: true, js: true do end end end - - it 'doesnt open autocomplete after non-word character' do - page.within '.timeline-content-form' do - find('#note_note').native.send_keys("@#{user.username[0..2]}!") - end - - expect(page).not_to have_selector('.atwho-view') - end end -- cgit v1.2.1 From 804198ab7f1bdd854c64da729a04fc65f2b6ff7d Mon Sep 17 00:00:00 2001 From: Sam Rose Date: Thu, 15 Dec 2016 10:07:41 -0500 Subject: Maintain milestone filter option when updating filter Setup teaspoon tests for Issuable --- .../javascripts/fixtures/issuable_filter.html.haml | 8 +++ spec/javascripts/issuable_spec.js.es6 | 81 ++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 spec/javascripts/fixtures/issuable_filter.html.haml create mode 100644 spec/javascripts/issuable_spec.js.es6 (limited to 'spec') diff --git a/spec/javascripts/fixtures/issuable_filter.html.haml b/spec/javascripts/fixtures/issuable_filter.html.haml new file mode 100644 index 00000000000..ae745b292e6 --- /dev/null +++ b/spec/javascripts/fixtures/issuable_filter.html.haml @@ -0,0 +1,8 @@ +%form.js-filter-form{action: '/user/project/issues?scope=all&state=closed'} + %input{id: 'utf8', name: 'utf8', value: '✓'} + %input{id: 'check_all_issues', name: 'check_all_issues'} + %input{id: 'search', name: 'search'} + %input{id: 'author_id', name: 'author_id'} + %input{id: 'assignee_id', name: 'assignee_id'} + %input{id: 'milestone_title', name: 'milestone_title'} + %input{id: 'label_name', name: 'label_name'} diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 new file mode 100644 index 00000000000..d61601ee4fb --- /dev/null +++ b/spec/javascripts/issuable_spec.js.es6 @@ -0,0 +1,81 @@ +/* global Issuable */ +/* global Turbolinks */ + +//= require issuable +//= require turbolinks + +(() => { + const BASE_URL = '/user/project/issues?scope=all&state=closed'; + const DEFAULT_PARAMS = '&utf8=%E2%9C%93'; + + function updateForm(formValues, form) { + $.each(formValues, (id, value) => { + $(`#${id}`, form).val(value); + }); + } + + function resetForm(form) { + $('input[name!="utf8"]', form).each((index, input) => { + input.setAttribute('value', ''); + }); + } + + describe('Issuable', () => { + fixture.preload('issuable_filter'); + + beforeEach(() => { + fixture.load('issuable_filter'); + Issuable.init(); + }); + + it('should be defined', () => { + expect(window.Issuable).toBeDefined(); + }); + + describe('filtering', () => { + let $filtersForm; + + beforeEach(() => { + $filtersForm = $('.js-filter-form'); + fixture.load('issuable_filter'); + resetForm($filtersForm); + }); + + it('should contain only the default parameters', () => { + spyOn(Turbolinks, 'visit'); + + Issuable.filterResults($filtersForm); + + expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + DEFAULT_PARAMS); + }); + + it('should filter for the phrase "broken"', () => { + spyOn(Turbolinks, 'visit'); + + updateForm({ search: 'broken' }, $filtersForm); + Issuable.filterResults($filtersForm); + const params = `${DEFAULT_PARAMS}&search=broken`; + + expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params); + }); + + it('should keep query parameters after modifying filter', () => { + spyOn(Turbolinks, 'visit'); + + // initial filter + updateForm({ milestone_title: 'v1.0' }, $filtersForm); + + Issuable.filterResults($filtersForm); + let params = `${DEFAULT_PARAMS}&milestone_title=v1.0`; + expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params); + + // update filter + updateForm({ label_name: 'Frontend' }, $filtersForm); + + Issuable.filterResults($filtersForm); + params = `${DEFAULT_PARAMS}&milestone_title=v1.0&label_name=Frontend`; + expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params); + }); + }); + }); +})(); -- cgit v1.2.1 From 90c6a1a3198ba8090c645d740ac619e01a2e834e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 21 Dec 2016 13:45:18 +0100 Subject: Use Grape's new Route methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use Route#request_method instead of Route#route_method - Use Route#path instead of Route#route_path Signed-off-by: Rémy Coutable --- spec/lib/gitlab/metrics/rack_middleware_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/lib/gitlab/metrics/rack_middleware_spec.rb b/spec/lib/gitlab/metrics/rack_middleware_spec.rb index bcaffd27909..7371b578a48 100644 --- a/spec/lib/gitlab/metrics/rack_middleware_spec.rb +++ b/spec/lib/gitlab/metrics/rack_middleware_spec.rb @@ -33,7 +33,7 @@ describe Gitlab::Metrics::RackMiddleware do end it 'tags a transaction with the method and path of the route in the grape endpoint' do - route = double(:route, route_method: "GET", route_path: "/:version/projects/:id/archive(.:format)") + route = double(:route, request_method: "GET", path: "/:version/projects/:id/archive(.:format)") endpoint = double(:endpoint, route: route) env['api.endpoint'] = endpoint @@ -117,7 +117,7 @@ describe Gitlab::Metrics::RackMiddleware do let(:transaction) { middleware.transaction_from_env(env) } it 'tags a transaction with the method and path of the route in the grape endpount' do - route = double(:route, route_method: "GET", route_path: "/:version/projects/:id/archive(.:format)") + route = double(:route, request_method: "GET", path: "/:version/projects/:id/archive(.:format)") endpoint = double(:endpoint, route: route) env['api.endpoint'] = endpoint -- cgit v1.2.1 From 1ac06396778dec216cf0467a50c67040690656ca Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Wed, 21 Dec 2016 13:34:24 +0100 Subject: Add new tests --- .../projects/mattermosts_controller_spec.rb | 7 ++++++- spec/lib/mattermost/client_spec.rb | 24 ++++++++++++++++++++++ spec/lib/mattermost/session_spec.rb | 24 ++++++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 spec/lib/mattermost/client_spec.rb (limited to 'spec') diff --git a/spec/controllers/projects/mattermosts_controller_spec.rb b/spec/controllers/projects/mattermosts_controller_spec.rb index 3f9482b0cde..2ae635a1244 100644 --- a/spec/controllers/projects/mattermosts_controller_spec.rb +++ b/spec/controllers/projects/mattermosts_controller_spec.rb @@ -11,6 +11,9 @@ describe Projects::MattermostsController do describe 'GET #new' do before do + allow_any_instance_of(MattermostSlashCommandsService). + to receive(:list_teams).and_return([]) + get(:new, namespace_id: project.namespace.to_param, project_id: project.to_param) @@ -33,7 +36,9 @@ describe Projects::MattermostsController do context 'no request can be made to mattermost' do it 'shows the error' do - expect(controller).to set_flash[:alert].to /\AFailed to open TCP connection to/ + allow_any_instance_of(MattermostSlashCommandsService).to receive(:configure).and_return([false, "error message"]) + + expect(subject).to redirect_to(new_namespace_project_mattermost_url(project.namespace, project)) end end diff --git a/spec/lib/mattermost/client_spec.rb b/spec/lib/mattermost/client_spec.rb new file mode 100644 index 00000000000..dc11a414717 --- /dev/null +++ b/spec/lib/mattermost/client_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe Mattermost::Client do + let(:user) { build(:user) } + + subject { described_class.new(user) } + + context 'JSON parse error' do + before do + Struct.new("Request", :body, :success?) + end + + it 'yields an error on malformed JSON' do + bad_json = Struct::Request.new("I'm not json", true) + expect { subject.send(:json_response, bad_json) }.to raise_error(Mattermost::ClientError) + end + + it 'shows a client error if the request was unsuccessful' do + bad_request = Struct::Request.new("true", false) + + expect { subject.send(:json_response, bad_request) }.to raise_error(Mattermost::ClientError) + end + end +end diff --git a/spec/lib/mattermost/session_spec.rb b/spec/lib/mattermost/session_spec.rb index 3c2eddbd221..74d12e37181 100644 --- a/spec/lib/mattermost/session_spec.rb +++ b/spec/lib/mattermost/session_spec.rb @@ -95,5 +95,29 @@ describe Mattermost::Session, type: :request do end end end + + context 'with lease' do + before do + allow(subject).to receive(:lease_try_obtain).and_return('aldkfjsldfk') + end + + it 'tries to obtain a lease' do + expect(subject).to receive(:lease_try_obtain) + expect(Gitlab::ExclusiveLease).to receive(:cancel) + + # Cannot setup a session, but we should still cancel the lease + expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) + end + end + + context 'without lease' do + before do + allow(subject).to receive(:lease_try_obtain).and_return(nil) + end + + it 'returns a NoSessionError error' do + expect { subject.with_session }.to raise_error(Mattermost::NoSessionError) + end + end end end -- cgit v1.2.1 From 9809a9af8a3980f8a65262295cfd9701e793ac11 Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Wed, 21 Dec 2016 16:21:55 +0100 Subject: Introduce "Set up autodeploy" button to help configure GitLab CI for deployment The button allows to choose a ".gitlab-ci.yml" template that automatically sets up the deployment of an application. The currently supported template is Kubernetes template. --- spec/factories/projects.rb | 26 +++++----- spec/features/auto_deploy_spec.rb | 56 ++++++++++++++++++++++ spec/features/environment_spec.rb | 2 +- spec/features/environments_spec.rb | 2 +- spec/models/environment_spec.rb | 6 +-- .../project_services/kubernetes_service_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/workers/reactive_caching_worker_spec.rb | 2 +- 8 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 spec/features/auto_deploy_spec.rb (limited to 'spec') diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index f7fa834d7a2..f4ab732caa4 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -48,6 +48,19 @@ FactoryGirl.define do end end + trait :kubernetes do + after :create do |project| + project.create_kubernetes_service( + active: true, + properties: { + namespace: project.path, + api_url: 'https://kubernetes.example.com/api', + token: 'a' * 40, + } + ) + end + end + # Nest Project Feature attributes transient do wiki_access_level ProjectFeature::ENABLED @@ -137,17 +150,4 @@ FactoryGirl.define do ) end end - - factory :kubernetes_project, parent: :empty_project do - after :create do |project| - project.create_kubernetes_service( - active: true, - properties: { - namespace: project.path, - api_url: 'https://kubernetes.example.com', - token: 'a' * 40, - } - ) - end - end end diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb new file mode 100644 index 00000000000..92c5b1cbb3b --- /dev/null +++ b/spec/features/auto_deploy_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +describe 'Auto deploy' do + include WaitForAjax + + let(:user) { create(:user) } + let(:project) { create(:project, :kubernetes) } + + before do + project.team << [user, :master] + login_as user + end + + context 'when no deployment service is active' do + before do + project.kubernetes_service.update!(active: false) + end + + it 'does not show a button to set up auto deploy' do + visit namespace_project_path(project.namespace, project) + expect(page).to have_no_content('Set up autodeploy') + end + end + + context 'when a deployment service is active' do + before do + project.kubernetes_service.update!(active: true) + visit namespace_project_path(project.namespace, project) + end + + it 'shows a button to set up auto deploy' do + expect(page).to have_link('Set up autodeploy') + end + + it 'includes Kubernetes as an available template', js: true do + click_link 'Set up autodeploy' + click_button 'Choose a GitLab CI Yaml template' + + within '.gitlab-ci-yml-selector' do + expect(page).to have_content('Kubernetes') + end + end + + it 'creates a merge request using "autodeploy" branch', js: true do + click_link 'Set up autodeploy' + click_button 'Choose a GitLab CI Yaml template' + within '.gitlab-ci-yml-selector' do + click_on 'Kubernetes' + end + wait_for_ajax + click_button 'Commit Changes' + + expect(page).to have_content('New Merge Request From autodeploy into master') + end + end +end diff --git a/spec/features/environment_spec.rb b/spec/features/environment_spec.rb index 56f6cd2e095..c7411f1f4ac 100644 --- a/spec/features/environment_spec.rb +++ b/spec/features/environment_spec.rb @@ -93,7 +93,7 @@ feature 'Environment', :feature do end context 'with terminal' do - let(:project) { create(:kubernetes_project, :test_repo) } + let(:project) { create(:empty_project, :kubernetes, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index 72b984cfab8..e1387e44be8 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -151,7 +151,7 @@ feature 'Environments page', :feature, :js do end context 'with terminal' do - let(:project) { create(:kubernetes_project, :test_repo) } + let(:project) { create(:empty_project, :kubernetes, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 93eb402e060..2aa63d7bcc3 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -200,7 +200,7 @@ describe Environment, models: true do context 'when the enviroment is available' do context 'with a deployment service' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } context 'and a deployment' do let!(:deployment) { create(:deployment, environment: environment) } @@ -218,14 +218,14 @@ describe Environment, models: true do end context 'when the environment is unavailable' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } before { environment.stop } it { is_expected.to be_falsy } end end describe '#terminals' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } subject { environment.terminals } context 'when the environment has terminals' do diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 4f3cd14e941..0b20f4d3154 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -4,7 +4,7 @@ describe KubernetesService, models: true, caching: true do include KubernetesHelpers include ReactiveCachingHelpers - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } let(:service) { project.kubernetes_service } # We use Kubeclient to interactive with the Kubernetes API. It will diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 88d5d14f855..8be99bbf3ee 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1719,7 +1719,7 @@ describe Project, models: true do end context 'when project has a deployment service' do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } it 'returns variables from this service' do expect(project.deployment_variables).to include( diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb index 5f4453c15d6..c6009e25713 100644 --- a/spec/workers/reactive_caching_worker_spec.rb +++ b/spec/workers/reactive_caching_worker_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ReactiveCachingWorker do - let(:project) { create(:kubernetes_project) } + let(:project) { create(:empty_project, :kubernetes) } let(:service) { project.deployment_service } subject { described_class.new.perform("KubernetesService", service.id) } -- cgit v1.2.1 From 15d83f6ae2e3b52a79e761a63c86907a6161acec Mon Sep 17 00:00:00 2001 From: Makoto Scott-Hinkle Date: Sat, 1 Oct 2016 13:53:08 -0700 Subject: Filter protocol-relative URLs in ExternalLinkFilter. Fixes issue #22742. --- spec/lib/banzai/filter/external_link_filter_spec.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'spec') diff --git a/spec/lib/banzai/filter/external_link_filter_spec.rb b/spec/lib/banzai/filter/external_link_filter_spec.rb index 167397c736b..d9e4525cb28 100644 --- a/spec/lib/banzai/filter/external_link_filter_spec.rb +++ b/spec/lib/banzai/filter/external_link_filter_spec.rb @@ -80,4 +80,18 @@ describe Banzai::Filter::ExternalLinkFilter, lib: true do expect(filter(act).to_html).to eq(exp) end end + + context 'for protocol-relative links' do + let(:doc) { filter %q(

Google

) } + + it 'adds rel="nofollow" to external links' do + expect(doc.at_css('a')).to have_attribute('rel') + expect(doc.at_css('a')['rel']).to include 'nofollow' + end + + it 'adds rel="noreferrer" to external links' do + expect(doc.at_css('a')).to have_attribute('rel') + expect(doc.at_css('a')['rel']).to include 'noreferrer' + end + end end -- cgit v1.2.1 From 3cb8f01b9a33925bd65347f4a97c6db2f787589c Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 21 Dec 2016 21:13:13 +0100 Subject: Added Autodeploy script for OpenShift --- spec/features/auto_deploy_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'spec') diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb index 92c5b1cbb3b..e581aa411b0 100644 --- a/spec/features/auto_deploy_spec.rb +++ b/spec/features/auto_deploy_spec.rb @@ -37,7 +37,7 @@ describe 'Auto deploy' do click_button 'Choose a GitLab CI Yaml template' within '.gitlab-ci-yml-selector' do - expect(page).to have_content('Kubernetes') + expect(page).to have_content('OpenShift') end end @@ -45,7 +45,7 @@ describe 'Auto deploy' do click_link 'Set up autodeploy' click_button 'Choose a GitLab CI Yaml template' within '.gitlab-ci-yml-selector' do - click_on 'Kubernetes' + click_on 'OpenShift' end wait_for_ajax click_button 'Commit Changes' -- cgit v1.2.1 From 4a1e1281ac862a0c86d62473ab09d559c7ec5485 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 21 Dec 2016 21:25:23 +0100 Subject: Revert conflicting EE changes --- spec/factories/projects.rb | 26 +++++++++++----------- spec/features/auto_deploy_spec.rb | 10 ++++++++- spec/features/environment_spec.rb | 2 +- spec/features/environments_spec.rb | 2 +- spec/models/environment_spec.rb | 6 ++--- .../project_services/kubernetes_service_spec.rb | 2 +- spec/models/project_spec.rb | 2 +- spec/workers/reactive_caching_worker_spec.rb | 2 +- 8 files changed, 30 insertions(+), 22 deletions(-) (limited to 'spec') diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb index f4ab732caa4..f7fa834d7a2 100644 --- a/spec/factories/projects.rb +++ b/spec/factories/projects.rb @@ -48,19 +48,6 @@ FactoryGirl.define do end end - trait :kubernetes do - after :create do |project| - project.create_kubernetes_service( - active: true, - properties: { - namespace: project.path, - api_url: 'https://kubernetes.example.com/api', - token: 'a' * 40, - } - ) - end - end - # Nest Project Feature attributes transient do wiki_access_level ProjectFeature::ENABLED @@ -150,4 +137,17 @@ FactoryGirl.define do ) end end + + factory :kubernetes_project, parent: :empty_project do + after :create do |project| + project.create_kubernetes_service( + active: true, + properties: { + namespace: project.path, + api_url: 'https://kubernetes.example.com', + token: 'a' * 40, + } + ) + end + end end diff --git a/spec/features/auto_deploy_spec.rb b/spec/features/auto_deploy_spec.rb index e581aa411b0..92f1ab90881 100644 --- a/spec/features/auto_deploy_spec.rb +++ b/spec/features/auto_deploy_spec.rb @@ -4,9 +4,17 @@ describe 'Auto deploy' do include WaitForAjax let(:user) { create(:user) } - let(:project) { create(:project, :kubernetes) } + let(:project) { create(:project) } before do + project.create_kubernetes_service( + active: true, + properties: { + namespace: project.path, + api_url: 'https://kubernetes.example.com', + token: 'a' * 40, + } + ) project.team << [user, :master] login_as user end diff --git a/spec/features/environment_spec.rb b/spec/features/environment_spec.rb index c7411f1f4ac..56f6cd2e095 100644 --- a/spec/features/environment_spec.rb +++ b/spec/features/environment_spec.rb @@ -93,7 +93,7 @@ feature 'Environment', :feature do end context 'with terminal' do - let(:project) { create(:empty_project, :kubernetes, :test_repo) } + let(:project) { create(:kubernetes_project, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/features/environments_spec.rb b/spec/features/environments_spec.rb index e1387e44be8..72b984cfab8 100644 --- a/spec/features/environments_spec.rb +++ b/spec/features/environments_spec.rb @@ -151,7 +151,7 @@ feature 'Environments page', :feature, :js do end context 'with terminal' do - let(:project) { create(:empty_project, :kubernetes, :test_repo) } + let(:project) { create(:kubernetes_project, :test_repo) } context 'for project master' do let(:role) { :master } diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 2aa63d7bcc3..93eb402e060 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -200,7 +200,7 @@ describe Environment, models: true do context 'when the enviroment is available' do context 'with a deployment service' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } context 'and a deployment' do let!(:deployment) { create(:deployment, environment: environment) } @@ -218,14 +218,14 @@ describe Environment, models: true do end context 'when the environment is unavailable' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } before { environment.stop } it { is_expected.to be_falsy } end end describe '#terminals' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } subject { environment.terminals } context 'when the environment has terminals' do diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 0b20f4d3154..4f3cd14e941 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -4,7 +4,7 @@ describe KubernetesService, models: true, caching: true do include KubernetesHelpers include ReactiveCachingHelpers - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } let(:service) { project.kubernetes_service } # We use Kubeclient to interactive with the Kubernetes API. It will diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 8be99bbf3ee..88d5d14f855 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1719,7 +1719,7 @@ describe Project, models: true do end context 'when project has a deployment service' do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } it 'returns variables from this service' do expect(project.deployment_variables).to include( diff --git a/spec/workers/reactive_caching_worker_spec.rb b/spec/workers/reactive_caching_worker_spec.rb index c6009e25713..5f4453c15d6 100644 --- a/spec/workers/reactive_caching_worker_spec.rb +++ b/spec/workers/reactive_caching_worker_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe ReactiveCachingWorker do - let(:project) { create(:empty_project, :kubernetes) } + let(:project) { create(:kubernetes_project) } let(:service) { project.deployment_service } subject { described_class.new.perform("KubernetesService", service.id) } -- cgit v1.2.1