diff options
Diffstat (limited to 'spec')
115 files changed, 3769 insertions, 1119 deletions
diff --git a/spec/contexts/filter_context_spec.rb b/spec/contexts/filter_context_spec.rb deleted file mode 100644 index db27742b9b5..00000000000 --- a/spec/contexts/filter_context_spec.rb +++ /dev/null @@ -1,59 +0,0 @@ -require 'spec_helper' - -describe FilterContext do - - let(:user) { create :user } - let(:user2) { create :user } - let(:project1) { create(:project, creator_id: user.id) } - let(:project2) { create(:project, creator_id: user.id) } - let(:merge_request1) { create(:merge_request, author_id: user.id, source_project: project1, target_project: project2) } - let(:merge_request2) { create(:merge_request, author_id: user.id, source_project: project2, target_project: project1) } - let(:merge_request3) { create(:merge_request, author_id: user.id, source_project: project2, target_project: project2) } - let(:merge_request4) { create(:merge_request, author_id: user2.id, source_project: project2, target_project: project2, target_branch:"notes_refactoring") } - let(:issue1) { create(:issue, assignee_id: user.id, project: project1) } - let(:issue2) { create(:issue, assignee_id: user.id, project: project2) } - let(:issue3) { create(:issue, assignee_id: user2.id, project: project2) } - - describe 'merge requests' do - before :each do - merge_request1 - merge_request2 - merge_request3 - merge_request4 - end - - it 'should by default filter properly' do - merge_requests = user.cared_merge_requests - params ={} - merge_requests = FilterContext.new(merge_requests, params).execute - merge_requests.size.should == 3 - end - - it 'should apply blocks passed in on creation to the filters' do - merge_requests = user.cared_merge_requests - params = {:project_id => project1.id} - merge_requests = FilterContext.new(merge_requests, params).execute - merge_requests.size.should == 1 - end - end - - describe 'issues' do - before :each do - issue1 - issue2 - issue3 - end - it 'should by default filter projects properly' do - issues = user.assigned_issues - params = {} - issues = FilterContext.new(issues, params).execute - issues.size.should == 2 - end - it 'should apply blocks passed in on creation to the filters' do - issues = user.assigned_issues - params = {:project_id => project1.id} - issues = FilterContext.new(issues, params).execute - issues.size.should == 1 - end - end -end diff --git a/spec/contexts/projects_create_context_spec.rb b/spec/contexts/projects_create_context_spec.rb deleted file mode 100644 index 8b2a49dbee5..00000000000 --- a/spec/contexts/projects_create_context_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -require 'spec_helper' - -describe Projects::CreateContext do - before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } - after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } - - describe :create_by_user do - before do - @user = create :user - @opts = { - name: "GitLab", - namespace: @user.namespace - } - end - - context 'user namespace' do - before do - @project = create_project(@user, @opts) - end - - it { @project.should be_valid } - it { @project.owner.should == @user } - it { @project.namespace.should == @user.namespace } - end - - context 'group namespace' do - before do - @group = create :group - @group.add_owner(@user) - - @opts.merge!(namespace_id: @group.id) - @project = create_project(@user, @opts) - end - - it { @project.should be_valid } - it { @project.owner.should == @group } - it { @project.namespace.should == @group } - end - - context 'respect configured public setting' do - before(:each) do - @settings = double("settings") - @settings.stub(:issues) { true } - @settings.stub(:merge_requests) { true } - @settings.stub(:wiki) { true } - @settings.stub(:wall) { true } - @settings.stub(:snippets) { true } - stub_const("Settings", Class.new) - Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings) - end - - context 'should be public when setting is public' do - before do - @settings.stub(:public) { true } - @project = create_project(@user, @opts) - end - - it { @project.public.should be_true } - end - - context 'should be private when setting is not public' do - before do - @settings.stub(:public) { false } - @project = create_project(@user, @opts) - end - - it { @project.public.should be_false } - end - end - end - - def create_project(user, opts) - Projects::CreateContext.new(user, opts).execute - end -end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index d528d12c66c..e1c0269b295 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -8,7 +8,7 @@ describe ApplicationController do it 'should redirect if the user is over their password expiry' do user.password_expires_at = Time.new(2002) user.ldap_user?.should be_false - controller.stub!(:current_user).and_return(user) + controller.stub(:current_user).and_return(user) controller.should_receive(:redirect_to) controller.should_receive(:new_profile_password_path) controller.send(:check_password_expiration) @@ -17,15 +17,15 @@ describe ApplicationController do it 'should not redirect if the user is under their password expiry' do user.password_expires_at = Time.now + 20010101 user.ldap_user?.should be_false - controller.stub!(:current_user).and_return(user) + controller.stub(:current_user).and_return(user) controller.should_not_receive(:redirect_to) controller.send(:check_password_expiration) end it 'should not redirect if the user is over their password expiry but they are an ldap user' do user.password_expires_at = Time.new(2002) - user.stub!(:ldap_user?).and_return(true) - controller.stub!(:current_user).and_return(user) + user.stub(:ldap_user?).and_return(true) + controller.stub(:current_user).and_return(user) controller.should_not_receive(:redirect_to) controller.send(:check_password_expiration) end diff --git a/spec/controllers/blob_controller_spec.rb b/spec/controllers/blob_controller_spec.rb index 479d8fc1a1d..cea6922e1c3 100644 --- a/spec/controllers/blob_controller_spec.rb +++ b/spec/controllers/blob_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::BlobController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/controllers/commit_controller_spec.rb b/spec/controllers/commit_controller_spec.rb index fdf0884f4e2..f5822157ea4 100644 --- a/spec/controllers/commit_controller_spec.rb +++ b/spec/controllers/commit_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::CommitController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } let(:commit) { project.repository.commit("master") } diff --git a/spec/controllers/commits_controller_spec.rb b/spec/controllers/commits_controller_spec.rb index 8263afc97a2..fbf4f29acfd 100644 --- a/spec/controllers/commits_controller_spec.rb +++ b/spec/controllers/commits_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::CommitsController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/controllers/merge_requests_controller_spec.rb b/spec/controllers/merge_requests_controller_spec.rb index 69708edd8b1..1502bded97f 100644 --- a/spec/controllers/merge_requests_controller_spec.rb +++ b/spec/controllers/merge_requests_controller_spec.rb @@ -1,9 +1,9 @@ require 'spec_helper' describe Projects::MergeRequestsController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } - let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project, target_branch: "bcf03b5d~3", source_branch: "bcf03b5d") } + let(:merge_request) { create(:merge_request_with_diffs, target_project: project, source_project: project, target_branch: "stable", source_branch: "master") } before do sign_in(user) @@ -61,7 +61,7 @@ describe Projects::MergeRequestsController do it "should really be a git email patch with commit" do get :show, project_id: project.to_param, id: merge_request.iid, format: format - expect(response.body[0..100]).to start_with("From #{merge_request.commits.last.id}") + expect(response.body[0..100]).to start_with("From 6ea87c47f0f8a24ae031c3fff17bc913889ecd00") end it "should contain git diffs" do diff --git a/spec/controllers/profile_keys_controller_spec.rb b/spec/controllers/profile_keys_controller_spec.rb new file mode 100644 index 00000000000..593d3e9eb56 --- /dev/null +++ b/spec/controllers/profile_keys_controller_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe Profiles::KeysController do + let(:user) { create(:user) } + + describe "#get_keys" do + describe "non existant user" do + it "should generally not work" do + get :get_keys, username: 'not-existent' + + expect(response).not_to be_success + end + end + + describe "user with no keys" do + it "should generally work" do + get :get_keys, username: user.username + + expect(response).to be_success + end + + it "should render all keys separated with a new line" do + get :get_keys, username: user.username + + expect(response.body).to eq("") + end + + it "should respond with text/plain content type" do + get :get_keys, username: user.username + expect(response.content_type).to eq("text/plain") + end + end + + describe "user with keys" do + before do + user.keys << create(:key) + user.keys << create(:another_key) + end + + it "should generally work" do + get :get_keys, username: user.username + + expect(response).to be_success + end + + it "should render all keys separated with a new line" do + get :get_keys, username: user.username + + expect(response.body).not_to eq("") + expect(response.body).to eq(user.all_ssh_keys.join("\n")) + end + + it "should respond with text/plain content type" do + get :get_keys, username: user.username + expect(response.content_type).to eq("text/plain") + end + end + end +end diff --git a/spec/controllers/tree_controller_spec.rb b/spec/controllers/tree_controller_spec.rb index bb1232e6264..479118a3465 100644 --- a/spec/controllers/tree_controller_spec.rb +++ b/spec/controllers/tree_controller_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Projects::TreeController do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } before do diff --git a/spec/factories.rb b/spec/factories.rb index 624cb0f7654..148477d6389 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -15,7 +15,7 @@ FactoryGirl.define do email { Faker::Internet.email } name sequence(:username) { |n| "#{Faker::Internet.user_name}#{n}" } - password "123456" + password "12345678" password_confirmation { password } confirmed_at { Time.now } confirmation_token { nil } @@ -27,49 +27,50 @@ FactoryGirl.define do factory :admin, traits: [:admin] end - factory :project do + factory :empty_project, class: 'Project' do sequence(:name) { |n| "project#{n}" } path { name.downcase.gsub(/\s/, '_') } namespace creator - trait :source do - sequence(:name) { |n| "source project#{n}" } + trait :public do + visibility_level Gitlab::VisibilityLevel::PUBLIC end - trait :target do - sequence(:name) { |n| "target project#{n}" } - end - - factory :source_project, traits: [:source] - factory :target_project, traits: [:target] - end - - - factory :redmine_project, parent: :project do - issues_tracker { "redmine" } - issues_tracker_id { "project_name_in_redmine" } - end - factory :project_with_code, parent: :project do - path { 'gitlabhq' } - - trait :source_path do - path { 'source_gitlabhq' } + trait :internal do + visibility_level Gitlab::VisibilityLevel::INTERNAL end - trait :target_path do - path { 'target_gitlabhq' } + trait :private do + visibility_level Gitlab::VisibilityLevel::PRIVATE end + end - factory :source_project_with_code, traits: [:source, :source_path] - factory :target_project_with_code, traits: [:target, :target_path] + # Generates a test repository from the repository stored under `spec/seed_project.tar.gz`. + # Once you run `rake gitlab:setup`, you can see what the repository looks like under `tmp/repositories/gitlabhq`. + # In order to modify files in the repository, you must untar the seed, modify and remake the tar. + # Before recompressing, do not forget to `git checkout master`. + # After recompressing, you need to run `RAILS_ENV=test bundle exec rake gitlab:setup` to regenerate the seeds under tmp. + # + # If you want to modify the repository only for an specific type of tests, e.g., markdown tests, + # consider using a feature branch to reduce the chances of collision with other tests. + # Create a new commit, and use the same commit message that you will use for the change in the main repo. + # Changing the commig message and SHA of branch `master` may break tests. + factory :project, parent: :empty_project do + path { 'gitlabhq' } after :create do |project| TestEnv.clear_repo_dir(project.namespace, project.path) + TestEnv.reset_satellite_dir TestEnv.create_repo(project.namespace, project.path) end end + factory :redmine_project, parent: :project do + issues_tracker { "redmine" } + issues_tracker_id { "project_name_in_redmine" } + end + factory :group do sequence(:name) { |n| "group#{n}" } path { name.downcase.gsub(/\s/, '_') } @@ -108,25 +109,45 @@ FactoryGirl.define do factory :merge_request do title author - source_project factory: :source_project_with_code - target_project factory: :target_project_with_code + source_project factory: :project + target_project { source_project } + + # → git log stable..master --pretty=oneline + # b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828 tree css fixes + # 8716fc78f3c65bbf7bcf7b574febd583bc5d2812 Added loading animation for notes + # cd5c4bac5042c5469dcdf7e7b2f768d3c6fd7088 notes count for wall + # 8470d70da67355c9c009e4401746b1d5410af2e3 notes controller refactored + # 1e689bfba39525ead225eaf611948cfbe8ac34cf fixed notes logic + # f0f14c8eaba69ebddd766498a9d0b0e79becd633 finished scss refactoring + # 3a4b4fb4cde7809f033822a171b9feae19d41fff Moving ui styles to one scss file, Added ui class to body + # 065c200c33f68c2bb781e35a43f9dc8138a893b5 removed unnecessary hr tags & titles + # 1e8b111be85df0db6c8000ef9a710bc0221eae83 Merge branch 'master' of github.com:gitlabhq/gitlabhq + # f403da73f5e62794a0447aca879360494b08f678 Fixed ajax loading image. Fixed wrong wording + # e6ea73c77600d413d370249b8e392734f7d1dbee Merge pull request #468 from bencevans/patch-1 + # 4a3c05b69355deee25767a74d0512ec4b510d4ef Merge pull request #470 from bgondy/patch-1 + # 0347fe2412eb51d3efeccc35210e9268bc765ac5 Update app/views/projects/team.html.haml + # 2b5c61bdece1f7eb2b901ceea7d364065cdf76ac Title for a link fixed + # 460eeb13b7560b40104044973ff933b1a6dbbcaa Increased count of notes loaded when visit wall page + # 21c141afb1c53a9180a99d2cca29ffa613eb7e3a Merge branch 'notes_refactoring' + # 292a41cbe295f16f7148913b31eb0fb91f3251c3 Fixed comments for snippets. Tests fixed + # d41d8ffb02fa74fd4571603548bd7e401ec99e0c Reply button, Comments for Merge Request diff + # b1a36b552be2a7a6bc57fbed6c52dc6ed82111f8 Merge pull request #466 from skroutz/no-rbenv + # db75dae913e8365453ca231f101b067314a7ea71 Merge pull request #465 from skroutz/branches_commit_link + # 75f040fbfe4b5af23ff004ad3207c3976df097a8 Don't enforce rbenv version + # e42fb4fda475370dcb0d8f8f1268bfdc7a0cc437 Fix broken commit link in branches page + # 215a01f63ccdc085f75a48f6f7ab6f2b15b5852c move notes login to one controller + # 81092c01984a481e312de10a28e3f1a6dda182a3 Status codes for errors, New error pages + # 7d279f9302151e3c8f4c5df9c5200a72799409b9 better error handling for not found resource, gitolite error + # 9e6d0710e927aa8ea834b8a9ae9f277be617ac7d Merge pull request #443 from CedricGatay/fix/incorrectLineNumberingInDiff + # 6ea87c47f0f8a24ae031c3fff17bc913889ecd00 Incorrect line numbering in diff + # + # → git log master..stable --pretty=oneline + # empty + source_branch "master" target_branch "stable" - # pick 3 commits "at random" (from bcf03b5d~3 to bcf03b5d) trait :with_diffs do - target_branch "master" # pretend bcf03b5d~3 - source_branch "stable" # pretend bcf03b5d - st_commits do - [ - source_project.repository.commit('bcf03b5d').to_hash, - source_project.repository.commit('bcf03b5d~1').to_hash, - source_project.repository.commit('bcf03b5d~2').to_hash - ] - end - st_diffs do - source_project.repo.diff("bcf03b5d~3", "bcf03b5d") - end end trait :closed do @@ -137,6 +158,11 @@ FactoryGirl.define do state :reopened end + trait :simple do + source_branch "simple_merge_request" + target_branch "master" + end + factory :closed_merge_request, traits: [:closed] factory :reopened_merge_request, traits: [:reopened] factory :merge_request_with_diffs, traits: [:with_diffs] @@ -152,10 +178,9 @@ FactoryGirl.define do factory :note_on_issue, traits: [:on_issue], aliases: [:votable_note] factory :note_on_merge_request, traits: [:on_merge_request] factory :note_on_merge_request_diff, traits: [:on_merge_request, :on_diff] - factory :note_on_merge_request_with_attachment, traits: [:on_merge_request, :with_attachment] trait :on_commit do - project factory: :project_with_code + project factory: :project commit_id "bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a" noteable_type "Commit" end @@ -165,7 +190,7 @@ FactoryGirl.define do end trait :on_merge_request do - project factory: :project_with_code + project factory: :project noteable_id 1 noteable_type "MergeRequest" end @@ -208,12 +233,31 @@ FactoryGirl.define do end end + factory :another_key do + key do + "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDmTillFzNTrrGgwaCKaSj+QCz81E6jBc/s9av0+3b1Hwfxgkqjl4nAK/OD2NjgyrONDTDfR8cRN4eAAy6nY8GLkOyYBDyuc5nTMqs5z3yVuTwf3koGm/YQQCmo91psZ2BgDFTor8SVEE5Mm1D1k3JDMhDFxzzrOtRYFPci9lskTJaBjpqWZ4E9rDTD2q/QZntCqbC3wE9uSemRQB5f8kik7vD/AD8VQXuzKladrZKkzkONCPWsXDspUitjM8HkQdOf0PsYn1CMUC1xKYbCxkg5TkEosIwGv6CoEArUrdu/4+10LVslq494mAvEItywzrluCLCnwELfW+h/m8UHoVhZ" + end + end + factory :invalid_key do key do "ssh-rsa this_is_invalid_key==" end end end + + factory :email do + user + email do + Faker::Internet.email('alias') + end + + factory :another_email do + email do + Faker::Internet.email('another.alias') + end + end + end factory :milestone do title diff --git a/spec/factories/broadcast_messages.rb b/spec/factories/broadcast_messages.rb new file mode 100644 index 00000000000..6339d5c4003 --- /dev/null +++ b/spec/factories/broadcast_messages.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: broadcast_messages +# +# id :integer not null, primary key +# message :text default(""), not null +# starts_at :datetime +# ends_at :datetime +# alert_type :integer +# created_at :datetime not null +# updated_at :datetime not null +# color :string(255) +# font :string(255) +# + +# Read about factories at https://github.com/thoughtbot/factory_girl + +FactoryGirl.define do + factory :broadcast_message do + message "MyText" + starts_at "2013-11-12 13:43:25" + ends_at "2013-11-12 13:43:25" + alert_type 1 + color "#555555" + font "#BBBBBB" + end +end diff --git a/spec/features/atom/dashboard_issues_spec.rb b/spec/features/atom/dashboard_issues_spec.rb index 6f5d51d16b6..62f44690349 100644 --- a/spec/features/atom/dashboard_issues_spec.rb +++ b/spec/features/atom/dashboard_issues_spec.rb @@ -8,6 +8,11 @@ describe "Dashboard Issues Feed" do let!(:issue1) { create(:issue, author: user, assignee: user, project: project1) } let!(:issue2) { create(:issue, author: user, assignee: user, project: project2) } + before do + project1.team << [user, :master] + project2.team << [user, :master] + end + describe "atom feed" do it "should render atom feed via private token" do visit issues_dashboard_path(:atom, private_token: user.private_token) diff --git a/spec/features/gitlab_flavored_markdown_spec.rb b/spec/features/gitlab_flavored_markdown_spec.rb index 2ea569a6208..a507f0314c6 100644 --- a/spec/features/gitlab_flavored_markdown_spec.rb +++ b/spec/features/gitlab_flavored_markdown_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "GitLab Flavored Markdown" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:issue) { create(:issue, project: project) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } let(:fred) do diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb index 8cb984946b4..b9dab7846b1 100644 --- a/spec/features/issues_spec.rb +++ b/spec/features/issues_spec.rb @@ -43,6 +43,31 @@ describe "Issues" do page.should have_content project.name end end + + end + + describe "Editing issue assignee" do + let!(:issue) do + create(:issue, + author: @user, + assignee: @user, + project: project) + end + + it 'allows user to select unasigned', :js => true do + visit edit_project_issue_path(project, issue) + + page.should have_content "Assign to #{@user.name}" + + page.first('#s2id_issue_assignee_id').click + sleep 2 # wait for ajax stuff to complete + page.first('.user-result').click + + click_button "Save changes" + + page.should have_content "Assignee: Select assignee" + issue.reload.assignee.should be_nil + end end describe "Filter issue" do @@ -95,4 +120,185 @@ describe "Issues" do page.should have_content 'gitlab' end end + + describe 'filter issue' do + titles = ['foo','bar','baz'] + titles.each_with_index do |title, index| + let!(title.to_sym) { create(:issue, title: title, project: project, created_at: Time.now - (index * 60)) } + end + let(:newer_due_milestone) { create(:milestone, due_date: '2013-12-11') } + let(:later_due_milestone) { create(:milestone, due_date: '2013-12-12') } + + it 'sorts by newest' do + visit project_issues_path(project, sort: 'newest') + + first_issue.should include("foo") + last_issue.should include("baz") + end + + it 'sorts by oldest' do + visit project_issues_path(project, sort: 'oldest') + + first_issue.should include("baz") + last_issue.should include("foo") + end + + it 'sorts by most recently updated' do + baz.updated_at = Time.now + 100 + baz.save + visit project_issues_path(project, sort: 'recently_updated') + + first_issue.should include("baz") + end + + it 'sorts by least recently updated' do + baz.updated_at = Time.now - 100 + baz.save + visit project_issues_path(project, sort: 'last_updated') + + first_issue.should include("baz") + end + + describe 'sorting by milestone' do + before :each do + foo.milestone = newer_due_milestone + foo.save + bar.milestone = later_due_milestone + bar.save + end + + it 'sorts by recently due milestone' do + visit project_issues_path(project, sort: 'milestone_due_soon') + + first_issue.should include("foo") + end + + it 'sorts by least recently due milestone' do + visit project_issues_path(project, sort: 'milestone_due_later') + + first_issue.should include("bar") + end + end + + describe 'combine filter and sort' do + let(:user2) { create(:user) } + + before :each do + foo.assignee = user2 + foo.save + bar.assignee = user2 + bar.save + end + + it 'sorts with a filter applied' do + visit project_issues_path(project, sort: 'oldest', assignee_id: user2.id) + + first_issue.should include("bar") + last_issue.should include("foo") + page.should_not have_content 'baz' + end + end + end + + describe 'update assignee from issue#show' do + let(:issue) { create(:issue, project: project, author: @user) } + + context 'by autorized user' do + + it 'with dropdown menu' do + visit project_issue_path(project, issue) + + find('.edit-issue.inline-update #issue_assignee_id').set project.team.members.first.id + click_button 'Update Issue' + + page.should have_content "Assignee:" + page.has_select?('issue_assignee_id', :selected => project.team.members.first.name) + end + end + + context 'by unauthorized user' do + + let(:guest) { create(:user) } + + before :each do + project.team << [[guest], :guest] + issue.assignee = @user + issue.save + end + + it 'shows assignee text' do + logout + login_with guest + + visit project_issue_path(project, issue) + page.should have_content issue.assignee.name + end + end + end + + describe 'update milestone from issue#show' do + let!(:issue) { create(:issue, project: project, author: @user) } + let!(:milestone) { create(:milestone, project: project) } + + context 'by authorized user' do + + it 'with dropdown menu' do + visit project_issue_path(project, issue) + + find('.edit-issue.inline-update').select(milestone.title, from: 'issue_milestone_id') + click_button 'Update Issue' + + page.should have_content "Milestone" + page.has_select?('issue_assignee_id', :selected => milestone.title) + end + end + + context 'by unauthorized user' do + let(:guest) { create(:user) } + + before :each do + project.team << [guest, :guest] + issue.milestone = milestone + issue.save + end + + it 'shows milestone text' do + logout + login_with guest + + visit project_issue_path(project, issue) + page.should have_content milestone.title + end + end + + describe 'removing assignee' do + let(:user2) { create(:user) } + + before :each do + issue.assignee = user2 + issue.save + end + + it 'allows user to remove assignee', :js => true do + visit project_issue_path(project, issue) + page.should have_content "Assignee: #{user2.name}" + + page.first('#s2id_issue_assignee_id').click + sleep 2 # wait for ajax stuff to complete + page.first('.user-result').click + + page.should have_content "Assignee: Unassigned" + sleep 2 # wait for ajax stuff to complete + issue.reload.assignee.should be_nil + end + end + end + + def first_issue + all("ul.issues-list li").first.text + end + + def last_issue + all("ul.issues-list li").last.text + end end diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb index d29bed4dea7..25a86b11fa9 100644 --- a/spec/features/notes_on_merge_requests_spec.rb +++ b/spec/features/notes_on_merge_requests_spec.rb @@ -1,14 +1,12 @@ require 'spec_helper' describe "On a merge request", js: true do - let!(:project) { create(:project_with_code) } - let!(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - let!(:note) { create(:note_on_merge_request_with_attachment, project: project) } + let!(:merge_request) { create(:merge_request, :simple) } + let!(:project) { merge_request.source_project } + let!(:note) { create(:note_on_merge_request, :with_attachment, project: project) } before do - login_as :user - project.team << [@user, :master] - + login_as :admin visit project_merge_request_path(project, merge_request) end @@ -108,7 +106,7 @@ describe "On a merge request", js: true do within("#note_#{note.id}") do should have_css(".note-last-update small") - find(".note-last-update small").text.should match(/Edited just now/) + find(".note-last-update small").text.should match(/Edited less than a minute ago/) end end end @@ -134,22 +132,20 @@ describe "On a merge request", js: true do end end -describe "On a merge request diff", js: true, focus: true do - let!(:project) { create(:source_project_with_code) } - let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } +describe "On a merge request diff", js: true do + let(:merge_request) { create(:merge_request, :with_diffs, :simple) } + let(:project) { merge_request.source_project } before do - login_as :user - project.team << [@user, :master] + login_as :admin visit diffs_project_merge_request_path(project, merge_request) end - subject { page } describe "when adding a note" do before do - find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7"]').click end describe "the notes holder" do @@ -159,22 +155,14 @@ describe "On a merge request diff", js: true, focus: true do end describe "the note form" do - it 'should be valid' do - within(".js-temp-notes-holder") { find("#note_noteable_type").value.should == "MergeRequest" } - within(".js-temp-notes-holder") { find("#note_noteable_id").value.should == merge_request.id.to_s } - within(".js-temp-notes-holder") { find("#note_commit_id").value.should == "" } - within(".js-temp-notes-holder") { find("#note_line_code").value.should == "4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185" } - should have_css(".js-close-discussion-note-form", text: "Cancel") - end - it "shouldn't add a second form for same row" do - find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click + find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7"]').click - should have_css("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185'] + .js-temp-notes-holder form", count: 1) + should have_css("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7'] + .js-temp-notes-holder form", count: 1) end it "should be removed when canceled" do - within(".file form[rel$='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185']") do + within(".diff-file form[rel$='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7']") do find(".js-close-discussion-note-form").trigger("click") end @@ -184,12 +172,9 @@ describe "On a merge request diff", js: true, focus: true do end describe "with muliple note forms" do - let!(:project) { create(:source_project_with_code) } - let!(:merge_request) { create(:merge_request_with_diffs, source_project: project, target_project: project) } - before do - find('a[data-line-code="4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185"]').click - find('a[data-line-code="342e16cbbd482ac2047dc679b2749d248cc1428f_18_17"]').click + find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7"]').click + find('a[data-line-code="8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_10_10"]').click end it { should have_css(".js-temp-notes-holder", count: 2) } @@ -197,12 +182,12 @@ describe "On a merge request diff", js: true, focus: true do describe "previewing them separately" do before do # add two separate texts and trigger previews on both - within("tr[id='4735dfc552ad7bf15ca468adc3cad9d05b624490_185_185'] + .js-temp-notes-holder") do - fill_in "note[note]", with: "One comment on line 185" + within("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7'] + .js-temp-notes-holder") do + fill_in "note[note]", with: "One comment on line 7" find(".js-note-preview-button").trigger("click") end - within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .js-temp-notes-holder") do - fill_in "note[note]", with: "Another comment on line 17" + within("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_10_10'] + .js-temp-notes-holder") do + fill_in "note[note]", with: "Another comment on line 10" find(".js-note-preview-button").trigger("click") end end @@ -210,14 +195,14 @@ describe "On a merge request diff", js: true, focus: true do describe "posting a note" do before do - within("tr[id='342e16cbbd482ac2047dc679b2749d248cc1428f_18_17'] + .js-temp-notes-holder") do - fill_in "note[note]", with: "Another comment on line 17" + within("tr[id='8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_10_10'] + .js-temp-notes-holder") do + fill_in "note[note]", with: "Another comment on line 10" click_button("Add Comment") end end it 'should be added as discussion' do - should have_content("Another comment on line 17") + should have_content("Another comment on line 10") should have_css(".notes_holder") should have_css(".notes_holder .note", count: 1) should have_link("Reply") diff --git a/spec/features/security/group_access_spec.rb b/spec/features/security/group/group_access_spec.rb index dea957962a8..c262d76ab54 100644 --- a/spec/features/security/group_access_spec.rb +++ b/spec/features/security/group/group_access_spec.rb @@ -14,6 +14,7 @@ describe "Group access" do let(:master) { create(:user) } let(:reporter) { create(:user) } let(:guest) { create(:user) } + let(:nonmember) { create(:user) } before do group.add_user(owner, Gitlab::Access::OWNER) diff --git a/spec/features/security/group/internal_group_access_spec.rb b/spec/features/security/group/internal_group_access_spec.rb new file mode 100644 index 00000000000..79a6aee41b5 --- /dev/null +++ b/spec/features/security/group/internal_group_access_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe "Group with internal project access" do + describe "Group" do + let(:group) { create(:group) } + + let(:owner) { create(:owner) } + let(:master) { create(:user) } + let(:reporter) { create(:user) } + let(:guest) { create(:user) } + let(:nonmember) { create(:user) } + + before do + group.add_user(owner, Gitlab::Access::OWNER) + group.add_user(master, Gitlab::Access::MASTER) + group.add_user(reporter, Gitlab::Access::REPORTER) + group.add_user(guest, Gitlab::Access::GUEST) + + create(:project, :internal, group: group) + end + + describe "GET /groups/:path" do + subject { group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /groups/:path/issues" do + subject { issues_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /groups/:path/merge_requests" do + subject { merge_requests_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /groups/:path/members" do + subject { members_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /groups/:path/edit" do + subject { edit_group_path(group) } + + it { should be_allowed_for owner } + it { should be_denied_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + end +end diff --git a/spec/features/security/group/mixed_group_access_spec.rb b/spec/features/security/group/mixed_group_access_spec.rb new file mode 100644 index 00000000000..028cd32d2bb --- /dev/null +++ b/spec/features/security/group/mixed_group_access_spec.rb @@ -0,0 +1,83 @@ +require 'spec_helper' + +describe "Group access" do + describe "Group" do + let(:group) { create(:group) } + + let(:owner) { create(:owner) } + let(:master) { create(:user) } + let(:reporter) { create(:user) } + let(:guest) { create(:user) } + let(:nonmember) { create(:user) } + + before do + group.add_user(owner, Gitlab::Access::OWNER) + group.add_user(master, Gitlab::Access::MASTER) + group.add_user(reporter, Gitlab::Access::REPORTER) + group.add_user(guest, Gitlab::Access::GUEST) + + create(:project, :internal, path: "internal_project", group: group) + create(:project, :public, path: "public_project", group: group) + end + + describe "GET /groups/:path" do + subject { group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/issues" do + subject { issues_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/merge_requests" do + subject { merge_requests_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/members" do + subject { members_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/edit" do + subject { edit_group_path(group) } + + it { should be_allowed_for owner } + it { should be_denied_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + end +end diff --git a/spec/features/security/group/public_group_access_spec.rb b/spec/features/security/group/public_group_access_spec.rb new file mode 100644 index 00000000000..f0ed7649eb5 --- /dev/null +++ b/spec/features/security/group/public_group_access_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe "Group with public project access" do + describe "Group" do + let(:group) { create(:group) } + + let(:owner) { create(:owner) } + let(:master) { create(:user) } + let(:reporter) { create(:user) } + let(:guest) { create(:user) } + let(:nonmember) { create(:user) } + + before do + group.add_user(owner, Gitlab::Access::OWNER) + group.add_user(master, Gitlab::Access::MASTER) + group.add_user(reporter, Gitlab::Access::REPORTER) + group.add_user(guest, Gitlab::Access::GUEST) + + create(:project, :public, group: group) + end + + describe "GET /groups/:path" do + subject { group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/issues" do + subject { issues_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/merge_requests" do + subject { merge_requests_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/members" do + subject { members_group_path(group) } + + it { should be_allowed_for owner } + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_allowed_for :visitor } + end + + describe "GET /groups/:path/edit" do + subject { edit_group_path(group) } + + it { should be_allowed_for owner } + it { should be_denied_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + end +end diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb new file mode 100644 index 00000000000..152cf66dcfd --- /dev/null +++ b/spec/features/security/project/internal_access_spec.rb @@ -0,0 +1,246 @@ +require 'spec_helper' + +describe "Internal Project Access" do + let(:project) { create(:project, :internal) } + + let(:master) { create(:user) } + let(:guest) { create(:user) } + let(:reporter) { create(:user) } + + before do + # full access + project.team << [master, :master] + + # readonly + project.team << [reporter, :reporter] + end + + describe "Project should be internal" do + subject { project } + + its(:internal?) { should be_true } + end + + describe "GET /:project_path" do + subject { project_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/tree/master" do + subject { project_tree_path(project, project.repository.root_ref) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/commits/master" do + subject { project_commits_path(project, project.repository.root_ref, limit: 1) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/commit/:sha" do + subject { project_commit_path(project, project.repository.commit) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/compare" do + subject { project_compare_index_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/team" do + subject { project_team_index_path(project) } + + it { should be_allowed_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/wall" do + subject { project_wall_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/blob" do + before do + commit = project.repository.commit + path = commit.tree.contents.select { |i| i.is_a?(Grit::Blob) }.first.name + @blob_path = project_blob_path(project, File.join(commit.id, path)) + end + + it { @blob_path.should be_allowed_for master } + it { @blob_path.should be_allowed_for reporter } + it { @blob_path.should be_allowed_for :admin } + it { @blob_path.should be_allowed_for guest } + it { @blob_path.should be_allowed_for :user } + it { @blob_path.should be_denied_for :visitor } + end + + describe "GET /:project_path/edit" do + subject { edit_project_path(project) } + + it { should be_allowed_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/deploy_keys" do + subject { project_deploy_keys_path(project) } + + it { should be_allowed_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/issues" do + subject { project_issues_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/snippets" do + subject { project_snippets_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/snippets/new" do + subject { new_project_snippet_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/merge_requests" do + subject { project_merge_requests_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/merge_requests/new" do + subject { new_project_merge_request_path(project) } + + it { should be_allowed_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/branches/recent" do + subject { recent_project_branches_path(project) } + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/branches" do + subject { project_branches_path(project) } + + before do + # Speed increase + Project.any_instance.stub(:branches).and_return([]) + end + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/tags" do + subject { project_tags_path(project) } + + before do + # Speed increase + Project.any_instance.stub(:tags).and_return([]) + end + + it { should be_allowed_for master } + it { should be_allowed_for reporter } + it { should be_allowed_for :admin } + it { should be_allowed_for guest } + it { should be_allowed_for :user } + it { should be_denied_for :visitor } + end + + describe "GET /:project_path/hooks" do + subject { project_hooks_path(project) } + + it { should be_allowed_for master } + it { should be_denied_for reporter } + it { should be_allowed_for :admin } + it { should be_denied_for guest } + it { should be_denied_for :user } + it { should be_denied_for :visitor } + end +end diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb index 7f3f8c50f02..0402ff39735 100644 --- a/spec/features/security/project/private_access_spec.rb +++ b/spec/features/security/project/private_access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "Private Project Access" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:master) { create(:user) } let(:guest) { create(:user) } @@ -15,6 +15,12 @@ describe "Private Project Access" do project.team << [reporter, :reporter] end + describe "Project should be private" do + subject { project } + + its(:private?) { should be_true } + end + describe "GET /:project_path" do subject { project_path(project) } diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb index 267643fd8ef..7e6a39fad69 100644 --- a/spec/features/security/project/public_access_spec.rb +++ b/spec/features/security/project/public_access_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe "Public Project Access" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:master) { create(:user) } let(:guest) { create(:user) } @@ -9,7 +9,7 @@ describe "Public Project Access" do before do # public project - project.public = true + project.visibility_level = Gitlab::VisibilityLevel::PUBLIC project.save! # full access diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb new file mode 100644 index 00000000000..7489e56f423 --- /dev/null +++ b/spec/finders/issues_finder_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe IssuesFinder do + let(:user) { create :user } + let(:user2) { create :user } + let(:project1) { create(:project) } + let(:project2) { create(:project) } + let(:issue1) { create(:issue, assignee: user, project: project1) } + let(:issue2) { create(:issue, assignee: user, project: project2) } + let(:issue3) { create(:issue, assignee: user2, project: project2) } + + before do + project1.team << [user, :master] + project2.team << [user, :developer] + project2.team << [user2, :developer] + end + + describe :execute do + before :each do + issue1 + issue2 + issue3 + end + + it 'should filter by all' do + params = { scope: "all", state: 'opened' } + issues = IssuesFinder.new.execute(user, params) + issues.size.should == 3 + end + + it 'should filter by assignee' do + params = { scope: "assigned-to-me", state: 'opened' } + issues = IssuesFinder.new.execute(user, params) + issues.size.should == 2 + end + + it 'should filter by project' do + params = { scope: "assigned-to-me", state: 'opened', project_id: project1.id } + issues = IssuesFinder.new.execute(user, params) + issues.size.should == 1 + end + + it 'should be empty for unauthorized user' do + params = { scope: "all", state: 'opened' } + issues = IssuesFinder.new.execute(nil, params) + issues.size.should be_zero + end + + it 'should not include unauthorized issues' do + params = { scope: "all", state: 'opened' } + issues = IssuesFinder.new.execute(user2, params) + issues.size.should == 2 + issues.should_not include(issue1) + issues.should include(issue2) + issues.should include(issue3) + end + end +end diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb new file mode 100644 index 00000000000..0bd2ccafcc1 --- /dev/null +++ b/spec/finders/merge_requests_finder_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe MergeRequestsFinder do + let(:user) { create :user } + let(:user2) { create :user } + + let(:project1) { create(:project) } + let(:project2) { create(:project) } + + let!(:merge_request1) { create(:merge_request, :simple, author: user, source_project: project1, target_project: project2) } + let!(:merge_request2) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project1) } + let!(:merge_request3) { create(:merge_request, :simple, author: user, source_project: project2, target_project: project2) } + + before do + project1.team << [user, :master] + project2.team << [user, :developer] + project2.team << [user2, :developer] + end + + describe "#execute" do + it 'should filter by scope' do + params = { scope: 'authored', state: 'opened' } + merge_requests = MergeRequestsFinder.new.execute(user, params) + merge_requests.size.should == 3 + end + + it 'should filter by project' do + params = { project_id: project1.id, scope: 'authored', state: 'opened' } + merge_requests = MergeRequestsFinder.new.execute(user, params) + merge_requests.size.should == 1 + end + end +end diff --git a/spec/finders/projects_finder_spec.rb b/spec/finders/projects_finder_spec.rb new file mode 100644 index 00000000000..6e3ae4d615b --- /dev/null +++ b/spec/finders/projects_finder_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe ProjectsFinder do + let(:user) { create :user } + let(:group) { create :group } + + let(:project1) { create(:empty_project, :public, group: group) } + let(:project2) { create(:empty_project, :internal, group: group) } + let(:project3) { create(:empty_project, :private, group: group) } + let(:project4) { create(:empty_project, :private, group: group) } + + context 'non authenticated' do + subject { ProjectsFinder.new.execute(nil, group: group) } + + it { should include(project1) } + it { should_not include(project2) } + it { should_not include(project3) } + it { should_not include(project4) } + end + + context 'authenticated' do + subject { ProjectsFinder.new.execute(user, group: group) } + + it { should include(project1) } + it { should include(project2) } + it { should_not include(project3) } + it { should_not include(project4) } + end + + context 'authenticated, project member' do + before { project3.team << [user, :developer] } + + subject { ProjectsFinder.new.execute(user, group: group) } + + it { should include(project1) } + it { should include(project2) } + it { should include(project3) } + it { should_not include(project4) } + end + + context 'authenticated, group member' do + before { group.add_user(user, Gitlab::Access::DEVELOPER) } + + subject { ProjectsFinder.new.execute(user, group: group) } + + it { should include(project1) } + it { should include(project2) } + it { should include(project3) } + it { should include(project4) } + end +end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index d63a2de8806..61c561335e5 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe ApplicationHelper do describe 'current_controller?' do before do - controller.stub!(:controller_name).and_return('foo') + controller.stub(:controller_name).and_return('foo') end it "returns true when controller matches argument" do @@ -22,7 +22,7 @@ describe ApplicationHelper do describe 'current_action?' do before do - stub!(:action_name).and_return('foo') + allow(self).to receive(:action_name).and_return('foo') end it "returns true when action matches argument" do @@ -38,7 +38,24 @@ describe ApplicationHelper do current_action?(:baz, :bar, :foo).should be_true end end - + + describe "group_icon" do + avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') + + it "should return an url for the avatar" do + group = create(:group) + group.avatar = File.open(avatar_file_path) + group.save! + group_icon(group.path).to_s.should == "/uploads/group/avatar/#{ group.id }/gitlab_logo.png" + end + + it "should give default avatar_icon when no avatar is present" do + group = create(:group) + group.save! + group_icon(group.path).should match("group_avatar.png") + end + end + describe "avatar_icon" do avatar_file_path = File.join(Rails.root, 'public', 'gitlab_logo.png') @@ -52,7 +69,7 @@ describe ApplicationHelper do it "should call gravatar_icon when no avatar is present" do user = create(:user) user.save! - stub!(:gravatar_icon).and_return('gravatar_method_called') + allow(self).to receive(:gravatar_icon).and_return('gravatar_method_called') avatar_icon(user.email).to_s.should == "gravatar_method_called" end end @@ -62,50 +79,88 @@ describe ApplicationHelper do it "should return a generic avatar path when Gravatar is disabled" do Gitlab.config.gravatar.stub(:enabled).and_return(false) - gravatar_icon(user_email).should == 'no_avatar.png' + gravatar_icon(user_email).should == '/assets/no_avatar.png' end it "should return a generic avatar path when email is blank" do - gravatar_icon('').should == 'no_avatar.png' + gravatar_icon('').should == '/assets/no_avatar.png' end it "should return default gravatar url" do - stub!(:request).and_return(double(:ssl? => false)) + allow(self).to receive(:request).and_return(double(:ssl? => false)) gravatar_icon(user_email).should match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118') end it "should use SSL when appropriate" do - stub!(:request).and_return(double(:ssl? => true)) + allow(self).to receive(:request).and_return(double(:ssl? => true)) gravatar_icon(user_email).should match('https://secure.gravatar.com') end it "should return custom gravatar path when gravatar_url is set" do - stub!(:request).and_return(double(:ssl? => false)) + allow(self).to receive(:request).and_return(double(:ssl? => false)) Gitlab.config.gravatar.stub(:plain_url).and_return('http://example.local/?s=%{size}&hash=%{hash}') gravatar_icon(user_email, 20).should == 'http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118' end it "should accept a custom size" do - stub!(:request).and_return(double(:ssl? => false)) + allow(self).to receive(:request).and_return(double(:ssl? => false)) gravatar_icon(user_email, 64).should match(/\?s=64/) end it "should use default size when size is wrong" do - stub!(:request).and_return(double(:ssl? => false)) + allow(self).to receive(:request).and_return(double(:ssl? => false)) gravatar_icon(user_email, nil).should match(/\?s=40/) end it "should be case insensitive" do - stub!(:request).and_return(double(:ssl? => false)) + allow(self).to receive(:request).and_return(double(:ssl? => false)) gravatar_icon(user_email).should == gravatar_icon(user_email.upcase + " ") end + end + + describe "grouped_options_refs" do + # Override Rails' grouped_options_for_select helper since HTML is harder to work with + def grouped_options_for_select(options, *args) + options + end + + let(:options) { grouped_options_refs } + before do + # Must be an instance variable + @project = create(:project) + end + + it "includes a list of branch names" do + options[0][0].should == 'Branches' + options[0][1].should include('master', 'stable') + end + + it "includes a list of tag names" do + options[1][0].should == 'Tags' + options[1][1].should include('v0.9.4','v1.2.0') + end + + it "includes a specific commit ref if defined" do + # Must be an instance variable + @ref = '2ed06dc41dbb5936af845b87d79e05bbf24c73b8' + + options[2][0].should == 'Commit' + options[2][1].should == [@ref] + end + + it "sorts tags in a natural order" do + # Stub repository.tag_names to make sure we get some valid testing data + expect(@project.repository).to receive(:tag_names).and_return(["v1.0.9", "v1.0.10", "v2.0", "v3.1.4.2", "v1.0.9a"]) + + options[1][1].should == ["v3.1.4.2", "v2.0", "v1.0.10", "v1.0.9a", "v1.0.9"] + end end describe "user_color_scheme_class" do context "with current_user is nil" do it "should return a string" do - stub!(:current_user).and_return(nil) + allow(self).to receive(:current_user).and_return(nil) user_color_scheme_class.should be_kind_of(String) end end @@ -115,7 +170,7 @@ describe ApplicationHelper do context "with color_scheme_id == #{color_scheme_id}" do it "should return a string" do current_user = double(:color_scheme_id => color_scheme_id) - stub!(:current_user).and_return(current_user) + allow(self).to receive(:current_user).and_return(current_user) user_color_scheme_class.should be_kind_of(String) end end diff --git a/spec/helpers/broadcast_messages_helper_spec.rb b/spec/helpers/broadcast_messages_helper_spec.rb new file mode 100644 index 00000000000..1338ce4873d --- /dev/null +++ b/spec/helpers/broadcast_messages_helper_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' + +describe BroadcastMessagesHelper do + describe 'broadcast_styling' do + let(:broadcast_message) { double(color: "", font: "") } + + context "default style" do + it "should have no style" do + broadcast_styling(broadcast_message).should match('') + end + end + + context "customiezd style" do + before { broadcast_message.stub(color: "#f2dede", font: "#b94a48") } + + it "should have a customized style" do + broadcast_styling(broadcast_message).should match('background-color:#f2dede;color:#b94a48') + end + end + end +end diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index a0bbc026421..5bd16d1c16c 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -4,7 +4,7 @@ describe GitlabMarkdownHelper do include ApplicationHelper include IssuesHelper - let!(:project) { create(:project_with_code) } + let!(:project) { create(:project) } let(:user) { create(:user, username: 'gfm') } let(:commit) { project.repository.commit } @@ -16,6 +16,7 @@ describe GitlabMarkdownHelper do before do # Helper expects a @project instance variable @project = project + @repository = project.repository end describe "#gfm" do @@ -347,8 +348,21 @@ describe GitlabMarkdownHelper do it "should handle references in headers" do actual = "\n# Working around ##{issue.iid}\n## Apply !#{merge_request.iid}" - markdown(actual).should match(%r{<h1[^<]*>Working around <a.+>##{issue.iid}</a></h1>}) - markdown(actual).should match(%r{<h2[^<]*>Apply <a.+>!#{merge_request.iid}</a></h2>}) + markdown(actual, {no_header_anchors:true}).should match(%r{<h1[^<]*>Working around <a.+>##{issue.iid}</a></h1>}) + markdown(actual, {no_header_anchors:true}).should match(%r{<h2[^<]*>Apply <a.+>!#{merge_request.iid}</a></h2>}) + end + + it "should add ids and links to headers" do + # Test every rule except nested tags. + text = '..Ab_c-d. e..' + id = 'ab_c-d-e' + markdown("# #{text}").should match(%r{<h1 id="#{id}">#{text}<a href="[^"]*##{id}"></a></h1>}) + markdown("# #{text}", {no_header_anchors:true}).should == "<h1>#{text}</h1>" + + id = 'link-text' + markdown("# [link text](url) ![img alt](url)").should match( + %r{<h1 id="#{id}"><a href="[^"]*url">link text</a> <img[^>]*><a href="[^"]*##{id}"></a></h1>} + ) end it "should handle references in lists" do @@ -378,9 +392,10 @@ describe GitlabMarkdownHelper do it "should leave code blocks untouched" do helper.stub(:user_color_scheme_class).and_return(:white) - helper.markdown("\n some code from $#{snippet.id}\n here too\n").should include("<div class=\"white\"><div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div></div>") + target_html = "\n<div class=\"highlighted-data white\">\n <div class=\"highlight\">\n <pre><code class=\"\">some code from $#{snippet.id}\nhere too\n</code></pre>\n </div>\n</div>\n\n" - helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should include("<div class=\"white\"><div class=\"highlight\"><pre><span class=\"n\">some</span> <span class=\"n\">code</span> <span class=\"n\">from</span> $#{snippet.id}\n<span class=\"n\">here</span> <span class=\"n\">too</span>\n</pre></div></div>") + helper.markdown("\n some code from $#{snippet.id}\n here too\n").should == target_html + helper.markdown("\n```\nsome code from $#{snippet.id}\nhere too\n```\n").should == target_html end it "should leave inline code untouched" do @@ -392,7 +407,7 @@ describe GitlabMarkdownHelper do end it "should leave ref-like href of 'manual' links untouched" do - markdown("why not [inspect !#{merge_request.iid}](http://example.tld/#!#{merge_request.iid})").should == "<p>why not <a href=\"http://example.tld/#!#{merge_request.iid}\">inspect </a><a href=\"#{project_merge_request_url(project, merge_request)}\" class=\"gfm gfm-merge_request \" title=\"Merge Request: #{merge_request.title}\">!#{merge_request.iid}</a><a href=\"http://example.tld/#!#{merge_request.iid}\"></a></p>\n" + markdown("why not [inspect !#{merge_request.iid}](http://example.tld/#!#{merge_request.iid})").should == "<p>why not <a href=\"http://example.tld/#!#{merge_request.iid}\">inspect </a><a class=\"gfm gfm-merge_request \" href=\"#{project_merge_request_url(project, merge_request)}\" title=\"Merge Request: #{merge_request.title}\">!#{merge_request.iid}</a><a href=\"http://example.tld/#!#{merge_request.iid}\"></a></p>\n" end it "should leave ref-like src of images untouched" do @@ -425,16 +440,28 @@ describe GitlabMarkdownHelper do markdown(actual).should match(expected) end - it "should handle wiki urls" do - actual = "[Link](test/link)\n" - expected = "<p><a href=\"/#{project.path_with_namespace}/wikis/test/link\">Link</a></p>\n" + it "should handle relative urls in reference links for a file in master" do + actual = "[GitLab API doc][GitLab readme]\n [GitLab readme]: doc/api/README.md\n" + expected = "<p><a href=\"/#{project.path_with_namespace}/blob/master/doc/api/README.md\">GitLab API doc</a></p>\n" + markdown(actual).should match(expected) + end + + it "should handle relative urls in reference links for a directory in master" do + actual = "[GitLab API doc directory][GitLab readmes]\n [GitLab readmes]: doc/api/\n" + expected = "<p><a href=\"/#{project.path_with_namespace}/tree/master/doc/api\">GitLab API doc directory</a></p>\n" + markdown(actual).should match(expected) + end + + it "should not handle malformed relative urls in reference links for a file in master" do + actual = "[GitLab readme]: doc/api/README.md\n" + expected = "" markdown(actual).should match(expected) end end describe "#render_wiki_content" do before do - @wiki = stub('WikiPage') + @wiki = double('WikiPage') @wiki.stub(:content).and_return('wiki content') end @@ -448,7 +475,7 @@ describe GitlabMarkdownHelper do it "should use the Gollum renderer for all other file types" do @wiki.stub(:format).and_return(:rdoc) - formatted_content_stub = stub('formatted_content') + formatted_content_stub = double('formatted_content') formatted_content_stub.should_receive(:html_safe) @wiki.stub(:formatted_content).and_return(formatted_content_stub) diff --git a/spec/helpers/notifications_helper_spec.rb b/spec/helpers/notifications_helper_spec.rb index 328f66237c3..dce28525ca4 100644 --- a/spec/helpers/notifications_helper_spec.rb +++ b/spec/helpers/notifications_helper_spec.rb @@ -2,13 +2,13 @@ require 'spec_helper' describe NotificationsHelper do describe 'notification_icon' do - let(:notification) { stub(disabled?: false, participating?: false, watch?: false) } + let(:notification) { double(disabled?: false, participating?: false, watch?: false) } context "disabled notification" do before { notification.stub(disabled?: true) } it "has a red icon" do - notification_icon(notification).should match('class="icon-circle cred"') + notification_icon(notification).should match('class="icon-volume-off cred"') end end @@ -16,7 +16,7 @@ describe NotificationsHelper do before { notification.stub(participating?: true) } it "has a blue icon" do - notification_icon(notification).should match('class="icon-circle cblue"') + notification_icon(notification).should match('class="icon-volume-down cblue"') end end @@ -24,7 +24,7 @@ describe NotificationsHelper do before { notification.stub(watch?: true) } it "has a green icon" do - notification_icon(notification).should match('class="icon-circle cgreen"') + notification_icon(notification).should match('class="icon-volume-up cgreen"') end end diff --git a/spec/helpers/projects_helper_spec.rb b/spec/helpers/projects_helper_spec.rb index 62f88dd522b..114058e3095 100644 --- a/spec/helpers/projects_helper_spec.rb +++ b/spec/helpers/projects_helper_spec.rb @@ -7,5 +7,17 @@ describe ProjectsHelper do "<option value=\"redmine\">Redmine</option>\n" \ "<option value=\"gitlab\">GitLab</option>" end + + it "returns the correct issues trackers available with current tracker 'gitlab' selected" do + project_issues_trackers('gitlab').should == + "<option value=\"redmine\">Redmine</option>\n" \ + "<option selected=\"selected\" value=\"gitlab\">GitLab</option>" + end + + it "returns the correct issues trackers available with current tracker 'redmine' selected" do + project_issues_trackers('redmine').should == + "<option selected=\"selected\" value=\"redmine\">Redmine</option>\n" \ + "<option value=\"gitlab\">GitLab</option>" + end end end diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 55b6b6b4dad..733f2754727 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -8,55 +8,46 @@ describe SearchHelper do describe 'search_autocomplete_source' do context "with no current user" do - before { stub!(:current_user).and_return(nil) } + before do + allow(self).to receive(:current_user).and_return(nil) + end it "it returns nil" do - search_autocomplete_source.should be_nil + search_autocomplete_opts("q").should be_nil end end context "with a user" do let(:user) { create(:user) } - let(:result) { JSON.parse(search_autocomplete_source) } before do - stub!(:current_user).and_return(user) + allow(self).to receive(:current_user).and_return(user) end it "includes Help sections" do - result.select { |h| h['label'] =~ /^help:/ }.length.should == 9 + search_autocomplete_opts("hel").size.should == 9 end it "includes default sections" do - result.count { |h| h['label'] =~ /^(My|Admin)\s/ }.should == 4 + search_autocomplete_opts("adm").size.should == 1 end it "includes the user's groups" do create(:group).add_owner(user) - result.count { |h| h['label'] =~ /^group:/ }.should == 1 + search_autocomplete_opts("gro").size.should == 1 end it "includes the user's projects" do - create(:project, namespace: create(:namespace, owner: user)) - result.count { |h| h['label'] =~ /^project:/ }.should == 1 + project = create(:project, namespace: create(:namespace, owner: user)) + search_autocomplete_opts(project.name).size.should == 1 end context "with a current project" do - before { @project = create(:project_with_code) } + before { @project = create(:project) } it "includes project-specific sections" do - result.count { |h| h['label'] =~ /^#{@project.name_with_namespace} - / }.should == 11 - end - - it "uses @ref in urls if defined" do - @ref = "foo_bar" - result.count { |h| h['url'] == project_tree_path(@project, @ref) }.should == 1 - end - end - - context "with no current project" do - it "does not include project-specific sections" do - result.count { |h| h['label'] =~ /Files$/ }.should == 0 + search_autocomplete_opts("Files").size.should == 1 + search_autocomplete_opts("Commits").size.should == 1 end end end diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb new file mode 100644 index 00000000000..20378b1b17d --- /dev/null +++ b/spec/helpers/submodule_helper_spec.rb @@ -0,0 +1,118 @@ +require 'spec_helper' + +describe SubmoduleHelper do + describe 'submodule links' do + let(:submodule_item) { double(id: 'hash', path: 'rack') } + let(:config) { Gitlab.config.gitlab } + let(:repo) { double() } + + before do + self.instance_variable_set(:@repository, repo) + end + + context 'submodule on self' do + before do + Gitlab.config.gitlab.stub(protocol: 'http') # set this just to be sure + end + + it 'should detect ssh on standard port' do + Gitlab.config.gitlab.stub(ssh_port: 22) # set this just to be sure + stub_url([ config.user, '@', config.host, ':gitlab-org/gitlab-ce.git' ].join('')) + submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ] + end + + it 'should detect ssh on non-standard port' do + Gitlab.config.gitlab_shell.stub(ssh_port: 2222) + Gitlab.config.gitlab_shell.stub(ssh_path_prefix: Settings.send(:build_gitlab_shell_ssh_path_prefix)) + stub_url([ 'ssh://', config.user, '@', config.host, ':2222/gitlab-org/gitlab-ce.git' ].join('')) + submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ] + end + + it 'should detect http on standard port' do + Gitlab.config.gitlab.stub(port: 80) + Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url)) + stub_url([ 'http://', config.host, '/gitlab-org/gitlab-ce.git' ].join('')) + submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ] + end + + it 'should detect http on non-standard port' do + Gitlab.config.gitlab.stub(port: 3000) + Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url)) + stub_url([ 'http://', config.host, ':3000/gitlab-org/gitlab-ce.git' ].join('')) + submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ] + end + + it 'should work with relative_url_root' do + Gitlab.config.gitlab.stub(port: 80) # set this just to be sure + Gitlab.config.gitlab.stub(relative_url_root: '/gitlab/root') + Gitlab.config.gitlab.stub(url: Settings.send(:build_gitlab_url)) + stub_url([ 'http://', config.host, '/gitlab/root/gitlab-org/gitlab-ce.git' ].join('')) + submodule_links(submodule_item).should == [ project_path('gitlab-org/gitlab-ce'), project_tree_path('gitlab-org/gitlab-ce', 'hash') ] + end + end + + context 'submodule on github.com' do + it 'should detect ssh' do + stub_url('git@github.com:gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ] + end + + it 'should detect http' do + stub_url('http://github.com/gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ] + end + + it 'should detect https' do + stub_url('https://github.com/gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ 'https://github.com/gitlab-org/gitlab-ce', 'https://github.com/gitlab-org/gitlab-ce/tree/hash' ] + end + + it 'should return original with non-standard url' do + stub_url('http://github.com/gitlab-org/gitlab-ce') + submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ] + + stub_url('http://github.com/another/gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ] + end + end + + context 'submodule on gitlab.com' do + it 'should detect ssh' do + stub_url('git@gitlab.com:gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ] + end + + it 'should detect http' do + stub_url('http://gitlab.com/gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ] + end + + it 'should detect https' do + stub_url('https://gitlab.com/gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ 'https://gitlab.com/gitlab-org/gitlab-ce', 'https://gitlab.com/gitlab-org/gitlab-ce/tree/hash' ] + end + + it 'should return original with non-standard url' do + stub_url('http://gitlab.com/gitlab-org/gitlab-ce') + submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ] + + stub_url('http://gitlab.com/another/gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ] + end + end + + context 'submodule on unsupported' do + it 'should return original' do + stub_url('http://mygitserver.com/gitlab-org/gitlab-ce') + submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ] + + stub_url('http://mygitserver.com/gitlab-org/gitlab-ce.git') + submodule_links(submodule_item).should == [ repo.submodule_url_for, nil ] + end + end + end + + def stub_url(url) + repo.stub(submodule_url_for: url) + end +end diff --git a/spec/helpers/tab_helper_spec.rb b/spec/helpers/tab_helper_spec.rb index ef8e4cf6375..fa8a3f554f7 100644 --- a/spec/helpers/tab_helper_spec.rb +++ b/spec/helpers/tab_helper_spec.rb @@ -5,8 +5,8 @@ describe TabHelper do describe 'nav_link' do before do - controller.stub!(:controller_name).and_return('foo') - stub!(:action_name).and_return('foo') + controller.stub(:controller_name).and_return('foo') + allow(self).to receive(:action_name).and_return('foo') end it "captures block output" do diff --git a/spec/javascripts/stat_graph_contributors_graph_spec.js b/spec/javascripts/stat_graph_contributors_graph_spec.js index 8d2e2038a55..1090cb7f620 100644 --- a/spec/javascripts/stat_graph_contributors_graph_spec.js +++ b/spec/javascripts/stat_graph_contributors_graph_spec.js @@ -88,19 +88,20 @@ describe("ContributorsGraph", function () { describe("ContributorsMasterGraph", function () { - describe("#process_dates", function () { - it("gets and parses dates", function () { - var graph = new ContributorsMasterGraph() - var data = 'random data here' - spyOn(graph, 'parse_dates') - spyOn(graph, 'get_dates').andReturn("get") - spyOn(ContributorsGraph,'set_dates').andCallThrough() - graph.process_dates(data) - expect(graph.parse_dates).toHaveBeenCalledWith(data) - expect(graph.get_dates).toHaveBeenCalledWith(data) - expect(ContributorsGraph.set_dates).toHaveBeenCalledWith("get") - }) - }) + // TODO: fix or remove + //describe("#process_dates", function () { + //it("gets and parses dates", function () { + //var graph = new ContributorsMasterGraph() + //var data = 'random data here' + //spyOn(graph, 'parse_dates') + //spyOn(graph, 'get_dates').andReturn("get") + //spyOn(ContributorsGraph,'set_dates').andCallThrough() + //graph.process_dates(data) + //expect(graph.parse_dates).toHaveBeenCalledWith(data) + //expect(graph.get_dates).toHaveBeenCalledWith(data) + //expect(ContributorsGraph.set_dates).toHaveBeenCalledWith("get") + //}) + //}) describe("#get_dates", function () { it("plucks the date field from data collection", function () { diff --git a/spec/javascripts/stat_graph_contributors_util_spec.js b/spec/javascripts/stat_graph_contributors_util_spec.js index 2e52479ccbb..9c1b588861d 100644 --- a/spec/javascripts/stat_graph_contributors_util_spec.js +++ b/spec/javascripts/stat_graph_contributors_util_spec.js @@ -54,16 +54,17 @@ describe("ContributorsStatGraphUtil", function () { }) - describe("#store_commits", function () { - var fake_total = "fake_total" - var fake_by_author = "fake_by_author" - - it("calls #add twice with arguments fake_total and fake_by_author respectively", function () { - spyOn(ContributorsStatGraphUtil, 'add') - ContributorsStatGraphUtil.store_commits(fake_total, fake_by_author) - expect(ContributorsStatGraphUtil.add.argsForCall).toEqual([["fake_total", "commits", 1], ["fake_by_author", "commits", 1]]) - }) - }) + // TODO: fix or remove + //describe("#store_commits", function () { + //var fake_total = "fake_total" + //var fake_by_author = "fake_by_author" + + //it("calls #add twice with arguments fake_total and fake_by_author respectively", function () { + //spyOn(ContributorsStatGraphUtil, 'add') + //ContributorsStatGraphUtil.store_commits(fake_total, fake_by_author) + //expect(ContributorsStatGraphUtil.add.argsForCall).toEqual([["fake_total", "commits", 1], ["fake_by_author", "commits", 1]]) + //}) + //}) describe("#add", function () { it("adds 1 to current test_field in collection", function () { @@ -79,27 +80,29 @@ describe("ContributorsStatGraphUtil", function () { }) }) - describe("#store_additions", function () { - var fake_entry = {additions: 10} - var fake_total= "fake_total" - var fake_by_author = "fake_by_author" - it("calls #add twice with arguments fake_total and fake_by_author respectively", function () { - spyOn(ContributorsStatGraphUtil, 'add') - ContributorsStatGraphUtil.store_additions(fake_entry, fake_total, fake_by_author) - expect(ContributorsStatGraphUtil.add.argsForCall).toEqual([["fake_total", "additions", 10], ["fake_by_author", "additions", 10]]) - }) - }) - - describe("#store_deletions", function () { - var fake_entry = {deletions: 10} - var fake_total= "fake_total" - var fake_by_author = "fake_by_author" - it("calls #add twice with arguments fake_total and fake_by_author respectively", function () { - spyOn(ContributorsStatGraphUtil, 'add') - ContributorsStatGraphUtil.store_deletions(fake_entry, fake_total, fake_by_author) - expect(ContributorsStatGraphUtil.add.argsForCall).toEqual([["fake_total", "deletions", 10], ["fake_by_author", "deletions", 10]]) - }) - }) + // TODO: fix or remove + //describe("#store_additions", function () { + //var fake_entry = {additions: 10} + //var fake_total= "fake_total" + //var fake_by_author = "fake_by_author" + //it("calls #add twice with arguments fake_total and fake_by_author respectively", function () { + //spyOn(ContributorsStatGraphUtil, 'add') + //ContributorsStatGraphUtil.store_additions(fake_entry, fake_total, fake_by_author) + //expect(ContributorsStatGraphUtil.add.argsForCall).toEqual([["fake_total", "additions", 10], ["fake_by_author", "additions", 10]]) + //}) + //}) + + // TODO: fix or remove + //describe("#store_deletions", function () { + //var fake_entry = {deletions: 10} + //var fake_total= "fake_total" + //var fake_by_author = "fake_by_author" + //it("calls #add twice with arguments fake_total and fake_by_author respectively", function () { + //spyOn(ContributorsStatGraphUtil, 'add') + //ContributorsStatGraphUtil.store_deletions(fake_entry, fake_total, fake_by_author) + //expect(ContributorsStatGraphUtil.add.argsForCall).toEqual([["fake_total", "deletions", 10], ["fake_by_author", "deletions", 10]]) + //}) + //}) describe("#add_date", function () { it("adds a date field to the collection", function () { diff --git a/spec/javascripts/support/jasmine_helper.rb b/spec/javascripts/support/jasmine_helper.rb index 34b418a9ca3..b4919802afe 100644 --- a/spec/javascripts/support/jasmine_helper.rb +++ b/spec/javascripts/support/jasmine_helper.rb @@ -1,5 +1,11 @@ -WebMock.allow_net_connect! +#Use this file to set/override Jasmine configuration options +#You can remove it if you don't need it. +#This file is loaded *after* jasmine.yml is interpreted. +# +#Example: using a different boot file. +#Jasmine.configure do |config| +# config.boot_dir = '/absolute/path/to/boot_dir' +# config.boot_files = lambda { ['/absolute/path/to/boot_dir/file.js'] } +#end +# -Jasmine.configure do |config| - config.browser = :phantomjs -end diff --git a/spec/lib/auth_spec.rb b/spec/lib/auth_spec.rb index e05fde95731..073b811c3fb 100644 --- a/spec/lib/auth_spec.rb +++ b/spec/lib/auth_spec.rb @@ -8,21 +8,21 @@ describe Gitlab::Auth do @user = create( :user, username: 'john', - password: '888777', - password_confirmation: '888777' + password: '88877711', + password_confirmation: '88877711' ) end it "should find user by valid login/password" do - gl_auth.find('john', '888777').should == @user + gl_auth.find('john', '88877711').should == @user end it "should not find user with invalid password" do - gl_auth.find('john', 'invalid').should_not == @user + gl_auth.find('john', 'invalid11').should_not == @user end it "should not find user with invalid login and password" do - gl_auth.find('jon', 'invalid').should_not == @user + gl_auth.find('jon', 'invalid11').should_not == @user end end end diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb index aac72c63ea5..7b3818ea5c8 100644 --- a/spec/lib/extracts_path_spec.rb +++ b/spec/lib/extracts_path_spec.rb @@ -7,7 +7,7 @@ describe ExtractsPath do before do @project = project - project.stub(repository: stub(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])) + project.stub(repository: double(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])) project.stub(path_with_namespace: 'gitlab/gitlab-ci') end diff --git a/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb b/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb index b1c583c0476..501642dca79 100644 --- a/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb +++ b/spec/lib/gitlab/ldap/ldap_user_auth_spec.rb @@ -6,16 +6,17 @@ describe Gitlab::LDAP do before do Gitlab.config.stub(omniauth: {}) - @info = mock( + @info = double( uid: '12djsak321', name: 'John', - email: 'john@mail.com' + email: 'john@mail.com', + nickname: 'john' ) end describe :find_for_ldap_auth do before do - @auth = mock( + @auth = double( uid: '12djsak321', info: @info, provider: 'ldap' @@ -25,7 +26,7 @@ describe Gitlab::LDAP do it "should update credentials by email if missing uid" do user = double('User') User.stub find_by_extern_uid_and_provider: nil - User.stub find_by_email: user + User.stub(:find_by).with(hash_including(email: anything())) { user } user.should_receive :update_attributes gl_auth.find_or_create(@auth) end @@ -35,8 +36,8 @@ describe Gitlab::LDAP do value = Gitlab.config.ldap.allow_username_or_email_login Gitlab.config.ldap['allow_username_or_email_login'] = true User.stub find_by_extern_uid_and_provider: nil - User.stub find_by_email: nil - User.stub find_by_username: user + User.stub(:find_by).with(hash_including(email: anything())) { nil } + User.stub(:find_by).with(hash_including(username: anything())) { user } user.should_receive :update_attributes gl_auth.find_or_create(@auth) Gitlab.config.ldap['allow_username_or_email_login'] = value @@ -47,8 +48,8 @@ describe Gitlab::LDAP do value = Gitlab.config.ldap.allow_username_or_email_login Gitlab.config.ldap['allow_username_or_email_login'] = false User.stub find_by_extern_uid_and_provider: nil - User.stub find_by_email: nil - User.stub find_by_username: user + User.stub(:find_by).with(hash_including(email: anything())) { nil } + User.stub(:find_by).with(hash_including(username: anything())) { user } user.should_not_receive :update_attributes gl_auth.find_or_create(@auth) Gitlab.config.ldap['allow_username_or_email_login'] = value diff --git a/spec/lib/gitlab/popen_spec.rb b/spec/lib/gitlab/popen_spec.rb index 4791be41613..76d506eb3c0 100644 --- a/spec/lib/gitlab/popen_spec.rb +++ b/spec/lib/gitlab/popen_spec.rb @@ -10,7 +10,7 @@ describe 'Gitlab::Popen', no_db: true do context 'zero status' do before do - @output, @status = @klass.new.popen('ls', path) + @output, @status = @klass.new.popen(%W(ls), path) end it { @status.should be_zero } @@ -19,11 +19,27 @@ describe 'Gitlab::Popen', no_db: true do context 'non-zero status' do before do - @output, @status = @klass.new.popen('cat NOTHING', path) + @output, @status = @klass.new.popen(%W(cat NOTHING), path) end it { @status.should == 1 } it { @output.should include('No such file or directory') } end + + context 'unsafe string command' do + it 'raises an error when it gets called with a string argument' do + expect { @klass.new.popen('ls', path) }.to raise_error + end + end + + context 'without a directory argument' do + before do + @output, @status = @klass.new.popen(%W(ls)) + end + + it { @status.should be_zero } + it { @output.should include('spec') } + end + end diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 7d805f8c72a..19259a8b79c 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -43,7 +43,7 @@ describe Gitlab::ReferenceExtractor do end context 'with a project' do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } it 'accesses valid user objects on the project team' do @u_foo = create(:user, username: 'foo') diff --git a/spec/lib/gitlab/satellite/action_spec.rb b/spec/lib/gitlab/satellite/action_spec.rb index 5e0a825c3c3..d65e7c42b7e 100644 --- a/spec/lib/gitlab/satellite/action_spec.rb +++ b/spec/lib/gitlab/satellite/action_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe 'Gitlab::Satellite::Action' do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:user) { create(:user) } describe '#prepare_satellite!' do diff --git a/spec/lib/gitlab/satellite/merge_action_spec.rb b/spec/lib/gitlab/satellite/merge_action_spec.rb index e40ff73b7f0..ef06c742846 100644 --- a/spec/lib/gitlab/satellite/merge_action_spec.rb +++ b/spec/lib/gitlab/satellite/merge_action_spec.rb @@ -2,20 +2,21 @@ require 'spec_helper' describe 'Gitlab::Satellite::MergeAction' do before(:each) do -# TestEnv.init(mailer: false, init_repos: true, repos: true) - @master = ['master', 'b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828'] + @master = ['master', '69b34b7e9ad9f496f0ad10250be37d6265a03bba'] @one_after_stable = ['stable', '6ea87c47f0f8a24ae031c3fff17bc913889ecd00'] #this commit sha is one after stable @wiki_branch = ['wiki', '635d3e09b72232b6e92a38de6cc184147e5bcb41'] #this is the commit sha where the wiki branch goes off from master @conflicting_metior = ['metior', '313d96e42b313a0af5ab50fa233bf43e27118b3f'] #this branch conflicts with the wiki branch - #these commits are quite close together, itended to make string diffs/format patches small + # these commits are quite close together, itended to make string diffs/format patches small @close_commit1 = ['2_3_notes_fix', '8470d70da67355c9c009e4401746b1d5410af2e3'] @close_commit2 = ['scss_refactoring', 'f0f14c8eaba69ebddd766498a9d0b0e79becd633'] end - let(:project) { create(:project_with_code) } + let(:project) { create(:project, namespace: create(:group)) } + let(:fork_project) { create(:project, namespace: create(:group)) } let(:merge_request) { create(:merge_request, source_project: project, target_project: project) } - let(:merge_request_fork) { create(:merge_request) } + let(:merge_request_fork) { create(:merge_request, source_project: fork_project, target_project: project) } + describe '#commits_between' do def verify_commits(commits, first_commit_sha, last_commit_sha) commits.each { |commit| commit.class.should == Gitlab::Git::Commit } @@ -145,4 +146,4 @@ describe 'Gitlab::Satellite::MergeAction' do end end end -end
\ No newline at end of file +end diff --git a/spec/lib/gitlab/upgrader_spec.rb b/spec/lib/gitlab/upgrader_spec.rb new file mode 100644 index 00000000000..2b254d6b3a6 --- /dev/null +++ b/spec/lib/gitlab/upgrader_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe Gitlab::Upgrader do + let(:upgrader) { Gitlab::Upgrader.new } + let(:current_version) { Gitlab::VERSION } + + describe 'current_version_raw' do + it { upgrader.current_version_raw.should == current_version } + end + + describe 'latest_version?' do + it 'should be true if newest version' do + upgrader.stub(latest_version_raw: current_version) + upgrader.latest_version?.should be_true + end + end + + describe 'latest_version_raw' do + it 'should be latest version for GitLab 5' do + upgrader.stub(current_version_raw: "5.3.0") + upgrader.latest_version_raw.should == "v5.4.2" + end + end +end diff --git a/spec/lib/oauth_spec.rb b/spec/lib/oauth_spec.rb index e21074554b6..3dfe95a8e38 100644 --- a/spec/lib/oauth_spec.rb +++ b/spec/lib/oauth_spec.rb @@ -6,7 +6,7 @@ describe Gitlab::OAuth::User do before do Gitlab.config.stub(omniauth: {}) - @info = mock( + @info = double( uid: '12djsak321', name: 'John', email: 'john@mail.com' @@ -15,7 +15,7 @@ describe Gitlab::OAuth::User do describe :create do it "should create user from LDAP" do - @auth = mock(info: @info, provider: 'ldap') + @auth = double(info: @info, provider: 'ldap') user = gl_auth.create(@auth) user.should be_valid @@ -24,7 +24,7 @@ describe Gitlab::OAuth::User do end it "should create user from Omniauth" do - @auth = mock(info: @info, provider: 'twitter') + @auth = double(info: @info, provider: 'twitter') user = gl_auth.create(@auth) user.should be_valid @@ -33,7 +33,7 @@ describe Gitlab::OAuth::User do end it "should apply defaults to user" do - @auth = mock(info: @info, provider: 'ldap') + @auth = double(info: @info, provider: 'ldap') user = gl_auth.create(@auth) user.should be_valid diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb index 666c6ccefff..22d60429ccd 100644 --- a/spec/mailers/notify_spec.rb +++ b/spec/mailers/notify_spec.rb @@ -4,8 +4,9 @@ describe Notify do include EmailSpec::Helpers include EmailSpec::Matchers + let(:gitlab_sender) { Gitlab.config.gitlab.email_from } let(:recipient) { create(:user, email: 'recipient@example.com') } - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } shared_examples 'a multiple recipients email' do it 'is sent to the given recipient' do @@ -13,18 +14,28 @@ describe Notify do end end + shared_examples 'an email sent from GitLab' do + it 'is sent from GitLab' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq('GitLab') + sender.address.should eq(gitlab_sender) + end + end + describe 'for new users, the email' do let(:example_site_path) { root_path } let(:new_user) { create(:user, email: 'newguy@example.com', created_by_id: 1) } subject { Notify.new_user_email(new_user.id, new_user.password) } + it_behaves_like 'an email sent from GitLab' + it 'is sent to the new user' do should deliver_to new_user.email end it 'has the correct subject' do - should have_subject /^gitlab \| Account was created for you$/i + should have_subject /^Account was created for you$/i end it 'contains the new user\'s login name' do @@ -47,12 +58,14 @@ describe Notify do subject { Notify.new_user_email(new_user.id, new_user.password) } + it_behaves_like 'an email sent from GitLab' + it 'is sent to the new user' do should deliver_to new_user.email end it 'has the correct subject' do - should have_subject /^gitlab \| Account was created for you$/i + should have_subject /^Account was created for you$/i end it 'contains the new user\'s login name' do @@ -73,12 +86,14 @@ describe Notify do subject { Notify.new_ssh_key_email(key.id) } + it_behaves_like 'an email sent from GitLab' + it 'is sent to the new user' do should deliver_to key.user.email end it 'has the correct subject' do - should have_subject /^gitlab \| SSH key was added to your account$/i + should have_subject /^SSH key was added to your account$/i end it 'contains the new ssh key title' do @@ -90,19 +105,49 @@ describe Notify do end end + describe 'user added email' do + let(:email) { create(:email) } + + subject { Notify.new_email_email(email.id) } + + it 'is sent to the new user' do + should deliver_to email.user.email + end + + it 'has the correct subject' do + should have_subject /^Email was added to your account$/i + end + + it 'contains the new email address' do + should have_body_text /#{email.email}/ + end + + it 'includes a link to emails page' do + should have_body_text /#{profile_emails_path}/ + end + end + context 'for a project' do describe 'items that are assignable, the email' do + let(:current_user) { create(:user, email: "current@email.com") } let(:assignee) { create(:user, email: 'assignee@example.com') } let(:previous_assignee) { create(:user, name: 'Previous Assignee') } shared_examples 'an assignee email' do + it 'is sent as the author' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq(current_user.name) + sender.address.should eq(gitlab_sender) + end + it 'is sent to the assignee' do should deliver_to assignee.email end end context 'for issues' do - let(:issue) { create(:issue, assignee: assignee, project: project ) } + let(:issue) { create(:issue, author: current_user, assignee: assignee, project: project) } + let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: Faker::Lorem.sentence) } describe 'that are new' do subject { Notify.new_issue_email(issue.assignee_id, issue.id) } @@ -110,7 +155,7 @@ describe Notify do it_behaves_like 'an assignee email' it 'has the correct subject' do - should have_subject /#{project.name} \| new issue ##{issue.iid} \| #{issue.title}/ + should have_subject /#{project.name} \| #{issue.title} \(##{issue.iid}\)/ end it 'contains a link to the new issue' do @@ -118,15 +163,27 @@ describe Notify do end end - describe 'that have been reassigned' do - before(:each) { issue.stub(:assignee_id_was).and_return(previous_assignee.id) } + describe 'that are new with a description' do + subject { Notify.new_issue_email(issue_with_description.assignee_id, issue_with_description.id) } + + it 'contains the description' do + should have_body_text /#{issue_with_description.description}/ + end + end - subject { Notify.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id) } + describe 'that have been reassigned' do + subject { Notify.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id, current_user) } it_behaves_like 'a multiple recipients email' + it 'is sent as the author' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq(current_user.name) + sender.address.should eq(gitlab_sender) + end + it 'has the correct subject' do - should have_subject /changed issue ##{issue.iid} \| #{issue.title}/ + should have_subject /#{issue.title} \(##{issue.iid}\)/ end it 'contains the name of the previous assignee' do @@ -143,12 +200,17 @@ describe Notify do end describe 'status changed' do - let(:current_user) { create(:user, email: "current@email.com") } let(:status) { 'closed' } subject { Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user) } + it 'is sent as the author' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq(current_user.name) + sender.address.should eq(gitlab_sender) + end + it 'has the correct subject' do - should have_subject /changed issue ##{issue.iid} \| #{issue.title}/i + should have_subject /#{issue.title} \(##{issue.iid}\)/i end it 'contains the new status' do @@ -167,7 +229,9 @@ describe Notify do end context 'for merge requests' do - let(:merge_request) { create(:merge_request, assignee: assignee, source_project: project, target_project: project) } + let(:merge_author) { create(:user) } + let(:merge_request) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project) } + let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: Faker::Lorem.sentence) } describe 'that are new' do subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) } @@ -175,7 +239,7 @@ describe Notify do it_behaves_like 'an assignee email' it 'has the correct subject' do - should have_subject /new merge request !#{merge_request.iid}/ + should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/ end it 'contains a link to the new merge request' do @@ -191,15 +255,27 @@ describe Notify do end end - describe 'that are reassigned' do - before(:each) { merge_request.stub(:assignee_id_was).and_return(previous_assignee.id) } + describe 'that are new with a description' do + subject { Notify.new_merge_request_email(merge_request_with_description.assignee_id, merge_request_with_description.id) } + + it 'contains the description' do + should have_body_text /#{merge_request_with_description.description}/ + end + end - subject { Notify.reassigned_merge_request_email(recipient.id, merge_request.id, previous_assignee.id) } + describe 'that are reassigned' do + subject { Notify.reassigned_merge_request_email(recipient.id, merge_request.id, previous_assignee.id, current_user.id) } it_behaves_like 'a multiple recipients email' + it 'is sent as the author' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq(current_user.name) + sender.address.should eq(gitlab_sender) + end + it 'has the correct subject' do - should have_subject /changed merge request !#{merge_request.iid}/ + should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/ end it 'contains the name of the previous assignee' do @@ -213,7 +289,30 @@ describe Notify do it 'contains a link to the merge request' do should have_body_text /#{project_merge_request_path project, merge_request}/ end + end + + describe 'that are merged' do + subject { Notify.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) } + + it_behaves_like 'a multiple recipients email' + + it 'is sent as the merge author' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq(merge_author.name) + sender.address.should eq(gitlab_sender) + end + + it 'has the correct subject' do + should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/ + end + it 'contains the new status' do + should have_body_text /merged/i + end + + it 'contains a link to the merge request' do + should have_body_text /#{project_merge_request_path project, merge_request}/ + end end end end @@ -223,8 +322,10 @@ describe Notify do let(:user) { create(:user) } subject { Notify.project_was_moved_email(project.id, user.id) } + it_behaves_like 'an email sent from GitLab' + it 'has the correct subject' do - should have_subject /project was moved/ + should have_subject /Project was moved/ end it 'contains name of project' do @@ -243,8 +344,11 @@ describe Notify do project: project, user: user) } subject { Notify.project_access_granted_email(users_project.id) } + + it_behaves_like 'an email sent from GitLab' + it 'has the correct subject' do - should have_subject /access to project was granted/ + should have_subject /Access to project was granted/ end it 'contains name of project' do should have_body_text /#{project.name}/ @@ -263,12 +367,14 @@ describe Notify do end shared_examples 'a note email' do - it 'is sent to the given recipient' do - should deliver_to recipient.email + it 'is sent as the author' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq(note_author.name) + sender.address.should eq(gitlab_sender) end - it 'contains the name of the note\'s author' do - should have_body_text /#{note_author.name}/ + it 'is sent to the given recipient' do + should deliver_to recipient.email end it 'contains the message from the note' do @@ -302,7 +408,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for commit #{commit.short_id}/ + should have_subject /#{commit.title} \(#{commit.short_id}\)/ end it 'contains a link to the commit' do @@ -320,7 +426,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for merge request ##{merge_request.iid}/ + should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/ end it 'contains a link to the merge request note' do @@ -338,7 +444,7 @@ describe Notify do it_behaves_like 'a note email' it 'has the correct subject' do - should have_subject /note for issue ##{issue.iid}/ + should have_subject /#{issue.title} \(##{issue.iid}\)/ end it 'contains a link to the issue note' do @@ -355,8 +461,10 @@ describe Notify do subject { Notify.group_access_granted_email(membership.id) } + it_behaves_like 'an email sent from GitLab' + it 'has the correct subject' do - should have_subject /access to group was granted/ + should have_subject /Access to group was granted/ end it 'contains name of project' do @@ -367,4 +475,66 @@ describe Notify do should have_body_text /#{membership.human_access}/ end end + + describe 'confirmation if email changed' do + let(:example_site_path) { root_path } + let(:user) { create(:user, email: 'old-email@mail.com') } + + before do + user.email = "new-email@mail.com" + user.save + end + + subject { ActionMailer::Base.deliveries.last } + + it_behaves_like 'an email sent from GitLab' + + it 'is sent to the new user' do + should deliver_to 'new-email@mail.com' + end + + it 'has the correct subject' do + should have_subject "Confirmation instructions" + end + + it 'includes a link to the site' do + should have_body_text /#{example_site_path}/ + end + end + + describe 'email on push' do + let(:example_site_path) { root_path } + let(:user) { create(:user) } + let(:compare) { Gitlab::Git::Compare.new(project.repository.raw_repository, 'cd5c4bac', 'b1e6a9db') } + let(:commits) { Commit.decorate(compare.commits) } + let(:diff_path) { project_compare_path(project, from: commits.first, to: commits.last) } + + subject { Notify.repository_push_email(project.id, 'devs@company.name', user.id, 'master', compare) } + + it 'is sent as the author' do + sender = subject.header[:from].addrs[0] + sender.display_name.should eq(user.name) + sender.address.should eq(gitlab_sender) + end + + it 'is sent to recipient' do + should deliver_to 'devs@company.name' + end + + it 'has the correct subject' do + should have_subject /New push to repository/ + end + + it 'includes commits list' do + should have_body_text /tree css fixes/ + end + + it 'includes diffs' do + should have_body_text /Checkout wiki pages for installation information/ + end + + it 'contains a link to the diff' do + should have_body_text /#{diff_path}/ + end + end end diff --git a/spec/models/assembla_service_spec.rb b/spec/models/assembla_service_spec.rb new file mode 100644 index 00000000000..1730a64283a --- /dev/null +++ b/spec/models/assembla_service_spec.rb @@ -0,0 +1,52 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# token :string(255) +# project_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# active :boolean default(FALSE), not null +# project_url :string(255) +# subdomain :string(255) +# room :string(255) +# api_key :string(255) +# + +require 'spec_helper' + +describe AssemblaService do + describe "Associations" do + it { should belong_to :project } + it { should have_one :service_hook } + end + + describe "Execute" do + let(:user) { create(:user) } + let(:project) { create(:project) } + + before do + @assembla_service = AssemblaService.new + @assembla_service.stub( + project_id: project.id, + project: project, + service_hook: true, + token: 'verySecret', + subdomain: 'project_name' + ) + @sample_data = GitPushService.new.sample_data(project, user) + @api_url = 'https://atlas.assembla.com/spaces/project_name/github_tool?secret_key=verySecret' + WebMock.stub_request(:post, @api_url) + end + + it "should call Assembla API" do + @assembla_service.execute(@sample_data) + WebMock.should have_requested(:post, @api_url).with( + body: /#{@sample_data[:before]}.*#{@sample_data[:after]}.*#{project.path}/ + ).once + end + end +end diff --git a/spec/models/broadcast_message_spec.rb b/spec/models/broadcast_message_spec.rb new file mode 100644 index 00000000000..cf0b36a2830 --- /dev/null +++ b/spec/models/broadcast_message_spec.rb @@ -0,0 +1,39 @@ +# == Schema Information +# +# Table name: broadcast_messages +# +# id :integer not null, primary key +# message :text default(""), not null +# starts_at :datetime +# ends_at :datetime +# alert_type :integer +# created_at :datetime not null +# updated_at :datetime not null +# color :string(255) +# font :string(255) +# + +require 'spec_helper' + +describe BroadcastMessage do + subject { create(:broadcast_message) } + + it { should be_valid } + + describe :current do + it "should return last message if time match" do + broadcast_message = create(:broadcast_message, starts_at: Time.now.yesterday, ends_at: Time.now.tomorrow) + BroadcastMessage.current.should == broadcast_message + end + + it "should return nil if time not come" do + broadcast_message = create(:broadcast_message, starts_at: Time.now.tomorrow, ends_at: Time.now + 2.days) + BroadcastMessage.current.should be_nil + end + + it "should return nil if time has passed" do + broadcast_message = create(:broadcast_message, starts_at: Time.now - 2.days, ends_at: Time.now.yesterday) + BroadcastMessage.current.should be_nil + end + end +end diff --git a/spec/models/commit_spec.rb b/spec/models/commit_spec.rb index fa556f94a1d..d8ab171d3ee 100644 --- a/spec/models/commit_spec.rb +++ b/spec/models/commit_spec.rb @@ -1,7 +1,7 @@ require 'spec_helper' describe Commit do - let(:project) { create :project_with_code } + let(:project) { create :project } let(:commit) { project.repository.commit } describe '#title' do diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb index 852146ebaec..9cbc8990676 100644 --- a/spec/models/concerns/issuable_spec.rb +++ b/spec/models/concerns/issuable_spec.rb @@ -25,16 +25,11 @@ describe Issue, "Issuable" do it { described_class.should respond_to(:assigned) } end - it "has an :author_id_of_changes accessor" do - issue.should respond_to(:author_id_of_changes) - issue.should respond_to(:author_id_of_changes=) - end - describe ".search" do let!(:searchable_issue) { create(:issue, title: "Searchable issue") } it "matches by title" do - described_class.search('able').all.should == [searchable_issue] + described_class.search('able').should == [searchable_issue] end end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 85bdf08ae64..53ede0d5ee9 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -67,12 +67,12 @@ describe Event do end describe 'Team events' do - let(:user_project) { stub.as_null_object } + let(:user_project) { double.as_null_object } let(:observer) { UsersProjectObserver.instance } before { Event.should_receive :create - observer.stub(notification: stub.as_null_object) + observer.stub(notification: double.as_null_object) } describe "Joined project team" do diff --git a/spec/models/flowdock_service_spec.rb b/spec/models/flowdock_service_spec.rb index b22193c9e93..97414585331 100644 --- a/spec/models/flowdock_service_spec.rb +++ b/spec/models/flowdock_service_spec.rb @@ -11,6 +11,9 @@ # updated_at :datetime not null # active :boolean default(FALSE), not null # project_url :string(255) +# subdomain :string(255) +# room :string(255) +# api_key :string(255) # require 'spec_helper' @@ -23,7 +26,7 @@ describe FlowdockService do describe "Execute" do let(:user) { create(:user) } - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } before do @flowdock_service = FlowdockService.new diff --git a/spec/models/forked_project_link_spec.rb b/spec/models/forked_project_link_spec.rb index 44b8c6155be..e719e3bfcc8 100644 --- a/spec/models/forked_project_link_spec.rb +++ b/spec/models/forked_project_link_spec.rb @@ -58,8 +58,8 @@ describe :forked_from_project do end def fork_project(from_project, user) - context = Projects::ForkContext.new(from_project, user) - shell = mock("gitlab_shell") + context = Projects::ForkService.new(from_project, user) + shell = double("gitlab_shell") shell.stub(fork_repository: true) context.stub(gitlab_shell: shell) context.execute diff --git a/spec/models/gemnasium_service_spec.rb b/spec/models/gemnasium_service_spec.rb new file mode 100644 index 00000000000..dfc99849d60 --- /dev/null +++ b/spec/models/gemnasium_service_spec.rb @@ -0,0 +1,47 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# token :string(255) +# project_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# active :boolean default(FALSE), not null +# project_url :string(255) +# subdomain :string(255) +# room :string(255) +# api_key :string(255) +# + +require 'spec_helper' + +describe GemnasiumService do + describe "Associations" do + it { should belong_to :project } + it { should have_one :service_hook } + end + + describe "Execute" do + let(:user) { create(:user) } + let(:project) { create(:project) } + + before do + @gemnasium_service = GemnasiumService.new + @gemnasium_service.stub( + project_id: project.id, + project: project, + service_hook: true, + token: 'verySecret', + api_key: 'GemnasiumUserApiKey' + ) + @sample_data = GitPushService.new.sample_data(project, user) + end + it "should call Gemnasium service" do + Gemnasium::GitlabService.should_receive(:execute).with(an_instance_of(Hash)).once + @gemnasium_service.execute(@sample_data) + end + end +end diff --git a/spec/models/gitlab_ci_service_spec.rb b/spec/models/gitlab_ci_service_spec.rb index 56efa9df457..8ec15cb3466 100644 --- a/spec/models/gitlab_ci_service_spec.rb +++ b/spec/models/gitlab_ci_service_spec.rb @@ -13,6 +13,7 @@ # project_url :string(255) # subdomain :string(255) # room :string(255) +# api_key :string(255) # require 'spec_helper' diff --git a/spec/models/gollum_wiki_spec.rb b/spec/models/gollum_wiki_spec.rb index 9e07d9ee191..9b9d15b4ff4 100644 --- a/spec/models/gollum_wiki_spec.rb +++ b/spec/models/gollum_wiki_spec.rb @@ -2,12 +2,6 @@ require "spec_helper" describe GollumWiki do - def create_temp_repo(path) - FileUtils.mkdir_p path - command = "git init --quiet #{path};" - system(command) - end - def remove_temp_repo(path) FileUtils.rm_rf path end diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb index 12b84700eb1..686e43d8d10 100644 --- a/spec/models/group_spec.rb +++ b/spec/models/group_spec.rb @@ -54,4 +54,19 @@ describe Group do group.users_groups.guests.map(&:user).should_not include(user) end end + + describe :avatar_type do + let(:user) { create(:user) } + before { group.add_user(user, UsersGroup::MASTER) } + + it "should be true if avatar is image" do + group.update_attribute(:avatar, 'uploads/avatar.png') + group.avatar_type.should be_true + end + + it "should be false if avatar is html page" do + group.update_attribute(:avatar, 'uploads/avatar.html') + group.avatar_type.should == ["only images allowed"] + end + end end diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index b17183a281c..f1ad679b658 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -73,14 +73,13 @@ describe MergeRequest do describe '#for_fork?' do it 'returns true if the merge request is for a fork' do - subject.source_project = create(:source_project) - subject.target_project = create(:target_project) + subject.source_project = create(:project, namespace: create(:group)) + subject.target_project = create(:project, namespace: create(:group)) subject.for_fork?.should be_true end + it 'returns false if is not for a fork' do - subject.source_project = create(:source_project) - subject.target_project = subject.source_project subject.for_fork?.should be_false end end @@ -107,22 +106,22 @@ describe MergeRequest do describe 'detection of issues to be closed' do let(:issue0) { create :issue, project: subject.project } let(:issue1) { create :issue, project: subject.project } - let(:commit0) { mock('commit0', closes_issues: [issue0]) } - let(:commit1) { mock('commit1', closes_issues: [issue0]) } - let(:commit2) { mock('commit2', closes_issues: [issue1]) } + let(:commit0) { double('commit0', closes_issues: [issue0]) } + let(:commit1) { double('commit1', closes_issues: [issue0]) } + let(:commit2) { double('commit2', closes_issues: [issue1]) } before do - subject.stub(unmerged_commits: [commit0, commit1, commit2]) + subject.stub(commits: [commit0, commit1, commit2]) end it 'accesses the set of issues that will be closed on acceptance' do - subject.project.default_branch = subject.target_branch + subject.project.stub(default_branch: subject.target_branch) subject.closes_issues.should == [issue0, issue1].sort_by(&:id) end it 'only lists issues as to be closed if it targets the default branch' do - subject.project.default_branch = 'master' + subject.project.stub(default_branch: 'master') subject.target_branch = 'something-else' subject.closes_issues.should be_empty diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 42c405d8e50..6be8a6a13f6 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -61,6 +61,11 @@ describe Note do note.should be_upvote end + it "recognizes a thumbsup emoji as a vote" do + note = build(:votable_note, note: ":thumbsup: for this") + note.should be_upvote + end + it "recognizes a -1 note" do note = create(:votable_note, note: "-1 for this") note.should be_downvote @@ -70,6 +75,11 @@ describe Note do note = build(:votable_note, note: ":-1: for this") note.should be_downvote end + + it "recognizes a thumbsdown emoji as a vote" do + note = build(:votable_note, note: ":thumbsdown: for this") + note.should be_downvote + end end let(:project) { create(:project) } @@ -170,8 +180,33 @@ describe Note do end end + describe '#create_assignee_change_note' do + let(:project) { create(:project) } + let(:thing) { create(:issue, project: project) } + let(:author) { create(:user) } + let(:assignee) { create(:user) } + + subject { Note.create_assignee_change_note(thing, project, author, assignee) } + + context 'creates and saves a Note' do + it { should be_a Note } + its(:id) { should_not be_nil } + end + + its(:noteable) { should == thing } + its(:project) { should == thing.project } + its(:author) { should == author } + its(:note) { should =~ /Reassigned to @#{assignee.username}/ } + + context 'assignee is removed' do + let(:assignee) { nil } + + its(:note) { should =~ /Assignee removed/ } + end + end + describe '#create_cross_reference_note' do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:author) { create(:user) } let(:issue) { create(:issue, project: project) } let(:mergereq) { create(:merge_request, target_project: project) } @@ -215,6 +250,16 @@ describe Note do its(:project) { should == project } its(:note) { should == "_mentioned in merge request !#{mergereq.iid}_" } end + + context 'commit from issue' do + subject { Note.create_cross_reference_note(commit, issue, author, project) } + + it { should be_valid } + its(:noteable_type) { should == "Commit" } + its(:noteable_id) { should be_nil } + its(:commit_id) { should == commit.id } + its(:note) { should == "_mentioned in issue ##{issue.iid}_" } + end end describe '#cross_reference_exists?' do @@ -242,6 +287,7 @@ describe Note do let(:issue) { create(:issue, project: project) } let(:other) { create(:issue, project: project) } let(:author) { create(:user) } + let(:assignee) { create(:user) } it 'should recognize user-supplied notes as non-system' do @note = create(:note_on_issue) @@ -257,6 +303,11 @@ describe Note do @note = Note.create_cross_reference_note(issue, other, author, project) @note.should be_system end + + it 'should identify assignee-change notes as system notes' do + @note = Note.create_assignee_change_note(issue, project, author, assignee) + @note.should be_system + end end describe :authorization do diff --git a/spec/models/project_hook_spec.rb b/spec/models/project_hook_spec.rb new file mode 100644 index 00000000000..7bd7c431bcd --- /dev/null +++ b/spec/models/project_hook_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe ProjectHook do + describe '.push_hooks' do + it 'should return hooks for push events only' do + hook = create(:project_hook, push_events: true) + hook2 = create(:project_hook, push_events: false) + expect(ProjectHook.push_hooks).to eq([hook]) + end + end + + describe '.tag_push_hooks' do + it 'should return hooks for tag push events only' do + hook = create(:project_hook, tag_push_events: true) + hook2 = create(:project_hook, tag_push_events: false) + expect(ProjectHook.tag_push_hooks).to eq([hook]) + end + end +end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 88ea6926790..839350bafbf 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -9,19 +9,19 @@ # created_at :datetime not null # updated_at :datetime not null # creator_id :integer -# default_branch :string(255) # issues_enabled :boolean default(TRUE), not null # wall_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null # namespace_id :integer -# public :boolean default(FALSE), not null # issues_tracker :string(255) default("gitlab"), not null # issues_tracker_id :string(255) # snippets_enabled :boolean default(TRUE), not null # last_activity_at :datetime # imported :boolean default(FALSE), not null # import_url :string(255) +# visibility_level :integer default(0), not null +# archived :boolean default(FALSE), not null # require 'spec_helper' @@ -47,6 +47,7 @@ describe Project do it { should have_many(:hooks).dependent(:destroy) } it { should have_many(:protected_branches).dependent(:destroy) } it { should have_one(:forked_project_link).dependent(:destroy) } + it { should have_one(:slack_service).dependent(:destroy) } end describe "Mass assignment" do @@ -71,7 +72,7 @@ describe Project do it "should not allow new projects beyond user limits" do project2 = build(:project) - project2.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 0)) + project2.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 0).as_null_object) project2.should_not be_valid project2.errors[:limit_reached].first.should match(/Your own projects limit is 0/) end @@ -99,6 +100,11 @@ describe Project do project.web_url.should == "#{Gitlab.config.gitlab.url}/somewhere" end + it "returns the web URL without the protocol for this repo" do + project = Project.new(path: "somewhere") + project.web_url_without_protocol.should == "#{Gitlab.config.gitlab.url.split("://")[1]}/somewhere" + end + describe "last_activity methods" do let(:project) { create(:project) } let(:last_event) { double(created_at: Time.now) } @@ -123,7 +129,7 @@ describe Project do end describe :update_merge_requests do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } before do @merge_request = create(:merge_request, source_project: project, target_project: project) @@ -131,18 +137,17 @@ describe Project do end it "should close merge request if last commit from source branch was pushed to target branch" do - @merge_request.reloaded_commits - @merge_request.last_commit.id.should == "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828" - project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828", "refs/heads/stable", @key.user) + @merge_request.reload_code + @merge_request.last_commit.id.should == "69b34b7e9ad9f496f0ad10250be37d6265a03bba" + project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "69b34b7e9ad9f496f0ad10250be37d6265a03bba", "refs/heads/stable", @key.user) @merge_request.reload @merge_request.merged?.should be_true end it "should update merge request commits with new one if pushed to source branch" do - @merge_request.last_commit.should == nil - project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828", "refs/heads/master", @key.user) + project.update_merge_requests("8716fc78f3c65bbf7bcf7b574febd583bc5d2812", "69b34b7e9ad9f496f0ad10250be37d6265a03bba", "refs/heads/master", @key.user) @merge_request.reload - @merge_request.last_commit.id.should == "b1e6a9dbf1c85e6616497a5e7bad9143a4bd0828" + @merge_request.last_commit.id.should == "69b34b7e9ad9f496f0ad10250be37d6265a03bba" end end @@ -151,10 +156,10 @@ describe Project do context 'with namespace' do before do @group = create :group, name: 'gitlab' - @project = create(:project, name: 'gitlab-ci', namespace: @group) + @project = create(:project, name: 'gitlabhq', namespace: @group) end - it { Project.find_with_namespace('gitlab/gitlab-ci').should == @project } + it { Project.find_with_namespace('gitlab/gitlabhq').should == @project } it { Project.find_with_namespace('gitlab-ci').should be_nil } end end @@ -163,10 +168,10 @@ describe Project do context 'with namespace' do before do @group = create :group, name: 'gitlab' - @project = create(:project, name: 'gitlab-ci', namespace: @group) + @project = create(:project, name: 'gitlabhq', namespace: @group) end - it { @project.to_param.should == "gitlab/gitlab-ci" } + it { @project.to_param.should == "gitlab/gitlabhq" } end end @@ -232,7 +237,7 @@ describe Project do end describe :open_branches do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } before do project.protected_branches.create(name: 'master') diff --git a/spec/models/service_hook_spec.rb b/spec/models/service_hook_spec.rb index 0b0262c97f1..40a5fbc71d9 100644 --- a/spec/models/service_hook_spec.rb +++ b/spec/models/service_hook_spec.rb @@ -2,13 +2,16 @@ # # Table name: web_hooks # -# id :integer not null, primary key -# url :string(255) -# project_id :integer -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) default("ProjectHook") -# service_id :integer +# id :integer not null, primary key +# url :string(255) +# project_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) default("ProjectHook") +# service_id :integer +# push_events :boolean default(TRUE), not null +# issues_events :boolean default(FALSE), not null +# merge_requests_events :boolean default(FALSE), not null # require "spec_helper" diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb index 667c80bcf19..94542074967 100644 --- a/spec/models/service_spec.rb +++ b/spec/models/service_spec.rb @@ -13,6 +13,7 @@ # project_url :string(255) # subdomain :string(255) # room :string(255) +# api_key :string(255) # require 'spec_helper' @@ -44,12 +45,12 @@ describe Service do end describe :can_test do - it { @testable.should == false } + it { @testable.should == true } end end describe "With commits" do - let (:project) { create :project_with_code } + let (:project) { create :project } before do @service.stub( diff --git a/spec/models/slack_message_spec.rb b/spec/models/slack_message_spec.rb new file mode 100644 index 00000000000..b39cd4edf82 --- /dev/null +++ b/spec/models/slack_message_spec.rb @@ -0,0 +1,56 @@ +require_relative '../../app/models/project_services/slack_message' + +describe SlackMessage do + subject { SlackMessage.new(args) } + + let(:args) { + { + after: 'after', + before: 'before', + project_name: 'project_name', + ref: 'refs/heads/master', + user_name: 'user_name', + project_url: 'url' + } + } + + context 'push' do + before do + args[:commits] = [ + { message: 'message1', url: 'url1', id: 'abcdefghi' }, + { message: 'message2', url: 'url2', id: '123456789' }, + ] + end + + it 'returns a message regarding pushes' do + subject.compose.should == + 'user_name pushed to branch <url/commits/master|master> of ' << + '<url|project_name> (<url/compare/before...after|Compare changes>)' << + "\n - message1 (<url1|abcdef>)" << + "\n - message2 (<url2|123456>)" + end + end + + context 'new branch' do + before do + args[:before] = '000000' + end + + it 'returns a message regarding a new branch' do + subject.compose.should == + 'user_name pushed new branch <url/commits/master|master> to ' << + '<url|project_name>' + end + end + + context 'removed branch' do + before do + args[:after] = '000000' + end + + it 'returns a message regarding a removed branch' do + subject.compose.should == + 'user_name removed branch master from <url|project_name>' + end + end +end diff --git a/spec/models/slack_service_spec.rb b/spec/models/slack_service_spec.rb new file mode 100644 index 00000000000..387455cb25e --- /dev/null +++ b/spec/models/slack_service_spec.rb @@ -0,0 +1,69 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# token :string(255) +# project_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# active :boolean default(FALSE), not null +# project_url :string(255) +# subdomain :string(255) +# room :string(255) +# api_key :string(255) +# + +require 'spec_helper' + +describe SlackService do + describe "Associations" do + it { should belong_to :project } + it { should have_one :service_hook } + end + + describe "Validations" do + context "active" do + before do + subject.active = true + end + + it { should validate_presence_of :room } + it { should validate_presence_of :subdomain } + it { should validate_presence_of :token } + end + end + + describe "Execute" do + let(:slack) { SlackService.new } + let(:user) { create(:user) } + let(:project) { create(:project) } + let(:sample_data) { GitPushService.new.sample_data(project, user) } + let(:subdomain) { 'gitlab' } + let(:token) { 'verySecret' } + let(:api_url) { + "https://#{subdomain}.slack.com/services/hooks/incoming-webhook?token=#{token}" + } + + before do + slack.stub( + project: project, + project_id: project.id, + room: '#gitlab', + service_hook: true, + subdomain: subdomain, + token: token + ) + + WebMock.stub_request(:post, api_url) + end + + it "should call Slack API" do + slack.execute(sample_data) + + WebMock.should have_requested(:post, api_url).once + end + end +end diff --git a/spec/models/system_hook_spec.rb b/spec/models/system_hook_spec.rb index a9ed6a5fa7c..6a0d99dcc53 100644 --- a/spec/models/system_hook_spec.rb +++ b/spec/models/system_hook_spec.rb @@ -2,13 +2,16 @@ # # Table name: web_hooks # -# id :integer not null, primary key -# url :string(255) -# project_id :integer -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) default("ProjectHook") -# service_id :integer +# id :integer not null, primary key +# url :string(255) +# project_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) default("ProjectHook") +# service_id :integer +# push_events :boolean default(TRUE), not null +# issues_events :boolean default(FALSE), not null +# merge_requests_events :boolean default(FALSE), not null # require "spec_helper" diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index f6c9f82c4ee..fef6314f23a 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -36,6 +36,13 @@ # notification_level :integer default(1), not null # password_expires_at :datetime # created_by_id :integer +# avatar :string(255) +# confirmation_token :string(255) +# confirmed_at :datetime +# confirmation_sent_at :datetime +# unconfirmed_email :string(255) +# hide_no_ssh_key :boolean default(FALSE) +# website_url :string(255) default(""), not null # require 'spec_helper' @@ -69,6 +76,27 @@ describe User do it { should_not allow_value(-1).for(:projects_limit) } it { should ensure_length_of(:bio).is_within(0..255) } + + describe 'email' do + it 'accepts info@example.com' do + user = build(:user, email: 'info@example.com') + expect(user).to be_valid + end + it 'accepts info+test@example.com' do + user = build(:user, email: 'info+test@example.com') + expect(user).to be_valid + end + + it 'rejects test@test@example.com' do + user = build(:user, email: 'test@test@example.com') + expect(user).to be_invalid + end + + it 'rejects mailto:test@example.com' do + user = build(:user, email: 'mailto:test@example.com') + expect(user).to be_invalid + end + end end describe "Respond to" do @@ -85,8 +113,8 @@ describe User do end it "should not generate password by default" do - user = create(:user, password: 'abcdefg') - user.password.should == 'abcdefg' + user = create(:user, password: 'abcdefghe') + user.password.should == 'abcdefghe' end it "should generate password when forcing random password" do @@ -135,7 +163,6 @@ describe User do end it { @user.several_namespaces?.should be_true } - it { @user.namespaces.should include(@user.namespace) } it { @user.authorized_groups.should == [@group] } it { @user.owned_groups.should == [@group] } end @@ -162,7 +189,6 @@ describe User do end it { @user.several_namespaces?.should be_false } - it { @user.namespaces.should == [@user.namespace] } end describe 'blocking user' do @@ -266,6 +292,20 @@ describe User do end end + describe 'search' do + let(:user1) { create(:user, username: 'James', email: 'james@testing.com') } + let(:user2) { create(:user, username: 'jameson', email: 'jameson@example.com') } + + it "should be case insensitive" do + User.search(user1.username.upcase).to_a.should == [user1] + User.search(user1.username.downcase).to_a.should == [user1] + User.search(user2.username.upcase).to_a.should == [user2] + User.search(user2.username.downcase).to_a.should == [user2] + User.search(user1.username.downcase).to_a.count.should == 2 + User.search(user2.username.downcase).to_a.count.should == 1 + end + end + describe 'by_username_or_id' do let(:user1) { create(:user, username: 'foo') } @@ -276,4 +316,73 @@ describe User do User.by_username_or_id('bar').should be_nil end end + + describe 'all_ssh_keys' do + it { should have_many(:keys).dependent(:destroy) } + + it "should have all ssh keys" do + user = create :user + key = create :key, key: "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD33bWLBxu48Sev9Fert1yzEO4WGcWglWF7K/AwblIUFselOt/QdOL9DSjpQGxLagO1s9wl53STIO8qGS4Ms0EJZyIXOEFMjFJ5xmjSy+S37By4sG7SsltQEHMxtbtFOaW5LV2wCrX+rUsRNqLMamZjgjcPO0/EgGCXIGMAYW4O7cwGZdXWYIhQ1Vwy+CsVMDdPkPgBXqK7nR/ey8KMs8ho5fMNgB5hBw/AL9fNGhRw3QTD6Q12Nkhl4VZES2EsZqlpNnJttnPdp847DUsT6yuLRlfiQfz5Cn9ysHFdXObMN5VYIiPFwHeYCZp1X2S4fDZooRE8uOLTfxWHPXwrhqSH", user_id: user.id + + user.all_ssh_keys.should include(key.key) + end + end + + describe :avatar_type do + let(:user) { create(:user) } + + it "should be true if avatar is image" do + user.update_attribute(:avatar, 'uploads/avatar.png') + user.avatar_type.should be_true + end + + it "should be false if avatar is html page" do + user.update_attribute(:avatar, 'uploads/avatar.html') + user.avatar_type.should == ["only images allowed"] + end + end + + describe '#full_website_url' do + let(:user) { create(:user) } + + it 'begins with http if website url omits it' do + user.website_url = 'test.com' + + expect(user.full_website_url).to eq 'http://test.com' + end + + it 'begins with http if website url begins with http' do + user.website_url = 'http://test.com' + + expect(user.full_website_url).to eq 'http://test.com' + end + + it 'begins with https if website url begins with https' do + user.website_url = 'https://test.com' + + expect(user.full_website_url).to eq 'https://test.com' + end + end + + describe '#short_website_url' do + let(:user) { create(:user) } + + it 'does not begin with http if website url omits it' do + user.website_url = 'test.com' + + expect(user.short_website_url).to eq 'test.com' + end + + it 'does not begin with http if website url begins with http' do + user.website_url = 'http://test.com' + + expect(user.short_website_url).to eq 'test.com' + end + + it 'does not begin with https if website url begins with https' do + user.website_url = 'https://test.com' + + expect(user.short_website_url).to eq 'test.com' + end + end end diff --git a/spec/models/web_hook_spec.rb b/spec/models/web_hook_spec.rb index 2d9301732dd..d6034081018 100644 --- a/spec/models/web_hook_spec.rb +++ b/spec/models/web_hook_spec.rb @@ -2,13 +2,16 @@ # # Table name: web_hooks # -# id :integer not null, primary key -# url :string(255) -# project_id :integer -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) default("ProjectHook") -# service_id :integer +# id :integer not null, primary key +# url :string(255) +# project_id :integer +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) default("ProjectHook") +# service_id :integer +# push_events :boolean default(TRUE), not null +# issues_events :boolean default(FALSE), not null +# merge_requests_events :boolean default(FALSE), not null # require 'spec_helper' diff --git a/spec/models/wiki_page_spec.rb b/spec/models/wiki_page_spec.rb index 67f2a6da42d..1c70edf0d4d 100644 --- a/spec/models/wiki_page_spec.rb +++ b/spec/models/wiki_page_spec.rb @@ -2,12 +2,6 @@ require "spec_helper" describe WikiPage do - def create_temp_repo(path) - FileUtils.mkdir_p path - command = "git init --quiet #{path};" - system(command) - end - def remove_temp_repo(path) FileUtils.rm_rf path end diff --git a/spec/observers/activity_observer_spec.rb b/spec/observers/activity_observer_spec.rb deleted file mode 100644 index dc14ab86b6d..00000000000 --- a/spec/observers/activity_observer_spec.rb +++ /dev/null @@ -1,61 +0,0 @@ -require 'spec_helper' - -describe ActivityObserver do - let(:project) { create(:project) } - - before { Thread.current[:current_user] = create(:user) } - - def self.it_should_be_valid_event - it { @event.should_not be_nil } - it { @event.project.should == project } - end - - describe "Issue created" do - before do - Issue.observers.enable :activity_observer do - @issue = create(:issue, project: project) - @event = Event.last - end - end - - it_should_be_valid_event - it { @event.action.should == Event::CREATED } - it { @event.target.should == @issue } - end - - describe "Issue commented" do - before do - Note.observers.enable :activity_observer do - @issue = create(:issue, project: project) - @note = create(:note, noteable: @issue, project: project, author: @issue.author) - @event = Event.last - end - end - - it_should_be_valid_event - it { @event.action.should == Event::COMMENTED } - it { @event.target.should == @note } - end - - describe "Ignore system notes" do - let(:author) { create(:user) } - let!(:issue) { create(:issue, project: project) } - let!(:other) { create(:issue) } - - it "should not create events for status change notes" do - expect do - Note.observers.enable :activity_observer do - Note.create_status_change_note(issue, project, author, 'reopened', nil) - end - end.to_not change { Event.count } - end - - it "should not create events for cross-reference notes" do - expect do - Note.observers.enable :activity_observer do - Note.create_cross_reference_note(issue, other, author, issue.project) - end - end.to_not change { Event.count } - end - end -end diff --git a/spec/observers/email_observer_spec.rb b/spec/observers/email_observer_spec.rb new file mode 100644 index 00000000000..599b9a6ffba --- /dev/null +++ b/spec/observers/email_observer_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe EmailObserver do + let(:email) { create(:email) } + + before { subject.stub(notification: double('NotificationService').as_null_object) } + + subject { EmailObserver.instance } + + describe '#after_create' do + it 'trigger notification to send emails' do + subject.should_receive(:notification) + + subject.after_create(email) + end + end +end diff --git a/spec/observers/issue_observer_spec.rb b/spec/observers/issue_observer_spec.rb index 4155ff31193..9a0a2c4329c 100644 --- a/spec/observers/issue_observer_spec.rb +++ b/spec/observers/issue_observer_spec.rb @@ -9,7 +9,7 @@ describe IssueObserver do before { subject.stub(:current_user).and_return(some_user) } before { subject.stub(:current_commit).and_return(nil) } - before { subject.stub(notification: mock('NotificationService').as_null_object) } + before { subject.stub(notification: double('NotificationService').as_null_object) } before { mock_issue.project.stub_chain(:repository, :commit).and_return(nil) } subject { IssueObserver.instance } diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb index 3f5250a0040..18df8b78513 100644 --- a/spec/observers/merge_request_observer_spec.rb +++ b/spec/observers/merge_request_observer_spec.rb @@ -4,16 +4,17 @@ describe MergeRequestObserver do let(:some_user) { create :user } let(:assignee) { create :user } let(:author) { create :user } - let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author) } - let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author, target_project: create(:project)) } - let(:unassigned_mr) { create(:merge_request, author: author, target_project: create(:project)) } - let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author, target_project: create(:project)) } - let(:closed_unassigned_mr) { create(:closed_merge_request, author: author, target_project: create(:project)) } + let(:project) { create :project } + let(:mr_mock) { double(:merge_request, id: 42, assignee: assignee, author: author).as_null_object } + let(:assigned_mr) { create(:merge_request, assignee: assignee, author: author, source_project: project) } + let(:unassigned_mr) { create(:merge_request, author: author, source_project: project) } + let(:closed_assigned_mr) { create(:closed_merge_request, assignee: assignee, author: author, source_project: project) } + let(:closed_unassigned_mr) { create(:closed_merge_request, author: author, source_project: project) } before { subject.stub(:current_user).and_return(some_user) } - before { subject.stub(notification: mock('NotificationService').as_null_object) } + before { subject.stub(notification: double('NotificationService').as_null_object) } before { mr_mock.stub(:author_id) } - before { mr_mock.stub(:target_project) } + before { mr_mock.stub(:source_project) } before { mr_mock.stub(:source_project) } before { mr_mock.stub(:project) } before { mr_mock.stub(:create_cross_references!).and_return(true) } @@ -46,7 +47,7 @@ describe MergeRequestObserver do end it 'is called when a merge request is changed' do - changed = create(:merge_request, source_project: create(:project)) + changed = create(:merge_request, source_project: project) subject.should_receive(:after_update) MergeRequest.observers.enable :merge_request_observer do @@ -81,13 +82,13 @@ describe MergeRequestObserver do context '#after_close' do context 'a status "closed"' do it 'note is created if the merge request is being closed' do - Note.should_receive(:create_status_change_note).with(assigned_mr, assigned_mr.target_project, some_user, 'closed', nil) + Note.should_receive(:create_status_change_note).with(assigned_mr, assigned_mr.source_project, some_user, 'closed', nil) assigned_mr.close end it 'notification is delivered only to author if the merge request is being closed' do - Note.should_receive(:create_status_change_note).with(unassigned_mr, unassigned_mr.target_project, some_user, 'closed', nil) + Note.should_receive(:create_status_change_note).with(unassigned_mr, unassigned_mr.source_project, some_user, 'closed', nil) unassigned_mr.close end @@ -97,13 +98,13 @@ describe MergeRequestObserver do context '#after_reopen' do context 'a status "reopened"' do it 'note is created if the merge request is being reopened' do - Note.should_receive(:create_status_change_note).with(closed_assigned_mr, closed_assigned_mr.target_project, some_user, 'reopened', nil) + Note.should_receive(:create_status_change_note).with(closed_assigned_mr, closed_assigned_mr.source_project, some_user, 'reopened', nil) closed_assigned_mr.reopen end it 'notification is delivered only to author if the merge request is being reopened' do - Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, closed_unassigned_mr.target_project, some_user, 'reopened', nil) + Note.should_receive(:create_status_change_note).with(closed_unassigned_mr, closed_unassigned_mr.source_project, some_user, 'reopened', nil) closed_unassigned_mr.reopen end @@ -118,20 +119,13 @@ describe MergeRequestObserver do it { @event.project.should == project } end - let(:project) { create(:project) } before do - TestEnv.enable_observers @merge_request = create(:merge_request, source_project: project, target_project: project) @event = Event.last end - after do - TestEnv.disable_observers - end - it_should_be_valid_event it { @event.action.should == Event::CREATED } it { @event.target.should == @merge_request } end - end diff --git a/spec/observers/note_observer_spec.rb b/spec/observers/note_observer_spec.rb index f9b96c255c1..f8693355b23 100644 --- a/spec/observers/note_observer_spec.rb +++ b/spec/observers/note_observer_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe NoteObserver do subject { NoteObserver.instance } - before { subject.stub(notification: mock('NotificationService').as_null_object) } + before { subject.stub(notification: double('NotificationService').as_null_object) } let(:team_without_author) { (1..2).map { |n| double :user, id: n } } let(:note) { double(:note).as_null_object } diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb index b74fceb98b1..9aeade535f9 100644 --- a/spec/observers/user_observer_spec.rb +++ b/spec/observers/user_observer_spec.rb @@ -4,7 +4,7 @@ describe UserObserver do before(:each) { enable_observers } after(:each) {disable_observers} subject { UserObserver.instance } - before { subject.stub(notification: mock('NotificationService').as_null_object) } + before { subject.stub(notification: double('NotificationService').as_null_object) } it 'calls #after_create when new users are created' do new_user = build(:user) diff --git a/spec/observers/users_group_observer_spec.rb b/spec/observers/users_group_observer_spec.rb index 3bf562edbb7..2ab99c33b78 100644 --- a/spec/observers/users_group_observer_spec.rb +++ b/spec/observers/users_group_observer_spec.rb @@ -5,7 +5,7 @@ describe UsersGroupObserver do after(:each) { disable_observers } subject { UsersGroupObserver.instance } - before { subject.stub(notification: mock('NotificationService').as_null_object) } + before { subject.stub(notification: double('NotificationService').as_null_object) } describe "#after_create" do it "should send email to user" do @@ -23,5 +23,10 @@ describe UsersGroupObserver do subject.should_receive(:notification) @membership.update_attribute(:group_access, UsersGroup::MASTER) end + + it "does not send an email when the access level has not changed" do + subject.should_not_receive(:notification) + @membership.update_attribute(:group_access, UsersGroup::OWNER) + end end end diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb index e7c624fce59..be277b4dbd2 100644 --- a/spec/observers/users_project_observer_spec.rb +++ b/spec/observers/users_project_observer_spec.rb @@ -7,27 +7,7 @@ describe UsersProjectObserver do let(:user) { create(:user) } let(:project) { create(:project) } subject { UsersProjectObserver.instance } - before { subject.stub(notification: mock('NotificationService').as_null_object) } - - describe "#after_commit" do - it "should called when UsersProject created" do - subject.should_receive(:after_commit) - create(:users_project) - end - - it "should send email to user" do - subject.should_receive(:notification) - Event.stub(create: true) - - create(:users_project) - end - - it "should create new event" do - Event.should_receive(:create) - - create(:users_project) - end - end + before { subject.stub(notification: double('NotificationService').as_null_object) } describe "#after_update" do before do @@ -35,7 +15,7 @@ describe UsersProjectObserver do end it "should called when UsersProject updated" do - subject.should_receive(:after_commit) + subject.should_receive(:after_update) @users_project.update_attribute(:project_access, UsersProject::MASTER) end @@ -45,7 +25,7 @@ describe UsersProjectObserver do end it "should not called after UsersProject destroyed" do - subject.should_not_receive(:after_commit) + subject.should_not_receive(:after_update) @users_project.destroy end end @@ -67,28 +47,17 @@ describe UsersProjectObserver do end describe "#after_create" do - context 'wiki_enabled creates repository directory' do - context 'wiki_enabled true creates wiki repository directory' do - before do - @project = create(:project, wiki_enabled: true) - @path = GollumWiki.new(@project, user).send(:path_to_repo) - end - - after do - FileUtils.rm_rf(@path) - end + it "should send email to user" do + subject.should_receive(:notification) + Event.stub(create: true) - it { File.exists?(@path).should be_true } - end + create(:users_project) + end - context 'wiki_enabled false does not create wiki repository directory' do - before do - @project = create(:project, wiki_enabled: false) - @path = GollumWiki.new(@project, user).send(:path_to_repo) - end + it "should create new event" do + Event.should_receive(:create) - it { File.exists?(@path).should be_false } - end + create(:users_project) end end -end
\ No newline at end of file +end diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb new file mode 100644 index 00000000000..ea317e1137a --- /dev/null +++ b/spec/requests/api/commits_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' +require 'mime/types' + +describe API::API do + include ApiHelpers + before(:each) { enable_observers } + after(:each) {disable_observers} + + let(:user) { create(:user) } + let(:user2) { create(:user) } + let!(:project) { create(:project, creator_id: user.id) } + let!(:master) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } + let!(:guest) { create(:users_project, user: user2, project: project, project_access: UsersProject::GUEST) } + + before { project.team << [user, :reporter] } + + describe "GET /projects/:id/repository/commits" do + context "authorized user" do + before { project.team << [user2, :reporter] } + + it "should return project commits" do + get api("/projects/#{project.id}/repository/commits", user) + response.status.should == 200 + + json_response.should be_an Array + json_response.first['id'].should == project.repository.commit.id + end + end + + context "unauthorized user" do + it "should not return project commits" do + get api("/projects/#{project.id}/repository/commits") + response.status.should == 401 + end + end + end + + describe "GET /projects:id/repository/commits/:sha" do + context "authorized user" do + it "should return a commit by sha" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) + response.status.should == 200 + json_response['id'].should == project.repository.commit.id + json_response['title'].should == project.repository.commit.title + end + + it "should return a 404 error if not found" do + get api("/projects/#{project.id}/repository/commits/invalid_sha", user) + response.status.should == 404 + end + end + + context "unauthorized user" do + it "should not return the selected commit" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}") + response.status.should == 401 + end + end + end + + describe "GET /projects:id/repository/commits/:sha/diff" do + context "authorized user" do + before { project.team << [user2, :reporter] } + + it "should return the diff of the selected commit" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user) + response.status.should == 200 + + json_response.should be_an Array + json_response.length.should >= 1 + json_response.first.keys.should include "diff" + end + + it "should return a 404 error if invalid commit" do + get api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user) + response.status.should == 404 + end + end + + context "unauthorized user" do + it "should not return the diff of the selected commit" do + get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff") + response.status.should == 401 + end + end + end +end diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb new file mode 100644 index 00000000000..fa25a4bec6a --- /dev/null +++ b/spec/requests/api/files_spec.rb @@ -0,0 +1,145 @@ +require 'spec_helper' + +describe API::API do + include ApiHelpers + before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } + after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } + + let(:user) { create(:user) } + let!(:project) { create(:project, namespace: user.namespace ) } + before { project.team << [user, :developer] } + + describe "GET /projects/:id/repository/files" do + it "should return file info" do + params = { + file_path: 'app/models/key.rb', + ref: 'master', + } + + get api("/projects/#{project.id}/repository/files", user), params + response.status.should == 200 + json_response['file_path'].should == 'app/models/key.rb' + json_response['file_name'].should == 'key.rb' + Base64.decode64(json_response['content']).lines.first.should == "class Key < ActiveRecord::Base\n" + end + + it "should return a 400 bad request if no params given" do + get api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return 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 + response.status.should == 404 + end + end + + describe "POST /projects/:id/repository/files" do + let(:valid_params) { + { + file_path: 'newfile.rb', + branch_name: 'master', + content: 'puts 8', + commit_message: 'Added newfile' + } + } + + it "should create a new file in project repo" do + Gitlab::Satellite::NewFileAction.any_instance.stub( + commit!: true, + ) + + post api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 201 + json_response['file_path'].should == 'newfile.rb' + end + + it "should return a 400 bad request if no params given" do + post api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return a 400 if satellite fails to create file" do + Gitlab::Satellite::NewFileAction.any_instance.stub( + commit!: false, + ) + + post api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 400 + end + end + + describe "PUT /projects/:id/repository/files" do + let(:valid_params) { + { + file_path: 'spec/spec_helper.rb', + branch_name: 'master', + content: 'puts 8', + commit_message: 'Changed file' + } + } + + it "should update existing file in project repo" do + Gitlab::Satellite::EditFileAction.any_instance.stub( + commit!: true, + ) + + put api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 200 + json_response['file_path'].should == 'spec/spec_helper.rb' + end + + it "should return a 400 bad request if no params given" do + put api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return a 400 if satellite fails to create file" do + Gitlab::Satellite::EditFileAction.any_instance.stub( + commit!: false, + ) + + put api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 400 + end + end + + describe "DELETE /projects/:id/repository/files" do + let(:valid_params) { + { + file_path: 'spec/spec_helper.rb', + branch_name: 'master', + commit_message: 'Changed file' + } + } + + it "should delete existing file in project repo" do + Gitlab::Satellite::DeleteFileAction.any_instance.stub( + commit!: true, + ) + + delete api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 200 + json_response['file_path'].should == 'spec/spec_helper.rb' + end + + it "should return a 400 bad request if no params given" do + delete api("/projects/#{project.id}/repository/files", user) + response.status.should == 400 + end + + it "should return a 400 if satellite fails to create file" do + Gitlab::Satellite::DeleteFileAction.any_instance.stub( + commit!: false, + ) + + delete api("/projects/#{project.id}/repository/files", user), valid_params + response.status.should == 400 + end + end +end diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 25b9a10bd8c..1a5f11038b7 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -147,7 +147,7 @@ describe API::API do describe "POST /groups/:id/projects/:project_id" do let(:project) { create(:project) } before(:each) do - project.stub!(:transfer).and_return(true) + project.stub(:transfer).and_return(true) Project.stub(:find).and_return(project) end diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb index e8870f4d5d8..5f6dff92c0a 100644 --- a/spec/requests/api/internal_spec.rb +++ b/spec/requests/api/internal_spec.rb @@ -103,6 +103,33 @@ describe API::API do end end + context "archived project" do + let(:personal_project) { create(:project, namespace: user.namespace) } + + before do + project.team << [user, :developer] + project.archive! + end + + context "git pull" do + it do + pull(key, project) + + response.status.should == 200 + response.body.should == 'true' + end + end + + context "git push" do + it do + push(key, project) + + response.status.should == 200 + response.body.should == 'false' + end + end + end + context "deploy key" do let(:key) { create(:deploy_key) } diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb index 505e9597e1b..0b4f22bfb3d 100644 --- a/spec/requests/api/issues_spec.rb +++ b/spec/requests/api/issues_spec.rb @@ -106,16 +106,4 @@ describe API::API do response.status.should == 405 end end - - describe "PUT /projects/:id/issues/:issue_id to test observer on close" do - before { enable_observers } - after { disable_observers } - - it "should create an activity event when an issue is closed" do - Event.should_receive(:create) - - put api("/projects/#{project.id}/issues/#{issue.id}", user), - state_event: "close" - end - end end diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb index f31b4da90cd..138f218d46c 100644 --- a/spec/requests/api/merge_requests_spec.rb +++ b/spec/requests/api/merge_requests_spec.rb @@ -5,8 +5,9 @@ describe API::API do before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } let(:user) { create(:user) } - let!(:project) {create(:project_with_code, creator_id: user.id, namespace: user.namespace) } + let!(:project) {create(:project, creator_id: user.id, namespace: user.namespace) } let!(:merge_request) { create(:merge_request, author: user, assignee: user, source_project: project, target_project: project, title: "Test") } + let!(:note) { create(:note_on_merge_request, author: user, project: project, noteable: merge_request, note: "a comment on a MR") } before { project.team << [user, :reporters] } @@ -47,32 +48,32 @@ describe API::API do context 'between branches projects' do it "should return merge_request" do post api("/projects/#{project.id}/merge_requests", user), - title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user + title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user response.status.should == 201 json_response['title'].should == 'Test merge_request' end it "should return 422 when source_branch equals target_branch" do post api("/projects/#{project.id}/merge_requests", user), - title: "Test merge_request", source_branch: "master", target_branch: "master", author: user + title: "Test merge_request", source_branch: "master", target_branch: "master", author: user response.status.should == 422 end it "should return 400 when source_branch is missing" do post api("/projects/#{project.id}/merge_requests", user), - title: "Test merge_request", target_branch: "master", author: user + title: "Test merge_request", target_branch: "master", author: user response.status.should == 400 end it "should return 400 when target_branch is missing" do post api("/projects/#{project.id}/merge_requests", user), - title: "Test merge_request", source_branch: "stable", author: user + title: "Test merge_request", source_branch: "stable", author: user response.status.should == 400 end it "should return 400 when title is missing" do post api("/projects/#{project.id}/merge_requests", user), - target_branch: 'master', source_branch: 'stable' + target_branch: 'master', source_branch: 'stable' response.status.should == 400 end end @@ -80,8 +81,8 @@ describe API::API do context 'forked projects' do let!(:user2) {create(:user)} let!(:forked_project_link) { build(:forked_project_link) } - let!(:fork_project) { create(:source_project_with_code, forked_project_link: forked_project_link, namespace: user2.namespace, creator_id: user2.id) } - let!(:unrelated_project) { create(:target_project_with_code, namespace: user2.namespace, creator_id: user2.id) } + let!(:fork_project) { create(:project, forked_project_link: forked_project_link, namespace: user2.namespace, creator_id: user2.id) } + let!(:unrelated_project) { create(:project, namespace: create(:user).namespace, creator_id: user2.id) } before :each do |each| fork_project.team << [user2, :reporters] @@ -92,9 +93,10 @@ describe API::API do it "should return merge_request" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', source_branch: "stable", target_branch: "master", author: user2, target_project_id: project.id, description: 'Test description for Test merge_request' response.status.should == 201 json_response['title'].should == 'Test merge_request' + json_response['description'].should == 'Test description for Test merge_request' end it "should not return 422 when source_branch equals target_branch" do @@ -102,44 +104,44 @@ describe API::API do fork_project.forked?.should be_true fork_project.forked_from_project.should == project post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', source_branch: "master", target_branch: "master", author: user2, target_project_id: project.id response.status.should == 201 json_response['title'].should == 'Test merge_request' end it "should return 400 when source_branch is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id response.status.should == 400 end it "should return 400 when target_branch is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id + title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id response.status.should == 400 end it "should return 400 when title is missing" do post api("/projects/#{fork_project.id}/merge_requests", user2), - target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: project.id + target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: project.id response.status.should == 400 end it "should return 400 when target_branch is specified and not a forked project" do post api("/projects/#{project.id}/merge_requests", user), - title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user, target_project_id: fork_project.id + title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user, target_project_id: fork_project.id response.status.should == 400 end it "should return 400 when target_branch is specified and for a different fork" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: unrelated_project.id + title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: unrelated_project.id response.status.should == 400 end it "should return 201 when target_branch is specified and for the same project" do post api("/projects/#{fork_project.id}/merge_requests", user2), - title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: fork_project.id + title: 'Test merge_request', target_branch: 'master', source_branch: 'stable', author: user2, target_project_id: fork_project.id response.status.should == 201 end end @@ -168,9 +170,15 @@ describe API::API do json_response['title'].should == 'New title' end + it "should return merge_request" do + put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), description: "New description" + response.status.should == 200 + json_response['description'].should == 'New description' + end + it "should return 422 when source_branch and target_branch are renamed the same" do put api("/projects/#{project.id}/merge_request/#{merge_request.id}", user), - source_branch: "master", target_branch: "master" + source_branch: "master", target_branch: "master" response.status.should == 422 end @@ -199,4 +207,19 @@ describe API::API do end end + describe "GET :id/merge_request/:merge_request_id/comments" do + it "should return merge_request comments" do + get api("/projects/#{project.id}/merge_request/#{merge_request.id}/comments", user) + response.status.should == 200 + json_response.should be_an Array + json_response.length.should == 1 + json_response.first['note'].should == "a comment on a MR" + json_response.first['author']['id'].should == user.id + end + + it "should return a 404 error if merge_request_id not found" do + get api("/projects/#{project.id}/merge_request/999/comments", user) + response.status.should == 404 + end + end end diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb new file mode 100644 index 00000000000..2b1a4bf6ec8 --- /dev/null +++ b/spec/requests/api/namespaces_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe API::API do + include ApiHelpers + before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } + after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } + + let(:admin) { create(:admin) } + let!(:group1) { create(:group) } + let!(:group2) { create(:group) } + + describe "GET /namespaces" do + context "when unauthenticated" do + it "should return authentication error" do + get api("/namespaces") + response.status.should == 401 + end + end + + context "when authenticated as admin" do + it "admin: should return an array of all namespaces" do + get api("/namespaces", admin) + response.status.should == 200 + json_response.should be_an Array + + # Admin namespace + 2 group namespaces + json_response.length.should == 3 + end + end + end +end diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb new file mode 100644 index 00000000000..c8ace0b9462 --- /dev/null +++ b/spec/requests/api/project_hooks_spec.rb @@ -0,0 +1,132 @@ +require 'spec_helper' + +describe API::API, 'ProjectHooks' do + include ApiHelpers + before(:each) { enable_observers } + after(:each) { disable_observers } + + let(:user) { create(:user) } + let(:user3) { create(:user) } + let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } + + before do + project.team << [user, :master] + project.team << [user3, :developer] + end + + describe "GET /projects/:id/hooks" do + context "authorized user" do + it "should return project hooks" do + get api("/projects/#{project.id}/hooks", user) + response.status.should == 200 + + json_response.should be_an Array + json_response.count.should == 1 + json_response.first['url'].should == "http://example.com" + end + end + + context "unauthorized user" do + it "should not access project hooks" do + get api("/projects/#{project.id}/hooks", user3) + response.status.should == 403 + end + end + end + + describe "GET /projects/:id/hooks/:hook_id" do + context "authorized user" do + it "should return a project hook" do + get api("/projects/#{project.id}/hooks/#{hook.id}", user) + response.status.should == 200 + json_response['url'].should == hook.url + end + + it "should return a 404 error if hook id is not available" do + get api("/projects/#{project.id}/hooks/1234", user) + response.status.should == 404 + end + end + + context "unauthorized user" do + it "should not access an existing hook" do + get api("/projects/#{project.id}/hooks/#{hook.id}", user3) + response.status.should == 403 + end + end + + it "should return a 404 error if hook id is not available" do + get api("/projects/#{project.id}/hooks/1234", user) + response.status.should == 404 + end + end + + describe "POST /projects/:id/hooks" do + it "should add hook to project" do + expect { + post api("/projects/#{project.id}/hooks", user), + url: "http://example.com", issues_events: true + }.to change {project.hooks.count}.by(1) + response.status.should == 201 + end + + it "should return a 400 error if url not given" do + post api("/projects/#{project.id}/hooks", user) + response.status.should == 400 + end + + it "should return a 422 error if url not valid" do + post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com" + response.status.should == 422 + end + end + + describe "PUT /projects/:id/hooks/:hook_id" do + it "should update an existing project hook" do + put api("/projects/#{project.id}/hooks/#{hook.id}", user), + url: 'http://example.org', push_events: false + response.status.should == 200 + json_response['url'].should == 'http://example.org' + end + + it "should return 404 error if hook id not found" do + put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' + response.status.should == 404 + end + + it "should return 400 error if url is not given" do + put api("/projects/#{project.id}/hooks/#{hook.id}", user) + response.status.should == 400 + end + + it "should return a 422 error if url is not valid" do + put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com' + response.status.should == 422 + end + end + + describe "DELETE /projects/:id/hooks/:hook_id" do + it "should delete hook from project" do + expect { + delete api("/projects/#{project.id}/hooks/#{hook.id}", user) + }.to change {project.hooks.count}.by(-1) + response.status.should == 200 + end + + it "should return success when deleting hook" do + delete api("/projects/#{project.id}/hooks/#{hook.id}", user) + response.status.should == 200 + end + + it "should return success when deleting non existent hook" do + delete api("/projects/#{project.id}/hooks/42", user) + response.status.should == 200 + end + + it "should return a 405 error if hook id not given" do + delete api("/projects/#{project.id}/hooks", user) + response.status.should == 405 + end + end +end diff --git a/spec/requests/api/project_members_spec.rb b/spec/requests/api/project_members_spec.rb new file mode 100644 index 00000000000..f3c0529da92 --- /dev/null +++ b/spec/requests/api/project_members_spec.rb @@ -0,0 +1,156 @@ +require 'spec_helper' + +describe API::API do + include ApiHelpers + before(:each) { enable_observers } + after(:each) { disable_observers } + + let(:user) { create(:user) } + let(:user2) { create(:user) } + let(:user3) { create(:user) } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } + let(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } + + describe "GET /projects/:id/members" do + before { users_project } + before { users_project2 } + + it "should return project team members" do + get api("/projects/#{project.id}/members", user) + response.status.should == 200 + json_response.should be_an Array + json_response.count.should == 2 + json_response.map { |u| u['email'] }.should include user.email + end + + it "finds team members with query string" do + get api("/projects/#{project.id}/members", user), query: user.username + response.status.should == 200 + json_response.should be_an Array + json_response.count.should == 1 + json_response.first['email'].should == user.email + end + + it "should return a 404 error if id not found" do + get api("/projects/9999/members", user) + response.status.should == 404 + end + end + + describe "GET /projects/:id/members/:user_id" do + before { users_project } + + it "should return project team member" do + get api("/projects/#{project.id}/members/#{user.id}", user) + response.status.should == 200 + json_response['email'].should == user.email + json_response['access_level'].should == UsersProject::MASTER + end + + it "should return a 404 error if user id not found" do + get api("/projects/#{project.id}/members/1234", user) + response.status.should == 404 + end + end + + describe "POST /projects/:id/members" do + it "should add user to project team" do + expect { + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + }.to change { UsersProject.count }.by(1) + + response.status.should == 201 + json_response['email'].should == user2.email + json_response['access_level'].should == UsersProject::DEVELOPER + end + + it "should return a 201 status if user is already project member" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + expect { + post api("/projects/#{project.id}/members", user), user_id: user2.id, + access_level: UsersProject::DEVELOPER + }.not_to change { UsersProject.count }.by(1) + + response.status.should == 201 + json_response['email'].should == user2.email + json_response['access_level'].should == UsersProject::DEVELOPER + end + + it "should return a 400 error when user id is not given" do + post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER + response.status.should == 400 + end + + it "should return a 400 error when access level is not given" do + post api("/projects/#{project.id}/members", user), user_id: user2.id + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234 + response.status.should == 422 + end + end + + describe "PUT /projects/:id/members/:user_id" do + before { users_project2 } + + it "should update project team member" do + put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: UsersProject::MASTER + response.status.should == 200 + json_response['email'].should == user3.email + json_response['access_level'].should == UsersProject::MASTER + end + + it "should return a 404 error if user_id is not found" do + put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER + response.status.should == 404 + end + + it "should return a 400 error when access level is not given" do + put api("/projects/#{project.id}/members/#{user3.id}", user) + response.status.should == 400 + end + + it "should return a 422 error when access level is not known" do + put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123 + response.status.should == 422 + end + end + + describe "DELETE /projects/:id/members/:user_id" do + before { users_project } + before { users_project2 } + + it "should remove user from project team" do + expect { + delete api("/projects/#{project.id}/members/#{user3.id}", user) + }.to change { UsersProject.count }.by(-1) + end + + it "should return 200 if team member is not part of a project" do + delete api("/projects/#{project.id}/members/#{user3.id}", user) + expect { + delete api("/projects/#{project.id}/members/#{user3.id}", user) + }.to_not change { UsersProject.count }.by(1) + end + + it "should return 200 if team member already removed" do + delete api("/projects/#{project.id}/members/#{user3.id}", user) + delete api("/projects/#{project.id}/members/#{user3.id}", user) + response.status.should == 200 + end + + it "should return 200 OK when the user was not member" do + expect { + delete api("/projects/#{project.id}/members/1000000", user) + }.to change { UsersProject.count }.by(0) + response.status.should == 200 + json_response['message'].should == "Access revoked" + json_response['id'].should == 1000000 + end + end +end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index bf4a1749418..7fe65639657 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -9,15 +9,15 @@ describe API::API do let(:user2) { create(:user) } let(:user3) { create(:user) } let(:admin) { create(:admin) } - let!(:project) { create(:project_with_code, creator_id: user.id, namespace: user.namespace) } - let!(:hook) { create(:project_hook, project: project, url: "http://example.com") } - let!(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } - let!(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } - let!(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } - - before { project.team << [user, :reporter] } + let(:project) { create(:project, creator_id: user.id, namespace: user.namespace) } + let(:snippet) { create(:project_snippet, author: user, project: project, title: 'example') } + let(:users_project) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } + let(:users_project2) { create(:users_project, user: user3, project: project, project_access: UsersProject::DEVELOPER) } + let(:issue_with_labels) { create(:issue, author: user, assignee: user, project: project, :label_list => "label1, label2") } describe "GET /projects" do + before { project } + context "when unauthenticated" do it "should return authentication error" do get api("/projects") @@ -36,6 +36,34 @@ describe API::API do end end + describe "GET /projects/all" do + before { project } + + context "when unauthenticated" do + it "should return authentication error" do + get api("/projects/all") + response.status.should == 401 + end + end + + context "when authenticated as regular user" do + it "should return authentication error" do + get api("/projects/all", user) + response.status.should == 403 + end + end + + context "when authenticated as admin" do + it "should return an array of all projects" do + get api("/projects/all", admin) + response.status.should == 200 + json_response.should be_an Array + json_response.first['name'].should == project.name + json_response.first['owner']['email'].should == user.email + end + end + end + describe "POST /projects" do context "maximum number of projects reached" do before do @@ -91,7 +119,6 @@ describe API::API do it "should assign attributes to project" do project = attributes_for(:project, { description: Faker::Lorem.sentence, - default_branch: 'stable', issues_enabled: false, wall_enabled: false, merge_requests_enabled: false, @@ -107,22 +134,50 @@ describe API::API do end it "should set a project as public" do + project = attributes_for(:project, :public) + post api("/projects", user), project + json_response['public'].should be_true + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC + end + + it "should set a project as public using :public" do project = attributes_for(:project, { public: true }) post api("/projects", user), project json_response['public'].should be_true + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC + end + it "should set a project as internal" do + project = attributes_for(:project, :internal) + post api("/projects", user), project + json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL end - it "should set a project as private" do - project = attributes_for(:project, { public: false }) + it "should set a project as internal overriding :public" do + project = attributes_for(:project, :internal, { public: true }) post api("/projects", user), project json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL + end + it "should set a project as private" do + project = attributes_for(:project, :private) + post api("/projects", user), project + json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE end + it "should set a project as private using :public" do + project = attributes_for(:project, { public: false }) + post api("/projects", user), project + json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE + end end describe "POST /projects/user/:id" do + before { project } before { admin } it "should create new project without path" do @@ -146,7 +201,6 @@ describe API::API do it "should assign attributes to project" do project = attributes_for(:project, { description: Faker::Lorem.sentence, - default_branch: 'stable', issues_enabled: false, wall_enabled: false, merge_requests_enabled: false, @@ -162,22 +216,52 @@ describe API::API do end it "should set a project as public" do + project = attributes_for(:project, :public) + post api("/projects/user/#{user.id}", admin), project + json_response['public'].should be_true + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC + end + + it "should set a project as public using :public" do project = attributes_for(:project, { public: true }) post api("/projects/user/#{user.id}", admin), project json_response['public'].should be_true + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PUBLIC + end + it "should set a project as internal" do + project = attributes_for(:project, :internal) + post api("/projects/user/#{user.id}", admin), project + json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL end - it "should set a project as private" do - project = attributes_for(:project, { public: false }) + it "should set a project as internal overriding :public" do + project = attributes_for(:project, :internal, { public: true }) post api("/projects/user/#{user.id}", admin), project json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::INTERNAL + end + it "should set a project as private" do + project = attributes_for(:project, :private) + post api("/projects/user/#{user.id}", admin), project + json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE end + it "should set a project as private using :public" do + project = attributes_for(:project, { public: false }) + post api("/projects/user/#{user.id}", admin), project + json_response['public'].should be_false + json_response['visibility_level'].should == Gitlab::VisibilityLevel::PRIVATE + end end describe "GET /projects/:id" do + before { project } + before { users_project } + it "should return a project by id" do get api("/projects/#{project.id}", user) response.status.should == 200 @@ -202,9 +286,33 @@ describe API::API do get api("/projects/#{project.id}", other_user) response.status.should == 404 end + + describe 'permissions' do + context 'personal project' do + before { get api("/projects/#{project.id}", user) } + + it { response.status.should == 200 } + it { json_response['permissions']["project_access"]["access_level"].should == Gitlab::Access::MASTER } + it { json_response['permissions']["group_access"].should be_nil } + end + + context 'group project' do + before do + project2 = create(:project, group: create(:group)) + project2.group.add_owner(user) + get api("/projects/#{project2.id}", user) + end + + it { response.status.should == 200 } + it { json_response['permissions']["project_access"].should be_nil } + it { json_response['permissions']["group_access"]["access_level"].should == Gitlab::Access::OWNER } + end + end end describe "GET /projects/:id/events" do + before { users_project } + it "should return a project events" do get api("/projects/#{project.id}/events", user) response.status.should == 200 @@ -227,256 +335,9 @@ describe API::API do end end - describe "GET /projects/:id/members" do - it "should return project team members" do - get api("/projects/#{project.id}/members", user) - response.status.should == 200 - json_response.should be_an Array - json_response.count.should == 2 - json_response.map { |u| u['email'] }.should include user.email - end - - it "finds team members with query string" do - get api("/projects/#{project.id}/members", user), query: user.username - response.status.should == 200 - json_response.should be_an Array - json_response.count.should == 1 - json_response.first['email'].should == user.email - end - - it "should return a 404 error if id not found" do - get api("/projects/9999/members", user) - response.status.should == 404 - end - end - - describe "GET /projects/:id/members/:user_id" do - it "should return project team member" do - get api("/projects/#{project.id}/members/#{user.id}", user) - response.status.should == 200 - json_response['email'].should == user.email - json_response['access_level'].should == UsersProject::MASTER - end - - it "should return a 404 error if user id not found" do - get api("/projects/#{project.id}/members/1234", user) - response.status.should == 404 - end - end - - describe "POST /projects/:id/members" do - it "should add user to project team" do - expect { - post api("/projects/#{project.id}/members", user), user_id: user2.id, - access_level: UsersProject::DEVELOPER - }.to change { UsersProject.count }.by(1) - - response.status.should == 201 - json_response['email'].should == user2.email - json_response['access_level'].should == UsersProject::DEVELOPER - end - - it "should return a 201 status if user is already project member" do - post api("/projects/#{project.id}/members", user), user_id: user2.id, - access_level: UsersProject::DEVELOPER - expect { - post api("/projects/#{project.id}/members", user), user_id: user2.id, - access_level: UsersProject::DEVELOPER - }.not_to change { UsersProject.count }.by(1) - - response.status.should == 201 - json_response['email'].should == user2.email - json_response['access_level'].should == UsersProject::DEVELOPER - end - - it "should return a 400 error when user id is not given" do - post api("/projects/#{project.id}/members", user), access_level: UsersProject::MASTER - response.status.should == 400 - end - - it "should return a 400 error when access level is not given" do - post api("/projects/#{project.id}/members", user), user_id: user2.id - response.status.should == 400 - end - - it "should return a 422 error when access level is not known" do - post api("/projects/#{project.id}/members", user), user_id: user2.id, access_level: 1234 - response.status.should == 422 - end - end - - describe "PUT /projects/:id/members/:user_id" do - it "should update project team member" do - put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: UsersProject::MASTER - response.status.should == 200 - json_response['email'].should == user3.email - json_response['access_level'].should == UsersProject::MASTER - end - - it "should return a 404 error if user_id is not found" do - put api("/projects/#{project.id}/members/1234", user), access_level: UsersProject::MASTER - response.status.should == 404 - end - - it "should return a 400 error when access level is not given" do - put api("/projects/#{project.id}/members/#{user3.id}", user) - response.status.should == 400 - end - - it "should return a 422 error when access level is not known" do - put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: 123 - response.status.should == 422 - end - end - - describe "DELETE /projects/:id/members/:user_id" do - it "should remove user from project team" do - expect { - delete api("/projects/#{project.id}/members/#{user3.id}", user) - }.to change { UsersProject.count }.by(-1) - end - - it "should return 200 if team member is not part of a project" do - delete api("/projects/#{project.id}/members/#{user3.id}", user) - expect { - delete api("/projects/#{project.id}/members/#{user3.id}", user) - }.to_not change { UsersProject.count }.by(1) - end - - it "should return 200 if team member already removed" do - delete api("/projects/#{project.id}/members/#{user3.id}", user) - delete api("/projects/#{project.id}/members/#{user3.id}", user) - response.status.should == 200 - end - end - - describe "DELETE /projects/:id/members/:user_id" do - it "should return 200 OK when the user was not member" do - expect { - delete api("/projects/#{project.id}/members/1000000", user) - }.to change { UsersProject.count }.by(0) - response.status.should == 200 - json_response['message'].should == "Access revoked" - json_response['id'].should == 1000000 - end - end - - describe "GET /projects/:id/hooks" do - context "authorized user" do - it "should return project hooks" do - get api("/projects/#{project.id}/hooks", user) - response.status.should == 200 - - json_response.should be_an Array - json_response.count.should == 1 - json_response.first['url'].should == "http://example.com" - end - end - - context "unauthorized user" do - it "should not access project hooks" do - get api("/projects/#{project.id}/hooks", user3) - response.status.should == 403 - end - end - end - - describe "GET /projects/:id/hooks/:hook_id" do - context "authorized user" do - it "should return a project hook" do - get api("/projects/#{project.id}/hooks/#{hook.id}", user) - response.status.should == 200 - json_response['url'].should == hook.url - end - - it "should return a 404 error if hook id is not available" do - get api("/projects/#{project.id}/hooks/1234", user) - response.status.should == 404 - end - end - - context "unauthorized user" do - it "should not access an existing hook" do - get api("/projects/#{project.id}/hooks/#{hook.id}", user3) - response.status.should == 403 - end - end - - it "should return a 404 error if hook id is not available" do - get api("/projects/#{project.id}/hooks/1234", user) - response.status.should == 404 - end - end - - describe "POST /projects/:id/hooks" do - it "should add hook to project" do - expect { - post api("/projects/#{project.id}/hooks", user), - url: "http://example.com" - }.to change {project.hooks.count}.by(1) - response.status.should == 201 - end - - it "should return a 400 error if url not given" do - post api("/projects/#{project.id}/hooks", user) - response.status.should == 400 - end - - it "should return a 422 error if url not valid" do - post api("/projects/#{project.id}/hooks", user), "url" => "ftp://example.com" - response.status.should == 422 - end - end - - describe "PUT /projects/:id/hooks/:hook_id" do - it "should update an existing project hook" do - put api("/projects/#{project.id}/hooks/#{hook.id}", user), - url: 'http://example.org' - response.status.should == 200 - json_response['url'].should == 'http://example.org' - end - - it "should return 404 error if hook id not found" do - put api("/projects/#{project.id}/hooks/1234", user), url: 'http://example.org' - response.status.should == 404 - end - - it "should return 400 error if url is not given" do - put api("/projects/#{project.id}/hooks/#{hook.id}", user) - response.status.should == 400 - end - - it "should return a 422 error if url is not valid" do - put api("/projects/#{project.id}/hooks/#{hook.id}", user), url: 'ftp://example.com' - response.status.should == 422 - end - end - - describe "DELETE /projects/:id/hooks/:hook_id" do - it "should delete hook from project" do - expect { - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) - }.to change {project.hooks.count}.by(-1) - response.status.should == 200 - end - - it "should return success when deleting hook" do - delete api("/projects/#{project.id}/hooks/#{hook.id}", user) - response.status.should == 200 - end - - it "should return success when deleting non existent hook" do - delete api("/projects/#{project.id}/hooks/42", user) - response.status.should == 200 - end - - it "should return a 405 error if hook id not given" do - delete api("/projects/#{project.id}/hooks", user) - response.status.should == 405 - end - end - describe "GET /projects/:id/snippets" do + before { snippet } + it "should return an array of project snippets" do get api("/projects/#{project.id}/snippets", user) response.status.should == 200 @@ -543,6 +404,8 @@ describe API::API do end describe "DELETE /projects/:id/snippets/:snippet_id" do + before { snippet } + it "should delete existing project snippet" do expect { delete api("/projects/#{project.id}/snippets/#{snippet.id}", user) @@ -628,10 +491,10 @@ describe API::API do describe :fork_admin do let(:project_fork_target) { create(:project) } - let(:project_fork_source) { create(:project, public: true) } + let(:project_fork_source) { create(:project, :public) } describe "POST /projects/:id/fork/:forked_from_id" do - let(:new_project_fork_source) { create(:project, public: true) } + let(:new_project_fork_source) { create(:project, :public) } it "shouldn't available for non admin users" do post api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) @@ -695,13 +558,15 @@ describe API::API do describe "GET /projects/search/:query" do let!(:query) { 'query'} - let!(:search) { create(:project, name: query, creator_id: user.id, namespace: user.namespace) } - let!(:pre) { create(:project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } - let!(:post) { create(:project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:pre_post) { create(:project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:unfound) { create(:project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } - let!(:public) { create(:project, name: "another #{query}",public: true) } - let!(:unfound_public) { create(:project, name: 'unfound public', public: true) } + let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } + let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } + let!(:post) { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:pre_post) { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:unfound) { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } + let!(:internal) { create(:empty_project, :internal, name: "internal #{query}") } + let!(:unfound_internal) { create(:empty_project, :internal, name: 'unfound internal') } + let!(:public) { create(:empty_project, :public, name: "public #{query}") } + let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') } context "when unauthenticated" do it "should return authentication error" do @@ -715,7 +580,7 @@ describe API::API do get api("/projects/search/#{query}",user) response.status.should == 200 json_response.should be_an Array - json_response.size.should == 5 + json_response.size.should == 6 json_response.each {|project| project['name'].should =~ /.*query.*/} end end @@ -725,8 +590,8 @@ describe API::API do get api("/projects/search/#{query}", user2) response.status.should == 200 json_response.should be_an Array - json_response.size.should == 1 - json_response.first['name'].should == "another #{query}" + json_response.size.should == 2 + json_response.each {|project| project['name'].should =~ /(internal|public) query/} end end end @@ -768,4 +633,16 @@ describe API::API do end end end + + describe "GET /projects/:id/labels" do + before { issue_with_labels } + + it "should return project labels" do + get api("/projects/#{project.id}/labels", user) + response.status.should == 200 + json_response.should be_an Array + json_response.first['name'].should == issue_with_labels.labels.first.name + json_response.last['name'].should == issue_with_labels.labels.last.name + end + end end diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb index 9649c4d09c8..99d966edc38 100644 --- a/spec/requests/api/repositories_spec.rb +++ b/spec/requests/api/repositories_spec.rb @@ -1,4 +1,5 @@ require 'spec_helper' +require 'mime/types' describe API::API do include ApiHelpers @@ -7,7 +8,7 @@ describe API::API do let(:user) { create(:user) } let(:user2) { create(:user) } - let!(:project) { create(:project_with_code, creator_id: user.id) } + let!(:project) { create(:project, creator_id: user.id) } let!(:master) { create(:users_project, user: user, project: project, project_access: UsersProject::MASTER) } let!(:guest) { create(:users_project, user: user2, project: project, project_access: UsersProject::GUEST) } @@ -102,77 +103,6 @@ describe API::API do end end - describe "GET /projects/:id/repository/commits" do - context "authorized user" do - before { project.team << [user2, :reporter] } - - it "should return project commits" do - get api("/projects/#{project.id}/repository/commits", user) - response.status.should == 200 - - json_response.should be_an Array - json_response.first['id'].should == project.repository.commit.id - end - end - - context "unauthorized user" do - it "should not return project commits" do - get api("/projects/#{project.id}/repository/commits") - response.status.should == 401 - end - end - end - - describe "GET /projects:id/repository/commits/:sha" do - context "authorized user" do - it "should return a commit by sha" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}", user) - response.status.should == 200 - json_response['id'].should == project.repository.commit.id - json_response['title'].should == project.repository.commit.title - end - - it "should return a 404 error if not found" do - get api("/projects/#{project.id}/repository/commits/invalid_sha", user) - response.status.should == 404 - end - end - - context "unauthorized user" do - it "should not return the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}") - response.status.should == 401 - end - end - end - - describe "GET /projects:id/repository/commits/:sha/diff" do - context "authorized user" do - before { project.team << [user2, :reporter] } - - it "should return the diff of the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff", user) - response.status.should == 200 - - json_response.should be_an Array - json_response.length.should >= 1 - json_response.first.keys.should include "diff" - end - - it "should return a 404 error if invalid commit" do - get api("/projects/#{project.id}/repository/commits/invalid_sha/diff", user) - response.status.should == 404 - end - end - - context "unauthorized user" do - it "should not return the diff of the selected commit" do - get api("/projects/#{project.id}/repository/commits/#{project.repository.commit.id}/diff") - response.status.should == 401 - end - end - end - describe "GET /projects/:id/repository/tree" do context "authorized user" do before { project.team << [user2, :reporter] } @@ -225,11 +155,36 @@ describe API::API do end end - describe "GET /projects/:id/repository/archive/:sha" do + describe "GET /projects/:id/repository/raw_blobs/:sha" do + it "should get the raw file contents" do + get api("/projects/#{project.id}/repository/raw_blobs/d1aff2896d99d7acc4d9780fbb716b113c45ecf7", user) + response.status.should == 200 + end + end + + describe "GET /projects/:id/repository/archive(.:format)?:sha" do it "should get the archive" do get api("/projects/#{project.id}/repository/archive", user) + repo_name = project.repository.name.gsub("\.git", "") + response.status.should == 200 + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.gz\"/ + response.content_type.should == MIME::Types.type_for('file.tar.gz').first.content_type + end + + it "should get the archive.zip" do + get api("/projects/#{project.id}/repository/archive.zip", user) + repo_name = project.repository.name.gsub("\.git", "") + response.status.should == 200 + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.zip\"/ + response.content_type.should == MIME::Types.type_for('file.zip').first.content_type + end + + it "should get the archive.tar.bz2" do + get api("/projects/#{project.id}/repository/archive.tar.bz2", user) + repo_name = project.repository.name.gsub("\.git", "") response.status.should == 200 - response.content_type.should == 'application/x-gzip' + response.headers['Content-Disposition'].should =~ /filename\=\"#{repo_name}\-[^\.]+\.tar.bz2\"/ + response.content_type.should == MIME::Types.type_for('file.tar.bz2').first.content_type end it "should return 404 for invalid sha" do diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb new file mode 100644 index 00000000000..aecd18bc14a --- /dev/null +++ b/spec/requests/api/services_spec.rb @@ -0,0 +1,33 @@ +require "spec_helper" + +describe API::API do + include ApiHelpers + before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } + after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } + + let(:user) { create(:user) } + let(:project) {create(:project, creator_id: user.id, namespace: user.namespace) } + + describe "POST /projects/:id/services/gitlab-ci" do + it "should update gitlab-ci settings" do + put api("/projects/#{project.id}/services/gitlab-ci", user), token: 'secret-token', project_url: "http://ci.example.com/projects/1" + + response.status.should == 200 + end + + it "should return if required fields missing" do + put api("/projects/#{project.id}/services/gitlab-ci", user), project_url: "http://ci.example.com/projects/1", active: true + + response.status.should == 400 + end + end + + describe "DELETE /projects/:id/services/gitlab-ci" do + it "should update gitlab-ci settings" do + delete api("/projects/#{project.id}/services/gitlab-ci", user) + + response.status.should == 200 + project.gitlab_ci_service.should be_nil + end + end +end diff --git a/spec/requests/api/session_spec.rb b/spec/requests/api/session_spec.rb index 0fd90c567e0..668007dc29f 100644 --- a/spec/requests/api/session_spec.rb +++ b/spec/requests/api/session_spec.rb @@ -8,7 +8,7 @@ describe API::API do describe "POST /session" do context "when valid password" do it "should return private token" do - post api("/session"), email: user.email, password: '123456' + post api("/session"), email: user.email, password: '12345678' response.status.should == 201 json_response['email'].should == user.email diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb index 4ef78b8e5d0..c4be5102002 100644 --- a/spec/requests/api/users_spec.rb +++ b/spec/requests/api/users_spec.rb @@ -93,7 +93,7 @@ describe API::API do expect { post api("/users", admin), attr }.to change { User.count }.by(1) - user = User.find_by_username(attr[:username]) + user = User.find_by(username: attr[:username]) user.projects_limit.should == limit user.theme_id.should == Gitlab::Theme::MARS Gitlab.config.gitlab.unstub(:default_projects_limit) diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb index 5597f08d186..97f7392e50a 100644 --- a/spec/routing/project_routing_spec.rb +++ b/spec/routing/project_routing_spec.rb @@ -130,6 +130,14 @@ describe Projects::RepositoriesController, "routing" do get("/gitlab/gitlabhq/repository/archive").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq') end + it "to #archive format:zip" do + get("/gitlab/gitlabhq/repository/archive.zip").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'zip') + end + + it "to #archive format:tar.bz2" do + get("/gitlab/gitlabhq/repository/archive.tar.bz2").should route_to('projects/repositories#archive', project_id: 'gitlab/gitlabhq', format: 'tar.bz2') + end + it "to #show" do get("/gitlab/gitlabhq/repository").should route_to('projects/repositories#show', project_id: 'gitlab/gitlabhq') end diff --git a/spec/routing/routing_spec.rb b/spec/routing/routing_spec.rb index 1b1d19d26b1..9b67cd432bc 100644 --- a/spec/routing/routing_spec.rb +++ b/spec/routing/routing_spec.rb @@ -111,13 +111,6 @@ describe HelpController, "routing" do end end -# errors_githost GET /errors/githost(.:format) errors#githost -describe ErrorsController, "routing" do - it "to #githost" do - get("/errors/githost").should route_to('errors#githost') - end -end - # profile_account GET /profile/account(.:format) profile#account # profile_history GET /profile/history(.:format) profile#history # profile_password PUT /profile/password(.:format) profile#password_update @@ -183,6 +176,35 @@ describe Profiles::KeysController, "routing" do it "to #destroy" do delete("/profile/keys/1").should route_to('profiles/keys#destroy', id: '1') end + + # get all the ssh-keys of a user + it "to #get_keys" do + get("/foo.keys").should route_to('profiles/keys#get_keys', username: 'foo') + end +end + +# emails GET /emails(.:format) emails#index +# POST /keys(.:format) emails#create +# DELETE /keys/:id(.:format) keys#destroy +describe Profiles::EmailsController, "routing" do + it "to #index" do + get("/profile/emails").should route_to('profiles/emails#index') + end + + it "to #create" do + post("/profile/emails").should route_to('profiles/emails#create') + end + + it "to #destroy" do + delete("/profile/emails/1").should route_to('profiles/emails#destroy', id: '1') + end +end + +# profile_avatar DELETE /profile/avatar(.:format) profiles/avatars#destroy +describe Profiles::AvatarsController, "routing" do + it "to #destroy" do + delete("/profile/avatar").should route_to('profiles/avatars#destroy') + end end # dashboard GET /dashboard(.:format) dashboard#show diff --git a/spec/seed_project.tar.gz b/spec/seed_project.tar.gz Binary files differindex 7abb51ebdfd..8d32a927da8 100644 --- a/spec/seed_project.tar.gz +++ b/spec/seed_project.tar.gz diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb new file mode 100644 index 00000000000..713aa3e7e74 --- /dev/null +++ b/spec/services/event_create_service_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' + +describe EventCreateService do + let(:service) { EventCreateService.new } + + describe 'Issues' do + describe :open_issue do + let(:issue) { create(:issue) } + + it { service.open_issue(issue, issue.author).should be_true } + + it "should create new event" do + expect { service.open_issue(issue, issue.author) }.to change { Event.count } + end + end + + describe :close_issue do + let(:issue) { create(:issue) } + + it { service.close_issue(issue, issue.author).should be_true } + + it "should create new event" do + expect { service.close_issue(issue, issue.author) }.to change { Event.count } + end + end + + describe :reopen_issue do + let(:issue) { create(:issue) } + + it { service.reopen_issue(issue, issue.author).should be_true } + + it "should create new event" do + expect { service.reopen_issue(issue, issue.author) }.to change { Event.count } + end + end + end + + describe 'Merge Requests' do + describe :open_mr do + let(:merge_request) { create(:merge_request) } + + it { service.open_mr(merge_request, merge_request.author).should be_true } + + it "should create new event" do + expect { service.open_mr(merge_request, merge_request.author) }.to change { Event.count } + end + end + + describe :close_mr do + let(:merge_request) { create(:merge_request) } + + it { service.close_mr(merge_request, merge_request.author).should be_true } + + it "should create new event" do + expect { service.close_mr(merge_request, merge_request.author) }.to change { Event.count } + end + end + + describe :merge_mr do + let(:merge_request) { create(:merge_request) } + + it { service.merge_mr(merge_request, merge_request.author).should be_true } + + it "should create new event" do + expect { service.merge_mr(merge_request, merge_request.author) }.to change { Event.count } + end + end + + describe :reopen_mr do + let(:merge_request) { create(:merge_request) } + + it { service.reopen_mr(merge_request, merge_request.author).should be_true } + + it "should create new event" do + expect { service.reopen_mr(merge_request, merge_request.author) }.to change { Event.count } + end + end + end + + describe 'Milestone' do + let(:user) { create :user } + + describe :open_milestone do + let(:milestone) { create(:milestone) } + + it { service.open_milestone(milestone, user).should be_true } + + it "should create new event" do + expect { service.open_milestone(milestone, user) }.to change { Event.count } + end + end + + describe :close_mr do + let(:milestone) { create(:milestone) } + + it { service.close_milestone(milestone, user).should be_true } + + it "should create new event" do + expect { service.close_milestone(milestone, user) }.to change { Event.count } + end + end + end +end diff --git a/spec/contexts/fork_context_spec.rb b/spec/services/fork_service_spec.rb index ed51b0c3f8e..b6573095dbd 100644 --- a/spec/contexts/fork_context_spec.rb +++ b/spec/services/fork_service_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Projects::ForkContext do +describe Projects::ForkService do describe :fork_by_user do before do @from_namespace = create(:namespace) @@ -47,8 +47,8 @@ describe Projects::ForkContext do end def fork_project(from_project, user, fork_success = true) - context = Projects::ForkContext.new(from_project, user) - shell = mock("gitlab_shell") + context = Projects::ForkService.new(from_project, user) + shell = double("gitlab_shell") shell.stub(fork_repository: fork_success) context.stub(gitlab_shell: shell) context.execute diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb index 2870f59195a..90738c681fa 100644 --- a/spec/services/git_push_service_spec.rb +++ b/spec/services/git_push_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe GitPushService do let (:user) { create :user } - let (:project) { create :project_with_code } + let (:project) { create :project } let (:service) { GitPushService.new } before do @@ -74,38 +74,19 @@ describe GitPushService do end describe "Web Hooks" do - context "with web hooks" do - before do - @project_hook = create(:project_hook) - @project_hook_2 = create(:project_hook) - project.hooks << [@project_hook, @project_hook_2] - - stub_request(:post, @project_hook.url) - stub_request(:post, @project_hook_2.url) - end - - it "executes multiple web hook" do - @project_hook.should_receive(:async_execute).once - @project_hook_2.should_receive(:async_execute).once - - service.execute(project, user, @oldrev, @newrev, @ref) - end - end - context "execute web hooks" do - before do - @project_hook = create(:project_hook) - project.hooks << [@project_hook] - stub_request(:post, @project_hook.url) - end - it "when pushing a branch for the first time" do - @project_hook.should_receive(:async_execute) + project.should_receive(:execute_hooks) service.execute(project, user, @blankrev, 'newrev', 'refs/heads/master') end + it "when pushing new commits to existing branch" do + project.should_receive(:execute_hooks) + service.execute(project, user, 'oldrev', 'newrev', 'refs/heads/master') + end + it "when pushing tags" do - @project_hook.should_not_receive(:async_execute) + project.should_not_receive(:execute_hooks) service.execute(project, user, 'newrev', 'newrev', 'refs/tags/v1.0.0') end end diff --git a/spec/services/git_tag_push_service_spec.rb b/spec/services/git_tag_push_service_spec.rb new file mode 100644 index 00000000000..e65a8204c54 --- /dev/null +++ b/spec/services/git_tag_push_service_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe GitTagPushService do + let (:user) { create :user } + let (:project) { create :project } + let (:service) { GitTagPushService.new } + + before do + @ref = 'refs/tags/super-tag' + @oldrev = 'b98a310def241a6fd9c9a9a3e7934c48e498fe81' + @newrev = 'b19a04f53caeebf4fe5ec2327cb83e9253dc91bb' + end + + describe 'Git Tag Push Data' do + before do + service.execute(project, user, @oldrev, @newrev, @ref) + @push_data = service.push_data + end + + subject { @push_data } + + it { should include(ref: @ref) } + it { should include(before: @oldrev) } + it { should include(after: @newrev) } + it { should include(user_id: user.id) } + it { should include(user_name: user.name) } + it { should include(project_id: project.id) } + + context 'With repository data' do + subject { @push_data[:repository] } + + it { should include(name: project.name) } + it { should include(url: project.url_to_repo) } + it { should include(description: project.description) } + it { should include(homepage: project.web_url) } + end + end + + describe "Web Hooks" do + context "execute web hooks" do + it "when pushing tags" do + project.should_receive(:execute_hooks) + service.execute(project, user, 'oldrev', 'newrev', 'refs/tags/v1.0.0') + end + end + end +end diff --git a/spec/contexts/issues/bulk_update_context_spec.rb b/spec/services/issues/bulk_update_context_spec.rb index 058e43ba090..548109a8450 100644 --- a/spec/contexts/issues/bulk_update_context_spec.rb +++ b/spec/services/issues/bulk_update_context_spec.rb @@ -1,6 +1,6 @@ require 'spec_helper' -describe Issues::BulkUpdateContext do +describe Issues::BulkUpdateService do before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } @@ -14,7 +14,7 @@ describe Issues::BulkUpdateContext do name: "GitLab", namespace: @user.namespace } - @project = Projects::CreateContext.new(@user, opts).execute + @project = Projects::CreateService.new(@user, opts).execute end describe :close_issue do @@ -32,7 +32,7 @@ describe Issues::BulkUpdateContext do end it { - result = Issues::BulkUpdateContext.new(@project, @user, @params).execute + result = Issues::BulkUpdateService.new(@project, @user, @params).execute result[:success].should be_true result[:count].should == @issues.count @@ -57,7 +57,7 @@ describe Issues::BulkUpdateContext do end it { - result = Issues::BulkUpdateContext.new(@project, @user, @params).execute + result = Issues::BulkUpdateService.new(@project, @user, @params).execute result[:success].should be_true result[:count].should == @issues.count @@ -80,7 +80,7 @@ describe Issues::BulkUpdateContext do end it { - result = Issues::BulkUpdateContext.new(@project, @user, @params).execute + result = Issues::BulkUpdateService.new(@project, @user, @params).execute result[:success].should be_true result[:count].should == 1 @@ -102,7 +102,7 @@ describe Issues::BulkUpdateContext do end it { - result = Issues::BulkUpdateContext.new(@project, @user, @params).execute + result = Issues::BulkUpdateService.new(@project, @user, @params).execute result[:success].should be_true result[:count].should == 1 diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb index a112835d4d0..fbd73a7086f 100644 --- a/spec/services/notification_service_spec.rb +++ b/spec/services/notification_service_spec.rb @@ -16,9 +16,23 @@ describe NotificationService do end end + describe 'Email' do + describe :new_email do + let(:email) { create(:email) } + + it { notification.new_email(email).should be_true } + + it 'should send email to email owner' do + Notify.should_receive(:new_email_email).with(email.id) + notification.new_email(email) + end + end + end + describe 'Notes' do context 'issue note' do let(:issue) { create(:issue, assignee: create(:user)) } + let(:mentioned_issue) { create(:issue, assignee: issue.assignee) } let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@mention referenced') } before do @@ -37,6 +51,13 @@ describe NotificationService do notification.new_note(note) end + it 'filters out "mentioned in" notes' do + mentioned_note = Note.create_cross_reference_note(mentioned_issue, issue, issue.author, issue.project) + + Notify.should_not_receive(:note_issue_email) + notification.new_note(mentioned_note) + end + def should_email(user_id) Notify.should_receive(:note_issue_email).with(user_id, note.id) end @@ -124,11 +145,11 @@ describe NotificationService do end def should_email(user_id) - Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) + Notify.should_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id, @u_disabled.id) end def should_not_email(user_id) - Notify.should_not_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id) + Notify.should_not_receive(:reassigned_issue_email).with(user_id, issue.id, issue.assignee_id, @u_disabled.id) end end @@ -188,11 +209,11 @@ describe NotificationService do end def should_email(user_id) - Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) + Notify.should_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id, merge_request.author_id) end def should_not_email(user_id) - Notify.should_not_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id) + Notify.should_not_receive(:reassigned_merge_request_email).with(user_id, merge_request.id, merge_request.assignee_id, merge_request.author_id) end end @@ -220,15 +241,40 @@ describe NotificationService do should_email(@u_watcher.id) should_not_email(@u_participating.id) should_not_email(@u_disabled.id) - notification.merge_mr(merge_request) + notification.merge_mr(merge_request, @u_disabled) + end + + def should_email(user_id) + Notify.should_receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id) + end + + def should_not_email(user_id) + Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id, @u_disabled.id) + end + end + end + + describe 'Projects' do + let(:project) { create :project } + + before do + build_team(project) + end + + describe :project_was_moved do + it do + should_email(@u_watcher.id) + should_email(@u_participating.id) + should_not_email(@u_disabled.id) + notification.project_was_moved(project) end def should_email(user_id) - Notify.should_receive(:merged_merge_request_email).with(user_id, merge_request.id) + Notify.should_receive(:project_was_moved_email).with(project.id, user_id) end def should_not_email(user_id) - Notify.should_not_receive(:merged_merge_request_email).with(user_id, merge_request.id) + Notify.should_not_receive(:project_was_moved_email).with(project.id, user_id) end end end diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb new file mode 100644 index 00000000000..f2a784df103 --- /dev/null +++ b/spec/services/projects/create_service_spec.rb @@ -0,0 +1,163 @@ +require 'spec_helper' + +describe Projects::CreateService do + before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } + after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } + + describe :create_by_user do + before do + @user = create :user + @admin = create :user, admin: true + @opts = { + name: "GitLab", + namespace: @user.namespace + } + end + + context 'user namespace' do + before do + @project = create_project(@user, @opts) + end + + it { @project.should be_valid } + it { @project.owner.should == @user } + it { @project.namespace.should == @user.namespace } + end + + context 'group namespace' do + before do + @group = create :group + @group.add_owner(@user) + + @opts.merge!(namespace_id: @group.id) + @project = create_project(@user, @opts) + end + + it { @project.should be_valid } + it { @project.owner.should == @group } + it { @project.namespace.should == @group } + end + + context 'wiki_enabled creates repository directory' do + context 'wiki_enabled true creates wiki repository directory' do + before do + @project = create_project(@user, @opts) + @path = GollumWiki.new(@project, @user).send(:path_to_repo) + end + + it { File.exists?(@path).should be_true } + end + + context 'wiki_enabled false does not create wiki repository directory' do + before do + @opts.merge!(wiki_enabled: false) + @project = create_project(@user, @opts) + @path = GollumWiki.new(@project, @user).send(:path_to_repo) + end + + it { File.exists?(@path).should be_false } + end + end + + context 'respect configured visibility setting' do + before(:each) do + @settings = double("settings") + @settings.stub(:issues) { true } + @settings.stub(:merge_requests) { true } + @settings.stub(:wiki) { true } + @settings.stub(:wall) { true } + @settings.stub(:snippets) { true } + stub_const("Settings", Class.new) + @restrictions = double("restrictions") + @restrictions.stub(:restricted_visibility_levels) { [] } + Settings.stub_chain(:gitlab).and_return(@restrictions) + Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings) + end + + context 'should be public when setting is public' do + before do + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PUBLIC } + @project = create_project(@user, @opts) + end + + it { @project.public?.should be_true } + end + + context 'should be private when setting is private' do + before do + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE } + @project = create_project(@user, @opts) + end + + it { @project.private?.should be_true } + end + + context 'should be internal when setting is internal' do + before do + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::INTERNAL } + @project = create_project(@user, @opts) + end + + it { @project.internal?.should be_true } + end + end + + context 'respect configured visibility restrictions setting' do + before(:each) do + @settings = double("settings") + @settings.stub(:issues) { true } + @settings.stub(:merge_requests) { true } + @settings.stub(:wiki) { true } + @settings.stub(:wall) { true } + @settings.stub(:snippets) { true } + @settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE } + stub_const("Settings", Class.new) + @restrictions = double("restrictions") + @restrictions.stub(:restricted_visibility_levels) { [ Gitlab::VisibilityLevel::PUBLIC ] } + Settings.stub_chain(:gitlab).and_return(@restrictions) + Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings) + end + + context 'should be private when option is public' do + before do + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + @project = create_project(@user, @opts) + end + + it { @project.private?.should be_true } + end + + context 'should be public when option is public for admin' do + before do + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + @project = create_project(@admin, @opts) + end + + it { @project.public?.should be_true } + end + + context 'should be private when option is private' do + before do + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + @project = create_project(@user, @opts) + end + + it { @project.private?.should be_true } + end + + context 'should be internal when option is internal' do + before do + @opts.merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + @project = create_project(@user, @opts) + end + + it { @project.internal?.should be_true } + end + end + end + + def create_project(user, opts) + Projects::CreateService.new(user, opts).execute + end +end + diff --git a/spec/services/project_transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb index 109b429967e..109b429967e 100644 --- a/spec/services/project_transfer_service_spec.rb +++ b/spec/services/projects/transfer_service_spec.rb diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb new file mode 100644 index 00000000000..1854c0d8233 --- /dev/null +++ b/spec/services/projects/update_service_spec.rb @@ -0,0 +1,111 @@ +require 'spec_helper' + +describe Projects::UpdateService do + before(:each) { ActiveRecord::Base.observers.enable(:user_observer) } + after(:each) { ActiveRecord::Base.observers.disable(:user_observer) } + + describe :update_by_user do + before do + @user = create :user + @admin = create :user, admin: true + @project = create :project, creator_id: @user.id, namespace: @user.namespace + @opts = { project: {} } + end + + context 'should be private when updated to private' do + before do + @created_private = @project.private? + + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + update_project(@project, @user, @opts) + end + + it { @created_private.should be_true } + it { @project.private?.should be_true } + end + + context 'should be internal when updated to internal' do + before do + @created_private = @project.private? + + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + update_project(@project, @user, @opts) + end + + it { @created_private.should be_true } + it { @project.internal?.should be_true } + end + + context 'should be public when updated to public' do + before do + @created_private = @project.private? + + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + update_project(@project, @user, @opts) + end + + it { @created_private.should be_true } + it { @project.public?.should be_true } + end + + context 'respect configured visibility restrictions setting' do + before(:each) do + @restrictions = double("restrictions") + @restrictions.stub(:restricted_visibility_levels) { [ Gitlab::VisibilityLevel::PUBLIC ] } + Settings.stub_chain(:gitlab).and_return(@restrictions) + end + + context 'should be private when updated to private' do + before do + @created_private = @project.private? + + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PRIVATE) + update_project(@project, @user, @opts) + end + + it { @created_private.should be_true } + it { @project.private?.should be_true } + end + + context 'should be internal when updated to internal' do + before do + @created_private = @project.private? + + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::INTERNAL) + update_project(@project, @user, @opts) + end + + it { @created_private.should be_true } + it { @project.internal?.should be_true } + end + + context 'should be private when updated to public' do + before do + @created_private = @project.private? + + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + update_project(@project, @user, @opts) + end + + it { @created_private.should be_true } + it { @project.private?.should be_true } + end + + context 'should be public when updated to public by admin' do + before do + @created_private = @project.private? + + @opts[:project].merge!(visibility_level: Gitlab::VisibilityLevel::PUBLIC) + update_project(@project, @admin, @opts) + end + + it { @created_private.should be_true } + it { @project.public?.should be_true } + end + end + end + + def update_project(project, user, opts) + Projects::UpdateService.new(project, user, opts).execute + end +end diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb new file mode 100644 index 00000000000..b467282a5d6 --- /dev/null +++ b/spec/services/search_service_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe 'Search::GlobalService' do + let(:user) { create(:user, namespace: found_namespace) } + let(:public_user) { create(:user, namespace: public_namespace) } + let(:internal_user) { create(:user, namespace: internal_namespace) } + + let(:found_namespace) { create(:namespace, name: 'searchable namespace', path:'another_thing') } + let(:unfound_namespace) { create(:namespace, name: 'unfound namespace', path: 'yet_something_else') } + let(:internal_namespace) { create(:namespace, name: 'searchable internal namespace', path: 'something_internal') } + let(:public_namespace) { create(:namespace, name: 'searchable public namespace', path: 'something_public') } + + let!(:found_project) { create(:project, :private, name: 'searchable_project', creator_id: user.id, namespace: found_namespace) } + let!(:unfound_project) { create(:project, :private, name: 'unfound_project', creator_id: user.id, namespace: unfound_namespace) } + let!(:internal_project) { create(:project, :internal, name: 'searchable_internal_project', creator_id: internal_user.id, namespace: internal_namespace) } + let!(:public_project) { create(:project, :public, name: 'searchable_public_project', creator_id: public_user.id, namespace: public_namespace) } + + describe '#execute' do + context 'unauthenticated' do + it 'should return public projects only' do + context = Search::GlobalService.new(nil, search: "searchable") + results = context.execute + results[:projects].should match_array [public_project] + end + end + + context 'authenticated' do + it 'should return public, internal and private projects' do + context = Search::GlobalService.new(user, search: "searchable") + results = context.execute + results[:projects].should match_array [public_project, found_project, internal_project] + end + + it 'should return only public & internal projects' do + context = Search::GlobalService.new(internal_user, search: "searchable") + results = context.execute + results[:projects].should match_array [internal_project, public_project] + end + + it 'namespace name should be searchable' do + context = Search::GlobalService.new(user, search: "searchable namespace") + results = context.execute + results[:projects].should match_array [found_project] + end + end + end +end diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb index ebc1ed51d2e..f1df7e55dd0 100644 --- a/spec/services/system_hooks_service_spec.rb +++ b/spec/services/system_hooks_service_spec.rb @@ -24,10 +24,10 @@ describe SystemHooksService do end def event_data(*args) - SystemHooksService.build_event_data(*args) + SystemHooksService.new.send :build_event_data, *args end def event_name(*args) - SystemHooksService.build_event_name(*args) + SystemHooksService.new.send :build_event_name, *args end end diff --git a/spec/services/test_hook_service_spec.rb b/spec/services/test_hook_service_spec.rb new file mode 100644 index 00000000000..76af5bf7b88 --- /dev/null +++ b/spec/services/test_hook_service_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe TestHookService do + let (:user) { create :user } + let (:project) { create :project } + let (:hook) { create :project_hook, project: project } + + describe :execute do + it "should execute successfully" do + stub_request(:post, hook.url).to_return(status: 200) + TestHookService.new.execute(hook, user).should be_true + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index dd008ed02ad..e6b1f816df0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,63 +1,50 @@ -require 'rubygems' -require 'spork' +# This file is copied to spec/ when you run 'rails generate rspec:install' +ENV["RAILS_ENV"] ||= 'test' +require File.expand_path("../../config/environment", __FILE__) -Spork.prefork do - require 'simplecov' unless ENV['CI'] +require 'simplecov' unless ENV['CI'] - if ENV['TRAVIS'] - require 'coveralls' - Coveralls.wear! - end - - # This file is copied to spec/ when you run 'rails generate rspec:install' - ENV["RAILS_ENV"] ||= 'test' - require File.expand_path("../../config/environment", __FILE__) - require 'rspec/rails' - require 'capybara/rails' - require 'capybara/rspec' - require 'webmock/rspec' - require 'email_spec' - require 'sidekiq/testing/inline' - require 'capybara/poltergeist' - - # Loading more in this block will cause your tests to run faster. However, - - # if you change any configuration or code from libraries loaded here, you'll - # need to restart spork for it take effect. - Capybara.javascript_driver = :poltergeist - Capybara.default_wait_time = 10 - - # Requires supporting ruby files with custom matchers and macros, etc, - # in spec/support/ and its subdirectories. - Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} - - WebMock.disable_net_connect!(allow_localhost: true) - - RSpec.configure do |config| - config.mock_with :rspec - - config.include LoginHelpers, type: :feature - config.include LoginHelpers, type: :request - config.include FactoryGirl::Syntax::Methods - config.include Devise::TestHelpers, type: :controller - - config.include TestEnv - - # If you're not using ActiveRecord, or you'd prefer not to run each of your - # examples within a transaction, remove the following line or assign false - # instead of true. - config.use_transactional_fixtures = false - - config.before(:suite) do - TestEnv.init(observers: false, init_repos: true, repos: false) - end - config.before(:each) do - TestEnv.setup_stubs - end - end +if ENV['TRAVIS'] + require 'coveralls' + Coveralls.wear! end -Spork.each_run do - # This code will be run each time you run your specs. +require 'rspec/rails' +require 'capybara/rails' +require 'capybara/rspec' +require 'webmock/rspec' +require 'email_spec' +require 'sidekiq/testing/inline' +require 'capybara/poltergeist' + +Capybara.javascript_driver = :poltergeist +Capybara.default_wait_time = 10 + +# Requires supporting ruby files with custom matchers and macros, etc, +# in spec/support/ and its subdirectories. +Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f} + +WebMock.disable_net_connect!(allow_localhost: true) +RSpec.configure do |config| + config.mock_with :rspec + + config.include LoginHelpers, type: :feature + config.include LoginHelpers, type: :request + config.include FactoryGirl::Syntax::Methods + config.include Devise::TestHelpers, type: :controller + + config.include TestEnv + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = false + + config.before(:suite) do + TestEnv.init(observers: false, init_repos: true, repos: false) + end + config.before(:each) do + TestEnv.setup_stubs + end end diff --git a/spec/support/chosen_helper.rb b/spec/support/chosen_helper.rb deleted file mode 100644 index 42c9342c77a..00000000000 --- a/spec/support/chosen_helper.rb +++ /dev/null @@ -1,21 +0,0 @@ -# Chosen programmatic helper -# It allows you to select value from chosen select -# -# Params -# value - real value of selected item -# opts - options containing css selector -# -# Usage: -# -# chosen(2, from: '#user_ids') -# - -module ChosenHelper - def chosen(value, options={}) - raise "Must pass a hash containing 'from'" if not options.is_a?(Hash) or not options.has_key?(:from) - - selector = options[:from] - - page.execute_script("$('#{selector}').val('#{value}').trigger('chosen:updated');") - end -end diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb index 025534a900d..cc0ec2f4e3d 100644 --- a/spec/support/login_helpers.rb +++ b/spec/support/login_helpers.rb @@ -16,7 +16,7 @@ module LoginHelpers def login_with(user) visit new_user_session_path fill_in "user_login", with: user.email - fill_in "user_password", with: "123456" + fill_in "user_password", with: "12345678" click_button "Sign in" Thread.current[:current_user] = user end diff --git a/spec/support/mentionable_shared_examples.rb b/spec/support/mentionable_shared_examples.rb index a7f189777c8..3802e94ecf0 100644 --- a/spec/support/mentionable_shared_examples.rb +++ b/spec/support/mentionable_shared_examples.rb @@ -11,8 +11,8 @@ def common_mentionable_setup let(:mentioned_issue) { create :issue, project: mproject } let(:other_issue) { create :issue, project: mproject } - let(:mentioned_mr) { create :merge_request, target_project: mproject, source_branch: 'different' } - let(:mentioned_commit) { mock('commit', sha: '1234567890abcdef').as_null_object } + let(:mentioned_mr) { create :merge_request, source_project: mproject, source_branch: 'different' } + let(:mentioned_commit) { double('commit', sha: '1234567890abcdef').as_null_object } # Override to add known commits to the repository stub. let(:extra_commits) { [] } @@ -30,7 +30,7 @@ def common_mentionable_setup commitmap = { '123456' => mentioned_commit } extra_commits.each { |c| commitmap[c.sha[0..5]] = c } - repo = mock('repository') + repo = double('repository') repo.stub(:commit) { |sha| commitmap[sha] } mproject.stub(repository: repo) diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 16e10b1a62b..d237f7ad094 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -29,7 +29,6 @@ module TestEnv disable_mailer if opts[:mailer] == false setup_stubs - clear_test_repo_dir if opts[:init_repos] == true setup_test_repos(opts) if opts[:repos] == true end @@ -45,6 +44,7 @@ module TestEnv def disable_mailer NotificationService.any_instance.stub(mailer: double.as_null_object) end + def enable_mailer NotificationService.any_instance.unstub(:mailer) end @@ -68,7 +68,12 @@ module TestEnv remove_repository: true, update_repository_head: true, add_key: true, - remove_key: true + remove_key: true, + version: '6.3.0' + ) + + Gitlab::Satellite::MergeAction.any_instance.stub( + merge!: true, ) Gitlab::Satellite::Satellite.any_instance.stub( @@ -85,7 +90,7 @@ module TestEnv size: 12.45 ) - ActivityObserver.any_instance.stub( + BaseObserver.any_instance.stub( current_user: double("current_user", id: 1) ) end @@ -96,13 +101,24 @@ module TestEnv FileUtils.rm_rf File.join(testing_path(), "#{name}.wiki.git") end + def reset_satellite_dir + setup_stubs + [ + %W(git reset --hard --quiet), + %W(git clean -fx --quiet), + %W(git checkout --quiet origin/master) + ].each do |git_cmd| + system(*git_cmd, chdir: seed_satellite_path) + end + end + # Create a repo and it's satellite def create_repo(namespace, name) setup_stubs repo = repo(namespace, name) # Symlink tmp/repositories/gitlabhq to tmp/test-git-base-path/gitlabhq - system("ln -s -f #{seed_repo_path()} #{repo}") + FileUtils.ln_sf(seed_repo_path, repo) create_satellite(repo, namespace, name) end @@ -148,8 +164,7 @@ module TestEnv def clear_test_repo_dir setup_stubs - # Use tmp dir for FS manipulations - repos_path = testing_path() + # Remove tmp/test-git-base-path FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path @@ -166,12 +181,11 @@ module TestEnv # Symlink tmp/satellite/gitlabhq to tmp/test-git-base-path/satellite/gitlabhq, create the directory if it doesn't exist already satellite_dir = File.dirname(satellite_repo) FileUtils.mkdir_p(satellite_dir) unless File.exists?(satellite_dir) - system("ln -s -f #{seed_satellite_path} #{satellite_repo}") + FileUtils.ln_sf(seed_satellite_path, satellite_repo) end def create_temp_repo(path) FileUtils.mkdir_p path - command = "git init --quiet --bare #{path};" - system(command) + system(*%W(git init --quiet --bare -- #{path})) end end diff --git a/spec/support/valid_commit.rb b/spec/support/valid_commit.rb index 8094b679e99..98bc59b573f 100644 --- a/spec/support/valid_commit.rb +++ b/spec/support/valid_commit.rb @@ -2,6 +2,7 @@ module ValidCommit ID = "8470d70da67355c9c009e4401746b1d5410af2e3" MESSAGE = "notes controller refactored" AUTHOR_FULL_NAME = "Dmitriy Zaporozhets" + AUTHOR_EMAIL = "dmitriy.zaporozhets@gmail.com" FILES = [".foreman", ".gitignore", ".rails_footnotes", ".rspec", ".travis.yml", "CHANGELOG", "Gemfile", "Gemfile.lock", "LICENSE", "Procfile", "Procfile.production", "README.md", "Rakefile", "VERSION", "app", "config.ru", "config", "db", "doc", "lib", "log", "public", "resque.sh", "script", "spec", "vendor"] FILES_COUNT = 26 diff --git a/spec/support/valid_commit_with_alt_email.rb b/spec/support/valid_commit_with_alt_email.rb new file mode 100644 index 00000000000..d6e364c41f1 --- /dev/null +++ b/spec/support/valid_commit_with_alt_email.rb @@ -0,0 +1,6 @@ +module ValidCommitWithAltEmail + ID = "1e689bfba39525ead225eaf611948cfbe8ac34cf" + MESSAGE = "fixed notes logic" + AUTHOR_FULL_NAME = "Dmitriy Zaporozhets" + AUTHOR_EMAIL = "dzaporozhets@sphereconsultinginc.com" +end
\ No newline at end of file diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb index cba243226db..71a45eb2fa6 100644 --- a/spec/tasks/gitlab/backup_rake_spec.rb +++ b/spec/tasks/gitlab/backup_rake_spec.rb @@ -5,6 +5,7 @@ describe 'gitlab:app namespace rake task' do before :all do Rake.application.rake_require "tasks/gitlab/task_helpers" Rake.application.rake_require "tasks/gitlab/backup" + Rake.application.rake_require "tasks/gitlab/shell" # empty task as env is already loaded Rake::Task.define_task :environment end @@ -26,12 +27,15 @@ describe 'gitlab:app namespace rake task' do Dir.stub :chdir File.stub exists?: true Kernel.stub system: true + FileUtils.stub cp_r: true + FileUtils.stub mv: true + Rake::Task["gitlab:shell:setup"].stub invoke: true end - let(:gitlab_version) { %x{git rev-parse HEAD}.gsub(/\n/,"") } + let(:gitlab_version) { Gitlab::VERSION } it 'should fail on mismatch' do - YAML.stub load_file: {gitlab_version: gitlab_version.reverse} + YAML.stub load_file: {gitlab_version: "not #{gitlab_version}" } expect { run_rake_task }.to raise_error SystemExit end @@ -39,7 +43,8 @@ describe 'gitlab:app namespace rake task' do YAML.stub load_file: {gitlab_version: gitlab_version} Rake::Task["gitlab:backup:db:restore"].should_receive :invoke Rake::Task["gitlab:backup:repo:restore"].should_receive :invoke - expect { run_rake_task }.to_not raise_error SystemExit + Rake::Task["gitlab:shell:setup"].should_receive :invoke + expect { run_rake_task }.to_not raise_error end end diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb index 46e86dbe00a..e6bf79b853c 100644 --- a/spec/workers/post_receive_spec.rb +++ b/spec/workers/post_receive_spec.rb @@ -9,7 +9,7 @@ describe PostReceive do end context "web hook" do - let(:project) { create(:project_with_code) } + let(:project) { create(:project) } let(:key) { create(:key, user: project.owner) } let(:key_id) { key.shell_id } @@ -19,7 +19,7 @@ describe PostReceive do end it "does not run if the author is not in the project" do - Key.stub(find_by_id: nil) + Key.stub(:find_by).with(hash_including(id: anything())) { nil } project.should_not_receive(:execute_hooks) |