From cc4ef4da11d46761ab0ce4fbd6b032a7e01baba9 Mon Sep 17 00:00:00 2001 From: Dmitriy Zaporozhets Date: Wed, 9 Sep 2015 14:17:16 +0200 Subject: Refactor CI tests --- spec/ci/features/admin/builds_spec.rb | 71 ----- spec/ci/features/admin/events_spec.rb | 20 -- spec/ci/features/admin/projects_spec.rb | 19 -- spec/ci/features/admin/runners_spec.rb | 63 ---- spec/ci/features/builds_spec.rb | 57 ---- spec/ci/features/commits_spec.rb | 66 ---- spec/ci/features/events_spec.rb | 20 -- spec/ci/features/lint_spec.rb | 28 -- spec/ci/features/projects_spec.rb | 57 ---- spec/ci/features/runners_spec.rb | 98 ------ spec/ci/features/triggers_spec.rb | 26 -- spec/ci/features/variables_spec.rb | 26 -- spec/ci/helpers/application_helper_spec.rb | 37 --- spec/ci/helpers/runners_helper_spec.rb | 18 -- spec/ci/helpers/user_helper_spec.rb | 49 --- spec/ci/helpers/user_sessions_helper_spec.rb | 69 ---- spec/ci/lib/ansi2html_spec.rb | 133 -------- spec/ci/lib/charts_spec.rb | 17 - spec/ci/lib/gitlab_ci_yaml_processor_spec.rb | 311 ------------------ spec/ci/lib/upgrader_spec.rb | 39 --- spec/ci/mailers/notify_spec.rb | 36 --- spec/ci/models/build_spec.rb | 350 --------------------- spec/ci/models/commit_spec.rb | 264 ---------------- spec/ci/models/mail_service_spec.rb | 184 ----------- spec/ci/models/network_spec.rb | 54 ---- .../project_services/hip_chat_message_spec.rb | 74 ----- .../project_services/hip_chat_service_spec.rb | 75 ----- .../models/project_services/slack_message_spec.rb | 84 ----- .../models/project_services/slack_service_spec.rb | 58 ---- spec/ci/models/project_spec.rb | 185 ----------- spec/ci/models/runner_project_spec.rb | 16 - spec/ci/models/runner_spec.rb | 70 ----- spec/ci/models/service_spec.rb | 49 --- spec/ci/models/trigger_spec.rb | 17 - spec/ci/models/user_spec.rb | 100 ------ spec/ci/models/variable_spec.rb | 44 --- spec/ci/models/web_hook_spec.rb | 64 ---- spec/ci/requests/api/builds_spec.rb | 115 ------- spec/ci/requests/api/commits_spec.rb | 65 ---- spec/ci/requests/api/forks_spec.rb | 60 ---- spec/ci/requests/api/projects_spec.rb | 251 --------------- spec/ci/requests/api/runners_spec.rb | 83 ----- spec/ci/requests/api/triggers_spec.rb | 78 ----- spec/ci/requests/builds_spec.rb | 18 -- spec/ci/requests/commits_spec.rb | 17 - spec/ci/services/create_commit_service_spec.rb | 130 -------- spec/ci/services/create_project_service_spec.rb | 40 --- .../create_trigger_request_service_spec.rb | 52 --- spec/ci/services/event_service_spec.rb | 34 -- spec/ci/services/image_for_build_service_spec.rb | 46 --- spec/ci/services/register_build_service_spec.rb | 89 ------ spec/ci/services/web_hook_service_spec.rb | 36 --- spec/ci/six.tar.gz | Bin 61937 -> 0 bytes spec/controllers/ci/projects_controller_spec.rb | 18 +- spec/factories/ci/trigger_requests.rb | 4 +- spec/factories/ci/triggers.rb | 2 +- spec/features/ci/admin/builds_spec.rb | 71 +++++ spec/features/ci/admin/events_spec.rb | 20 ++ spec/features/ci/admin/projects_spec.rb | 19 ++ spec/features/ci/admin/runners_spec.rb | 63 ++++ spec/features/ci/builds_spec.rb | 57 ++++ spec/features/ci/commits_spec.rb | 66 ++++ spec/features/ci/events_spec.rb | 20 ++ spec/features/ci/lint_spec.rb | 28 ++ spec/features/ci/projects_spec.rb | 57 ++++ spec/features/ci/runners_spec.rb | 98 ++++++ spec/features/ci/triggers_spec.rb | 26 ++ spec/features/ci/variables_spec.rb | 26 ++ spec/helpers/ci/application_helper_spec.rb | 37 +++ spec/helpers/ci/runners_helper_spec.rb | 18 ++ spec/helpers/ci/user_helper_spec.rb | 49 +++ spec/helpers/ci/user_sessions_helper_spec.rb | 69 ++++ spec/lib/ci/ansi2html_spec.rb | 133 ++++++++ spec/lib/ci/charts_spec.rb | 17 + spec/lib/ci/gitlab_ci_yaml_processor_spec.rb | 311 ++++++++++++++++++ spec/lib/ci/upgrader_spec.rb | 39 +++ spec/mailers/ci/notify_spec.rb | 36 +++ spec/models/ci/build_spec.rb | 350 +++++++++++++++++++++ spec/models/ci/commit_spec.rb | 264 ++++++++++++++++ spec/models/ci/mail_service_spec.rb | 184 +++++++++++ spec/models/ci/network_spec.rb | 54 ++++ .../ci/project_services/hip_chat_message_spec.rb | 74 +++++ .../ci/project_services/hip_chat_service_spec.rb | 75 +++++ .../ci/project_services/slack_message_spec.rb | 84 +++++ .../ci/project_services/slack_service_spec.rb | 58 ++++ spec/models/ci/project_spec.rb | 185 +++++++++++ spec/models/ci/runner_project_spec.rb | 16 + spec/models/ci/runner_spec.rb | 70 +++++ spec/models/ci/service_spec.rb | 49 +++ spec/models/ci/trigger_spec.rb | 17 + spec/models/ci/user_spec.rb | 100 ++++++ spec/models/ci/variable_spec.rb | 44 +++ spec/models/ci/web_hook_spec.rb | 64 ++++ spec/requests/ci/api/builds_spec.rb | 115 +++++++ spec/requests/ci/api/commits_spec.rb | 65 ++++ spec/requests/ci/api/forks_spec.rb | 60 ++++ spec/requests/ci/api/projects_spec.rb | 251 +++++++++++++++ spec/requests/ci/api/runners_spec.rb | 83 +++++ spec/requests/ci/api/triggers_spec.rb | 78 +++++ spec/requests/ci/builds_spec.rb | 18 ++ spec/requests/ci/commits_spec.rb | 17 + spec/services/ci/create_commit_service_spec.rb | 130 ++++++++ spec/services/ci/create_project_service_spec.rb | 40 +++ .../ci/create_trigger_request_service_spec.rb | 52 +++ spec/services/ci/event_service_spec.rb | 34 ++ spec/services/ci/image_for_build_service_spec.rb | 46 +++ spec/services/ci/register_build_service_spec.rb | 89 ++++++ spec/services/ci/web_hook_service_spec.rb | 36 +++ 108 files changed, 4074 insertions(+), 4074 deletions(-) delete mode 100644 spec/ci/features/admin/builds_spec.rb delete mode 100644 spec/ci/features/admin/events_spec.rb delete mode 100644 spec/ci/features/admin/projects_spec.rb delete mode 100644 spec/ci/features/admin/runners_spec.rb delete mode 100644 spec/ci/features/builds_spec.rb delete mode 100644 spec/ci/features/commits_spec.rb delete mode 100644 spec/ci/features/events_spec.rb delete mode 100644 spec/ci/features/lint_spec.rb delete mode 100644 spec/ci/features/projects_spec.rb delete mode 100644 spec/ci/features/runners_spec.rb delete mode 100644 spec/ci/features/triggers_spec.rb delete mode 100644 spec/ci/features/variables_spec.rb delete mode 100644 spec/ci/helpers/application_helper_spec.rb delete mode 100644 spec/ci/helpers/runners_helper_spec.rb delete mode 100644 spec/ci/helpers/user_helper_spec.rb delete mode 100644 spec/ci/helpers/user_sessions_helper_spec.rb delete mode 100644 spec/ci/lib/ansi2html_spec.rb delete mode 100644 spec/ci/lib/charts_spec.rb delete mode 100644 spec/ci/lib/gitlab_ci_yaml_processor_spec.rb delete mode 100644 spec/ci/lib/upgrader_spec.rb delete mode 100644 spec/ci/mailers/notify_spec.rb delete mode 100644 spec/ci/models/build_spec.rb delete mode 100644 spec/ci/models/commit_spec.rb delete mode 100644 spec/ci/models/mail_service_spec.rb delete mode 100644 spec/ci/models/network_spec.rb delete mode 100644 spec/ci/models/project_services/hip_chat_message_spec.rb delete mode 100644 spec/ci/models/project_services/hip_chat_service_spec.rb delete mode 100644 spec/ci/models/project_services/slack_message_spec.rb delete mode 100644 spec/ci/models/project_services/slack_service_spec.rb delete mode 100644 spec/ci/models/project_spec.rb delete mode 100644 spec/ci/models/runner_project_spec.rb delete mode 100644 spec/ci/models/runner_spec.rb delete mode 100644 spec/ci/models/service_spec.rb delete mode 100644 spec/ci/models/trigger_spec.rb delete mode 100644 spec/ci/models/user_spec.rb delete mode 100644 spec/ci/models/variable_spec.rb delete mode 100644 spec/ci/models/web_hook_spec.rb delete mode 100644 spec/ci/requests/api/builds_spec.rb delete mode 100644 spec/ci/requests/api/commits_spec.rb delete mode 100644 spec/ci/requests/api/forks_spec.rb delete mode 100644 spec/ci/requests/api/projects_spec.rb delete mode 100644 spec/ci/requests/api/runners_spec.rb delete mode 100644 spec/ci/requests/api/triggers_spec.rb delete mode 100644 spec/ci/requests/builds_spec.rb delete mode 100644 spec/ci/requests/commits_spec.rb delete mode 100644 spec/ci/services/create_commit_service_spec.rb delete mode 100644 spec/ci/services/create_project_service_spec.rb delete mode 100644 spec/ci/services/create_trigger_request_service_spec.rb delete mode 100644 spec/ci/services/event_service_spec.rb delete mode 100644 spec/ci/services/image_for_build_service_spec.rb delete mode 100644 spec/ci/services/register_build_service_spec.rb delete mode 100644 spec/ci/services/web_hook_service_spec.rb delete mode 100644 spec/ci/six.tar.gz create mode 100644 spec/features/ci/admin/builds_spec.rb create mode 100644 spec/features/ci/admin/events_spec.rb create mode 100644 spec/features/ci/admin/projects_spec.rb create mode 100644 spec/features/ci/admin/runners_spec.rb create mode 100644 spec/features/ci/builds_spec.rb create mode 100644 spec/features/ci/commits_spec.rb create mode 100644 spec/features/ci/events_spec.rb create mode 100644 spec/features/ci/lint_spec.rb create mode 100644 spec/features/ci/projects_spec.rb create mode 100644 spec/features/ci/runners_spec.rb create mode 100644 spec/features/ci/triggers_spec.rb create mode 100644 spec/features/ci/variables_spec.rb create mode 100644 spec/helpers/ci/application_helper_spec.rb create mode 100644 spec/helpers/ci/runners_helper_spec.rb create mode 100644 spec/helpers/ci/user_helper_spec.rb create mode 100644 spec/helpers/ci/user_sessions_helper_spec.rb create mode 100644 spec/lib/ci/ansi2html_spec.rb create mode 100644 spec/lib/ci/charts_spec.rb create mode 100644 spec/lib/ci/gitlab_ci_yaml_processor_spec.rb create mode 100644 spec/lib/ci/upgrader_spec.rb create mode 100644 spec/mailers/ci/notify_spec.rb create mode 100644 spec/models/ci/build_spec.rb create mode 100644 spec/models/ci/commit_spec.rb create mode 100644 spec/models/ci/mail_service_spec.rb create mode 100644 spec/models/ci/network_spec.rb create mode 100644 spec/models/ci/project_services/hip_chat_message_spec.rb create mode 100644 spec/models/ci/project_services/hip_chat_service_spec.rb create mode 100644 spec/models/ci/project_services/slack_message_spec.rb create mode 100644 spec/models/ci/project_services/slack_service_spec.rb create mode 100644 spec/models/ci/project_spec.rb create mode 100644 spec/models/ci/runner_project_spec.rb create mode 100644 spec/models/ci/runner_spec.rb create mode 100644 spec/models/ci/service_spec.rb create mode 100644 spec/models/ci/trigger_spec.rb create mode 100644 spec/models/ci/user_spec.rb create mode 100644 spec/models/ci/variable_spec.rb create mode 100644 spec/models/ci/web_hook_spec.rb create mode 100644 spec/requests/ci/api/builds_spec.rb create mode 100644 spec/requests/ci/api/commits_spec.rb create mode 100644 spec/requests/ci/api/forks_spec.rb create mode 100644 spec/requests/ci/api/projects_spec.rb create mode 100644 spec/requests/ci/api/runners_spec.rb create mode 100644 spec/requests/ci/api/triggers_spec.rb create mode 100644 spec/requests/ci/builds_spec.rb create mode 100644 spec/requests/ci/commits_spec.rb create mode 100644 spec/services/ci/create_commit_service_spec.rb create mode 100644 spec/services/ci/create_project_service_spec.rb create mode 100644 spec/services/ci/create_trigger_request_service_spec.rb create mode 100644 spec/services/ci/event_service_spec.rb create mode 100644 spec/services/ci/image_for_build_service_spec.rb create mode 100644 spec/services/ci/register_build_service_spec.rb create mode 100644 spec/services/ci/web_hook_service_spec.rb diff --git a/spec/ci/features/admin/builds_spec.rb b/spec/ci/features/admin/builds_spec.rb deleted file mode 100644 index e62e83692da..00000000000 --- a/spec/ci/features/admin/builds_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -require 'spec_helper' - -describe "Admin Builds" do - let(:project) { FactoryGirl.create :project } - let(:commit) { FactoryGirl.create :commit, project: project } - let(:build) { FactoryGirl.create :build, commit: commit } - - before do - skip_admin_auth - login_as :user - end - - describe "GET /admin/builds" do - before do - build - visit admin_builds_path - end - - it { page.should have_content "All builds" } - it { page.should have_content build.short_sha } - end - - describe "Tabs" do - it "shows all builds" do - build = FactoryGirl.create :build, commit: commit, status: "pending" - build1 = FactoryGirl.create :build, commit: commit, status: "running" - build2 = FactoryGirl.create :build, commit: commit, status: "success" - build3 = FactoryGirl.create :build, commit: commit, status: "failed" - - visit admin_builds_path - - page.all(".build-link").size.should == 4 - end - - it "shows pending builds" do - build = FactoryGirl.create :build, commit: commit, status: "pending" - build1 = FactoryGirl.create :build, commit: commit, status: "running" - build2 = FactoryGirl.create :build, commit: commit, status: "success" - build3 = FactoryGirl.create :build, commit: commit, status: "failed" - - visit admin_builds_path - - within ".nav.nav-tabs" do - click_on "Pending" - end - - page.find(".build-link").should have_content(build.id) - page.find(".build-link").should_not have_content(build1.id) - page.find(".build-link").should_not have_content(build2.id) - page.find(".build-link").should_not have_content(build3.id) - end - - it "shows running builds" do - build = FactoryGirl.create :build, commit: commit, status: "pending" - build1 = FactoryGirl.create :build, commit: commit, status: "running" - build2 = FactoryGirl.create :build, commit: commit, status: "success" - build3 = FactoryGirl.create :build, commit: commit, status: "failed" - - visit admin_builds_path - - within ".nav.nav-tabs" do - click_on "Running" - end - - page.find(".build-link").should have_content(build1.id) - page.find(".build-link").should_not have_content(build.id) - page.find(".build-link").should_not have_content(build2.id) - page.find(".build-link").should_not have_content(build3.id) - end - end -end diff --git a/spec/ci/features/admin/events_spec.rb b/spec/ci/features/admin/events_spec.rb deleted file mode 100644 index 469c6ed102d..00000000000 --- a/spec/ci/features/admin/events_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'spec_helper' - -describe "Admin Events" do - let(:event) { FactoryGirl.create :admin_event } - - before do - skip_admin_auth - login_as :user - end - - describe "GET /admin/events" do - before do - event - visit admin_events_path - end - - it { page.should have_content "Events" } - it { page.should have_content event.description } - end -end diff --git a/spec/ci/features/admin/projects_spec.rb b/spec/ci/features/admin/projects_spec.rb deleted file mode 100644 index 6f87e368deb..00000000000 --- a/spec/ci/features/admin/projects_spec.rb +++ /dev/null @@ -1,19 +0,0 @@ -require 'spec_helper' - -describe "Admin Projects" do - let(:project) { FactoryGirl.create :project } - - before do - skip_admin_auth - login_as :user - end - - describe "GET /admin/projects" do - before do - project - visit admin_projects_path - end - - it { page.should have_content "Projects" } - end -end diff --git a/spec/ci/features/admin/runners_spec.rb b/spec/ci/features/admin/runners_spec.rb deleted file mode 100644 index 2827a7fc6e5..00000000000 --- a/spec/ci/features/admin/runners_spec.rb +++ /dev/null @@ -1,63 +0,0 @@ -require 'spec_helper' - -describe "Admin Runners" do - before do - skip_admin_auth - login_as :user - end - - describe "Runners page" do - before do - runner = FactoryGirl.create(:runner) - commit = FactoryGirl.create(:commit) - FactoryGirl.create(:build, commit: commit, runner_id: runner.id) - visit admin_runners_path - end - - it { page.has_text? "Manage Runners" } - it { page.has_text? "To register a new runner" } - it { page.has_text? "Runners with last contact less than a minute ago: 1" } - - describe 'search' do - before do - FactoryGirl.create :runner, description: 'foo' - FactoryGirl.create :runner, description: 'bar' - - fill_in 'search', with: 'foo' - click_button 'Search' - end - - it { page.should have_content("foo") } - it { page.should_not have_content("bar") } - end - end - - describe "Runner show page" do - let(:runner) { FactoryGirl.create :runner } - - before do - FactoryGirl.create(:project, name: "foo") - FactoryGirl.create(:project, name: "bar") - visit admin_runner_path(runner) - end - - describe 'runner info' do - it { find_field('runner_token').value.should eq runner.token } - end - - describe 'projects' do - it { page.should have_content("foo") } - it { page.should have_content("bar") } - end - - describe 'search' do - before do - fill_in 'search', with: 'foo' - click_button 'Search' - end - - it { page.should have_content("foo") } - it { page.should_not have_content("bar") } - end - end -end diff --git a/spec/ci/features/builds_spec.rb b/spec/ci/features/builds_spec.rb deleted file mode 100644 index fcd7996efd7..00000000000 --- a/spec/ci/features/builds_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'spec_helper' - -describe "Builds" do - before do - @project = FactoryGirl.create :project - @commit = FactoryGirl.create :commit, project: @project - @build = FactoryGirl.create :build, commit: @commit - end - - describe "GET /:project/builds/:id" do - before do - login_as :user - visit project_build_path(@project, @build) - end - - it { page.should have_content @commit.sha[0..7] } - it { page.should have_content @commit.git_commit_message } - it { page.should have_content @commit.git_author_name } - end - - describe "GET /:project/builds/:id/cancel" do - before do - login_as :user - @build.run! - visit cancel_project_build_path(@project, @build) - end - - it { page.should have_content 'canceled' } - it { page.should have_content 'Retry' } - end - - describe "POST /:project/builds/:id/retry" do - before do - login_as :user - @build.cancel! - visit project_build_path(@project, @build) - click_link 'Retry' - end - - it { page.should have_content 'pending' } - it { page.should have_content 'Cancel' } - end - - describe "Show page public accessible" do - before do - @project = FactoryGirl.create :public_project - @commit = FactoryGirl.create :commit, project: @project - @runner = FactoryGirl.create :specific_runner - @build = FactoryGirl.create :build, commit: @commit, runner: @runner - - stub_gitlab_calls - visit project_build_path(@project, @build) - end - - it { page.should have_content @commit.sha[0..7] } - end -end diff --git a/spec/ci/features/commits_spec.rb b/spec/ci/features/commits_spec.rb deleted file mode 100644 index 202f05c516f..00000000000 --- a/spec/ci/features/commits_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -require 'spec_helper' - -describe "Commits" do - context "Authenticated user" do - before do - login_as :user - @project = FactoryGirl.create :project - @commit = FactoryGirl.create :commit, project: @project - @build = FactoryGirl.create :build, commit: @commit - end - - describe "GET /:project/commits/:sha" do - before do - visit project_ref_commit_path(@project, @commit.ref, @commit.sha) - end - - it { page.should have_content @commit.sha[0..7] } - it { page.should have_content @commit.git_commit_message } - it { page.should have_content @commit.git_author_name } - end - - describe "Cancel commit" do - it "cancels commit" do - visit project_ref_commit_path(@project, @commit.ref, @commit.sha) - click_on "Cancel" - - page.should have_content "canceled" - end - end - - describe ".gitlab-ci.yml not found warning" do - it "does not show warning" do - visit project_ref_commit_path(@project, @commit.ref, @commit.sha) - - page.should_not have_content ".gitlab-ci.yml not found in this commit" - end - - it "shows warning" do - @commit.push_data[:ci_yaml_file] = nil - @commit.save - - visit project_ref_commit_path(@project, @commit.ref, @commit.sha) - - page.should have_content ".gitlab-ci.yml not found in this commit" - end - end - end - - context "Public pages" do - before do - @project = FactoryGirl.create :public_project - @commit = FactoryGirl.create :commit, project: @project - @build = FactoryGirl.create :build, commit: @commit - end - - describe "GET /:project/commits/:sha" do - before do - visit project_ref_commit_path(@project, @commit.ref, @commit.sha) - end - - it { page.should have_content @commit.sha[0..7] } - it { page.should have_content @commit.git_commit_message } - it { page.should have_content @commit.git_author_name } - end - end -end diff --git a/spec/ci/features/events_spec.rb b/spec/ci/features/events_spec.rb deleted file mode 100644 index 77d1fba5769..00000000000 --- a/spec/ci/features/events_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'spec_helper' - -describe "Events" do - let(:project) { FactoryGirl.create :project } - let(:event) { FactoryGirl.create :admin_event, project: project } - - before do - login_as :user - end - - describe "GET /project/:id/events" do - before do - event - visit project_events_path(project) - end - - it { page.should have_content "Events" } - it { page.should have_content event.description } - end -end diff --git a/spec/ci/features/lint_spec.rb b/spec/ci/features/lint_spec.rb deleted file mode 100644 index 0b3d4e099fb..00000000000 --- a/spec/ci/features/lint_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require 'spec_helper' - -describe "Lint" do - before do - login_as :user - end - - it "Yaml parsing", js: true do - content = File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) - visit lint_path - fill_in "content", with: content - click_on "Validate" - within "table" do - page.should have_content("Job - rspec") - page.should have_content("Job - spinach") - page.should have_content("Deploy Job - staging") - page.should have_content("Deploy Job - production") - end - end - - it "Yaml parsing with error", js: true do - visit lint_path - fill_in "content", with: "" - click_on "Validate" - page.should have_content("Status: syntax is incorrect") - page.should have_content("Error: Please provide content of .gitlab-ci.yml") - end -end diff --git a/spec/ci/features/projects_spec.rb b/spec/ci/features/projects_spec.rb deleted file mode 100644 index 3f21af92a2b..00000000000 --- a/spec/ci/features/projects_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'spec_helper' - -describe "Projects" do - before do - login_as :user - @project = FactoryGirl.create :project, name: "GitLab / gitlab-shell" - end - - describe "GET /projects", js: true do - before do - stub_js_gitlab_calls - visit projects_path - end - - it { page.should have_content "GitLab / gitlab-shell" } - it { page.should have_selector ".search input#search" } - end - - describe "GET /projects/:id" do - before do - visit project_path(@project) - end - - it { page.should have_content @project.name } - it { page.should have_content 'All commits' } - end - - describe "GET /projects/:id/edit" do - before do - visit edit_project_path(@project) - end - - it { page.should have_content @project.name } - it { page.should have_content 'Build Schedule' } - - it "updates configuration" do - fill_in 'Timeout', with: '70' - click_button 'Save changes' - - page.should have_content 'was successfully updated' - - find_field('Timeout').value.should eq '70' - end - end - - describe "GET /projects/:id/charts" do - before do - visit project_charts_path(@project) - end - - it { page.should have_content 'Overall' } - it { page.should have_content 'Builds chart for last week' } - it { page.should have_content 'Builds chart for last month' } - it { page.should have_content 'Builds chart for last year' } - it { page.should have_content 'Commit duration in minutes for last 30 commits' } - end -end diff --git a/spec/ci/features/runners_spec.rb b/spec/ci/features/runners_spec.rb deleted file mode 100644 index c41dc5b2e2e..00000000000 --- a/spec/ci/features/runners_spec.rb +++ /dev/null @@ -1,98 +0,0 @@ -require 'spec_helper' - -describe "Runners" do - before do - login_as :user - end - - describe "specific runners" do - before do - @project = FactoryGirl.create :project - @project2 = FactoryGirl.create :project - stub_js_gitlab_calls - - # all projects should be authorized for user - Network.any_instance.stub(:projects).and_return([ - OpenStruct.new({id: @project.gitlab_id}), - OpenStruct.new({id: @project2.gitlab_id}) - ]) - - @shared_runner = FactoryGirl.create :shared_runner - @specific_runner = FactoryGirl.create :specific_runner - @specific_runner2 = FactoryGirl.create :specific_runner - @project.runners << @specific_runner - @project2.runners << @specific_runner2 - end - - it "places runners in right places" do - visit project_runners_path(@project) - page.find(".available-specific-runners").should have_content(@specific_runner2.display_name) - page.find(".activated-specific-runners").should have_content(@specific_runner.display_name) - page.find(".available-shared-runners").should have_content(@shared_runner.display_name) - end - - it "enables specific runner for project" do - visit project_runners_path(@project) - - within ".available-specific-runners" do - click_on "Enable for this project" - end - - page.find(".activated-specific-runners").should have_content(@specific_runner2.display_name) - end - - it "disables specific runner for project" do - @project2.runners << @specific_runner - - visit project_runners_path(@project) - - within ".activated-specific-runners" do - click_on "Disable for this project" - end - - page.find(".available-specific-runners").should have_content(@specific_runner.display_name) - end - - it "removes specific runner for project if this is last project for that runners" do - visit project_runners_path(@project) - - within ".activated-specific-runners" do - click_on "Remove runner" - end - - Runner.exists?(id: @specific_runner).should be_false - end - end - - describe "shared runners" do - before do - @project = FactoryGirl.create :project - stub_js_gitlab_calls - end - - it "enables shared runners" do - visit project_runners_path(@project) - - click_on "Enable shared runners" - - @project.reload.shared_runners_enabled.should be_true - end - end - - describe "show page" do - before do - @project = FactoryGirl.create :project - stub_js_gitlab_calls - @specific_runner = FactoryGirl.create :specific_runner - @project.runners << @specific_runner - end - - it "shows runner information" do - visit project_runners_path(@project) - - click_on @specific_runner.short_sha - - page.should have_content(@specific_runner.platform) - end - end -end diff --git a/spec/ci/features/triggers_spec.rb b/spec/ci/features/triggers_spec.rb deleted file mode 100644 index 2076429383d..00000000000 --- a/spec/ci/features/triggers_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' - -describe 'Variables' do - before do - login_as :user - @project = FactoryGirl.create :project - stub_js_gitlab_calls - visit project_triggers_path(@project) - end - - context 'create a trigger' do - before do - click_on 'Add Trigger' - @project.triggers.count.should == 1 - end - - it 'contains trigger token' do - page.should have_content(@project.triggers.first.token) - end - - it 'revokes the trigger' do - click_on 'Revoke' - @project.triggers.count.should == 0 - end - end -end diff --git a/spec/ci/features/variables_spec.rb b/spec/ci/features/variables_spec.rb deleted file mode 100644 index 2bb0d9dedde..00000000000 --- a/spec/ci/features/variables_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require 'spec_helper' - -describe "Variables" do - before do - login_as :user - end - - describe "specific runners" do - before do - @project = FactoryGirl.create :project - stub_js_gitlab_calls - end - - it "creates variable", js: true do - visit project_variables_path(@project) - click_on "Add a variable" - fill_in "Key", with: "SECRET_KEY" - fill_in "Value", with: "SECRET_VALUE" - click_on "Save changes" - - page.should have_content("Variables were successfully updated.") - @project.variables.count.should == 1 - end - - end -end diff --git a/spec/ci/helpers/application_helper_spec.rb b/spec/ci/helpers/application_helper_spec.rb deleted file mode 100644 index c2b1058a8fa..00000000000 --- a/spec/ci/helpers/application_helper_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -require 'spec_helper' - -describe ApplicationHelper do - describe "#duration_in_words" do - it "returns minutes and seconds" do - intervals_in_words = { - 100 => "1 minute 40 seconds", - 121 => "2 minutes 1 second", - 3721 => "62 minutes 1 second", - 0 => "0 seconds" - } - - intervals_in_words.each do |interval, expectation| - duration_in_words(Time.now + interval, Time.now).should == expectation - end - end - - it "calculates interval from now if there is no finished_at" do - duration_in_words(nil, Time.now - 5).should == "5 seconds" - end - end - - describe "#time_interval_in_words" do - it "returns minutes and seconds" do - intervals_in_words = { - 100 => "1 minute 40 seconds", - 121 => "2 minutes 1 second", - 3721 => "62 minutes 1 second", - 0 => "0 seconds" - } - - intervals_in_words.each do |interval, expectation| - time_interval_in_words(interval).should == expectation - end - end - end -end diff --git a/spec/ci/helpers/runners_helper_spec.rb b/spec/ci/helpers/runners_helper_spec.rb deleted file mode 100644 index 02d497b40d2..00000000000 --- a/spec/ci/helpers/runners_helper_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -describe RunnersHelper do - it "returns - not contacted yet" do - runner = FactoryGirl.build :runner - runner_status_icon(runner).should include("not connected yet") - end - - it "returns offline text" do - runner = FactoryGirl.build(:runner, contacted_at: 1.day.ago, active: true) - runner_status_icon(runner).should include("Runner is offline") - end - - it "returns online text" do - runner = FactoryGirl.build(:runner, contacted_at: 1.hour.ago, active: true) - runner_status_icon(runner).should include("Runner is online") - end -end diff --git a/spec/ci/helpers/user_helper_spec.rb b/spec/ci/helpers/user_helper_spec.rb deleted file mode 100644 index 7215dc41a85..00000000000 --- a/spec/ci/helpers/user_helper_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'spec_helper' - -describe UserHelper do - describe :user_avatar_url do - let (:user) { User.new({'avatar_url' => avatar_url}) } - - context 'no avatar' do - let (:avatar_url) { nil } - - it 'should return a generic avatar' do - user_avatar_url(user).should == 'ci/no_avatar.png' - end - end - - context 'plain gravatar' do - let (:base_url) { 'http://www.gravatar.com/avatar/abcdefgh' } - let (:avatar_url) { "#{base_url}?s=40&d=mm" } - - it 'should return gravatar with default size' do - user_avatar_url(user).should == "#{base_url}?s=40&d=identicon" - end - - it 'should return gravatar with custom size' do - user_avatar_url(user, 120).should == "#{base_url}?s=120&d=identicon" - end - end - - context 'secure gravatar' do - let (:base_url) { 'https://secure.gravatar.com/avatar/abcdefgh' } - let (:avatar_url) { "#{base_url}?s=40&d=mm" } - - it 'should return gravatar with default size' do - user_avatar_url(user).should == "#{base_url}?s=40&d=identicon" - end - - it 'should return gravatar with custom size' do - user_avatar_url(user, 120).should == "#{base_url}?s=120&d=identicon" - end - end - - context 'custom avatar' do - let (:avatar_url) { 'http://example.local/avatar.png' } - - it 'should return custom avatar' do - user_avatar_url(user).should == avatar_url - end - end - end -end diff --git a/spec/ci/helpers/user_sessions_helper_spec.rb b/spec/ci/helpers/user_sessions_helper_spec.rb deleted file mode 100644 index a2ab1f1e023..00000000000 --- a/spec/ci/helpers/user_sessions_helper_spec.rb +++ /dev/null @@ -1,69 +0,0 @@ -require 'spec_helper' - -describe UserSessionsHelper do - describe :generate_oauth_hmac do - let (:salt) { 'a' } - let (:salt2) { 'b' } - let (:return_to) { 'b' } - - it 'should return null if return_to is also null' do - generate_oauth_hmac(salt, nil).should be_nil - end - - it 'should return not null if return_to is also not null' do - generate_oauth_hmac(salt, return_to).should_not be_nil - end - - it 'should return different hmacs for different salts' do - secret1 = generate_oauth_hmac(salt, return_to) - secret2 = generate_oauth_hmac(salt2, return_to) - secret1.should_not eq(secret2) - end - end - - describe :generate_oauth_state do - let (:return_to) { 'b' } - - it 'should return null if return_to is also null' do - generate_oauth_state(nil).should be_nil - end - - it 'should return two different states for same return_to' do - state1 = generate_oauth_state(return_to) - state2 = generate_oauth_state(return_to) - state1.should_not eq(state2) - end - end - - describe :get_ouath_state_return_to do - let (:return_to) { 'a' } - let (:state) { generate_oauth_state(return_to) } - - it 'should return return_to' do - get_ouath_state_return_to(state).should eq(return_to) - end - end - - describe :is_oauth_state_valid? do - let (:return_to) { 'a' } - let (:state) { generate_oauth_state(return_to) } - let (:forged) { "forged#{state}" } - let (:invalid) { 'aa' } - let (:invalid2) { 'aa:bb' } - let (:invalid3) { 'aa:bb:' } - - it 'should validate oauth state' do - is_oauth_state_valid?(state).should be_true - end - - it 'should not validate forged state' do - is_oauth_state_valid?(forged).should be_false - end - - it 'should not validate invalid state' do - is_oauth_state_valid?(invalid).should be_false - is_oauth_state_valid?(invalid2).should be_false - is_oauth_state_valid?(invalid3).should be_false - end - end -end diff --git a/spec/ci/lib/ansi2html_spec.rb b/spec/ci/lib/ansi2html_spec.rb deleted file mode 100644 index aa60011685b..00000000000 --- a/spec/ci/lib/ansi2html_spec.rb +++ /dev/null @@ -1,133 +0,0 @@ -require 'spec_helper' - -describe Ansi2html do - - it "prints non-ansi as-is" do - Ansi2html::convert("Hello").should == 'Hello' - end - - it "strips non-color-changing controll sequences" do - Ansi2html::convert("Hello \e[2Kworld").should == 'Hello world' - end - - it "prints simply red" do - Ansi2html::convert("\e[31mHello\e[0m").should == 'Hello' - end - - it "prints simply red without trailing reset" do - Ansi2html::convert("\e[31mHello").should == 'Hello' - end - - it "prints simply yellow" do - Ansi2html::convert("\e[33mHello\e[0m").should == 'Hello' - end - - it "prints default on blue" do - Ansi2html::convert("\e[39;44mHello").should == 'Hello' - end - - it "prints red on blue" do - Ansi2html::convert("\e[31;44mHello").should == 'Hello' - end - - it "resets colors after red on blue" do - Ansi2html::convert("\e[31;44mHello\e[0m world").should == 'Hello world' - end - - it "performs color change from red/blue to yellow/blue" do - Ansi2html::convert("\e[31;44mHello \e[33mworld").should == 'Hello world' - end - - it "performs color change from red/blue to yellow/green" do - Ansi2html::convert("\e[31;44mHello \e[33;42mworld").should == 'Hello world' - end - - it "performs color change from red/blue to reset to yellow/green" do - Ansi2html::convert("\e[31;44mHello\e[0m \e[33;42mworld").should == 'Hello world' - end - - it "ignores unsupported codes" do - Ansi2html::convert("\e[51mHello\e[0m").should == 'Hello' - end - - it "prints light red" do - Ansi2html::convert("\e[91mHello\e[0m").should == 'Hello' - end - - it "prints default on light red" do - Ansi2html::convert("\e[101mHello\e[0m").should == 'Hello' - end - - it "performs color change from red/blue to default/blue" do - Ansi2html::convert("\e[31;44mHello \e[39mworld").should == 'Hello world' - end - - it "performs color change from light red/blue to default/blue" do - Ansi2html::convert("\e[91;44mHello \e[39mworld").should == 'Hello world' - end - - it "prints bold text" do - Ansi2html::convert("\e[1mHello").should == 'Hello' - end - - it "resets bold text" do - Ansi2html::convert("\e[1mHello\e[21m world").should == 'Hello world' - Ansi2html::convert("\e[1mHello\e[22m world").should == 'Hello world' - end - - it "prints italic text" do - Ansi2html::convert("\e[3mHello").should == 'Hello' - end - - it "resets italic text" do - Ansi2html::convert("\e[3mHello\e[23m world").should == 'Hello world' - end - - it "prints underlined text" do - Ansi2html::convert("\e[4mHello").should == 'Hello' - end - - it "resets underlined text" do - Ansi2html::convert("\e[4mHello\e[24m world").should == 'Hello world' - end - - it "prints concealed text" do - Ansi2html::convert("\e[8mHello").should == 'Hello' - end - - it "resets concealed text" do - Ansi2html::convert("\e[8mHello\e[28m world").should == 'Hello world' - end - - it "prints crossed-out text" do - Ansi2html::convert("\e[9mHello").should == 'Hello' - end - - it "resets crossed-out text" do - Ansi2html::convert("\e[9mHello\e[29m world").should == 'Hello world' - end - - it "can print 256 xterm fg colors" do - Ansi2html::convert("\e[38;5;16mHello").should == 'Hello' - end - - it "can print 256 xterm fg colors on normal magenta background" do - Ansi2html::convert("\e[38;5;16;45mHello").should == 'Hello' - end - - it "can print 256 xterm bg colors" do - Ansi2html::convert("\e[48;5;240mHello").should == 'Hello' - end - - it "can print 256 xterm bg colors on normal magenta foreground" do - Ansi2html::convert("\e[48;5;16;35mHello").should == 'Hello' - end - - it "prints bold colored text vividly" do - Ansi2html::convert("\e[1;31mHello\e[0m").should == 'Hello' - end - - it "prints bold light colored text correctly" do - Ansi2html::convert("\e[1;91mHello\e[0m").should == 'Hello' - end -end diff --git a/spec/ci/lib/charts_spec.rb b/spec/ci/lib/charts_spec.rb deleted file mode 100644 index 236cfc2a1f6..00000000000 --- a/spec/ci/lib/charts_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'spec_helper' - -describe "Charts" do - - context "build_times" do - before do - @project = FactoryGirl.create(:project) - @commit = FactoryGirl.create(:commit, project: @project) - FactoryGirl.create(:build, commit: @commit) - end - - it 'should return build times in minutes' do - chart = Charts::BuildTime.new(@project) - chart.build_times.should == [2] - end - end -end diff --git a/spec/ci/lib/gitlab_ci_yaml_processor_spec.rb b/spec/ci/lib/gitlab_ci_yaml_processor_spec.rb deleted file mode 100644 index ed3d4e84054..00000000000 --- a/spec/ci/lib/gitlab_ci_yaml_processor_spec.rb +++ /dev/null @@ -1,311 +0,0 @@ -require 'spec_helper' - -describe GitlabCiYamlProcessor do - - describe "#builds_for_ref" do - let (:type) { 'test' } - - it "returns builds if no branch specified" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: {script: "rspec"} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref(type, "master").size.should == 1 - config_processor.builds_for_stage_and_ref(type, "master").first.should == { - stage: "test", - except: nil, - name: :rspec, - only: nil, - script: "pwd\nrspec", - tags: [], - options: {}, - allow_failure: false - } - end - - it "does not return builds if only has another branch" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: {script: "rspec", only: ["deploy"]} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref(type, "master").size.should == 0 - end - - it "does not return builds if only has regexp with another branch" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: {script: "rspec", only: ["/^deploy$/"]} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref(type, "master").size.should == 0 - end - - it "returns builds if only has specified this branch" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: {script: "rspec", only: ["master"]} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref(type, "master").size.should == 1 - end - - it "does not build tags" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: {script: "rspec", except: ["tags"]} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref(type, "0-1", true).size.should == 0 - end - - it "returns builds if only has a list of branches including specified" do - config = YAML.dump({ - before_script: ["pwd"], - rspec: {script: "rspec", type: type, only: ["master", "deploy"]} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref(type, "deploy").size.should == 1 - end - - it "returns build only for specified type" do - - config = YAML.dump({ - before_script: ["pwd"], - build: {script: "build", type: "build", only: ["master", "deploy"]}, - rspec: {script: "rspec", type: type, only: ["master", "deploy"]}, - staging: {script: "deploy", type: "deploy", only: ["master", "deploy"]}, - production: {script: "deploy", type: "deploy", only: ["master", "deploy"]}, - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref("production", "deploy").size.should == 0 - config_processor.builds_for_stage_and_ref(type, "deploy").size.should == 1 - config_processor.builds_for_stage_and_ref("deploy", "deploy").size.should == 2 - end - end - - describe "Image and service handling" do - it "returns image and service when defined" do - config = YAML.dump({ - image: "ruby:2.1", - services: ["mysql"], - before_script: ["pwd"], - rspec: {script: "rspec"} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref("test", "master").size.should == 1 - config_processor.builds_for_stage_and_ref("test", "master").first.should == { - except: nil, - stage: "test", - name: :rspec, - only: nil, - script: "pwd\nrspec", - tags: [], - options: { - image: "ruby:2.1", - services: ["mysql"] - }, - allow_failure: false - } - end - - it "returns image and service when overridden for job" do - config = YAML.dump({ - image: "ruby:2.1", - services: ["mysql"], - before_script: ["pwd"], - rspec: {image: "ruby:2.5", services: ["postgresql"], script: "rspec"} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - - config_processor.builds_for_stage_and_ref("test", "master").size.should == 1 - config_processor.builds_for_stage_and_ref("test", "master").first.should == { - except: nil, - stage: "test", - name: :rspec, - only: nil, - script: "pwd\nrspec", - tags: [], - options: { - image: "ruby:2.5", - services: ["postgresql"] - }, - allow_failure: false - } - end - end - - describe "Variables" do - it "returns variables when defined" do - variables = { - var1: "value1", - var2: "value2", - } - config = YAML.dump({ - variables: variables, - before_script: ["pwd"], - rspec: {script: "rspec"} - }) - - config_processor = GitlabCiYamlProcessor.new(config) - config_processor.variables.should == variables - end - end - - describe "Error handling" do - it "indicates that object is invalid" do - expect{GitlabCiYamlProcessor.new("invalid_yaml\n!ccdvlf%612334@@@@")}.to raise_error(GitlabCiYamlProcessor::ValidationError) - end - - it "returns errors if tags parameter is invalid" do - config = YAML.dump({rspec: {script: "test", tags: "mysql"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: tags parameter should be an array of strings") - end - - it "returns errors if before_script parameter is invalid" do - config = YAML.dump({before_script: "bundle update", rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings") - end - - it "returns errors if image parameter is invalid" do - config = YAML.dump({image: ["test"], rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image should be a string") - end - - it "returns errors if job image parameter is invalid" do - config = YAML.dump({rspec: {script: "test", image: ["test"]}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: image should be a string") - end - - it "returns errors if services parameter is not an array" do - config = YAML.dump({services: "test", rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings") - end - - it "returns errors if services parameter is not an array of strings" do - config = YAML.dump({services: [10, "test"], rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings") - end - - it "returns errors if job services parameter is not an array" do - config = YAML.dump({rspec: {script: "test", services: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings") - end - - it "returns errors if job services parameter is not an array of strings" do - config = YAML.dump({rspec: {script: "test", services: [10, "test"]}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings") - end - - it "returns errors if there are unknown parameters" do - config = YAML.dump({extra: "bundle update"}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra") - end - - it "returns errors if there are unknown parameters that are hashes, but doesn't have a script" do - config = YAML.dump({extra: {services: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra") - end - - it "returns errors if there is no any jobs defined" do - config = YAML.dump({before_script: ["bundle update"]}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Please define at least one job") - end - - it "returns errors if job allow_failure parameter is not an boolean" do - config = YAML.dump({rspec: {script: "test", allow_failure: "string"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: allow_failure parameter should be an boolean") - end - - it "returns errors if job stage is not a string" do - config = YAML.dump({rspec: {script: "test", type: 1, allow_failure: "string"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") - end - - it "returns errors if job stage is not a pre-defined stage" do - config = YAML.dump({rspec: {script: "test", type: "acceptance", allow_failure: "string"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") - end - - it "returns errors if job stage is not a defined stage" do - config = YAML.dump({types: ["build", "test"], rspec: {script: "test", type: "acceptance", allow_failure: "string"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test") - end - - it "returns errors if stages is not an array" do - config = YAML.dump({types: "test", rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings") - end - - it "returns errors if stages is not an array of strings" do - config = YAML.dump({types: [true, "test"], rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings") - end - - it "returns errors if variables is not a map" do - config = YAML.dump({variables: "test", rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") - end - - it "returns errors if variables is not a map of key-valued strings" do - config = YAML.dump({variables: {test: false}, rspec: {script: "test"}}) - expect do - GitlabCiYamlProcessor.new(config) - end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") - end - end -end diff --git a/spec/ci/lib/upgrader_spec.rb b/spec/ci/lib/upgrader_spec.rb deleted file mode 100644 index 40a98307ad2..00000000000 --- a/spec/ci/lib/upgrader_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -require 'spec_helper' - -describe Upgrader do - let(:upgrader) { Upgrader.new } - let(:current_version) { GitlabCi::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 GitlabCI 3' do - allow(upgrader).to receive(:current_version_raw).and_return('3.0.0') - expect(upgrader.latest_version_raw).to eq('v3.2.0') - end - - it 'should get the latest version from tags' do - allow(upgrader).to receive(:fetch_git_tags).and_return([ - '1b5bee25b51724214c7a3307ef94027ab93ec982 refs/tags/v7.8.1', - '424cb42e35947fa304ef83eb211ffc657e31aef3 refs/tags/v7.8.1^{}', - '498e5ba63be1bb99e30c6e720902d864aac4413c refs/tags/v7.9.0.rc1', - '96aaf45ae93bd43e8b3f5d4d353d64d3cbe1e63b refs/tags/v7.9.0.rc1^{}', - '94aaf45ae93bd43e8b3fad4a353d64d3cbe1e62b refs/tags/v7.1.0', - '96aaf45ae93ba13e8b3f5d4d353d64d3cbe1e251 refs/tags/v7.1.0^{}', - '29359d64442bf54b4ca1d8b439fd9e5f9cd83252 refs/tags/v7.10.0', - '4d9213a6378bff43a69ae099702fb81e29335e7a refs/tags/v7.10.0^{}', - '1d93e1626bda93622ca7a2ae2825e2e94dabf3c6 refs/tags/v7.12.0', - '0188a9d1c2efdc52bfad36ad303686be997de713 refs/tags/v7.12.0^{}']) - expect(upgrader.latest_version_raw).to eq("v7.12.0") - end - end -end diff --git a/spec/ci/mailers/notify_spec.rb b/spec/ci/mailers/notify_spec.rb deleted file mode 100644 index 6a2c845cd0e..00000000000 --- a/spec/ci/mailers/notify_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'spec_helper' - -describe Notify do - include EmailSpec::Helpers - include EmailSpec::Matchers - - before do - @project = FactoryGirl.create :project - @commit = FactoryGirl.create :commit, project: @project - @build = FactoryGirl.create :build, commit: @commit - end - - describe 'build success' do - subject { Notify.build_success_email(@build.id, 'wow@example.com') } - - it 'has the correct subject' do - should have_subject /Build success for/ - end - - it 'contains name of project' do - should have_body_text /build successful/ - end - end - - describe 'build fail' do - subject { Notify.build_fail_email(@build.id, 'wow@example.com') } - - it 'has the correct subject' do - should have_subject /Build failed for/ - end - - it 'contains name of project' do - should have_body_text /build failed/ - end - end -end diff --git a/spec/ci/models/build_spec.rb b/spec/ci/models/build_spec.rb deleted file mode 100644 index 733398176bf..00000000000 --- a/spec/ci/models/build_spec.rb +++ /dev/null @@ -1,350 +0,0 @@ -# == Schema Information -# -# Table name: builds -# -# id :integer not null, primary key -# project_id :integer -# status :string(255) -# finished_at :datetime -# trace :text -# created_at :datetime -# updated_at :datetime -# started_at :datetime -# runner_id :integer -# commit_id :integer -# coverage :float -# commands :text -# job_id :integer -# name :string(255) -# deploy :boolean default(FALSE) -# options :text -# allow_failure :boolean default(FALSE), not null -# stage :string(255) -# trigger_request_id :integer -# - -require 'spec_helper' - -describe Build do - let(:project) { FactoryGirl.create :project } - let(:commit) { FactoryGirl.create :commit, project: project } - let(:build) { FactoryGirl.create :build, commit: commit } - - it { should belong_to(:commit) } - it { should validate_presence_of :status } - - it { should respond_to :success? } - it { should respond_to :failed? } - it { should respond_to :running? } - it { should respond_to :pending? } - it { should respond_to :trace_html } - - describe :first_pending do - let(:first) { FactoryGirl.create :build, commit: commit, status: 'pending', created_at: Date.yesterday } - let(:second) { FactoryGirl.create :build, commit: commit, status: 'pending' } - before { first; second } - subject { Build.first_pending } - - it { should be_a(Build) } - it('returns with the first pending build') { should eq(first) } - end - - describe :create_from do - before do - build.status = 'success' - build.save - end - let(:create_from_build) { Build.create_from build } - - it ('there should be a pending task') do - expect(Build.pending.count(:all)).to eq 0 - create_from_build - expect(Build.pending.count(:all)).to be > 0 - end - end - - describe :started? do - subject { build.started? } - - context 'without started_at' do - before { build.started_at = nil } - - it { should be_false } - end - - %w(running success failed).each do |status| - context "if build status is #{status}" do - before { build.status = status } - - it { should be_true } - end - end - - %w(pending canceled).each do |status| - context "if build status is #{status}" do - before { build.status = status } - - it { should be_false } - end - end - end - - describe :active? do - subject { build.active? } - - %w(pending running).each do |state| - context "if build.status is #{state}" do - before { build.status = state } - - it { should be_true } - end - end - - %w(success failed canceled).each do |state| - context "if build.status is #{state}" do - before { build.status = state } - - it { should be_false } - end - end - end - - describe :complete? do - subject { build.complete? } - - %w(success failed canceled).each do |state| - context "if build.status is #{state}" do - before { build.status = state } - - it { should be_true } - end - end - - %w(pending running).each do |state| - context "if build.status is #{state}" do - before { build.status = state } - - it { should be_false } - end - end - end - - describe :ignored? do - subject { build.ignored? } - - context 'if build is not allowed to fail' do - before { build.allow_failure = false } - - context 'and build.status is success' do - before { build.status = 'success' } - - it { should be_false } - end - - context 'and build.status is failed' do - before { build.status = 'failed' } - - it { should be_false } - end - end - - context 'if build is allowed to fail' do - before { build.allow_failure = true } - - context 'and build.status is success' do - before { build.status = 'success' } - - it { should be_false } - end - - context 'and build.status is failed' do - before { build.status = 'failed' } - - it { should be_true } - end - end - end - - describe :trace do - subject { build.trace_html } - - it { should be_empty } - - context 'if build.trace contains text' do - let(:text) { 'example output' } - before { build.trace = text } - - it { should include(text) } - it { should have_at_least(text.length).items } - end - end - - describe :timeout do - subject { build.timeout } - - it { should eq(commit.project.timeout) } - end - - describe :duration do - subject { build.duration } - - it { should eq(120.0) } - - context 'if the building process has not started yet' do - before do - build.started_at = nil - build.finished_at = nil - end - - it { should be_nil } - end - - context 'if the building process has started' do - before do - build.started_at = Time.now - 1.minute - build.finished_at = nil - end - - it { should be_a(Float) } - it { should > 0.0 } - end - end - - describe :options do - let(:options) { - { - :image => "ruby:2.1", - :services => [ - "postgres" - ] - } - } - - subject { build.options } - it { should eq(options) } - end - - describe :ref do - subject { build.ref } - - it { should eq(commit.ref) } - end - - describe :sha do - subject { build.sha } - - it { should eq(commit.sha) } - end - - describe :short_sha do - subject { build.short_sha } - - it { should eq(commit.short_sha) } - end - - describe :before_sha do - subject { build.before_sha } - - it { should eq(commit.before_sha) } - end - - describe :allow_git_fetch do - subject { build.allow_git_fetch } - - it { should eq(project.allow_git_fetch) } - end - - describe :project do - subject { build.project } - - it { should eq(commit.project) } - end - - describe :project_id do - subject { build.project_id } - - it { should eq(commit.project_id) } - end - - describe :project_name do - subject { build.project_name } - - it { should eq(project.name) } - end - - describe :repo_url do - subject { build.repo_url } - - it { should eq(project.repo_url_with_auth) } - end - - describe :extract_coverage do - context 'valid content & regex' do - subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', '\(\d+.\d+\%\) covered') } - - it { should eq(98.29) } - end - - context 'valid content & bad regex' do - subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', 'very covered') } - - it { should be_nil } - end - - context 'no coverage content & regex' do - subject { build.extract_coverage('No coverage for today :sad:', '\(\d+.\d+\%\) covered') } - - it { should be_nil } - end - - context 'multiple results in content & regex' do - subject { build.extract_coverage(' (98.39%) covered. (98.29%) covered', '\(\d+.\d+\%\) covered') } - - it { should eq(98.29) } - end - end - - describe :variables do - context 'returns variables' do - subject { build.variables } - - let(:variables) { - [ - {key: :DB_NAME, value: 'postgres', public: true} - ] - } - - it { should eq(variables) } - - context 'and secure variables' do - let(:secure_variables) { - [ - {key: 'SECRET_KEY', value: 'secret_value', public: false} - ] - } - - before do - build.project.variables << Variable.new(key: 'SECRET_KEY', value: 'secret_value') - end - - it { should eq(variables + secure_variables) } - - context 'and trigger variables' do - let(:trigger) { FactoryGirl.create :trigger, project: project } - let(:trigger_request) { FactoryGirl.create :trigger_request_with_variables, commit: commit, trigger: trigger } - let(:trigger_variables) { - [ - {key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false} - ] - } - - before do - build.trigger_request = trigger_request - end - - it { should eq(variables + secure_variables + trigger_variables) } - end - end - end - end -end diff --git a/spec/ci/models/commit_spec.rb b/spec/ci/models/commit_spec.rb deleted file mode 100644 index 6f644d20aaf..00000000000 --- a/spec/ci/models/commit_spec.rb +++ /dev/null @@ -1,264 +0,0 @@ -# == Schema Information -# -# Table name: commits -# -# id :integer not null, primary key -# project_id :integer -# ref :string(255) -# sha :string(255) -# before_sha :string(255) -# push_data :text -# created_at :datetime -# updated_at :datetime -# tag :boolean default(FALSE) -# yaml_errors :text -# committed_at :datetime -# - -require 'spec_helper' - -describe Commit do - let(:project) { FactoryGirl.create :project } - let(:commit) { FactoryGirl.create :commit, project: project } - let(:commit_with_project) { FactoryGirl.create :commit, project: project } - let(:config_processor) { GitlabCiYamlProcessor.new(gitlab_ci_yaml) } - - it { should belong_to(:project) } - it { should have_many(:builds) } - it { should validate_presence_of :before_sha } - it { should validate_presence_of :sha } - it { should validate_presence_of :ref } - it { should validate_presence_of :push_data } - - it { should respond_to :git_author_name } - it { should respond_to :git_author_email } - it { should respond_to :short_sha } - - describe :last_build do - subject { commit.last_build } - before do - @first = FactoryGirl.create :build, commit: commit, created_at: Date.yesterday - @second = FactoryGirl.create :build, commit: commit - end - - it { should be_a(Build) } - it('returns with the most recently created build') { should eq(@second) } - end - - describe :retry do - before do - @first = FactoryGirl.create :build, commit: commit, created_at: Date.yesterday - @second = FactoryGirl.create :build, commit: commit - end - - it "creates new build" do - expect(commit.builds.count(:all)).to eq 2 - commit.retry - expect(commit.builds.count(:all)).to eq 3 - end - end - - describe :project_recipients do - - context 'always sending notification' do - it 'should return commit_pusher_email as only recipient when no additional recipients are given' do - project = FactoryGirl.create :project, - email_add_pusher: true, - email_recipients: '' - commit = FactoryGirl.create :commit, project: project - expected = 'commit_pusher_email' - commit.stub(:push_data) { { user_email: expected } } - commit.project_recipients.should == [expected] - end - - it 'should return commit_pusher_email and additional recipients' do - project = FactoryGirl.create :project, - email_add_pusher: true, - email_recipients: 'rec1 rec2' - commit = FactoryGirl.create :commit, project: project - expected = 'commit_pusher_email' - commit.stub(:push_data) { { user_email: expected } } - commit.project_recipients.should == ['rec1', 'rec2', expected] - end - - it 'should return recipients' do - project = FactoryGirl.create :project, - email_add_pusher: false, - email_recipients: 'rec1 rec2' - commit = FactoryGirl.create :commit, project: project - commit.project_recipients.should == ['rec1', 'rec2'] - end - - it 'should return unique recipients only' do - project = FactoryGirl.create :project, - email_add_pusher: true, - email_recipients: 'rec1 rec1 rec2' - commit = FactoryGirl.create :commit, project: project - expected = 'rec2' - commit.stub(:push_data) { { user_email: expected } } - commit.project_recipients.should == ['rec1', 'rec2'] - end - end - end - - describe :valid_commit_sha do - context 'commit.sha can not start with 00000000' do - before do - commit.sha = '0' * 40 - commit.valid_commit_sha - end - - it('commit errors should not be empty') { commit.errors.should_not be_empty } - end - end - - describe :compare? do - subject { commit_with_project.compare? } - - context 'if commit.before_sha are not nil' do - it { should be_true } - end - end - - describe :short_sha do - subject { commit.short_before_sha } - - it { should have(8).items } - it { commit.before_sha.should start_with(subject) } - end - - describe :short_sha do - subject { commit.short_sha } - - it { should have(8).items } - it { commit.sha.should start_with(subject) } - end - - describe :create_next_builds do - before do - commit.stub(:config_processor).and_return(config_processor) - end - - it "creates builds for next type" do - commit.create_builds.should be_true - commit.builds.reload - commit.builds.size.should == 2 - - commit.create_next_builds(nil).should be_true - commit.builds.reload - commit.builds.size.should == 4 - - commit.create_next_builds(nil).should be_true - commit.builds.reload - commit.builds.size.should == 5 - - commit.create_next_builds(nil).should be_false - end - end - - describe :create_builds do - before do - commit.stub(:config_processor).and_return(config_processor) - end - - it 'creates builds' do - commit.create_builds.should be_true - commit.builds.reload - commit.builds.size.should == 2 - end - - context 'for build triggers' do - let(:trigger) { FactoryGirl.create :trigger, project: project } - let(:trigger_request) { FactoryGirl.create :trigger_request, commit: commit, trigger: trigger } - - it 'creates builds' do - commit.create_builds(trigger_request).should be_true - commit.builds.reload - commit.builds.size.should == 2 - end - - it 'rebuilds commit' do - commit.create_builds.should be_true - commit.builds.reload - commit.builds.size.should == 2 - - commit.create_builds(trigger_request).should be_true - commit.builds.reload - commit.builds.size.should == 4 - end - - it 'creates next builds' do - commit.create_builds(trigger_request).should be_true - commit.builds.reload - commit.builds.size.should == 2 - - commit.create_next_builds(trigger_request).should be_true - commit.builds.reload - commit.builds.size.should == 4 - end - - context 'for [ci skip]' do - before do - commit.push_data[:commits][0][:message] = 'skip this commit [ci skip]' - commit.save - end - - it 'rebuilds commit' do - commit.status.should == 'skipped' - commit.create_builds(trigger_request).should be_true - commit.builds.reload - commit.builds.size.should == 2 - commit.status.should == 'pending' - end - end - end - end - - describe "#finished_at" do - let(:project) { FactoryGirl.create :project } - let(:commit) { FactoryGirl.create :commit, project: project } - - it "returns finished_at of latest build" do - build = FactoryGirl.create :build, commit: commit, finished_at: Time.now - 60 - build1 = FactoryGirl.create :build, commit: commit, finished_at: Time.now - 120 - - commit.finished_at.to_i.should == build.finished_at.to_i - end - - it "returns nil if there is no finished build" do - build = FactoryGirl.create :not_started_build, commit: commit - - commit.finished_at.should be_nil - end - end - - describe "coverage" do - let(:project) { FactoryGirl.create :project, coverage_regex: "/.*/" } - let(:commit) { FactoryGirl.create :commit, project: project } - - it "calculates average when there are two builds with coverage" do - FactoryGirl.create :build, name: "rspec", coverage: 30, commit: commit - FactoryGirl.create :build, name: "rubocop", coverage: 40, commit: commit - commit.coverage.should == "35.00" - end - - it "calculates average when there are two builds with coverage and one with nil" do - FactoryGirl.create :build, name: "rspec", coverage: 30, commit: commit - FactoryGirl.create :build, name: "rubocop", coverage: 40, commit: commit - FactoryGirl.create :build, commit: commit - commit.coverage.should == "35.00" - end - - it "calculates average when there are two builds with coverage and one is retried" do - FactoryGirl.create :build, name: "rspec", coverage: 30, commit: commit - FactoryGirl.create :build, name: "rubocop", coverage: 30, commit: commit - FactoryGirl.create :build, name: "rubocop", coverage: 40, commit: commit - commit.coverage.should == "35.00" - end - - it "calculates average when there is one build without coverage" do - FactoryGirl.create :build, commit: commit - commit.coverage.should be_nil - end - end -end diff --git a/spec/ci/models/mail_service_spec.rb b/spec/ci/models/mail_service_spec.rb deleted file mode 100644 index d66a6591f8f..00000000000 --- a/spec/ci/models/mail_service_spec.rb +++ /dev/null @@ -1,184 +0,0 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# - -require 'spec_helper' - -describe MailService do - describe "Associations" do - it { should belong_to :project } - end - - describe "Validations" do - context "active" do - before do - subject.active = true - end - end - end - - describe 'Sends email for' do - let(:mail) { MailService.new } - - describe 'failed build' do - let(:project) { FactoryGirl.create(:project, email_add_pusher: true) } - let(:commit) { FactoryGirl.create(:commit, project: project) } - let(:build) { FactoryGirl.create(:build, status: :failed, commit: commit) } - - before do - mail.stub( - project: project - ) - end - - it do - should_email("git@example.com") - mail.execute(build) - end - - def should_email(email) - Notify.should_receive(:build_fail_email).with(build.id, email) - Notify.should_not_receive(:build_success_email).with(build.id, email) - end - end - - describe 'successfull build' do - let(:project) { FactoryGirl.create(:project, email_add_pusher: true, email_only_broken_builds: false) } - let(:commit) { FactoryGirl.create(:commit, project: project) } - let(:build) { FactoryGirl.create(:build, status: :success, commit: commit) } - - before do - mail.stub( - project: project - ) - end - - it do - should_email("git@example.com") - mail.execute(build) - end - - def should_email(email) - Notify.should_receive(:build_success_email).with(build.id, email) - Notify.should_not_receive(:build_fail_email).with(build.id, email) - end - end - - describe 'successfull build and project has email_recipients' do - let(:project) { - FactoryGirl.create(:project, - email_add_pusher: true, - email_only_broken_builds: false, - email_recipients: "jeroen@example.com") - } - let(:commit) { FactoryGirl.create(:commit, project: project) } - let(:build) { FactoryGirl.create(:build, status: :success, commit: commit) } - - before do - mail.stub( - project: project - ) - end - - it do - should_email("git@example.com") - should_email("jeroen@example.com") - mail.execute(build) - end - - def should_email(email) - Notify.should_receive(:build_success_email).with(build.id, email) - Notify.should_not_receive(:build_fail_email).with(build.id, email) - end - end - - describe 'successful build and notify only broken builds' do - let(:project) { - FactoryGirl.create(:project, - email_add_pusher: true, - email_only_broken_builds: true, - email_recipients: "jeroen@example.com") - } - let(:commit) { FactoryGirl.create(:commit, project: project) } - let(:build) { FactoryGirl.create(:build, status: :success, commit: commit) } - - before do - mail.stub( - project: project - ) - end - - it do - should_email(commit.git_author_email) - should_email("jeroen@example.com") - mail.execute(build) if mail.can_execute?(build) - end - - def should_email(email) - Notify.should_not_receive(:build_success_email).with(build.id, email) - Notify.should_not_receive(:build_fail_email).with(build.id, email) - end - end - - describe 'successful build and can test service' do - let(:project) { - FactoryGirl.create(:project, - email_add_pusher: true, - email_only_broken_builds: false, - email_recipients: "jeroen@example.com") - } - let(:commit) { FactoryGirl.create(:commit, project: project) } - let(:build) { FactoryGirl.create(:build, status: :success, commit: commit) } - - before do - mail.stub( - project: project - ) - build - end - - it do - mail.can_test?.should == true - end - end - - describe 'retried build should not receive email' do - let(:project) { - FactoryGirl.create(:project, - email_add_pusher: true, - email_only_broken_builds: true, - email_recipients: "jeroen@example.com") - } - let(:commit) { FactoryGirl.create(:commit, project: project) } - let(:build) { FactoryGirl.create(:build, status: :failed, commit: commit) } - - before do - mail.stub( - project: project - ) - end - - it do - Build.retry(build) - should_email(commit.git_author_email) - should_email("jeroen@example.com") - mail.execute(build) if mail.can_execute?(build) - end - - def should_email(email) - Notify.should_not_receive(:build_success_email).with(build.id, email) - Notify.should_not_receive(:build_fail_email).with(build.id, email) - end - end - end -end diff --git a/spec/ci/models/network_spec.rb b/spec/ci/models/network_spec.rb deleted file mode 100644 index b80adba5b08..00000000000 --- a/spec/ci/models/network_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require 'spec_helper' - -describe Network do - let(:network) { Network.new } - - describe :enable_ci do - subject { network.enable_ci '', '', '' } - - context 'on success' do - before do - response = double - response.stub(:code) { 200 } - network.class.stub(:put) { response } - end - - it { should be_true } - end - - context 'on failure' do - before do - response = double - response.stub(:code) { 404 } - network.class.stub(:put) { response } - end - - it { should be_nil } - end - end - - describe :disable_ci do - let(:response) { double } - subject { network.disable_ci '', '' } - - context 'on success' do - let(:parsed_response) { 'parsed' } - before do - response.stub(:code) { 200 } - response.stub(:parsed_response) { parsed_response } - network.class.stub(:delete) { response } - end - - it { should equal(parsed_response) } - end - - context 'on failure' do - before do - response.stub(:code) { 404 } - network.class.stub(:delete) { response } - end - - it { should be_nil } - end - end -end diff --git a/spec/ci/models/project_services/hip_chat_message_spec.rb b/spec/ci/models/project_services/hip_chat_message_spec.rb deleted file mode 100644 index f1ad875ebcf..00000000000 --- a/spec/ci/models/project_services/hip_chat_message_spec.rb +++ /dev/null @@ -1,74 +0,0 @@ -require 'spec_helper' - -describe HipChatMessage do - subject { HipChatMessage.new(build) } - - let(:project) { FactoryGirl.create(:project) } - - context "One build" do - let(:commit) { FactoryGirl.create(:commit_with_one_job, project: project) } - - let(:build) do - commit.create_builds - commit.builds.first - end - - context 'when build succeeds' do - it 'returns a successful message' do - build.update(status: "success") - - expect( subject.status_color ).to eq 'green' - expect( subject.notify? ).to be_false - expect( subject.to_s ).to match(/Build '[^']+' #\d+/) - expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./) - end - end - - context 'when build fails' do - it 'returns a failure message' do - build.update(status: "failed") - - expect( subject.status_color ).to eq 'red' - expect( subject.notify? ).to be_true - expect( subject.to_s ).to match(/Build '[^']+' #\d+/) - expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./) - end - end - end - - context "Several builds" do - let(:commit) { FactoryGirl.create(:commit_with_two_jobs, project: project) } - - let(:build) do - commit.builds.first - end - - context 'when all matrix builds succeed' do - it 'returns a successful message' do - commit.create_builds - commit.builds.update_all(status: "success") - commit.reload - - expect( subject.status_color ).to eq 'green' - expect( subject.notify? ).to be_false - expect( subject.to_s ).to match(/Commit #\d+/) - expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./) - end - end - - context 'when at least one matrix build fails' do - it 'returns a failure message' do - commit.create_builds - first_build = commit.builds.first - second_build = commit.builds.last - first_build.update(status: "success") - second_build.update(status: "failed") - - expect( subject.status_color ).to eq 'red' - expect( subject.notify? ).to be_true - expect( subject.to_s ).to match(/Commit #\d+/) - expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./) - end - end - end -end diff --git a/spec/ci/models/project_services/hip_chat_service_spec.rb b/spec/ci/models/project_services/hip_chat_service_spec.rb deleted file mode 100644 index 37ce4905af8..00000000000 --- a/spec/ci/models/project_services/hip_chat_service_spec.rb +++ /dev/null @@ -1,75 +0,0 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# - - -require 'spec_helper' - -describe HipChatService do - - describe "Validations" do - - context "active" do - before do - subject.active = true - end - - it { should validate_presence_of :hipchat_room } - it { should validate_presence_of :hipchat_token } - - end - end - - describe "Execute" do - - let(:service) { HipChatService.new } - let(:project) { FactoryGirl.create :project } - let(:commit) { FactoryGirl.create :commit, project: project } - let(:build) { FactoryGirl.create :build, commit: commit, status: 'failed' } - let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' } - - before do - service.stub( - project: project, - project_id: project.id, - notify_only_broken_builds: false, - hipchat_room: 123, - hipchat_token: 'a1b2c3d4e5f6' - ) - - WebMock.stub_request(:post, api_url) - end - - - it "should call the HipChat API" do - service.execute(build) - HipChatNotifierWorker.drain - - expect( WebMock ).to have_requested(:post, api_url).once - end - - it "calls the worker with expected arguments" do - expect( HipChatNotifierWorker ).to receive(:perform_async) \ - .with(an_instance_of(String), hash_including( - token: 'a1b2c3d4e5f6', - room: 123, - server: 'https://api.hipchat.com', - color: 'red', - notify: true - )) - - service.execute(build) - end - end -end - diff --git a/spec/ci/models/project_services/slack_message_spec.rb b/spec/ci/models/project_services/slack_message_spec.rb deleted file mode 100644 index 88e0f373206..00000000000 --- a/spec/ci/models/project_services/slack_message_spec.rb +++ /dev/null @@ -1,84 +0,0 @@ -require 'spec_helper' - -describe SlackMessage do - subject { SlackMessage.new(commit) } - - let(:project) { FactoryGirl.create :project } - - context "One build" do - let(:commit) { FactoryGirl.create(:commit_with_one_job, project: project) } - - let(:build) do - commit.create_builds - commit.builds.first - end - - context 'when build succeeded' do - let(:color) { 'good' } - - it 'returns a message with succeeded build' do - build.update(status: "success") - - subject.color.should == color - subject.fallback.should include('Build') - subject.fallback.should include("\##{build.id}") - subject.fallback.should include('succeeded') - subject.attachments.first[:fields].should be_empty - end - end - - context 'when build failed' do - let(:color) { 'danger' } - - it 'returns a message with failed build' do - build.update(status: "failed") - - subject.color.should == color - subject.fallback.should include('Build') - subject.fallback.should include("\##{build.id}") - subject.fallback.should include('failed') - subject.attachments.first[:fields].should be_empty - end - end - end - - context "Several builds" do - let(:commit) { FactoryGirl.create(:commit_with_two_jobs, project: project) } - - context 'when all matrix builds succeeded' do - let(:color) { 'good' } - - it 'returns a message with success' do - commit.create_builds - commit.builds.update_all(status: "success") - commit.reload - - subject.color.should == color - subject.fallback.should include('Commit') - subject.fallback.should include("\##{commit.id}") - subject.fallback.should include('succeeded') - subject.attachments.first[:fields].should be_empty - end - end - - context 'when one of matrix builds failed' do - let(:color) { 'danger' } - - it 'returns a message with information about failed build' do - commit.create_builds - first_build = commit.builds.first - second_build = commit.builds.last - first_build.update(status: "success") - second_build.update(status: "failed") - - subject.color.should == color - subject.fallback.should include('Commit') - subject.fallback.should include("\##{commit.id}") - subject.fallback.should include('failed') - subject.attachments.first[:fields].size.should == 1 - subject.attachments.first[:fields].first[:title].should == second_build.name - subject.attachments.first[:fields].first[:value].should include("\##{second_build.id}") - end - end - end -end diff --git a/spec/ci/models/project_services/slack_service_spec.rb b/spec/ci/models/project_services/slack_service_spec.rb deleted file mode 100644 index e1c14281274..00000000000 --- a/spec/ci/models/project_services/slack_service_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# - -require 'spec_helper' - -describe SlackService do - describe "Associations" do - it { should belong_to :project } - end - - describe "Validations" do - context "active" do - before do - subject.active = true - end - - it { should validate_presence_of :webhook } - end - end - - describe "Execute" do - let(:slack) { SlackService.new } - let(:project) { FactoryGirl.create :project } - let(:commit) { FactoryGirl.create :commit, project: project } - let(:build) { FactoryGirl.create :build, commit: commit, status: 'failed' } - let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' } - let(:notify_only_broken_builds) { false } - - before do - slack.stub( - project: project, - project_id: project.id, - webhook: webhook_url, - notify_only_broken_builds: notify_only_broken_builds - ) - - WebMock.stub_request(:post, webhook_url) - end - - it "should call Slack API" do - slack.execute(build) - SlackNotifierWorker.drain - - WebMock.should have_requested(:post, webhook_url).once - end - end -end diff --git a/spec/ci/models/project_spec.rb b/spec/ci/models/project_spec.rb deleted file mode 100644 index aa76b99154b..00000000000 --- a/spec/ci/models/project_spec.rb +++ /dev/null @@ -1,185 +0,0 @@ -# == Schema Information -# -# Table name: projects -# -# id :integer not null, primary key -# name :string(255) not null -# timeout :integer default(3600), not null -# created_at :datetime -# updated_at :datetime -# token :string(255) -# default_ref :string(255) -# path :string(255) -# always_build :boolean default(FALSE), not null -# polling_interval :integer -# public :boolean default(FALSE), not null -# ssh_url_to_repo :string(255) -# gitlab_id :integer -# allow_git_fetch :boolean default(TRUE), not null -# email_recipients :string(255) default(""), not null -# email_add_pusher :boolean default(TRUE), not null -# email_only_broken_builds :boolean default(TRUE), not null -# skip_refs :string(255) -# coverage_regex :string(255) -# shared_runners_enabled :boolean default(FALSE) -# generated_yaml_config :text -# - -require 'spec_helper' - -describe Project do - subject { FactoryGirl.build :project } - - it { should have_many(:commits) } - - it { should validate_presence_of :name } - it { should validate_presence_of :timeout } - it { should validate_presence_of :default_ref } - - describe 'before_validation' do - it 'should set an random token if none provided' do - project = FactoryGirl.create :project_without_token - project.token.should_not == "" - end - - it 'should not set an random toke if one provided' do - project = FactoryGirl.create :project - project.token.should == "iPWx6WM4lhHNedGfBpPJNP" - end - end - - describe "ordered_by_last_commit_date" do - it "returns ordered projects" do - newest_project = FactoryGirl.create :project - oldest_project = FactoryGirl.create :project - project_without_commits = FactoryGirl.create :project - - FactoryGirl.create :commit, committed_at: 1.hour.ago, project: newest_project - FactoryGirl.create :commit, committed_at: 2.hour.ago, project: oldest_project - - Project.ordered_by_last_commit_date.should == [newest_project, oldest_project, project_without_commits] - end - end - - context :valid_project do - let(:project) { FactoryGirl.create :project } - - context :project_with_commit_and_builds do - before do - commit = FactoryGirl.create(:commit, project: project) - FactoryGirl.create(:build, commit: commit) - end - - it { project.status.should == 'pending' } - it { project.last_commit.should be_kind_of(Commit) } - it { project.human_status.should == 'pending' } - end - end - - describe '#email_notification?' do - it do - project = FactoryGirl.create :project, email_add_pusher: true - project.email_notification?.should == true - end - - it do - project = FactoryGirl.create :project, email_add_pusher: false, email_recipients: 'test tesft' - project.email_notification?.should == true - end - - it do - project = FactoryGirl.create :project, email_add_pusher: false, email_recipients: '' - project.email_notification?.should == false - end - end - - describe '#broken_or_success?' do - it { - project = FactoryGirl.create :project, email_add_pusher: true - project.stub(:broken?).and_return(true) - project.stub(:success?).and_return(true) - project.broken_or_success?.should == true - } - - it { - project = FactoryGirl.create :project, email_add_pusher: true - project.stub(:broken?).and_return(true) - project.stub(:success?).and_return(false) - project.broken_or_success?.should == true - } - - it { - project = FactoryGirl.create :project, email_add_pusher: true - project.stub(:broken?).and_return(false) - project.stub(:success?).and_return(true) - project.broken_or_success?.should == true - } - - it { - project = FactoryGirl.create :project, email_add_pusher: true - project.stub(:broken?).and_return(false) - project.stub(:success?).and_return(false) - project.broken_or_success?.should == false - } - end - - describe 'Project.parse' do - let(:project_dump) { YAML.load File.read(Rails.root.join('spec/support/gitlab_stubs/raw_project.yml')) } - let(:parsed_project) { Project.parse(project_dump) } - - - it { parsed_project.should be_valid } - it { parsed_project.should be_kind_of(Project) } - it { parsed_project.name.should eq("GitLab / api.gitlab.org") } - it { parsed_project.gitlab_id.should eq(189) } - it { parsed_project.gitlab_url.should eq("http://demo.gitlab.com/gitlab/api-gitlab-org") } - - it "parses plain hash" do - Project.parse(project_dump).name.should eq("GitLab / api.gitlab.org") - end - end - - describe :repo_url_with_auth do - let(:project) { FactoryGirl.create :project } - subject { project.repo_url_with_auth } - - it { should be_a(String) } - it { should end_with(".git") } - it { should start_with(project.gitlab_url[0..6]) } - it { should include(project.token) } - it { should include('gitlab-ci-token') } - it { should include(project.gitlab_url[7..-1]) } - end - - describe :search do - let!(:project) { FactoryGirl.create(:project, name: "foo") } - - it { Project.search('fo').should include(project) } - it { Project.search('bar').should be_empty } - end - - describe :any_runners do - it "there are no runners available" do - project = FactoryGirl.create(:project) - project.any_runners?.should be_false - end - - it "there is a specific runner" do - project = FactoryGirl.create(:project) - project.runners << FactoryGirl.create(:specific_runner) - project.any_runners?.should be_true - end - - it "there is a shared runner" do - project = FactoryGirl.create(:project, shared_runners_enabled: true) - FactoryGirl.create(:shared_runner) - project.any_runners?.should be_true - end - - it "there is a shared runner, but they are prohibited to use" do - project = FactoryGirl.create(:project) - FactoryGirl.create(:shared_runner) - project.any_runners?.should be_false - end - end -end diff --git a/spec/ci/models/runner_project_spec.rb b/spec/ci/models/runner_project_spec.rb deleted file mode 100644 index cbefb24705a..00000000000 --- a/spec/ci/models/runner_project_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -# == Schema Information -# -# Table name: runner_projects -# -# id :integer not null, primary key -# runner_id :integer not null -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# - -require 'spec_helper' - -describe RunnerProject do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/ci/models/runner_spec.rb b/spec/ci/models/runner_spec.rb deleted file mode 100644 index 6902c0a94e6..00000000000 --- a/spec/ci/models/runner_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -# == Schema Information -# -# Table name: runners -# -# id :integer not null, primary key -# token :string(255) -# created_at :datetime -# updated_at :datetime -# description :string(255) -# contacted_at :datetime -# active :boolean default(TRUE), not null -# is_shared :boolean default(FALSE) -# name :string(255) -# version :string(255) -# revision :string(255) -# platform :string(255) -# architecture :string(255) -# - -require 'spec_helper' - -describe Runner do - describe '#display_name' do - it 'should return the description if it has a value' do - runner = FactoryGirl.build(:runner, description: 'Linux/Ruby-1.9.3-p448') - expect(runner.display_name).to eq 'Linux/Ruby-1.9.3-p448' - end - - it 'should return the token if it does not have a description' do - runner = FactoryGirl.create(:runner) - expect(runner.display_name).to eq runner.description - end - - it 'should return the token if the description is an empty string' do - runner = FactoryGirl.build(:runner, description: '') - expect(runner.display_name).to eq runner.token - end - end - - describe :assign_to do - let!(:project) { FactoryGirl.create :project } - let!(:shared_runner) { FactoryGirl.create(:shared_runner) } - - before { shared_runner.assign_to(project) } - - it { shared_runner.should be_specific } - it { shared_runner.projects.should == [project] } - it { shared_runner.only_for?(project).should be_true } - end - - describe "belongs_to_one_project?" do - it "returns false if there are two projects runner assigned to" do - runner = FactoryGirl.create(:specific_runner) - project = FactoryGirl.create(:project) - project1 = FactoryGirl.create(:project) - project.runners << runner - project1.runners << runner - - runner.belongs_to_one_project?.should be_false - end - - it "returns true" do - runner = FactoryGirl.create(:specific_runner) - project = FactoryGirl.create(:project) - project.runners << runner - - runner.belongs_to_one_project?.should be_true - end - end -end diff --git a/spec/ci/models/service_spec.rb b/spec/ci/models/service_spec.rb deleted file mode 100644 index 22a49e10a6c..00000000000 --- a/spec/ci/models/service_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -# == Schema Information -# -# Table name: services -# -# id :integer not null, primary key -# type :string(255) -# title :string(255) -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# active :boolean default(FALSE), not null -# properties :text -# - -require 'spec_helper' - -describe Service do - - describe "Associations" do - it { should belong_to :project } - end - - describe "Mass assignment" do - end - - describe "Test Button" do - before do - @service = Service.new - end - - describe "Testable" do - let (:project) { FactoryGirl.create :project } - let (:commit) { FactoryGirl.create :commit, project: project } - let (:build) { FactoryGirl.create :build, commit: commit } - - before do - @service.stub( - project: project - ) - build - @testable = @service.can_test? - end - - describe :can_test do - it { @testable.should == true } - end - end - end -end diff --git a/spec/ci/models/trigger_spec.rb b/spec/ci/models/trigger_spec.rb deleted file mode 100644 index bba638e7817..00000000000 --- a/spec/ci/models/trigger_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'spec_helper' - -describe Trigger do - let(:project) { FactoryGirl.create :project } - - describe 'before_validation' do - it 'should set an random token if none provided' do - trigger = FactoryGirl.create :trigger_without_token, project: project - trigger.token.should_not be_nil - end - - it 'should not set an random token if one provided' do - trigger = FactoryGirl.create :trigger, project: project - trigger.token.should == 'token' - end - end -end diff --git a/spec/ci/models/user_spec.rb b/spec/ci/models/user_spec.rb deleted file mode 100644 index 73a7a7d5fbc..00000000000 --- a/spec/ci/models/user_spec.rb +++ /dev/null @@ -1,100 +0,0 @@ -require 'spec_helper' - -describe User do - - describe "has_developer_access?" do - before do - @user = User.new({}) - end - - let(:project_with_owner_access) do - { - "name" => "gitlab-shell", - "permissions" => { - "project_access" => { - "access_level"=> 10, - "notification_level" => 3 - }, - "group_access" => { - "access_level" => 50, - "notification_level" => 3 - } - } - } - end - - let(:project_with_reporter_access) do - { - "name" => "gitlab-shell", - "permissions" => { - "project_access" => { - "access_level" => 20, - "notification_level" => 3 - }, - "group_access" => { - "access_level" => 10, - "notification_level" => 3 - } - } - } - end - - it "returns false for reporter" do - @user.stub(:project_info).and_return(project_with_reporter_access) - - @user.has_developer_access?(1).should be_false - end - - it "returns true for owner" do - @user.stub(:project_info).and_return(project_with_owner_access) - - @user.has_developer_access?(1).should be_true - end - end - - describe "authorized_projects" do - let (:user) { User.new({}) } - - before do - FactoryGirl.create :project, gitlab_id: 1 - FactoryGirl.create :project, gitlab_id: 2 - gitlab_project = OpenStruct.new({id: 1}) - gitlab_project1 = OpenStruct.new({id: 2}) - User.any_instance.stub(:gitlab_projects).and_return([gitlab_project, gitlab_project1]) - end - - it "returns projects" do - User.any_instance.stub(:can_manage_project?).and_return(true) - - user.authorized_projects.count.should == 2 - end - - it "empty list if user miss manage permission" do - User.any_instance.stub(:can_manage_project?).and_return(false) - - user.authorized_projects.count.should == 0 - end - end - - describe "authorized_runners" do - it "returns authorized runners" do - project = FactoryGirl.create :project, gitlab_id: 1 - project1 = FactoryGirl.create :project, gitlab_id: 2 - gitlab_project = OpenStruct.new({id: 1}) - gitlab_project1 = OpenStruct.new({id: 2}) - User.any_instance.stub(:gitlab_projects).and_return([gitlab_project, gitlab_project1]) - User.any_instance.stub(:can_manage_project?).and_return(true) - user = User.new({}) - - runner = FactoryGirl.create :specific_runner - runner1 = FactoryGirl.create :specific_runner - runner2 = FactoryGirl.create :specific_runner - - project.runners << runner - project1.runners << runner1 - - user.authorized_runners.should include(runner, runner1) - user.authorized_runners.should_not include(runner2) - end - end -end diff --git a/spec/ci/models/variable_spec.rb b/spec/ci/models/variable_spec.rb deleted file mode 100644 index 4575115ccfb..00000000000 --- a/spec/ci/models/variable_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -# == Schema Information -# -# Table name: variables -# -# id :integer not null, primary key -# project_id :integer not null -# key :string(255) -# value :text -# encrypted_value :text -# encrypted_value_salt :string(255) -# encrypted_value_iv :string(255) -# - -require 'spec_helper' - -describe Variable do - subject { Variable.new } - - let(:secret_value) { 'secret' } - - before :each do - subject.value = secret_value - end - - describe :value do - it 'stores the encrypted value' do - subject.encrypted_value.should_not be_nil - end - - it 'stores an iv for value' do - subject.encrypted_value_iv.should_not be_nil - end - - it 'stores a salt for value' do - subject.encrypted_value_salt.should_not be_nil - end - - it 'fails to decrypt if iv is incorrect' do - subject.encrypted_value_iv = nil - subject.instance_variable_set(:@value, nil) - expect { subject.value }.to raise_error - end - end -end diff --git a/spec/ci/models/web_hook_spec.rb b/spec/ci/models/web_hook_spec.rb deleted file mode 100644 index 0f0f175a7a3..00000000000 --- a/spec/ci/models/web_hook_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -# == Schema Information -# -# Table name: web_hooks -# -# id :integer not null, primary key -# url :string(255) not null -# project_id :integer not null -# created_at :datetime -# updated_at :datetime -# - -require 'spec_helper' - -describe WebHook do - describe "Associations" do - it { should belong_to :project } - end - - describe "Validations" do - it { should validate_presence_of(:url) } - - context "url format" do - it { should allow_value("http://example.com").for(:url) } - it { should allow_value("https://excample.com").for(:url) } - it { should allow_value("http://test.com/api").for(:url) } - it { should allow_value("http://test.com/api?key=abc").for(:url) } - it { should allow_value("http://test.com/api?key=abc&type=def").for(:url) } - - it { should_not allow_value("example.com").for(:url) } - it { should_not allow_value("ftp://example.com").for(:url) } - it { should_not allow_value("herp-and-derp").for(:url) } - end - end - - describe "execute" do - before(:each) do - @web_hook = FactoryGirl.create(:web_hook) - @project = @web_hook.project - @data = { before: 'oldrev', after: 'newrev', ref: 'ref'} - - WebMock.stub_request(:post, @web_hook.url) - end - - it "POSTs to the web hook URL" do - @web_hook.execute(@data) - WebMock.should have_requested(:post, @web_hook.url).once - end - - it "POSTs the data as JSON" do - json = @data.to_json - - @web_hook.execute(@data) - WebMock.should have_requested(:post, @web_hook.url).with(body: json).once - end - - it "catches exceptions" do - WebHook.should_receive(:post).and_raise("Some HTTP Post error") - - lambda { - @web_hook.execute(@data) - }.should raise_error - end - end -end diff --git a/spec/ci/requests/api/builds_spec.rb b/spec/ci/requests/api/builds_spec.rb deleted file mode 100644 index be55e9ff479..00000000000 --- a/spec/ci/requests/api/builds_spec.rb +++ /dev/null @@ -1,115 +0,0 @@ -require 'spec_helper' - -describe API::API do - include ApiHelpers - - let(:runner) { FactoryGirl.create(:runner, tag_list: ["mysql", "ruby"]) } - let(:project) { FactoryGirl.create(:project) } - - describe "Builds API for runners" do - let(:shared_runner) { FactoryGirl.create(:runner, token: "SharedRunner") } - let(:shared_project) { FactoryGirl.create(:project, name: "SharedProject") } - - before do - FactoryGirl.create :runner_project, project_id: project.id, runner_id: runner.id - end - - describe "POST /builds/register" do - it "should start a build" do - commit = FactoryGirl.create(:commit, project: project) - commit.create_builds - build = commit.builds.first - - post api("/builds/register"), token: runner.token, info: {platform: :darwin} - - response.status.should == 201 - json_response['sha'].should == build.sha - runner.reload.platform.should == "darwin" - end - - it "should return 404 error if no pending build found" do - post api("/builds/register"), token: runner.token - - response.status.should == 404 - end - - it "should return 404 error if no builds for specific runner" do - commit = FactoryGirl.create(:commit, project: shared_project) - FactoryGirl.create(:build, commit: commit, status: 'pending' ) - - post api("/builds/register"), token: runner.token - - response.status.should == 404 - end - - it "should return 404 error if no builds for shared runner" do - commit = FactoryGirl.create(:commit, project: project) - FactoryGirl.create(:build, commit: commit, status: 'pending' ) - - post api("/builds/register"), token: shared_runner.token - - response.status.should == 404 - end - - it "returns options" do - commit = FactoryGirl.create(:commit, project: project) - commit.create_builds - - post api("/builds/register"), token: runner.token, info: {platform: :darwin} - - response.status.should == 201 - json_response["options"].should == {"image" => "ruby:2.1", "services" => ["postgres"]} - end - - it "returns variables" do - commit = FactoryGirl.create(:commit, project: project) - commit.create_builds - project.variables << Variable.new(key: "SECRET_KEY", value: "secret_value") - - post api("/builds/register"), token: runner.token, info: {platform: :darwin} - - response.status.should == 201 - json_response["variables"].should == [ - {"key" => "DB_NAME", "value" => "postgres", "public" => true}, - {"key" => "SECRET_KEY", "value" => "secret_value", "public" => false}, - ] - end - - it "returns variables for triggers" do - trigger = FactoryGirl.create(:trigger, project: project) - commit = FactoryGirl.create(:commit, project: project) - - trigger_request = FactoryGirl.create(:trigger_request_with_variables, commit: commit, trigger: trigger) - commit.create_builds(trigger_request) - project.variables << Variable.new(key: "SECRET_KEY", value: "secret_value") - - post api("/builds/register"), token: runner.token, info: {platform: :darwin} - - response.status.should == 201 - json_response["variables"].should == [ - {"key" => "DB_NAME", "value" => "postgres", "public" => true}, - {"key" => "SECRET_KEY", "value" => "secret_value", "public" => false}, - {"key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false}, - ] - end - end - - describe "PUT /builds/:id" do - let(:commit) { FactoryGirl.create(:commit, project: project)} - let(:build) { FactoryGirl.create(:build, commit: commit, runner_id: runner.id) } - - it "should update a running build" do - build.run! - put api("/builds/#{build.id}"), token: runner.token - response.status.should == 200 - end - - it 'Should not override trace information when no trace is given' do - build.run! - build.update!(trace: 'hello_world') - put api("/builds/#{build.id}"), token: runner.token - expect(build.reload.trace).to eq 'hello_world' - end - end - end -end diff --git a/spec/ci/requests/api/commits_spec.rb b/spec/ci/requests/api/commits_spec.rb deleted file mode 100644 index 190df70c1a5..00000000000 --- a/spec/ci/requests/api/commits_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require 'spec_helper' - -describe API::API, 'Commits' do - include ApiHelpers - - let(:project) { FactoryGirl.create(:project) } - let(:commit) { FactoryGirl.create(:commit, project: project) } - - let(:options) { - { - project_token: project.token, - project_id: project.id - } - } - - describe "GET /commits" do - before { commit } - - it "should return commits per project" do - get api("/commits"), options - - response.status.should == 200 - json_response.count.should == 1 - json_response.first["project_id"].should == project.id - json_response.first["sha"].should == commit.sha - end - end - - describe "POST /commits" do - let(:data) { - { - "before" => "95790bf891e76fee5e1747ab589903a6a1f80f22", - "after" => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", - "ref" => "refs/heads/master", - "commits" => [ - { - "id" => "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", - "message" => "Update Catalan translation to e38cb41.", - "timestamp" => "2011-12-12T14:27:31+02:00", - "url" => "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", - "author" => { - "name" => "Jordi Mallach", - "email" => "jordi@softcatala.org", - } - } - ], - ci_yaml_file: gitlab_ci_yaml - } - } - - it "should create a build" do - post api("/commits"), options.merge(data: data) - - response.status.should == 201 - json_response['sha'].should == "da1560886d4f094c3e6c9ef40349f7d38b5d27d7" - end - - it "should return 400 error if no data passed" do - post api("/commits"), options - - response.status.should == 400 - json_response['message'].should == "400 (Bad request) \"data\" not given" - end - end -end diff --git a/spec/ci/requests/api/forks_spec.rb b/spec/ci/requests/api/forks_spec.rb deleted file mode 100644 index af523421c65..00000000000 --- a/spec/ci/requests/api/forks_spec.rb +++ /dev/null @@ -1,60 +0,0 @@ -require 'spec_helper' - -describe API::API do - include ApiHelpers - - let(:project) { FactoryGirl.create(:project) } - let(:gitlab_url) { GitlabCi.config.gitlab_server.url } - let(:private_token) { Network.new.authenticate(access_token: "some_token")["private_token"] } - - let(:options) { - { - private_token: private_token, - url: gitlab_url - } - } - - before { - stub_gitlab_calls - } - - - describe "POST /forks" do - let(:project_info) { - { - project_id: project.gitlab_id, - project_token: project.token, - data: { - id: 2, - name_with_namespace: "Gitlab.org / Underscore", - path_with_namespace: "gitlab-org/underscore", - default_branch: "master", - ssh_url_to_repo: "git@example.com:gitlab-org/underscore" - } - } - } - - context "with valid info" do - before do - options.merge!(project_info) - end - - it "should create a project with valid data" do - post api("/forks"), options - response.status.should == 201 - json_response['name'].should == "Gitlab.org / Underscore" - end - end - - context "with invalid project info" do - before do - options.merge!({}) - end - - it "should error with invalid data" do - post api("/forks"), options - response.status.should == 400 - end - end - end -end diff --git a/spec/ci/requests/api/projects_spec.rb b/spec/ci/requests/api/projects_spec.rb deleted file mode 100644 index 014a9efc617..00000000000 --- a/spec/ci/requests/api/projects_spec.rb +++ /dev/null @@ -1,251 +0,0 @@ -require 'spec_helper' - -describe API::API do - include ApiHelpers - - let(:gitlab_url) { GitlabCi.config.gitlab_server.url } - let(:private_token) { Network.new.authenticate(access_token: "some_token")["private_token"] } - - let(:options) { - { - private_token: private_token, - url: gitlab_url - } - } - - before { - stub_gitlab_calls - } - - context "requests for scoped projects" do - # NOTE: These ids are tied to the actual projects on demo.gitlab.com - describe "GET /projects" do - let!(:project1) { FactoryGirl.create(:project, name: "gitlabhq", gitlab_id: 3) } - let!(:project2) { FactoryGirl.create(:project, name: "gitlab-ci", gitlab_id: 4) } - - it "should return all projects on the CI instance" do - get api("/projects"), options - response.status.should == 200 - json_response.count.should == 2 - json_response.first["id"].should == project1.id - json_response.last["id"].should == project2.id - end - end - - describe "GET /projects/owned" do - # NOTE: This user doesn't own any of these projects on demo.gitlab.com - let!(:project1) { FactoryGirl.create(:project, name: "gitlabhq", gitlab_id: 3) } - let!(:project2) { FactoryGirl.create(:project, name: "random-project", gitlab_id: 9898) } - - it "should return all projects on the CI instance" do - get api("/projects/owned"), options - - response.status.should == 200 - json_response.count.should == 0 - end - end - end - - describe "POST /projects/:project_id/webhooks" do - let!(:project) { FactoryGirl.create(:project) } - - context "Valid Webhook URL" do - let!(:webhook) { {web_hook: "http://example.com/sth/1/ala_ma_kota" } } - - before do - options.merge!(webhook) - end - - it "should create webhook for specified project" do - post api("/projects/#{project.id}/webhooks"), options - response.status.should == 201 - json_response["url"].should == webhook[:web_hook] - end - - it "fails to create webhook for non existsing project" do - post api("/projects/non-existant-id/webhooks"), options - response.status.should == 404 - end - - it "non-manager is not authorized" do - User.any_instance.stub(:can_manage_project?).and_return(false) - post api("/projects/#{project.id}/webhooks"), options - response.status.should == 401 - end - end - - context "Invalid Webhook URL" do - let!(:webhook) { {web_hook: "ala_ma_kota" } } - - before do - options.merge!(webhook) - end - - it "fails to create webhook for not valid url" do - post api("/projects/#{project.id}/webhooks"), options - response.status.should == 400 - end - end - - context "Missed web_hook parameter" do - it "fails to create webhook for not provided url" do - post api("/projects/#{project.id}/webhooks"), options - response.status.should == 400 - end - end - end - - describe "GET /projects/:id" do - let!(:project) { FactoryGirl.create(:project) } - - context "with an existing project" do - it "should retrieve the project info" do - get api("/projects/#{project.id}"), options - response.status.should == 200 - json_response['id'].should == project.id - end - end - - context "with a non-existing project" do - it "should return 404 error if project not found" do - get api("/projects/non_existent_id"), options - response.status.should == 404 - end - end - end - - describe "PUT /projects/:id" do - let!(:project) { FactoryGirl.create(:project) } - let!(:project_info) { {name: "An updated name!" } } - - before do - options.merge!(project_info) - end - - it "should update a specific project's information" do - put api("/projects/#{project.id}"), options - response.status.should == 200 - json_response["name"].should == project_info[:name] - end - - it "fails to update a non-existing project" do - put api("/projects/non-existant-id"), options - response.status.should == 404 - end - - it "non-manager is not authorized" do - User.any_instance.stub(:can_manage_project?).and_return(false) - put api("/projects/#{project.id}"), options - response.status.should == 401 - end - end - - describe "DELETE /projects/:id" do - let!(:project) { FactoryGirl.create(:project) } - - it "should delete a specific project" do - delete api("/projects/#{project.id}"), options - response.status.should == 200 - - expect { project.reload }.to raise_error - end - - it "non-manager is not authorized" do - User.any_instance.stub(:can_manage_project?).and_return(false) - delete api("/projects/#{project.id}"), options - response.status.should == 401 - end - - it "is getting not found error" do - delete api("/projects/not-existing_id"), options - response.status.should == 404 - end - end - - describe "POST /projects" do - let(:project_info) { - { - name: "My project", - gitlab_id: 1, - path: "testing/testing", - ssh_url_to_repo: "ssh://example.com/testing/testing.git" - } - } - - let(:invalid_project_info) { {} } - - context "with valid project info" do - before do - options.merge!(project_info) - end - - it "should create a project with valid data" do - post api("/projects"), options - response.status.should == 201 - json_response['name'].should == project_info[:name] - end - end - - context "with invalid project info" do - before do - options.merge!(invalid_project_info) - end - - it "should error with invalid data" do - post api("/projects"), options - response.status.should == 400 - end - end - - describe "POST /projects/:id/runners/:id" do - let(:project) { FactoryGirl.create(:project) } - let(:runner) { FactoryGirl.create(:runner) } - - it "should add the project to the runner" do - post api("/projects/#{project.id}/runners/#{runner.id}"), options - response.status.should == 201 - - project.reload - project.runners.first.id.should == runner.id - end - - it "should fail if it tries to link a non-existing project or runner" do - post api("/projects/#{project.id}/runners/non-existing"), options - response.status.should == 404 - - post api("/projects/non-existing/runners/#{runner.id}"), options - response.status.should == 404 - end - - it "non-manager is not authorized" do - User.any_instance.stub(:can_manage_project?).and_return(false) - post api("/projects/#{project.id}/runners/#{runner.id}"), options - response.status.should == 401 - end - end - - describe "DELETE /projects/:id/runners/:id" do - let(:project) { FactoryGirl.create(:project) } - let(:runner) { FactoryGirl.create(:runner) } - - before do - post api("/projects/#{project.id}/runners/#{runner.id}"), options - end - - it "should remove the project from the runner" do - project.runners.should be_present - delete api("/projects/#{project.id}/runners/#{runner.id}"), options - response.status.should == 200 - - project.reload - project.runners.should be_empty - end - - it "non-manager is not authorized" do - User.any_instance.stub(:can_manage_project?).and_return(false) - post api("/projects/#{project.id}/runners/#{runner.id}"), options - response.status.should == 401 - end - end - end -end diff --git a/spec/ci/requests/api/runners_spec.rb b/spec/ci/requests/api/runners_spec.rb deleted file mode 100644 index 47de3c2a95c..00000000000 --- a/spec/ci/requests/api/runners_spec.rb +++ /dev/null @@ -1,83 +0,0 @@ -require 'spec_helper' - -describe API::API do - include ApiHelpers - include StubGitlabCalls - - before { - stub_gitlab_calls - } - - describe "GET /runners" do - let(:gitlab_url) { GitlabCi.config.gitlab_server.url } - let(:private_token) { Network.new.authenticate(access_token: "some_token")["private_token"] } - let(:options) { - { - :private_token => private_token, - :url => gitlab_url - } - } - - before do - 5.times { FactoryGirl.create(:runner) } - end - - it "should retrieve a list of all runners" do - get api("/runners"), options - response.status.should == 200 - json_response.count.should == 5 - json_response.last.should have_key("id") - json_response.last.should have_key("token") - end - end - - describe "POST /runners/register" do - describe "should create a runner if token provided" do - before { post api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN } - - it { response.status.should == 201 } - end - - describe "should create a runner with description" do - before { post api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, description: "server.hostname" } - - it { response.status.should == 201 } - it { Runner.first.description.should == "server.hostname" } - end - - describe "should create a runner with tags" do - before { post api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, tag_list: "tag1, tag2" } - - it { response.status.should == 201 } - it { Runner.first.tag_list.sort.should == ["tag1", "tag2"] } - end - - describe "should create a runner if project token provided" do - let(:project) { FactoryGirl.create(:project) } - before { post api("/runners/register"), token: project.token } - - it { response.status.should == 201 } - it { project.runners.size.should == 1 } - end - - it "should return 403 error if token is invalid" do - post api("/runners/register"), token: 'invalid' - - response.status.should == 403 - end - - it "should return 400 error if no token" do - post api("/runners/register") - - response.status.should == 400 - end - end - - describe "DELETE /runners/delete" do - let!(:runner) { FactoryGirl.create(:runner) } - before { delete api("/runners/delete"), token: runner.token } - - it { response.status.should == 200 } - it { Runner.count.should == 0 } - end -end diff --git a/spec/ci/requests/api/triggers_spec.rb b/spec/ci/requests/api/triggers_spec.rb deleted file mode 100644 index 6e56c4b3b22..00000000000 --- a/spec/ci/requests/api/triggers_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -require 'spec_helper' - -describe API::API do - include ApiHelpers - - describe 'POST /projects/:project_id/refs/:ref/trigger' do - let!(:trigger_token) { 'secure token' } - let!(:project) { FactoryGirl.create(:project) } - let!(:project2) { FactoryGirl.create(:project) } - let!(:trigger) { FactoryGirl.create(:trigger, project: project, token: trigger_token) } - let(:options) { - { - token: trigger_token - } - } - - context 'Handles errors' do - it 'should return bad request if token is missing' do - post api("/projects/#{project.id}/refs/master/trigger") - response.status.should == 400 - end - - it 'should return not found if project is not found' do - post api('/projects/0/refs/master/trigger'), options - response.status.should == 404 - end - - it 'should return unauthorized if token is for different project' do - post api("/projects/#{project2.id}/refs/master/trigger"), options - response.status.should == 401 - end - end - - context 'Have a commit' do - before do - @commit = FactoryGirl.create(:commit, project: project) - end - - it 'should create builds' do - post api("/projects/#{project.id}/refs/master/trigger"), options - response.status.should == 201 - @commit.builds.reload - @commit.builds.size.should == 2 - end - - it 'should return bad request with no builds created if there\'s no commit for that ref' do - post api("/projects/#{project.id}/refs/other-branch/trigger"), options - response.status.should == 400 - json_response['message'].should == 'No builds created' - end - - context 'Validates variables' do - let(:variables) { - {'TRIGGER_KEY' => 'TRIGGER_VALUE'} - } - - it 'should validate variables to be a hash' do - post api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: 'value') - response.status.should == 400 - json_response['message'].should == 'variables needs to be a hash' - end - - it 'should validate variables needs to be a map of key-valued strings' do - post api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: {key: %w(1 2)}) - response.status.should == 400 - json_response['message'].should == 'variables needs to be a map of key-valued strings' - end - - it 'create trigger request with variables' do - post api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: variables) - response.status.should == 201 - @commit.builds.reload - @commit.builds.first.trigger_request.variables.should == variables - end - end - end - end -end diff --git a/spec/ci/requests/builds_spec.rb b/spec/ci/requests/builds_spec.rb deleted file mode 100644 index 73d540e372a..00000000000 --- a/spec/ci/requests/builds_spec.rb +++ /dev/null @@ -1,18 +0,0 @@ -require 'spec_helper' - -describe "Builds" do - before do - @project = FactoryGirl.create :project - @commit = FactoryGirl.create :commit, project: @project - @build = FactoryGirl.create :build, commit: @commit - end - - describe "GET /:project/builds/:id/status.json" do - before do - get status_project_build_path(@project, @build), format: :json - end - - it { response.status.should == 200 } - it { response.body.should include(@build.sha) } - end -end diff --git a/spec/ci/requests/commits_spec.rb b/spec/ci/requests/commits_spec.rb deleted file mode 100644 index e9d8366c41a..00000000000 --- a/spec/ci/requests/commits_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require 'spec_helper' - -describe "Commits" do - before do - @project = FactoryGirl.create :project - @commit = FactoryGirl.create :commit, project: @project - end - - describe "GET /:project/refs/:ref_name/commits/:id/status.json" do - before do - get status_project_ref_commit_path(@project, @commit.ref, @commit.sha), format: :json - end - - it { response.status.should == 200 } - it { response.body.should include(@commit.sha) } - end -end diff --git a/spec/ci/services/create_commit_service_spec.rb b/spec/ci/services/create_commit_service_spec.rb deleted file mode 100644 index 34e00d5b3c0..00000000000 --- a/spec/ci/services/create_commit_service_spec.rb +++ /dev/null @@ -1,130 +0,0 @@ -require 'spec_helper' - -describe CreateCommitService do - let(:service) { CreateCommitService.new } - let(:project) { FactoryGirl.create(:project) } - - describe :execute do - context 'valid params' do - let(:commit) do - service.execute(project, - ref: 'refs/heads/master', - before: '00000000', - after: '31das312', - ci_yaml_file: gitlab_ci_yaml, - commits: [ { message: "Message" } ] - ) - end - - it { commit.should be_kind_of(Commit) } - it { commit.should be_valid } - it { commit.should be_persisted } - it { commit.should == project.commits.last } - it { commit.builds.first.should be_kind_of(Build) } - end - - context "skip tag if there is no build for it" do - it "creates commit if there is appropriate job" do - result = service.execute(project, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - ci_yaml_file: gitlab_ci_yaml, - commits: [ { message: "Message" } ] - ) - result.should be_persisted - end - - it "creates commit if there is no appropriate job but deploy job has right ref setting" do - config = YAML.dump({deploy: {deploy: "ls", only: ["0_1"]}}) - - result = service.execute(project, - ref: 'refs/heads/0_1', - before: '00000000', - after: '31das312', - ci_yaml_file: config, - commits: [ { message: "Message" } ] - ) - result.should be_persisted - end - end - - describe :ci_skip? do - it "skips builds creation if there is [ci skip] tag in commit message" do - commits = [{message: "some message[ci skip]"}] - commit = service.execute(project, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits, - ci_yaml_file: gitlab_ci_yaml - ) - commit.builds.any?.should be_false - commit.status.should == "skipped" - end - - it "does not skips builds creation if there is no [ci skip] tag in commit message" do - commits = [{message: "some message"}] - - commit = service.execute(project, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits, - ci_yaml_file: gitlab_ci_yaml - ) - - commit.builds.first.name.should == "staging" - end - - it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do - commits = [{message: "some message[ci skip]"}] - commit = service.execute(project, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits, - ci_yaml_file: "invalid: file" - ) - commit.builds.any?.should be_false - commit.status.should == "skipped" - end - end - - it "skips build creation if there are already builds" do - commits = [{message: "message"}] - commit = service.execute(project, - ref: 'refs/heads/master', - before: '00000000', - after: '31das312', - commits: commits, - ci_yaml_file: gitlab_ci_yaml - ) - commit.builds.count(:all).should == 2 - - commit = service.execute(project, - ref: 'refs/heads/master', - before: '00000000', - after: '31das312', - commits: commits, - ci_yaml_file: gitlab_ci_yaml - ) - commit.builds.count(:all).should == 2 - end - - it "creates commit with failed status if yaml is invalid" do - commits = [{message: "some message"}] - - commit = service.execute(project, - ref: 'refs/tags/0_1', - before: '00000000', - after: '31das312', - commits: commits, - ci_yaml_file: "invalid: file" - ) - - commit.status.should == "failed" - commit.builds.any?.should be_false - end - end -end diff --git a/spec/ci/services/create_project_service_spec.rb b/spec/ci/services/create_project_service_spec.rb deleted file mode 100644 index 31614968d55..00000000000 --- a/spec/ci/services/create_project_service_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require 'spec_helper' - -describe CreateProjectService do - let(:service) { CreateProjectService.new } - let(:current_user) { double.as_null_object } - let(:project_dump) { YAML.load File.read(Rails.root.join('spec/support/gitlab_stubs/raw_project.yml')) } - - before { Network.any_instance.stub(enable_ci: true) } - - describe :execute do - context 'valid params' do - let(:project) { service.execute(current_user, project_dump, 'http://localhost/projects/:project_id') } - - it { project.should be_kind_of(Project) } - it { project.should be_persisted } - end - - context 'without project dump' do - it 'should raise exception' do - expect { service.execute(current_user, '', '') }.to raise_error - end - end - - context "forking" do - it "uses project as a template for settings and jobs" do - origin_project = FactoryGirl.create(:project) - origin_project.shared_runners_enabled = true - origin_project.public = true - origin_project.allow_git_fetch = true - origin_project.save! - - project = service.execute(current_user, project_dump, 'http://localhost/projects/:project_id', origin_project) - - project.shared_runners_enabled.should be_true - project.public.should be_true - project.allow_git_fetch.should be_true - end - end - end -end diff --git a/spec/ci/services/create_trigger_request_service_spec.rb b/spec/ci/services/create_trigger_request_service_spec.rb deleted file mode 100644 index 41db01c2235..00000000000 --- a/spec/ci/services/create_trigger_request_service_spec.rb +++ /dev/null @@ -1,52 +0,0 @@ -require 'spec_helper' - -describe CreateTriggerRequestService do - let(:service) { CreateTriggerRequestService.new } - let(:project) { FactoryGirl.create :project } - let(:trigger) { FactoryGirl.create :trigger, project: project } - - describe :execute do - context 'valid params' do - subject { service.execute(project, trigger, 'master') } - - before do - @commit = FactoryGirl.create :commit, project: project - end - - it { subject.should be_kind_of(TriggerRequest) } - it { subject.commit.should == @commit } - end - - context 'no commit for ref' do - subject { service.execute(project, trigger, 'other-branch') } - - it { subject.should be_nil } - end - - context 'no builds created' do - subject { service.execute(project, trigger, 'master') } - - before do - FactoryGirl.create :commit_without_jobs, project: project - end - - it { subject.should be_nil } - end - - context 'for multiple commits' do - subject { service.execute(project, trigger, 'master') } - - before do - @commit1 = FactoryGirl.create :commit, committed_at: 2.hour.ago, project: project - @commit2 = FactoryGirl.create :commit, committed_at: 1.hour.ago, project: project - @commit3 = FactoryGirl.create :commit, committed_at: 3.hour.ago, project: project - end - - context 'retries latest one' do - it { subject.should be_kind_of(TriggerRequest) } - it { subject.should be_persisted } - it { subject.commit.should == @commit2 } - end - end - end -end diff --git a/spec/ci/services/event_service_spec.rb b/spec/ci/services/event_service_spec.rb deleted file mode 100644 index f7b9bf58127..00000000000 --- a/spec/ci/services/event_service_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require 'spec_helper' - -describe EventService do - let (:project) { FactoryGirl.create :project, name: "GitLab / gitlab-shell" } - let (:user) { double(username: "root", id: 1) } - - before do - Event.destroy_all - end - - describe :remove_project do - it "creates event" do - EventService.new.remove_project(user, project) - - Event.admin.last.description.should == "Project \"GitLab / gitlab-shell\" has been removed by root" - end - end - - describe :create_project do - it "creates event" do - EventService.new.create_project(user, project) - - Event.admin.last.description.should == "Project \"GitLab / gitlab-shell\" has been created by root" - end - end - - describe :change_project_settings do - it "creates event" do - EventService.new.change_project_settings(user, project) - - Event.last.description.should == "User \"root\" updated projects settings" - end - end -end \ No newline at end of file diff --git a/spec/ci/services/image_for_build_service_spec.rb b/spec/ci/services/image_for_build_service_spec.rb deleted file mode 100644 index 4c7094146bb..00000000000 --- a/spec/ci/services/image_for_build_service_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'spec_helper' - -describe ImageForBuildService do - let(:service) { ImageForBuildService.new } - let(:project) { FactoryGirl.create(:project) } - let(:commit) { FactoryGirl.create(:commit, project: project, ref: 'master') } - let(:build) { FactoryGirl.create(:build, commit: commit) } - - describe :execute do - before { build } - - context 'branch name' do - before { build.run! } - let(:image) { service.execute(project, ref: 'master') } - - it { image.should be_kind_of(OpenStruct) } - it { image.path.to_s.should include('public/build-running.svg') } - it { image.name.should == 'build-running.svg' } - end - - context 'unknown branch name' do - let(:image) { service.execute(project, ref: 'feature') } - - it { image.should be_kind_of(OpenStruct) } - it { image.path.to_s.should include('public/build-unknown.svg') } - it { image.name.should == 'build-unknown.svg' } - end - - context 'commit sha' do - before { build.run! } - let(:image) { service.execute(project, sha: build.sha) } - - it { image.should be_kind_of(OpenStruct) } - it { image.path.to_s.should include('public/build-running.svg') } - it { image.name.should == 'build-running.svg' } - end - - context 'unknown commit sha' do - let(:image) { service.execute(project, sha: '0000000') } - - it { image.should be_kind_of(OpenStruct) } - it { image.path.to_s.should include('public/build-unknown.svg') } - it { image.name.should == 'build-unknown.svg' } - end - end -end diff --git a/spec/ci/services/register_build_service_spec.rb b/spec/ci/services/register_build_service_spec.rb deleted file mode 100644 index b5af777dd1d..00000000000 --- a/spec/ci/services/register_build_service_spec.rb +++ /dev/null @@ -1,89 +0,0 @@ -require 'spec_helper' - -describe RegisterBuildService do - let!(:service) { RegisterBuildService.new } - let!(:project) { FactoryGirl.create :project } - let!(:commit) { FactoryGirl.create :commit, project: project } - let!(:pending_build) { FactoryGirl.create :build, project: project, commit: commit } - let!(:shared_runner) { FactoryGirl.create(:runner, is_shared: true) } - let!(:specific_runner) { FactoryGirl.create(:runner, is_shared: false) } - - before do - specific_runner.assign_to(project) - end - - describe :execute do - context 'runner follow tag list' do - it "picks build with the same tag" do - pending_build.tag_list = ["linux"] - pending_build.save - specific_runner.tag_list = ["linux"] - service.execute(specific_runner).should == pending_build - end - - it "does not pick build with different tag" do - pending_build.tag_list = ["linux"] - pending_build.save - specific_runner.tag_list = ["win32"] - service.execute(specific_runner).should be_false - end - - it "picks build without tag" do - service.execute(specific_runner).should == pending_build - end - - it "does not pick build with tag" do - pending_build.tag_list = ["linux"] - pending_build.save - service.execute(specific_runner).should be_false - end - - it "pick build without tag" do - specific_runner.tag_list = ["win32"] - service.execute(specific_runner).should == pending_build - end - end - - context 'allow shared runners' do - before do - project.shared_runners_enabled = true - project.save - end - - context 'shared runner' do - let(:build) { service.execute(shared_runner) } - - it { build.should be_kind_of(Build) } - it { build.should be_valid } - it { build.should be_running } - it { build.runner.should == shared_runner } - end - - context 'specific runner' do - let(:build) { service.execute(specific_runner) } - - it { build.should be_kind_of(Build) } - it { build.should be_valid } - it { build.should be_running } - it { build.runner.should == specific_runner } - end - end - - context 'disallow shared runners' do - context 'shared runner' do - let(:build) { service.execute(shared_runner) } - - it { build.should be_nil } - end - - context 'specific runner' do - let(:build) { service.execute(specific_runner) } - - it { build.should be_kind_of(Build) } - it { build.should be_valid } - it { build.should be_running } - it { build.runner.should == specific_runner } - end - end - end -end diff --git a/spec/ci/services/web_hook_service_spec.rb b/spec/ci/services/web_hook_service_spec.rb deleted file mode 100644 index 2bb153942e8..00000000000 --- a/spec/ci/services/web_hook_service_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require 'spec_helper' - -describe WebHookService do - let (:project) { FactoryGirl.create :project } - let (:commit) { FactoryGirl.create :commit, project: project } - let (:build) { FactoryGirl.create :build, commit: commit } - let (:hook) { FactoryGirl.create :web_hook, project: project } - - describe :execute do - it "should execute successfully" do - stub_request(:post, hook.url).to_return(status: 200) - WebHookService.new.build_end(build).should be_true - end - end - - context 'build_data' do - it "contains all needed fields" do - build_data(build).should include( - :build_id, - :project_id, - :ref, - :build_status, - :build_started_at, - :build_finished_at, - :before_sha, - :project_name, - :gitlab_url, - :build_name - ) - end - end - - def build_data(build) - WebHookService.new.send :build_data, build - end -end diff --git a/spec/ci/six.tar.gz b/spec/ci/six.tar.gz deleted file mode 100644 index 80a8c6644e4..00000000000 Binary files a/spec/ci/six.tar.gz and /dev/null differ diff --git a/spec/controllers/ci/projects_controller_spec.rb b/spec/controllers/ci/projects_controller_spec.rb index 0069a782511..9af766eff33 100644 --- a/spec/controllers/ci/projects_controller_spec.rb +++ b/spec/controllers/ci/projects_controller_spec.rb @@ -1,8 +1,8 @@ require "spec_helper" -describe ProjectsController do +describe Ci::ProjectsController do before do - @project = FactoryGirl.create :project + @project = FactoryGirl.create :ci_project end describe "POST #build" do @@ -55,25 +55,25 @@ describe ProjectsController do end let(:user) do - User.new(user_data) + Ci::User.new(user_data) end it "creates project" do allow(controller).to receive(:reset_cache) { true } allow(controller).to receive(:current_user) { user } - Network.any_instance.stub(:enable_ci).and_return(true) - Network.any_instance.stub(:project_hooks).and_return(true) + allow_any_instance_of(Ci::Network).to receive(:enable_ci).and_return(true) + allow_any_instance_of(Ci::Network).to receive(:project_hooks).and_return(true) post :create, { project: JSON.dump(project_dump.to_h) }.with_indifferent_access expect(response.code).to eq('302') - expect(assigns(:project)).not_to be_a_new(Project) + expect(assigns(:project)).not_to be_a_new(Ci::Project) end it "shows error" do allow(controller).to receive(:reset_cache) { true } allow(controller).to receive(:current_user) { user } - User.any_instance.stub(:can_manage_project?).and_return(false) + allow_any_instance_of(Ci::User).to receive(:can_manage_project?).and_return(false) post :create, { project: JSON.dump(project_dump.to_h) }.with_indifferent_access @@ -91,13 +91,13 @@ describe ProjectsController do end let(:user) do - User.new(user_data) + Ci::User.new(user_data) end it "searches projects" do allow(controller).to receive(:reset_cache) { true } allow(controller).to receive(:current_user) { user } - Network.any_instance.should_receive(:projects).with(hash_including(search: 'str'), :authorized) + allow_any_instance_of(Ci::Network).to receive(:projects).with(hash_including(search: 'str'), :authorized) xhr :get, :gitlab, { search: "str", format: "js" }.with_indifferent_access diff --git a/spec/factories/ci/trigger_requests.rb b/spec/factories/ci/trigger_requests.rb index c85d1027ce6..da8b7342fcf 100644 --- a/spec/factories/ci/trigger_requests.rb +++ b/spec/factories/ci/trigger_requests.rb @@ -1,8 +1,8 @@ # Read about factories at https://github.com/thoughtbot/factory_girl FactoryGirl.define do - factory :trigger_request do - factory :trigger_request_with_variables do + factory :ci_trigger_request do + factory :ci_trigger_request_with_variables do variables do { TRIGGER_KEY: 'TRIGGER_VALUE' diff --git a/spec/factories/ci/triggers.rb b/spec/factories/ci/triggers.rb index 38cd3cbceb6..fd3afdb1ec2 100644 --- a/spec/factories/ci/triggers.rb +++ b/spec/factories/ci/triggers.rb @@ -2,7 +2,7 @@ FactoryGirl.define do factory :ci_trigger_without_token, class: Ci::Trigger do - factory :trigger do + factory :ci_trigger do token 'token' end end diff --git a/spec/features/ci/admin/builds_spec.rb b/spec/features/ci/admin/builds_spec.rb new file mode 100644 index 00000000000..e62e83692da --- /dev/null +++ b/spec/features/ci/admin/builds_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe "Admin Builds" do + let(:project) { FactoryGirl.create :project } + let(:commit) { FactoryGirl.create :commit, project: project } + let(:build) { FactoryGirl.create :build, commit: commit } + + before do + skip_admin_auth + login_as :user + end + + describe "GET /admin/builds" do + before do + build + visit admin_builds_path + end + + it { page.should have_content "All builds" } + it { page.should have_content build.short_sha } + end + + describe "Tabs" do + it "shows all builds" do + build = FactoryGirl.create :build, commit: commit, status: "pending" + build1 = FactoryGirl.create :build, commit: commit, status: "running" + build2 = FactoryGirl.create :build, commit: commit, status: "success" + build3 = FactoryGirl.create :build, commit: commit, status: "failed" + + visit admin_builds_path + + page.all(".build-link").size.should == 4 + end + + it "shows pending builds" do + build = FactoryGirl.create :build, commit: commit, status: "pending" + build1 = FactoryGirl.create :build, commit: commit, status: "running" + build2 = FactoryGirl.create :build, commit: commit, status: "success" + build3 = FactoryGirl.create :build, commit: commit, status: "failed" + + visit admin_builds_path + + within ".nav.nav-tabs" do + click_on "Pending" + end + + page.find(".build-link").should have_content(build.id) + page.find(".build-link").should_not have_content(build1.id) + page.find(".build-link").should_not have_content(build2.id) + page.find(".build-link").should_not have_content(build3.id) + end + + it "shows running builds" do + build = FactoryGirl.create :build, commit: commit, status: "pending" + build1 = FactoryGirl.create :build, commit: commit, status: "running" + build2 = FactoryGirl.create :build, commit: commit, status: "success" + build3 = FactoryGirl.create :build, commit: commit, status: "failed" + + visit admin_builds_path + + within ".nav.nav-tabs" do + click_on "Running" + end + + page.find(".build-link").should have_content(build1.id) + page.find(".build-link").should_not have_content(build.id) + page.find(".build-link").should_not have_content(build2.id) + page.find(".build-link").should_not have_content(build3.id) + end + end +end diff --git a/spec/features/ci/admin/events_spec.rb b/spec/features/ci/admin/events_spec.rb new file mode 100644 index 00000000000..469c6ed102d --- /dev/null +++ b/spec/features/ci/admin/events_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe "Admin Events" do + let(:event) { FactoryGirl.create :admin_event } + + before do + skip_admin_auth + login_as :user + end + + describe "GET /admin/events" do + before do + event + visit admin_events_path + end + + it { page.should have_content "Events" } + it { page.should have_content event.description } + end +end diff --git a/spec/features/ci/admin/projects_spec.rb b/spec/features/ci/admin/projects_spec.rb new file mode 100644 index 00000000000..6f87e368deb --- /dev/null +++ b/spec/features/ci/admin/projects_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe "Admin Projects" do + let(:project) { FactoryGirl.create :project } + + before do + skip_admin_auth + login_as :user + end + + describe "GET /admin/projects" do + before do + project + visit admin_projects_path + end + + it { page.should have_content "Projects" } + end +end diff --git a/spec/features/ci/admin/runners_spec.rb b/spec/features/ci/admin/runners_spec.rb new file mode 100644 index 00000000000..2827a7fc6e5 --- /dev/null +++ b/spec/features/ci/admin/runners_spec.rb @@ -0,0 +1,63 @@ +require 'spec_helper' + +describe "Admin Runners" do + before do + skip_admin_auth + login_as :user + end + + describe "Runners page" do + before do + runner = FactoryGirl.create(:runner) + commit = FactoryGirl.create(:commit) + FactoryGirl.create(:build, commit: commit, runner_id: runner.id) + visit admin_runners_path + end + + it { page.has_text? "Manage Runners" } + it { page.has_text? "To register a new runner" } + it { page.has_text? "Runners with last contact less than a minute ago: 1" } + + describe 'search' do + before do + FactoryGirl.create :runner, description: 'foo' + FactoryGirl.create :runner, description: 'bar' + + fill_in 'search', with: 'foo' + click_button 'Search' + end + + it { page.should have_content("foo") } + it { page.should_not have_content("bar") } + end + end + + describe "Runner show page" do + let(:runner) { FactoryGirl.create :runner } + + before do + FactoryGirl.create(:project, name: "foo") + FactoryGirl.create(:project, name: "bar") + visit admin_runner_path(runner) + end + + describe 'runner info' do + it { find_field('runner_token').value.should eq runner.token } + end + + describe 'projects' do + it { page.should have_content("foo") } + it { page.should have_content("bar") } + end + + describe 'search' do + before do + fill_in 'search', with: 'foo' + click_button 'Search' + end + + it { page.should have_content("foo") } + it { page.should_not have_content("bar") } + end + end +end diff --git a/spec/features/ci/builds_spec.rb b/spec/features/ci/builds_spec.rb new file mode 100644 index 00000000000..fcd7996efd7 --- /dev/null +++ b/spec/features/ci/builds_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe "Builds" do + before do + @project = FactoryGirl.create :project + @commit = FactoryGirl.create :commit, project: @project + @build = FactoryGirl.create :build, commit: @commit + end + + describe "GET /:project/builds/:id" do + before do + login_as :user + visit project_build_path(@project, @build) + end + + it { page.should have_content @commit.sha[0..7] } + it { page.should have_content @commit.git_commit_message } + it { page.should have_content @commit.git_author_name } + end + + describe "GET /:project/builds/:id/cancel" do + before do + login_as :user + @build.run! + visit cancel_project_build_path(@project, @build) + end + + it { page.should have_content 'canceled' } + it { page.should have_content 'Retry' } + end + + describe "POST /:project/builds/:id/retry" do + before do + login_as :user + @build.cancel! + visit project_build_path(@project, @build) + click_link 'Retry' + end + + it { page.should have_content 'pending' } + it { page.should have_content 'Cancel' } + end + + describe "Show page public accessible" do + before do + @project = FactoryGirl.create :public_project + @commit = FactoryGirl.create :commit, project: @project + @runner = FactoryGirl.create :specific_runner + @build = FactoryGirl.create :build, commit: @commit, runner: @runner + + stub_gitlab_calls + visit project_build_path(@project, @build) + end + + it { page.should have_content @commit.sha[0..7] } + end +end diff --git a/spec/features/ci/commits_spec.rb b/spec/features/ci/commits_spec.rb new file mode 100644 index 00000000000..202f05c516f --- /dev/null +++ b/spec/features/ci/commits_spec.rb @@ -0,0 +1,66 @@ +require 'spec_helper' + +describe "Commits" do + context "Authenticated user" do + before do + login_as :user + @project = FactoryGirl.create :project + @commit = FactoryGirl.create :commit, project: @project + @build = FactoryGirl.create :build, commit: @commit + end + + describe "GET /:project/commits/:sha" do + before do + visit project_ref_commit_path(@project, @commit.ref, @commit.sha) + end + + it { page.should have_content @commit.sha[0..7] } + it { page.should have_content @commit.git_commit_message } + it { page.should have_content @commit.git_author_name } + end + + describe "Cancel commit" do + it "cancels commit" do + visit project_ref_commit_path(@project, @commit.ref, @commit.sha) + click_on "Cancel" + + page.should have_content "canceled" + end + end + + describe ".gitlab-ci.yml not found warning" do + it "does not show warning" do + visit project_ref_commit_path(@project, @commit.ref, @commit.sha) + + page.should_not have_content ".gitlab-ci.yml not found in this commit" + end + + it "shows warning" do + @commit.push_data[:ci_yaml_file] = nil + @commit.save + + visit project_ref_commit_path(@project, @commit.ref, @commit.sha) + + page.should have_content ".gitlab-ci.yml not found in this commit" + end + end + end + + context "Public pages" do + before do + @project = FactoryGirl.create :public_project + @commit = FactoryGirl.create :commit, project: @project + @build = FactoryGirl.create :build, commit: @commit + end + + describe "GET /:project/commits/:sha" do + before do + visit project_ref_commit_path(@project, @commit.ref, @commit.sha) + end + + it { page.should have_content @commit.sha[0..7] } + it { page.should have_content @commit.git_commit_message } + it { page.should have_content @commit.git_author_name } + end + end +end diff --git a/spec/features/ci/events_spec.rb b/spec/features/ci/events_spec.rb new file mode 100644 index 00000000000..77d1fba5769 --- /dev/null +++ b/spec/features/ci/events_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe "Events" do + let(:project) { FactoryGirl.create :project } + let(:event) { FactoryGirl.create :admin_event, project: project } + + before do + login_as :user + end + + describe "GET /project/:id/events" do + before do + event + visit project_events_path(project) + end + + it { page.should have_content "Events" } + it { page.should have_content event.description } + end +end diff --git a/spec/features/ci/lint_spec.rb b/spec/features/ci/lint_spec.rb new file mode 100644 index 00000000000..0b3d4e099fb --- /dev/null +++ b/spec/features/ci/lint_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe "Lint" do + before do + login_as :user + end + + it "Yaml parsing", js: true do + content = File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml')) + visit lint_path + fill_in "content", with: content + click_on "Validate" + within "table" do + page.should have_content("Job - rspec") + page.should have_content("Job - spinach") + page.should have_content("Deploy Job - staging") + page.should have_content("Deploy Job - production") + end + end + + it "Yaml parsing with error", js: true do + visit lint_path + fill_in "content", with: "" + click_on "Validate" + page.should have_content("Status: syntax is incorrect") + page.should have_content("Error: Please provide content of .gitlab-ci.yml") + end +end diff --git a/spec/features/ci/projects_spec.rb b/spec/features/ci/projects_spec.rb new file mode 100644 index 00000000000..3f21af92a2b --- /dev/null +++ b/spec/features/ci/projects_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe "Projects" do + before do + login_as :user + @project = FactoryGirl.create :project, name: "GitLab / gitlab-shell" + end + + describe "GET /projects", js: true do + before do + stub_js_gitlab_calls + visit projects_path + end + + it { page.should have_content "GitLab / gitlab-shell" } + it { page.should have_selector ".search input#search" } + end + + describe "GET /projects/:id" do + before do + visit project_path(@project) + end + + it { page.should have_content @project.name } + it { page.should have_content 'All commits' } + end + + describe "GET /projects/:id/edit" do + before do + visit edit_project_path(@project) + end + + it { page.should have_content @project.name } + it { page.should have_content 'Build Schedule' } + + it "updates configuration" do + fill_in 'Timeout', with: '70' + click_button 'Save changes' + + page.should have_content 'was successfully updated' + + find_field('Timeout').value.should eq '70' + end + end + + describe "GET /projects/:id/charts" do + before do + visit project_charts_path(@project) + end + + it { page.should have_content 'Overall' } + it { page.should have_content 'Builds chart for last week' } + it { page.should have_content 'Builds chart for last month' } + it { page.should have_content 'Builds chart for last year' } + it { page.should have_content 'Commit duration in minutes for last 30 commits' } + end +end diff --git a/spec/features/ci/runners_spec.rb b/spec/features/ci/runners_spec.rb new file mode 100644 index 00000000000..c41dc5b2e2e --- /dev/null +++ b/spec/features/ci/runners_spec.rb @@ -0,0 +1,98 @@ +require 'spec_helper' + +describe "Runners" do + before do + login_as :user + end + + describe "specific runners" do + before do + @project = FactoryGirl.create :project + @project2 = FactoryGirl.create :project + stub_js_gitlab_calls + + # all projects should be authorized for user + Network.any_instance.stub(:projects).and_return([ + OpenStruct.new({id: @project.gitlab_id}), + OpenStruct.new({id: @project2.gitlab_id}) + ]) + + @shared_runner = FactoryGirl.create :shared_runner + @specific_runner = FactoryGirl.create :specific_runner + @specific_runner2 = FactoryGirl.create :specific_runner + @project.runners << @specific_runner + @project2.runners << @specific_runner2 + end + + it "places runners in right places" do + visit project_runners_path(@project) + page.find(".available-specific-runners").should have_content(@specific_runner2.display_name) + page.find(".activated-specific-runners").should have_content(@specific_runner.display_name) + page.find(".available-shared-runners").should have_content(@shared_runner.display_name) + end + + it "enables specific runner for project" do + visit project_runners_path(@project) + + within ".available-specific-runners" do + click_on "Enable for this project" + end + + page.find(".activated-specific-runners").should have_content(@specific_runner2.display_name) + end + + it "disables specific runner for project" do + @project2.runners << @specific_runner + + visit project_runners_path(@project) + + within ".activated-specific-runners" do + click_on "Disable for this project" + end + + page.find(".available-specific-runners").should have_content(@specific_runner.display_name) + end + + it "removes specific runner for project if this is last project for that runners" do + visit project_runners_path(@project) + + within ".activated-specific-runners" do + click_on "Remove runner" + end + + Runner.exists?(id: @specific_runner).should be_false + end + end + + describe "shared runners" do + before do + @project = FactoryGirl.create :project + stub_js_gitlab_calls + end + + it "enables shared runners" do + visit project_runners_path(@project) + + click_on "Enable shared runners" + + @project.reload.shared_runners_enabled.should be_true + end + end + + describe "show page" do + before do + @project = FactoryGirl.create :project + stub_js_gitlab_calls + @specific_runner = FactoryGirl.create :specific_runner + @project.runners << @specific_runner + end + + it "shows runner information" do + visit project_runners_path(@project) + + click_on @specific_runner.short_sha + + page.should have_content(@specific_runner.platform) + end + end +end diff --git a/spec/features/ci/triggers_spec.rb b/spec/features/ci/triggers_spec.rb new file mode 100644 index 00000000000..2076429383d --- /dev/null +++ b/spec/features/ci/triggers_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe 'Variables' do + before do + login_as :user + @project = FactoryGirl.create :project + stub_js_gitlab_calls + visit project_triggers_path(@project) + end + + context 'create a trigger' do + before do + click_on 'Add Trigger' + @project.triggers.count.should == 1 + end + + it 'contains trigger token' do + page.should have_content(@project.triggers.first.token) + end + + it 'revokes the trigger' do + click_on 'Revoke' + @project.triggers.count.should == 0 + end + end +end diff --git a/spec/features/ci/variables_spec.rb b/spec/features/ci/variables_spec.rb new file mode 100644 index 00000000000..2bb0d9dedde --- /dev/null +++ b/spec/features/ci/variables_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe "Variables" do + before do + login_as :user + end + + describe "specific runners" do + before do + @project = FactoryGirl.create :project + stub_js_gitlab_calls + end + + it "creates variable", js: true do + visit project_variables_path(@project) + click_on "Add a variable" + fill_in "Key", with: "SECRET_KEY" + fill_in "Value", with: "SECRET_VALUE" + click_on "Save changes" + + page.should have_content("Variables were successfully updated.") + @project.variables.count.should == 1 + end + + end +end diff --git a/spec/helpers/ci/application_helper_spec.rb b/spec/helpers/ci/application_helper_spec.rb new file mode 100644 index 00000000000..478c0266770 --- /dev/null +++ b/spec/helpers/ci/application_helper_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe Ci::ApplicationHelper do + describe "#duration_in_words" do + it "returns minutes and seconds" do + intervals_in_words = { + 100 => "1 minute 40 seconds", + 121 => "2 minutes 1 second", + 3721 => "62 minutes 1 second", + 0 => "0 seconds" + } + + intervals_in_words.each do |interval, expectation| + duration_in_words(Time.now + interval, Time.now).should == expectation + end + end + + it "calculates interval from now if there is no finished_at" do + duration_in_words(nil, Time.now - 5).should == "5 seconds" + end + end + + describe "#time_interval_in_words" do + it "returns minutes and seconds" do + intervals_in_words = { + 100 => "1 minute 40 seconds", + 121 => "2 minutes 1 second", + 3721 => "62 minutes 1 second", + 0 => "0 seconds" + } + + intervals_in_words.each do |interval, expectation| + time_interval_in_words(interval).should == expectation + end + end + end +end diff --git a/spec/helpers/ci/runners_helper_spec.rb b/spec/helpers/ci/runners_helper_spec.rb new file mode 100644 index 00000000000..e7681df10bd --- /dev/null +++ b/spec/helpers/ci/runners_helper_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe Ci::RunnersHelper do + it "returns - not contacted yet" do + runner = FactoryGirl.build :runner + runner_status_icon(runner).should include("not connected yet") + end + + it "returns offline text" do + runner = FactoryGirl.build(:runner, contacted_at: 1.day.ago, active: true) + runner_status_icon(runner).should include("Runner is offline") + end + + it "returns online text" do + runner = FactoryGirl.build(:runner, contacted_at: 1.hour.ago, active: true) + runner_status_icon(runner).should include("Runner is online") + end +end diff --git a/spec/helpers/ci/user_helper_spec.rb b/spec/helpers/ci/user_helper_spec.rb new file mode 100644 index 00000000000..f95bfb355ed --- /dev/null +++ b/spec/helpers/ci/user_helper_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe Ci::UserHelper do + describe :user_avatar_url do + let (:user) { User.new({'avatar_url' => avatar_url}) } + + context 'no avatar' do + let (:avatar_url) { nil } + + it 'should return a generic avatar' do + user_avatar_url(user).should == 'ci/no_avatar.png' + end + end + + context 'plain gravatar' do + let (:base_url) { 'http://www.gravatar.com/avatar/abcdefgh' } + let (:avatar_url) { "#{base_url}?s=40&d=mm" } + + it 'should return gravatar with default size' do + user_avatar_url(user).should == "#{base_url}?s=40&d=identicon" + end + + it 'should return gravatar with custom size' do + user_avatar_url(user, 120).should == "#{base_url}?s=120&d=identicon" + end + end + + context 'secure gravatar' do + let (:base_url) { 'https://secure.gravatar.com/avatar/abcdefgh' } + let (:avatar_url) { "#{base_url}?s=40&d=mm" } + + it 'should return gravatar with default size' do + user_avatar_url(user).should == "#{base_url}?s=40&d=identicon" + end + + it 'should return gravatar with custom size' do + user_avatar_url(user, 120).should == "#{base_url}?s=120&d=identicon" + end + end + + context 'custom avatar' do + let (:avatar_url) { 'http://example.local/avatar.png' } + + it 'should return custom avatar' do + user_avatar_url(user).should == avatar_url + end + end + end +end diff --git a/spec/helpers/ci/user_sessions_helper_spec.rb b/spec/helpers/ci/user_sessions_helper_spec.rb new file mode 100644 index 00000000000..5f654866d99 --- /dev/null +++ b/spec/helpers/ci/user_sessions_helper_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' + +describe Ci::UserSessionsHelper do + describe :generate_oauth_hmac do + let (:salt) { 'a' } + let (:salt2) { 'b' } + let (:return_to) { 'b' } + + it 'should return null if return_to is also null' do + generate_oauth_hmac(salt, nil).should be_nil + end + + it 'should return not null if return_to is also not null' do + generate_oauth_hmac(salt, return_to).should_not be_nil + end + + it 'should return different hmacs for different salts' do + secret1 = generate_oauth_hmac(salt, return_to) + secret2 = generate_oauth_hmac(salt2, return_to) + secret1.should_not eq(secret2) + end + end + + describe :generate_oauth_state do + let (:return_to) { 'b' } + + it 'should return null if return_to is also null' do + generate_oauth_state(nil).should be_nil + end + + it 'should return two different states for same return_to' do + state1 = generate_oauth_state(return_to) + state2 = generate_oauth_state(return_to) + state1.should_not eq(state2) + end + end + + describe :get_ouath_state_return_to do + let (:return_to) { 'a' } + let (:state) { generate_oauth_state(return_to) } + + it 'should return return_to' do + get_ouath_state_return_to(state).should eq(return_to) + end + end + + describe :is_oauth_state_valid? do + let (:return_to) { 'a' } + let (:state) { generate_oauth_state(return_to) } + let (:forged) { "forged#{state}" } + let (:invalid) { 'aa' } + let (:invalid2) { 'aa:bb' } + let (:invalid3) { 'aa:bb:' } + + it 'should validate oauth state' do + is_oauth_state_valid?(state).should be_true + end + + it 'should not validate forged state' do + is_oauth_state_valid?(forged).should be_false + end + + it 'should not validate invalid state' do + is_oauth_state_valid?(invalid).should be_false + is_oauth_state_valid?(invalid2).should be_false + is_oauth_state_valid?(invalid3).should be_false + end + end +end diff --git a/spec/lib/ci/ansi2html_spec.rb b/spec/lib/ci/ansi2html_spec.rb new file mode 100644 index 00000000000..aa60011685b --- /dev/null +++ b/spec/lib/ci/ansi2html_spec.rb @@ -0,0 +1,133 @@ +require 'spec_helper' + +describe Ansi2html do + + it "prints non-ansi as-is" do + Ansi2html::convert("Hello").should == 'Hello' + end + + it "strips non-color-changing controll sequences" do + Ansi2html::convert("Hello \e[2Kworld").should == 'Hello world' + end + + it "prints simply red" do + Ansi2html::convert("\e[31mHello\e[0m").should == 'Hello' + end + + it "prints simply red without trailing reset" do + Ansi2html::convert("\e[31mHello").should == 'Hello' + end + + it "prints simply yellow" do + Ansi2html::convert("\e[33mHello\e[0m").should == 'Hello' + end + + it "prints default on blue" do + Ansi2html::convert("\e[39;44mHello").should == 'Hello' + end + + it "prints red on blue" do + Ansi2html::convert("\e[31;44mHello").should == 'Hello' + end + + it "resets colors after red on blue" do + Ansi2html::convert("\e[31;44mHello\e[0m world").should == 'Hello world' + end + + it "performs color change from red/blue to yellow/blue" do + Ansi2html::convert("\e[31;44mHello \e[33mworld").should == 'Hello world' + end + + it "performs color change from red/blue to yellow/green" do + Ansi2html::convert("\e[31;44mHello \e[33;42mworld").should == 'Hello world' + end + + it "performs color change from red/blue to reset to yellow/green" do + Ansi2html::convert("\e[31;44mHello\e[0m \e[33;42mworld").should == 'Hello world' + end + + it "ignores unsupported codes" do + Ansi2html::convert("\e[51mHello\e[0m").should == 'Hello' + end + + it "prints light red" do + Ansi2html::convert("\e[91mHello\e[0m").should == 'Hello' + end + + it "prints default on light red" do + Ansi2html::convert("\e[101mHello\e[0m").should == 'Hello' + end + + it "performs color change from red/blue to default/blue" do + Ansi2html::convert("\e[31;44mHello \e[39mworld").should == 'Hello world' + end + + it "performs color change from light red/blue to default/blue" do + Ansi2html::convert("\e[91;44mHello \e[39mworld").should == 'Hello world' + end + + it "prints bold text" do + Ansi2html::convert("\e[1mHello").should == 'Hello' + end + + it "resets bold text" do + Ansi2html::convert("\e[1mHello\e[21m world").should == 'Hello world' + Ansi2html::convert("\e[1mHello\e[22m world").should == 'Hello world' + end + + it "prints italic text" do + Ansi2html::convert("\e[3mHello").should == 'Hello' + end + + it "resets italic text" do + Ansi2html::convert("\e[3mHello\e[23m world").should == 'Hello world' + end + + it "prints underlined text" do + Ansi2html::convert("\e[4mHello").should == 'Hello' + end + + it "resets underlined text" do + Ansi2html::convert("\e[4mHello\e[24m world").should == 'Hello world' + end + + it "prints concealed text" do + Ansi2html::convert("\e[8mHello").should == 'Hello' + end + + it "resets concealed text" do + Ansi2html::convert("\e[8mHello\e[28m world").should == 'Hello world' + end + + it "prints crossed-out text" do + Ansi2html::convert("\e[9mHello").should == 'Hello' + end + + it "resets crossed-out text" do + Ansi2html::convert("\e[9mHello\e[29m world").should == 'Hello world' + end + + it "can print 256 xterm fg colors" do + Ansi2html::convert("\e[38;5;16mHello").should == 'Hello' + end + + it "can print 256 xterm fg colors on normal magenta background" do + Ansi2html::convert("\e[38;5;16;45mHello").should == 'Hello' + end + + it "can print 256 xterm bg colors" do + Ansi2html::convert("\e[48;5;240mHello").should == 'Hello' + end + + it "can print 256 xterm bg colors on normal magenta foreground" do + Ansi2html::convert("\e[48;5;16;35mHello").should == 'Hello' + end + + it "prints bold colored text vividly" do + Ansi2html::convert("\e[1;31mHello\e[0m").should == 'Hello' + end + + it "prints bold light colored text correctly" do + Ansi2html::convert("\e[1;91mHello\e[0m").should == 'Hello' + end +end diff --git a/spec/lib/ci/charts_spec.rb b/spec/lib/ci/charts_spec.rb new file mode 100644 index 00000000000..236cfc2a1f6 --- /dev/null +++ b/spec/lib/ci/charts_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe "Charts" do + + context "build_times" do + before do + @project = FactoryGirl.create(:project) + @commit = FactoryGirl.create(:commit, project: @project) + FactoryGirl.create(:build, commit: @commit) + end + + it 'should return build times in minutes' do + chart = Charts::BuildTime.new(@project) + chart.build_times.should == [2] + end + end +end diff --git a/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb new file mode 100644 index 00000000000..ed3d4e84054 --- /dev/null +++ b/spec/lib/ci/gitlab_ci_yaml_processor_spec.rb @@ -0,0 +1,311 @@ +require 'spec_helper' + +describe GitlabCiYamlProcessor do + + describe "#builds_for_ref" do + let (:type) { 'test' } + + it "returns builds if no branch specified" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: {script: "rspec"} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref(type, "master").size.should == 1 + config_processor.builds_for_stage_and_ref(type, "master").first.should == { + stage: "test", + except: nil, + name: :rspec, + only: nil, + script: "pwd\nrspec", + tags: [], + options: {}, + allow_failure: false + } + end + + it "does not return builds if only has another branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: {script: "rspec", only: ["deploy"]} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref(type, "master").size.should == 0 + end + + it "does not return builds if only has regexp with another branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: {script: "rspec", only: ["/^deploy$/"]} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref(type, "master").size.should == 0 + end + + it "returns builds if only has specified this branch" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: {script: "rspec", only: ["master"]} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref(type, "master").size.should == 1 + end + + it "does not build tags" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: {script: "rspec", except: ["tags"]} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref(type, "0-1", true).size.should == 0 + end + + it "returns builds if only has a list of branches including specified" do + config = YAML.dump({ + before_script: ["pwd"], + rspec: {script: "rspec", type: type, only: ["master", "deploy"]} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref(type, "deploy").size.should == 1 + end + + it "returns build only for specified type" do + + config = YAML.dump({ + before_script: ["pwd"], + build: {script: "build", type: "build", only: ["master", "deploy"]}, + rspec: {script: "rspec", type: type, only: ["master", "deploy"]}, + staging: {script: "deploy", type: "deploy", only: ["master", "deploy"]}, + production: {script: "deploy", type: "deploy", only: ["master", "deploy"]}, + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref("production", "deploy").size.should == 0 + config_processor.builds_for_stage_and_ref(type, "deploy").size.should == 1 + config_processor.builds_for_stage_and_ref("deploy", "deploy").size.should == 2 + end + end + + describe "Image and service handling" do + it "returns image and service when defined" do + config = YAML.dump({ + image: "ruby:2.1", + services: ["mysql"], + before_script: ["pwd"], + rspec: {script: "rspec"} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref("test", "master").size.should == 1 + config_processor.builds_for_stage_and_ref("test", "master").first.should == { + except: nil, + stage: "test", + name: :rspec, + only: nil, + script: "pwd\nrspec", + tags: [], + options: { + image: "ruby:2.1", + services: ["mysql"] + }, + allow_failure: false + } + end + + it "returns image and service when overridden for job" do + config = YAML.dump({ + image: "ruby:2.1", + services: ["mysql"], + before_script: ["pwd"], + rspec: {image: "ruby:2.5", services: ["postgresql"], script: "rspec"} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + + config_processor.builds_for_stage_and_ref("test", "master").size.should == 1 + config_processor.builds_for_stage_and_ref("test", "master").first.should == { + except: nil, + stage: "test", + name: :rspec, + only: nil, + script: "pwd\nrspec", + tags: [], + options: { + image: "ruby:2.5", + services: ["postgresql"] + }, + allow_failure: false + } + end + end + + describe "Variables" do + it "returns variables when defined" do + variables = { + var1: "value1", + var2: "value2", + } + config = YAML.dump({ + variables: variables, + before_script: ["pwd"], + rspec: {script: "rspec"} + }) + + config_processor = GitlabCiYamlProcessor.new(config) + config_processor.variables.should == variables + end + end + + describe "Error handling" do + it "indicates that object is invalid" do + expect{GitlabCiYamlProcessor.new("invalid_yaml\n!ccdvlf%612334@@@@")}.to raise_error(GitlabCiYamlProcessor::ValidationError) + end + + it "returns errors if tags parameter is invalid" do + config = YAML.dump({rspec: {script: "test", tags: "mysql"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: tags parameter should be an array of strings") + end + + it "returns errors if before_script parameter is invalid" do + config = YAML.dump({before_script: "bundle update", rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script should be an array of strings") + end + + it "returns errors if image parameter is invalid" do + config = YAML.dump({image: ["test"], rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image should be a string") + end + + it "returns errors if job image parameter is invalid" do + config = YAML.dump({rspec: {script: "test", image: ["test"]}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: image should be a string") + end + + it "returns errors if services parameter is not an array" do + config = YAML.dump({services: "test", rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings") + end + + it "returns errors if services parameter is not an array of strings" do + config = YAML.dump({services: [10, "test"], rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services should be an array of strings") + end + + it "returns errors if job services parameter is not an array" do + config = YAML.dump({rspec: {script: "test", services: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings") + end + + it "returns errors if job services parameter is not an array of strings" do + config = YAML.dump({rspec: {script: "test", services: [10, "test"]}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings") + end + + it "returns errors if there are unknown parameters" do + config = YAML.dump({extra: "bundle update"}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra") + end + + it "returns errors if there are unknown parameters that are hashes, but doesn't have a script" do + config = YAML.dump({extra: {services: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra") + end + + it "returns errors if there is no any jobs defined" do + config = YAML.dump({before_script: ["bundle update"]}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Please define at least one job") + end + + it "returns errors if job allow_failure parameter is not an boolean" do + config = YAML.dump({rspec: {script: "test", allow_failure: "string"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: allow_failure parameter should be an boolean") + end + + it "returns errors if job stage is not a string" do + config = YAML.dump({rspec: {script: "test", type: 1, allow_failure: "string"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") + end + + it "returns errors if job stage is not a pre-defined stage" do + config = YAML.dump({rspec: {script: "test", type: "acceptance", allow_failure: "string"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy") + end + + it "returns errors if job stage is not a defined stage" do + config = YAML.dump({types: ["build", "test"], rspec: {script: "test", type: "acceptance", allow_failure: "string"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test") + end + + it "returns errors if stages is not an array" do + config = YAML.dump({types: "test", rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings") + end + + it "returns errors if stages is not an array of strings" do + config = YAML.dump({types: [true, "test"], rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages should be an array of strings") + end + + it "returns errors if variables is not a map" do + config = YAML.dump({variables: "test", rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") + end + + it "returns errors if variables is not a map of key-valued strings" do + config = YAML.dump({variables: {test: false}, rspec: {script: "test"}}) + expect do + GitlabCiYamlProcessor.new(config) + end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables should be a map of key-valued strings") + end + end +end diff --git a/spec/lib/ci/upgrader_spec.rb b/spec/lib/ci/upgrader_spec.rb new file mode 100644 index 00000000000..40a98307ad2 --- /dev/null +++ b/spec/lib/ci/upgrader_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe Upgrader do + let(:upgrader) { Upgrader.new } + let(:current_version) { GitlabCi::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 GitlabCI 3' do + allow(upgrader).to receive(:current_version_raw).and_return('3.0.0') + expect(upgrader.latest_version_raw).to eq('v3.2.0') + end + + it 'should get the latest version from tags' do + allow(upgrader).to receive(:fetch_git_tags).and_return([ + '1b5bee25b51724214c7a3307ef94027ab93ec982 refs/tags/v7.8.1', + '424cb42e35947fa304ef83eb211ffc657e31aef3 refs/tags/v7.8.1^{}', + '498e5ba63be1bb99e30c6e720902d864aac4413c refs/tags/v7.9.0.rc1', + '96aaf45ae93bd43e8b3f5d4d353d64d3cbe1e63b refs/tags/v7.9.0.rc1^{}', + '94aaf45ae93bd43e8b3fad4a353d64d3cbe1e62b refs/tags/v7.1.0', + '96aaf45ae93ba13e8b3f5d4d353d64d3cbe1e251 refs/tags/v7.1.0^{}', + '29359d64442bf54b4ca1d8b439fd9e5f9cd83252 refs/tags/v7.10.0', + '4d9213a6378bff43a69ae099702fb81e29335e7a refs/tags/v7.10.0^{}', + '1d93e1626bda93622ca7a2ae2825e2e94dabf3c6 refs/tags/v7.12.0', + '0188a9d1c2efdc52bfad36ad303686be997de713 refs/tags/v7.12.0^{}']) + expect(upgrader.latest_version_raw).to eq("v7.12.0") + end + end +end diff --git a/spec/mailers/ci/notify_spec.rb b/spec/mailers/ci/notify_spec.rb new file mode 100644 index 00000000000..6a2c845cd0e --- /dev/null +++ b/spec/mailers/ci/notify_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe Notify do + include EmailSpec::Helpers + include EmailSpec::Matchers + + before do + @project = FactoryGirl.create :project + @commit = FactoryGirl.create :commit, project: @project + @build = FactoryGirl.create :build, commit: @commit + end + + describe 'build success' do + subject { Notify.build_success_email(@build.id, 'wow@example.com') } + + it 'has the correct subject' do + should have_subject /Build success for/ + end + + it 'contains name of project' do + should have_body_text /build successful/ + end + end + + describe 'build fail' do + subject { Notify.build_fail_email(@build.id, 'wow@example.com') } + + it 'has the correct subject' do + should have_subject /Build failed for/ + end + + it 'contains name of project' do + should have_body_text /build failed/ + end + end +end diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb new file mode 100644 index 00000000000..d1e58438f7b --- /dev/null +++ b/spec/models/ci/build_spec.rb @@ -0,0 +1,350 @@ +# == Schema Information +# +# Table name: builds +# +# id :integer not null, primary key +# project_id :integer +# status :string(255) +# finished_at :datetime +# trace :text +# created_at :datetime +# updated_at :datetime +# started_at :datetime +# runner_id :integer +# commit_id :integer +# coverage :float +# commands :text +# job_id :integer +# name :string(255) +# deploy :boolean default(FALSE) +# options :text +# allow_failure :boolean default(FALSE), not null +# stage :string(255) +# trigger_request_id :integer +# + +require 'spec_helper' + +describe Ci::Build do + let(:project) { FactoryGirl.create :ci_project } + let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:build) { FactoryGirl.create :ci_build, commit: commit } + + it { should belong_to(:commit) } + it { should validate_presence_of :status } + + it { should respond_to :success? } + it { should respond_to :failed? } + it { should respond_to :running? } + it { should respond_to :pending? } + it { should respond_to :trace_html } + + describe :first_pending do + let(:first) { FactoryGirl.create :ci_build, commit: commit, status: 'pending', created_at: Date.yesterday } + let(:second) { FactoryGirl.create :ci_build, commit: commit, status: 'pending' } + before { first; second } + subject { Ci::Build.first_pending } + + it { should be_a(Ci::Build) } + it('returns with the first pending build') { should eq(first) } + end + + describe :create_from do + before do + build.status = 'success' + build.save + end + let(:create_from_build) { Ci::Build.create_from build } + + it ('there should be a pending task') do + expect(Ci::Build.pending.count(:all)).to eq 0 + create_from_build + expect(Ci::Build.pending.count(:all)).to be > 0 + end + end + + describe :started? do + subject { build.started? } + + context 'without started_at' do + before { build.started_at = nil } + + it { should be_falsey } + end + + %w(running success failed).each do |status| + context "if build status is #{status}" do + before { build.status = status } + + it { should be_truthy } + end + end + + %w(pending canceled).each do |status| + context "if build status is #{status}" do + before { build.status = status } + + it { should be_falsey } + end + end + end + + describe :active? do + subject { build.active? } + + %w(pending running).each do |state| + context "if build.status is #{state}" do + before { build.status = state } + + it { should be_truthy } + end + end + + %w(success failed canceled).each do |state| + context "if build.status is #{state}" do + before { build.status = state } + + it { should be_falsey } + end + end + end + + describe :complete? do + subject { build.complete? } + + %w(success failed canceled).each do |state| + context "if build.status is #{state}" do + before { build.status = state } + + it { should be_truthy } + end + end + + %w(pending running).each do |state| + context "if build.status is #{state}" do + before { build.status = state } + + it { should be_falsey } + end + end + end + + describe :ignored? do + subject { build.ignored? } + + context 'if build is not allowed to fail' do + before { build.allow_failure = false } + + context 'and build.status is success' do + before { build.status = 'success' } + + it { should be_falsey } + end + + context 'and build.status is failed' do + before { build.status = 'failed' } + + it { should be_falsey } + end + end + + context 'if build is allowed to fail' do + before { build.allow_failure = true } + + context 'and build.status is success' do + before { build.status = 'success' } + + it { should be_falsey } + end + + context 'and build.status is failed' do + before { build.status = 'failed' } + + it { should be_truthy } + end + end + end + + describe :trace do + subject { build.trace_html } + + it { should be_empty } + + context 'if build.trace contains text' do + let(:text) { 'example output' } + before { build.trace = text } + + it { should include(text) } + it { should have_at_least(text.length).items } + end + end + + describe :timeout do + subject { build.timeout } + + it { should eq(commit.project.timeout) } + end + + describe :duration do + subject { build.duration } + + it { should eq(120.0) } + + context 'if the building process has not started yet' do + before do + build.started_at = nil + build.finished_at = nil + end + + it { should be_nil } + end + + context 'if the building process has started' do + before do + build.started_at = Time.now - 1.minute + build.finished_at = nil + end + + it { should be_a(Float) } + it { should > 0.0 } + end + end + + describe :options do + let(:options) { + { + :image => "ruby:2.1", + :services => [ + "postgres" + ] + } + } + + subject { build.options } + it { should eq(options) } + end + + describe :ref do + subject { build.ref } + + it { should eq(commit.ref) } + end + + describe :sha do + subject { build.sha } + + it { should eq(commit.sha) } + end + + describe :short_sha do + subject { build.short_sha } + + it { should eq(commit.short_sha) } + end + + describe :before_sha do + subject { build.before_sha } + + it { should eq(commit.before_sha) } + end + + describe :allow_git_fetch do + subject { build.allow_git_fetch } + + it { should eq(project.allow_git_fetch) } + end + + describe :project do + subject { build.project } + + it { should eq(commit.project) } + end + + describe :project_id do + subject { build.project_id } + + it { should eq(commit.project_id) } + end + + describe :project_name do + subject { build.project_name } + + it { should eq(project.name) } + end + + describe :repo_url do + subject { build.repo_url } + + it { should eq(project.repo_url_with_auth) } + end + + describe :extract_coverage do + context 'valid content & regex' do + subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', '\(\d+.\d+\%\) covered') } + + it { should eq(98.29) } + end + + context 'valid content & bad regex' do + subject { build.extract_coverage('Coverage 1033 / 1051 LOC (98.29%) covered', 'very covered') } + + it { should be_nil } + end + + context 'no coverage content & regex' do + subject { build.extract_coverage('No coverage for today :sad:', '\(\d+.\d+\%\) covered') } + + it { should be_nil } + end + + context 'multiple results in content & regex' do + subject { build.extract_coverage(' (98.39%) covered. (98.29%) covered', '\(\d+.\d+\%\) covered') } + + it { should eq(98.29) } + end + end + + describe :variables do + context 'returns variables' do + subject { build.variables } + + let(:variables) { + [ + {key: :DB_NAME, value: 'postgres', public: true} + ] + } + + it { should eq(variables) } + + context 'and secure variables' do + let(:secure_variables) { + [ + {key: 'SECRET_KEY', value: 'secret_value', public: false} + ] + } + + before do + build.project.variables << Ci::Variable.new(key: 'SECRET_KEY', value: 'secret_value') + end + + it { should eq(variables + secure_variables) } + + context 'and trigger variables' do + let(:trigger) { FactoryGirl.create :ci_trigger, project: project } + let(:trigger_request) { FactoryGirl.create :ci_trigger_request_with_variables, commit: commit, trigger: trigger } + let(:trigger_variables) { + [ + {key: :TRIGGER_KEY, value: 'TRIGGER_VALUE', public: false} + ] + } + + before do + build.trigger_request = trigger_request + end + + it { should eq(variables + secure_variables + trigger_variables) } + end + end + end + end +end diff --git a/spec/models/ci/commit_spec.rb b/spec/models/ci/commit_spec.rb new file mode 100644 index 00000000000..6d5b0597e13 --- /dev/null +++ b/spec/models/ci/commit_spec.rb @@ -0,0 +1,264 @@ +# == Schema Information +# +# Table name: commits +# +# id :integer not null, primary key +# project_id :integer +# ref :string(255) +# sha :string(255) +# before_sha :string(255) +# push_data :text +# created_at :datetime +# updated_at :datetime +# tag :boolean default(FALSE) +# yaml_errors :text +# committed_at :datetime +# + +require 'spec_helper' + +describe Ci::Commit do + let(:project) { FactoryGirl.create :ci_project } + let(:commit) { FactoryGirl.create :ci_commit, project: project } + let(:commit_with_project) { FactoryGirl.create :ci_commit, project: project } + let(:config_processor) { GitlabCiYamlProcessor.new(gitlab_ci_yaml) } + + it { should belong_to(:project) } + it { should have_many(:builds) } + it { should validate_presence_of :before_sha } + it { should validate_presence_of :sha } + it { should validate_presence_of :ref } + it { should validate_presence_of :push_data } + + it { should respond_to :git_author_name } + it { should respond_to :git_author_email } + it { should respond_to :short_sha } + + describe :last_build do + subject { commit.last_build } + before do + @first = FactoryGirl.create :ci_build, commit: commit, created_at: Date.yesterday + @second = FactoryGirl.create :ci_build, commit: commit + end + + it { should be_a(Ci::Build) } + it('returns with the most recently created build') { should eq(@second) } + end + + describe :retry do + before do + @first = FactoryGirl.create :ci_build, commit: commit, created_at: Date.yesterday + @second = FactoryGirl.create :ci_build, commit: commit + end + + it "creates new build" do + expect(commit.builds.count(:all)).to eq 2 + commit.retry + expect(commit.builds.count(:all)).to eq 3 + end + end + + describe :project_recipients do + + context 'always sending notification' do + it 'should return commit_pusher_email as only recipient when no additional recipients are given' do + project = FactoryGirl.create :ci_project, + email_add_pusher: true, + email_recipients: '' + commit = FactoryGirl.create :ci_commit, project: project + expected = 'commit_pusher_email' + commit.stub(:push_data) { { user_email: expected } } + commit.project_recipients.should == [expected] + end + + it 'should return commit_pusher_email and additional recipients' do + project = FactoryGirl.create :ci_project, + email_add_pusher: true, + email_recipients: 'rec1 rec2' + commit = FactoryGirl.create :ci_commit, project: project + expected = 'commit_pusher_email' + commit.stub(:push_data) { { user_email: expected } } + commit.project_recipients.should == ['rec1', 'rec2', expected] + end + + it 'should return recipients' do + project = FactoryGirl.create :ci_project, + email_add_pusher: false, + email_recipients: 'rec1 rec2' + commit = FactoryGirl.create :ci_commit, project: project + commit.project_recipients.should == ['rec1', 'rec2'] + end + + it 'should return unique recipients only' do + project = FactoryGirl.create :ci_project, + email_add_pusher: true, + email_recipients: 'rec1 rec1 rec2' + commit = FactoryGirl.create :ci_commit, project: project + expected = 'rec2' + commit.stub(:push_data) { { user_email: expected } } + commit.project_recipients.should == ['rec1', 'rec2'] + end + end + end + + describe :valid_commit_sha do + context 'commit.sha can not start with 00000000' do + before do + commit.sha = '0' * 40 + commit.valid_commit_sha + end + + it('commit errors should not be empty') { commit.errors.should_not be_empty } + end + end + + describe :compare? do + subject { commit_with_project.compare? } + + context 'if commit.before_sha are not nil' do + it { should be_true } + end + end + + describe :short_sha do + subject { commit.short_before_sha } + + it { should have(8).items } + it { commit.before_sha.should start_with(subject) } + end + + describe :short_sha do + subject { commit.short_sha } + + it { should have(8).items } + it { commit.sha.should start_with(subject) } + end + + describe :create_next_builds do + before do + commit.stub(:config_processor).and_return(config_processor) + end + + it "creates builds for next type" do + commit.create_builds.should be_true + commit.builds.reload + commit.builds.size.should == 2 + + commit.create_next_builds(nil).should be_true + commit.builds.reload + commit.builds.size.should == 4 + + commit.create_next_builds(nil).should be_true + commit.builds.reload + commit.builds.size.should == 5 + + commit.create_next_builds(nil).should be_false + end + end + + describe :create_builds do + before do + commit.stub(:config_processor).and_return(config_processor) + end + + it 'creates builds' do + commit.create_builds.should be_true + commit.builds.reload + commit.builds.size.should == 2 + end + + context 'for build triggers' do + let(:trigger) { FactoryGirl.create :ci_trigger, project: project } + let(:trigger_request) { FactoryGirl.create :ci_trigger_request, commit: commit, trigger: trigger } + + it 'creates builds' do + commit.create_builds(trigger_request).should be_true + commit.builds.reload + commit.builds.size.should == 2 + end + + it 'rebuilds commit' do + commit.create_builds.should be_true + commit.builds.reload + commit.builds.size.should == 2 + + commit.create_builds(trigger_request).should be_true + commit.builds.reload + commit.builds.size.should == 4 + end + + it 'creates next builds' do + commit.create_builds(trigger_request).should be_true + commit.builds.reload + commit.builds.size.should == 2 + + commit.create_next_builds(trigger_request).should be_true + commit.builds.reload + commit.builds.size.should == 4 + end + + context 'for [ci skip]' do + before do + commit.push_data[:commits][0][:message] = 'skip this commit [ci skip]' + commit.save + end + + it 'rebuilds commit' do + commit.status.should == 'skipped' + commit.create_builds(trigger_request).should be_true + commit.builds.reload + commit.builds.size.should == 2 + commit.status.should == 'pending' + end + end + end + end + + describe "#finished_at" do + let(:project) { FactoryGirl.create :ci_project } + let(:commit) { FactoryGirl.create :ci_commit, project: project } + + it "returns finished_at of latest build" do + build = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 60 + build1 = FactoryGirl.create :ci_build, commit: commit, finished_at: Time.now - 120 + + commit.finished_at.to_i.should == build.finished_at.to_i + end + + it "returns nil if there is no finished build" do + build = FactoryGirl.create :ci_not_started_build, commit: commit + + commit.finished_at.should be_nil + end + end + + describe "coverage" do + let(:project) { FactoryGirl.create :ci_project, coverage_regex: "/.*/" } + let(:commit) { FactoryGirl.create :ci_commit, project: project } + + it "calculates average when there are two builds with coverage" do + FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit + FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, commit: commit + commit.coverage.should == "35.00" + end + + it "calculates average when there are two builds with coverage and one with nil" do + FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit + FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, commit: commit + FactoryGirl.create :ci_build, commit: commit + commit.coverage.should == "35.00" + end + + it "calculates average when there are two builds with coverage and one is retried" do + FactoryGirl.create :ci_build, name: "rspec", coverage: 30, commit: commit + FactoryGirl.create :ci_build, name: "rubocop", coverage: 30, commit: commit + FactoryGirl.create :ci_build, name: "rubocop", coverage: 40, commit: commit + commit.coverage.should == "35.00" + end + + it "calculates average when there is one build without coverage" do + FactoryGirl.create :ci_build, commit: commit + commit.coverage.should be_nil + end + end +end diff --git a/spec/models/ci/mail_service_spec.rb b/spec/models/ci/mail_service_spec.rb new file mode 100644 index 00000000000..4830d98bdf8 --- /dev/null +++ b/spec/models/ci/mail_service_spec.rb @@ -0,0 +1,184 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# + +require 'spec_helper' + +describe Ci::MailService do + describe "Associations" do + it { should belong_to :project } + end + + describe "Validations" do + context "active" do + before do + subject.active = true + end + end + end + + describe 'Sends email for' do + let(:mail) { Ci::MailService.new } + + describe 'failed build' do + let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true) } + let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) } + + before do + mail.stub( + project: project + ) + end + + it do + should_email("git@example.com") + mail.execute(build) + end + + def should_email(email) + Notify.should_receive(:build_fail_email).with(build.id, email) + Notify.should_not_receive(:build_success_email).with(build.id, email) + end + end + + describe 'successfull build' do + let(:project) { FactoryGirl.create(:ci_project, email_add_pusher: true, email_only_broken_builds: false) } + let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } + + before do + mail.stub( + project: project + ) + end + + it do + should_email("git@example.com") + mail.execute(build) + end + + def should_email(email) + Notify.should_receive(:build_success_email).with(build.id, email) + Notify.should_not_receive(:build_fail_email).with(build.id, email) + end + end + + describe 'successfull build and project has email_recipients' do + let(:project) { + FactoryGirl.create(:ci_project, + email_add_pusher: true, + email_only_broken_builds: false, + email_recipients: "jeroen@example.com") + } + let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } + + before do + mail.stub( + project: project + ) + end + + it do + should_email("git@example.com") + should_email("jeroen@example.com") + mail.execute(build) + end + + def should_email(email) + Notify.should_receive(:build_success_email).with(build.id, email) + Notify.should_not_receive(:build_fail_email).with(build.id, email) + end + end + + describe 'successful build and notify only broken builds' do + let(:project) { + FactoryGirl.create(:ci_project, + email_add_pusher: true, + email_only_broken_builds: true, + email_recipients: "jeroen@example.com") + } + let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } + + before do + mail.stub( + project: project + ) + end + + it do + should_email(commit.git_author_email) + should_email("jeroen@example.com") + mail.execute(build) if mail.can_execute?(build) + end + + def should_email(email) + Notify.should_not_receive(:build_success_email).with(build.id, email) + Notify.should_not_receive(:build_fail_email).with(build.id, email) + end + end + + describe 'successful build and can test service' do + let(:project) { + FactoryGirl.create(:ci_project, + email_add_pusher: true, + email_only_broken_builds: false, + email_recipients: "jeroen@example.com") + } + let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:build) { FactoryGirl.create(:ci_build, status: :success, commit: commit) } + + before do + mail.stub( + project: project + ) + build + end + + it do + mail.can_test?.should == true + end + end + + describe 'retried build should not receive email' do + let(:project) { + FactoryGirl.create(:ci_project, + email_add_pusher: true, + email_only_broken_builds: true, + email_recipients: "jeroen@example.com") + } + let(:commit) { FactoryGirl.create(:ci_commit, project: project) } + let(:build) { FactoryGirl.create(:ci_build, status: :failed, commit: commit) } + + before do + mail.stub( + project: project + ) + end + + it do + Build.retry(build) + should_email(commit.git_author_email) + should_email("jeroen@example.com") + mail.execute(build) if mail.can_execute?(build) + end + + def should_email(email) + Notify.should_not_receive(:build_success_email).with(build.id, email) + Notify.should_not_receive(:build_fail_email).with(build.id, email) + end + end + end +end diff --git a/spec/models/ci/network_spec.rb b/spec/models/ci/network_spec.rb new file mode 100644 index 00000000000..b80adba5b08 --- /dev/null +++ b/spec/models/ci/network_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe Network do + let(:network) { Network.new } + + describe :enable_ci do + subject { network.enable_ci '', '', '' } + + context 'on success' do + before do + response = double + response.stub(:code) { 200 } + network.class.stub(:put) { response } + end + + it { should be_true } + end + + context 'on failure' do + before do + response = double + response.stub(:code) { 404 } + network.class.stub(:put) { response } + end + + it { should be_nil } + end + end + + describe :disable_ci do + let(:response) { double } + subject { network.disable_ci '', '' } + + context 'on success' do + let(:parsed_response) { 'parsed' } + before do + response.stub(:code) { 200 } + response.stub(:parsed_response) { parsed_response } + network.class.stub(:delete) { response } + end + + it { should equal(parsed_response) } + end + + context 'on failure' do + before do + response.stub(:code) { 404 } + network.class.stub(:delete) { response } + end + + it { should be_nil } + end + end +end diff --git a/spec/models/ci/project_services/hip_chat_message_spec.rb b/spec/models/ci/project_services/hip_chat_message_spec.rb new file mode 100644 index 00000000000..3571cb94793 --- /dev/null +++ b/spec/models/ci/project_services/hip_chat_message_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe Ci::HipChatMessage do + subject { HipChatMessage.new(build) } + + let(:project) { FactoryGirl.create(:project) } + + context "One build" do + let(:commit) { FactoryGirl.create(:commit_with_one_job, project: project) } + + let(:build) do + commit.create_builds + commit.builds.first + end + + context 'when build succeeds' do + it 'returns a successful message' do + build.update(status: "success") + + expect( subject.status_color ).to eq 'green' + expect( subject.notify? ).to be_false + expect( subject.to_s ).to match(/Build '[^']+' #\d+/) + expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./) + end + end + + context 'when build fails' do + it 'returns a failure message' do + build.update(status: "failed") + + expect( subject.status_color ).to eq 'red' + expect( subject.notify? ).to be_true + expect( subject.to_s ).to match(/Build '[^']+' #\d+/) + expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./) + end + end + end + + context "Several builds" do + let(:commit) { FactoryGirl.create(:commit_with_two_jobs, project: project) } + + let(:build) do + commit.builds.first + end + + context 'when all matrix builds succeed' do + it 'returns a successful message' do + commit.create_builds + commit.builds.update_all(status: "success") + commit.reload + + expect( subject.status_color ).to eq 'green' + expect( subject.notify? ).to be_false + expect( subject.to_s ).to match(/Commit #\d+/) + expect( subject.to_s ).to match(/Successful in \d+ second\(s\)\./) + end + end + + context 'when at least one matrix build fails' do + it 'returns a failure message' do + commit.create_builds + first_build = commit.builds.first + second_build = commit.builds.last + first_build.update(status: "success") + second_build.update(status: "failed") + + expect( subject.status_color ).to eq 'red' + expect( subject.notify? ).to be_true + expect( subject.to_s ).to match(/Commit #\d+/) + expect( subject.to_s ).to match(/Failed in \d+ second\(s\)\./) + end + end + end +end diff --git a/spec/models/ci/project_services/hip_chat_service_spec.rb b/spec/models/ci/project_services/hip_chat_service_spec.rb new file mode 100644 index 00000000000..71dba8fc358 --- /dev/null +++ b/spec/models/ci/project_services/hip_chat_service_spec.rb @@ -0,0 +1,75 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# + + +require 'spec_helper' + +describe Ci::HipChatService do + + describe "Validations" do + + context "active" do + before do + subject.active = true + end + + it { should validate_presence_of :hipchat_room } + it { should validate_presence_of :hipchat_token } + + end + end + + describe "Execute" do + + let(:service) { HipChatService.new } + let(:project) { FactoryGirl.create :project } + let(:commit) { FactoryGirl.create :commit, project: project } + let(:build) { FactoryGirl.create :build, commit: commit, status: 'failed' } + let(:api_url) { 'https://api.hipchat.com/v2/room/123/notification?auth_token=a1b2c3d4e5f6' } + + before do + service.stub( + project: project, + project_id: project.id, + notify_only_broken_builds: false, + hipchat_room: 123, + hipchat_token: 'a1b2c3d4e5f6' + ) + + WebMock.stub_request(:post, api_url) + end + + + it "should call the HipChat API" do + service.execute(build) + HipChatNotifierWorker.drain + + expect( WebMock ).to have_requested(:post, api_url).once + end + + it "calls the worker with expected arguments" do + expect( HipChatNotifierWorker ).to receive(:perform_async) \ + .with(an_instance_of(String), hash_including( + token: 'a1b2c3d4e5f6', + room: 123, + server: 'https://api.hipchat.com', + color: 'red', + notify: true + )) + + service.execute(build) + end + end +end + diff --git a/spec/models/ci/project_services/slack_message_spec.rb b/spec/models/ci/project_services/slack_message_spec.rb new file mode 100644 index 00000000000..4a7284fe460 --- /dev/null +++ b/spec/models/ci/project_services/slack_message_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper' + +describe Ci::SlackMessage do + subject { SlackMessage.new(commit) } + + let(:project) { FactoryGirl.create :project } + + context "One build" do + let(:commit) { FactoryGirl.create(:commit_with_one_job, project: project) } + + let(:build) do + commit.create_builds + commit.builds.first + end + + context 'when build succeeded' do + let(:color) { 'good' } + + it 'returns a message with succeeded build' do + build.update(status: "success") + + subject.color.should == color + subject.fallback.should include('Build') + subject.fallback.should include("\##{build.id}") + subject.fallback.should include('succeeded') + subject.attachments.first[:fields].should be_empty + end + end + + context 'when build failed' do + let(:color) { 'danger' } + + it 'returns a message with failed build' do + build.update(status: "failed") + + subject.color.should == color + subject.fallback.should include('Build') + subject.fallback.should include("\##{build.id}") + subject.fallback.should include('failed') + subject.attachments.first[:fields].should be_empty + end + end + end + + context "Several builds" do + let(:commit) { FactoryGirl.create(:commit_with_two_jobs, project: project) } + + context 'when all matrix builds succeeded' do + let(:color) { 'good' } + + it 'returns a message with success' do + commit.create_builds + commit.builds.update_all(status: "success") + commit.reload + + subject.color.should == color + subject.fallback.should include('Commit') + subject.fallback.should include("\##{commit.id}") + subject.fallback.should include('succeeded') + subject.attachments.first[:fields].should be_empty + end + end + + context 'when one of matrix builds failed' do + let(:color) { 'danger' } + + it 'returns a message with information about failed build' do + commit.create_builds + first_build = commit.builds.first + second_build = commit.builds.last + first_build.update(status: "success") + second_build.update(status: "failed") + + subject.color.should == color + subject.fallback.should include('Commit') + subject.fallback.should include("\##{commit.id}") + subject.fallback.should include('failed') + subject.attachments.first[:fields].size.should == 1 + subject.attachments.first[:fields].first[:title].should == second_build.name + subject.attachments.first[:fields].first[:value].should include("\##{second_build.id}") + end + end + end +end diff --git a/spec/models/ci/project_services/slack_service_spec.rb b/spec/models/ci/project_services/slack_service_spec.rb new file mode 100644 index 00000000000..952349a9def --- /dev/null +++ b/spec/models/ci/project_services/slack_service_spec.rb @@ -0,0 +1,58 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# + +require 'spec_helper' + +describe Ci::SlackService do + describe "Associations" do + it { should belong_to :project } + end + + describe "Validations" do + context "active" do + before do + subject.active = true + end + + it { should validate_presence_of :webhook } + end + end + + describe "Execute" do + let(:slack) { SlackService.new } + let(:project) { FactoryGirl.create :project } + let(:commit) { FactoryGirl.create :commit, project: project } + let(:build) { FactoryGirl.create :build, commit: commit, status: 'failed' } + let(:webhook_url) { 'https://hooks.slack.com/services/SVRWFV0VVAR97N/B02R25XN3/ZBqu7xMupaEEICInN685' } + let(:notify_only_broken_builds) { false } + + before do + slack.stub( + project: project, + project_id: project.id, + webhook: webhook_url, + notify_only_broken_builds: notify_only_broken_builds + ) + + WebMock.stub_request(:post, webhook_url) + end + + it "should call Slack API" do + slack.execute(build) + SlackNotifierWorker.drain + + WebMock.should have_requested(:post, webhook_url).once + end + end +end diff --git a/spec/models/ci/project_spec.rb b/spec/models/ci/project_spec.rb new file mode 100644 index 00000000000..aa76b99154b --- /dev/null +++ b/spec/models/ci/project_spec.rb @@ -0,0 +1,185 @@ +# == Schema Information +# +# Table name: projects +# +# id :integer not null, primary key +# name :string(255) not null +# timeout :integer default(3600), not null +# created_at :datetime +# updated_at :datetime +# token :string(255) +# default_ref :string(255) +# path :string(255) +# always_build :boolean default(FALSE), not null +# polling_interval :integer +# public :boolean default(FALSE), not null +# ssh_url_to_repo :string(255) +# gitlab_id :integer +# allow_git_fetch :boolean default(TRUE), not null +# email_recipients :string(255) default(""), not null +# email_add_pusher :boolean default(TRUE), not null +# email_only_broken_builds :boolean default(TRUE), not null +# skip_refs :string(255) +# coverage_regex :string(255) +# shared_runners_enabled :boolean default(FALSE) +# generated_yaml_config :text +# + +require 'spec_helper' + +describe Project do + subject { FactoryGirl.build :project } + + it { should have_many(:commits) } + + it { should validate_presence_of :name } + it { should validate_presence_of :timeout } + it { should validate_presence_of :default_ref } + + describe 'before_validation' do + it 'should set an random token if none provided' do + project = FactoryGirl.create :project_without_token + project.token.should_not == "" + end + + it 'should not set an random toke if one provided' do + project = FactoryGirl.create :project + project.token.should == "iPWx6WM4lhHNedGfBpPJNP" + end + end + + describe "ordered_by_last_commit_date" do + it "returns ordered projects" do + newest_project = FactoryGirl.create :project + oldest_project = FactoryGirl.create :project + project_without_commits = FactoryGirl.create :project + + FactoryGirl.create :commit, committed_at: 1.hour.ago, project: newest_project + FactoryGirl.create :commit, committed_at: 2.hour.ago, project: oldest_project + + Project.ordered_by_last_commit_date.should == [newest_project, oldest_project, project_without_commits] + end + end + + context :valid_project do + let(:project) { FactoryGirl.create :project } + + context :project_with_commit_and_builds do + before do + commit = FactoryGirl.create(:commit, project: project) + FactoryGirl.create(:build, commit: commit) + end + + it { project.status.should == 'pending' } + it { project.last_commit.should be_kind_of(Commit) } + it { project.human_status.should == 'pending' } + end + end + + describe '#email_notification?' do + it do + project = FactoryGirl.create :project, email_add_pusher: true + project.email_notification?.should == true + end + + it do + project = FactoryGirl.create :project, email_add_pusher: false, email_recipients: 'test tesft' + project.email_notification?.should == true + end + + it do + project = FactoryGirl.create :project, email_add_pusher: false, email_recipients: '' + project.email_notification?.should == false + end + end + + describe '#broken_or_success?' do + it { + project = FactoryGirl.create :project, email_add_pusher: true + project.stub(:broken?).and_return(true) + project.stub(:success?).and_return(true) + project.broken_or_success?.should == true + } + + it { + project = FactoryGirl.create :project, email_add_pusher: true + project.stub(:broken?).and_return(true) + project.stub(:success?).and_return(false) + project.broken_or_success?.should == true + } + + it { + project = FactoryGirl.create :project, email_add_pusher: true + project.stub(:broken?).and_return(false) + project.stub(:success?).and_return(true) + project.broken_or_success?.should == true + } + + it { + project = FactoryGirl.create :project, email_add_pusher: true + project.stub(:broken?).and_return(false) + project.stub(:success?).and_return(false) + project.broken_or_success?.should == false + } + end + + describe 'Project.parse' do + let(:project_dump) { YAML.load File.read(Rails.root.join('spec/support/gitlab_stubs/raw_project.yml')) } + let(:parsed_project) { Project.parse(project_dump) } + + + it { parsed_project.should be_valid } + it { parsed_project.should be_kind_of(Project) } + it { parsed_project.name.should eq("GitLab / api.gitlab.org") } + it { parsed_project.gitlab_id.should eq(189) } + it { parsed_project.gitlab_url.should eq("http://demo.gitlab.com/gitlab/api-gitlab-org") } + + it "parses plain hash" do + Project.parse(project_dump).name.should eq("GitLab / api.gitlab.org") + end + end + + describe :repo_url_with_auth do + let(:project) { FactoryGirl.create :project } + subject { project.repo_url_with_auth } + + it { should be_a(String) } + it { should end_with(".git") } + it { should start_with(project.gitlab_url[0..6]) } + it { should include(project.token) } + it { should include('gitlab-ci-token') } + it { should include(project.gitlab_url[7..-1]) } + end + + describe :search do + let!(:project) { FactoryGirl.create(:project, name: "foo") } + + it { Project.search('fo').should include(project) } + it { Project.search('bar').should be_empty } + end + + describe :any_runners do + it "there are no runners available" do + project = FactoryGirl.create(:project) + project.any_runners?.should be_false + end + + it "there is a specific runner" do + project = FactoryGirl.create(:project) + project.runners << FactoryGirl.create(:specific_runner) + project.any_runners?.should be_true + end + + it "there is a shared runner" do + project = FactoryGirl.create(:project, shared_runners_enabled: true) + FactoryGirl.create(:shared_runner) + project.any_runners?.should be_true + end + + it "there is a shared runner, but they are prohibited to use" do + project = FactoryGirl.create(:project) + FactoryGirl.create(:shared_runner) + project.any_runners?.should be_false + end + end +end diff --git a/spec/models/ci/runner_project_spec.rb b/spec/models/ci/runner_project_spec.rb new file mode 100644 index 00000000000..0218d484130 --- /dev/null +++ b/spec/models/ci/runner_project_spec.rb @@ -0,0 +1,16 @@ +# == Schema Information +# +# Table name: runner_projects +# +# id :integer not null, primary key +# runner_id :integer not null +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# + +require 'spec_helper' + +describe Ci::RunnerProject do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb new file mode 100644 index 00000000000..8677d86aa02 --- /dev/null +++ b/spec/models/ci/runner_spec.rb @@ -0,0 +1,70 @@ +# == Schema Information +# +# Table name: runners +# +# id :integer not null, primary key +# token :string(255) +# created_at :datetime +# updated_at :datetime +# description :string(255) +# contacted_at :datetime +# active :boolean default(TRUE), not null +# is_shared :boolean default(FALSE) +# name :string(255) +# version :string(255) +# revision :string(255) +# platform :string(255) +# architecture :string(255) +# + +require 'spec_helper' + +describe Ci::Runner do + describe '#display_name' do + it 'should return the description if it has a value' do + runner = FactoryGirl.build(:runner, description: 'Linux/Ruby-1.9.3-p448') + expect(runner.display_name).to eq 'Linux/Ruby-1.9.3-p448' + end + + it 'should return the token if it does not have a description' do + runner = FactoryGirl.create(:runner) + expect(runner.display_name).to eq runner.description + end + + it 'should return the token if the description is an empty string' do + runner = FactoryGirl.build(:runner, description: '') + expect(runner.display_name).to eq runner.token + end + end + + describe :assign_to do + let!(:project) { FactoryGirl.create :project } + let!(:shared_runner) { FactoryGirl.create(:shared_runner) } + + before { shared_runner.assign_to(project) } + + it { shared_runner.should be_specific } + it { shared_runner.projects.should == [project] } + it { shared_runner.only_for?(project).should be_true } + end + + describe "belongs_to_one_project?" do + it "returns false if there are two projects runner assigned to" do + runner = FactoryGirl.create(:specific_runner) + project = FactoryGirl.create(:project) + project1 = FactoryGirl.create(:project) + project.runners << runner + project1.runners << runner + + runner.belongs_to_one_project?.should be_false + end + + it "returns true" do + runner = FactoryGirl.create(:specific_runner) + project = FactoryGirl.create(:project) + project.runners << runner + + runner.belongs_to_one_project?.should be_true + end + end +end diff --git a/spec/models/ci/service_spec.rb b/spec/models/ci/service_spec.rb new file mode 100644 index 00000000000..5a90229ec43 --- /dev/null +++ b/spec/models/ci/service_spec.rb @@ -0,0 +1,49 @@ +# == Schema Information +# +# Table name: services +# +# id :integer not null, primary key +# type :string(255) +# title :string(255) +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# active :boolean default(FALSE), not null +# properties :text +# + +require 'spec_helper' + +describe Ci::Service do + + describe "Associations" do + it { should belong_to :project } + end + + describe "Mass assignment" do + end + + describe "Test Button" do + before do + @service = Service.new + end + + describe "Testable" do + let (:project) { FactoryGirl.create :project } + let (:commit) { FactoryGirl.create :commit, project: project } + let (:build) { FactoryGirl.create :build, commit: commit } + + before do + @service.stub( + project: project + ) + build + @testable = @service.can_test? + end + + describe :can_test do + it { @testable.should == true } + end + end + end +end diff --git a/spec/models/ci/trigger_spec.rb b/spec/models/ci/trigger_spec.rb new file mode 100644 index 00000000000..7c928f9d9dc --- /dev/null +++ b/spec/models/ci/trigger_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Ci::Trigger do + let(:project) { FactoryGirl.create :project } + + describe 'before_validation' do + it 'should set an random token if none provided' do + trigger = FactoryGirl.create :trigger_without_token, project: project + trigger.token.should_not be_nil + end + + it 'should not set an random token if one provided' do + trigger = FactoryGirl.create :trigger, project: project + trigger.token.should == 'token' + end + end +end diff --git a/spec/models/ci/user_spec.rb b/spec/models/ci/user_spec.rb new file mode 100644 index 00000000000..d1b87988b74 --- /dev/null +++ b/spec/models/ci/user_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper' + +describe Ci::User do + + describe "has_developer_access?" do + before do + @user = User.new({}) + end + + let(:project_with_owner_access) do + { + "name" => "gitlab-shell", + "permissions" => { + "project_access" => { + "access_level"=> 10, + "notification_level" => 3 + }, + "group_access" => { + "access_level" => 50, + "notification_level" => 3 + } + } + } + end + + let(:project_with_reporter_access) do + { + "name" => "gitlab-shell", + "permissions" => { + "project_access" => { + "access_level" => 20, + "notification_level" => 3 + }, + "group_access" => { + "access_level" => 10, + "notification_level" => 3 + } + } + } + end + + it "returns false for reporter" do + @user.stub(:project_info).and_return(project_with_reporter_access) + + @user.has_developer_access?(1).should be_false + end + + it "returns true for owner" do + @user.stub(:project_info).and_return(project_with_owner_access) + + @user.has_developer_access?(1).should be_true + end + end + + describe "authorized_projects" do + let (:user) { User.new({}) } + + before do + FactoryGirl.create :project, gitlab_id: 1 + FactoryGirl.create :project, gitlab_id: 2 + gitlab_project = OpenStruct.new({id: 1}) + gitlab_project1 = OpenStruct.new({id: 2}) + User.any_instance.stub(:gitlab_projects).and_return([gitlab_project, gitlab_project1]) + end + + it "returns projects" do + User.any_instance.stub(:can_manage_project?).and_return(true) + + user.authorized_projects.count.should == 2 + end + + it "empty list if user miss manage permission" do + User.any_instance.stub(:can_manage_project?).and_return(false) + + user.authorized_projects.count.should == 0 + end + end + + describe "authorized_runners" do + it "returns authorized runners" do + project = FactoryGirl.create :project, gitlab_id: 1 + project1 = FactoryGirl.create :project, gitlab_id: 2 + gitlab_project = OpenStruct.new({id: 1}) + gitlab_project1 = OpenStruct.new({id: 2}) + User.any_instance.stub(:gitlab_projects).and_return([gitlab_project, gitlab_project1]) + User.any_instance.stub(:can_manage_project?).and_return(true) + user = User.new({}) + + runner = FactoryGirl.create :specific_runner + runner1 = FactoryGirl.create :specific_runner + runner2 = FactoryGirl.create :specific_runner + + project.runners << runner + project1.runners << runner1 + + user.authorized_runners.should include(runner, runner1) + user.authorized_runners.should_not include(runner2) + end + end +end diff --git a/spec/models/ci/variable_spec.rb b/spec/models/ci/variable_spec.rb new file mode 100644 index 00000000000..447512bf6df --- /dev/null +++ b/spec/models/ci/variable_spec.rb @@ -0,0 +1,44 @@ +# == Schema Information +# +# Table name: variables +# +# id :integer not null, primary key +# project_id :integer not null +# key :string(255) +# value :text +# encrypted_value :text +# encrypted_value_salt :string(255) +# encrypted_value_iv :string(255) +# + +require 'spec_helper' + +describe Ci::Variable do + subject { Variable.new } + + let(:secret_value) { 'secret' } + + before :each do + subject.value = secret_value + end + + describe :value do + it 'stores the encrypted value' do + subject.encrypted_value.should_not be_nil + end + + it 'stores an iv for value' do + subject.encrypted_value_iv.should_not be_nil + end + + it 'stores a salt for value' do + subject.encrypted_value_salt.should_not be_nil + end + + it 'fails to decrypt if iv is incorrect' do + subject.encrypted_value_iv = nil + subject.instance_variable_set(:@value, nil) + expect { subject.value }.to raise_error + end + end +end diff --git a/spec/models/ci/web_hook_spec.rb b/spec/models/ci/web_hook_spec.rb new file mode 100644 index 00000000000..4211576ce5e --- /dev/null +++ b/spec/models/ci/web_hook_spec.rb @@ -0,0 +1,64 @@ +# == Schema Information +# +# Table name: web_hooks +# +# id :integer not null, primary key +# url :string(255) not null +# project_id :integer not null +# created_at :datetime +# updated_at :datetime +# + +require 'spec_helper' + +describe Ci::WebHook do + describe "Associations" do + it { should belong_to :project } + end + + describe "Validations" do + it { should validate_presence_of(:url) } + + context "url format" do + it { should allow_value("http://example.com").for(:url) } + it { should allow_value("https://excample.com").for(:url) } + it { should allow_value("http://test.com/api").for(:url) } + it { should allow_value("http://test.com/api?key=abc").for(:url) } + it { should allow_value("http://test.com/api?key=abc&type=def").for(:url) } + + it { should_not allow_value("example.com").for(:url) } + it { should_not allow_value("ftp://example.com").for(:url) } + it { should_not allow_value("herp-and-derp").for(:url) } + end + end + + describe "execute" do + before(:each) do + @web_hook = FactoryGirl.create(:web_hook) + @project = @web_hook.project + @data = { before: 'oldrev', after: 'newrev', ref: 'ref'} + + WebMock.stub_request(:post, @web_hook.url) + end + + it "POSTs to the web hook URL" do + @web_hook.execute(@data) + WebMock.should have_requested(:post, @web_hook.url).once + end + + it "POSTs the data as JSON" do + json = @data.to_json + + @web_hook.execute(@data) + WebMock.should have_requested(:post, @web_hook.url).with(body: json).once + end + + it "catches exceptions" do + WebHook.should_receive(:post).and_raise("Some HTTP Post error") + + lambda { + @web_hook.execute(@data) + }.should raise_error + end + end +end diff --git a/spec/requests/ci/api/builds_spec.rb b/spec/requests/ci/api/builds_spec.rb new file mode 100644 index 00000000000..7da212da83a --- /dev/null +++ b/spec/requests/ci/api/builds_spec.rb @@ -0,0 +1,115 @@ +require 'spec_helper' + +describe Ci::API::API do + include ApiHelpers + + let(:runner) { FactoryGirl.create(:runner, tag_list: ["mysql", "ruby"]) } + let(:project) { FactoryGirl.create(:project) } + + describe "Builds API for runners" do + let(:shared_runner) { FactoryGirl.create(:runner, token: "SharedRunner") } + let(:shared_project) { FactoryGirl.create(:project, name: "SharedProject") } + + before do + FactoryGirl.create :runner_project, project_id: project.id, runner_id: runner.id + end + + describe "POST /builds/register" do + it "should start a build" do + commit = FactoryGirl.create(:commit, project: project) + commit.create_builds + build = commit.builds.first + + post api("/builds/register"), token: runner.token, info: {platform: :darwin} + + response.status.should == 201 + json_response['sha'].should == build.sha + runner.reload.platform.should == "darwin" + end + + it "should return 404 error if no pending build found" do + post api("/builds/register"), token: runner.token + + response.status.should == 404 + end + + it "should return 404 error if no builds for specific runner" do + commit = FactoryGirl.create(:commit, project: shared_project) + FactoryGirl.create(:build, commit: commit, status: 'pending' ) + + post api("/builds/register"), token: runner.token + + response.status.should == 404 + end + + it "should return 404 error if no builds for shared runner" do + commit = FactoryGirl.create(:commit, project: project) + FactoryGirl.create(:build, commit: commit, status: 'pending' ) + + post api("/builds/register"), token: shared_runner.token + + response.status.should == 404 + end + + it "returns options" do + commit = FactoryGirl.create(:commit, project: project) + commit.create_builds + + post api("/builds/register"), token: runner.token, info: {platform: :darwin} + + response.status.should == 201 + json_response["options"].should == {"image" => "ruby:2.1", "services" => ["postgres"]} + end + + it "returns variables" do + commit = FactoryGirl.create(:commit, project: project) + commit.create_builds + project.variables << Variable.new(key: "SECRET_KEY", value: "secret_value") + + post api("/builds/register"), token: runner.token, info: {platform: :darwin} + + response.status.should == 201 + json_response["variables"].should == [ + {"key" => "DB_NAME", "value" => "postgres", "public" => true}, + {"key" => "SECRET_KEY", "value" => "secret_value", "public" => false}, + ] + end + + it "returns variables for triggers" do + trigger = FactoryGirl.create(:trigger, project: project) + commit = FactoryGirl.create(:commit, project: project) + + trigger_request = FactoryGirl.create(:trigger_request_with_variables, commit: commit, trigger: trigger) + commit.create_builds(trigger_request) + project.variables << Variable.new(key: "SECRET_KEY", value: "secret_value") + + post api("/builds/register"), token: runner.token, info: {platform: :darwin} + + response.status.should == 201 + json_response["variables"].should == [ + {"key" => "DB_NAME", "value" => "postgres", "public" => true}, + {"key" => "SECRET_KEY", "value" => "secret_value", "public" => false}, + {"key" => "TRIGGER_KEY", "value" => "TRIGGER_VALUE", "public" => false}, + ] + end + end + + describe "PUT /builds/:id" do + let(:commit) { FactoryGirl.create(:commit, project: project)} + let(:build) { FactoryGirl.create(:build, commit: commit, runner_id: runner.id) } + + it "should update a running build" do + build.run! + put api("/builds/#{build.id}"), token: runner.token + response.status.should == 200 + end + + it 'Should not override trace information when no trace is given' do + build.run! + build.update!(trace: 'hello_world') + put api("/builds/#{build.id}"), token: runner.token + expect(build.reload.trace).to eq 'hello_world' + end + end + end +end diff --git a/spec/requests/ci/api/commits_spec.rb b/spec/requests/ci/api/commits_spec.rb new file mode 100644 index 00000000000..99021dd681d --- /dev/null +++ b/spec/requests/ci/api/commits_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe Ci::API::API, 'Commits' do + include ApiHelpers + + let(:project) { FactoryGirl.create(:project) } + let(:commit) { FactoryGirl.create(:commit, project: project) } + + let(:options) { + { + project_token: project.token, + project_id: project.id + } + } + + describe "GET /commits" do + before { commit } + + it "should return commits per project" do + get api("/commits"), options + + response.status.should == 200 + json_response.count.should == 1 + json_response.first["project_id"].should == project.id + json_response.first["sha"].should == commit.sha + end + end + + describe "POST /commits" do + let(:data) { + { + "before" => "95790bf891e76fee5e1747ab589903a6a1f80f22", + "after" => "da1560886d4f094c3e6c9ef40349f7d38b5d27d7", + "ref" => "refs/heads/master", + "commits" => [ + { + "id" => "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "message" => "Update Catalan translation to e38cb41.", + "timestamp" => "2011-12-12T14:27:31+02:00", + "url" => "http://localhost/diaspora/commits/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327", + "author" => { + "name" => "Jordi Mallach", + "email" => "jordi@softcatala.org", + } + } + ], + ci_yaml_file: gitlab_ci_yaml + } + } + + it "should create a build" do + post api("/commits"), options.merge(data: data) + + response.status.should == 201 + json_response['sha'].should == "da1560886d4f094c3e6c9ef40349f7d38b5d27d7" + end + + it "should return 400 error if no data passed" do + post api("/commits"), options + + response.status.should == 400 + json_response['message'].should == "400 (Bad request) \"data\" not given" + end + end +end diff --git a/spec/requests/ci/api/forks_spec.rb b/spec/requests/ci/api/forks_spec.rb new file mode 100644 index 00000000000..74efc0c30be --- /dev/null +++ b/spec/requests/ci/api/forks_spec.rb @@ -0,0 +1,60 @@ +require 'spec_helper' + +describe Ci::API::API do + include ApiHelpers + + let(:project) { FactoryGirl.create(:project) } + let(:gitlab_url) { GitlabCi.config.gitlab_server.url } + let(:private_token) { Network.new.authenticate(access_token: "some_token")["private_token"] } + + let(:options) { + { + private_token: private_token, + url: gitlab_url + } + } + + before { + stub_gitlab_calls + } + + + describe "POST /forks" do + let(:project_info) { + { + project_id: project.gitlab_id, + project_token: project.token, + data: { + id: 2, + name_with_namespace: "Gitlab.org / Underscore", + path_with_namespace: "gitlab-org/underscore", + default_branch: "master", + ssh_url_to_repo: "git@example.com:gitlab-org/underscore" + } + } + } + + context "with valid info" do + before do + options.merge!(project_info) + end + + it "should create a project with valid data" do + post api("/forks"), options + response.status.should == 201 + json_response['name'].should == "Gitlab.org / Underscore" + end + end + + context "with invalid project info" do + before do + options.merge!({}) + end + + it "should error with invalid data" do + post api("/forks"), options + response.status.should == 400 + end + end + end +end diff --git a/spec/requests/ci/api/projects_spec.rb b/spec/requests/ci/api/projects_spec.rb new file mode 100644 index 00000000000..65cfc909b48 --- /dev/null +++ b/spec/requests/ci/api/projects_spec.rb @@ -0,0 +1,251 @@ +require 'spec_helper' + +describe Ci::API::API do + include ApiHelpers + + let(:gitlab_url) { GitlabCi.config.gitlab_server.url } + let(:private_token) { Network.new.authenticate(access_token: "some_token")["private_token"] } + + let(:options) { + { + private_token: private_token, + url: gitlab_url + } + } + + before { + stub_gitlab_calls + } + + context "requests for scoped projects" do + # NOTE: These ids are tied to the actual projects on demo.gitlab.com + describe "GET /projects" do + let!(:project1) { FactoryGirl.create(:project, name: "gitlabhq", gitlab_id: 3) } + let!(:project2) { FactoryGirl.create(:project, name: "gitlab-ci", gitlab_id: 4) } + + it "should return all projects on the CI instance" do + get api("/projects"), options + response.status.should == 200 + json_response.count.should == 2 + json_response.first["id"].should == project1.id + json_response.last["id"].should == project2.id + end + end + + describe "GET /projects/owned" do + # NOTE: This user doesn't own any of these projects on demo.gitlab.com + let!(:project1) { FactoryGirl.create(:project, name: "gitlabhq", gitlab_id: 3) } + let!(:project2) { FactoryGirl.create(:project, name: "random-project", gitlab_id: 9898) } + + it "should return all projects on the CI instance" do + get api("/projects/owned"), options + + response.status.should == 200 + json_response.count.should == 0 + end + end + end + + describe "POST /projects/:project_id/webhooks" do + let!(:project) { FactoryGirl.create(:project) } + + context "Valid Webhook URL" do + let!(:webhook) { {web_hook: "http://example.com/sth/1/ala_ma_kota" } } + + before do + options.merge!(webhook) + end + + it "should create webhook for specified project" do + post api("/projects/#{project.id}/webhooks"), options + response.status.should == 201 + json_response["url"].should == webhook[:web_hook] + end + + it "fails to create webhook for non existsing project" do + post api("/projects/non-existant-id/webhooks"), options + response.status.should == 404 + end + + it "non-manager is not authorized" do + User.any_instance.stub(:can_manage_project?).and_return(false) + post api("/projects/#{project.id}/webhooks"), options + response.status.should == 401 + end + end + + context "Invalid Webhook URL" do + let!(:webhook) { {web_hook: "ala_ma_kota" } } + + before do + options.merge!(webhook) + end + + it "fails to create webhook for not valid url" do + post api("/projects/#{project.id}/webhooks"), options + response.status.should == 400 + end + end + + context "Missed web_hook parameter" do + it "fails to create webhook for not provided url" do + post api("/projects/#{project.id}/webhooks"), options + response.status.should == 400 + end + end + end + + describe "GET /projects/:id" do + let!(:project) { FactoryGirl.create(:project) } + + context "with an existing project" do + it "should retrieve the project info" do + get api("/projects/#{project.id}"), options + response.status.should == 200 + json_response['id'].should == project.id + end + end + + context "with a non-existing project" do + it "should return 404 error if project not found" do + get api("/projects/non_existent_id"), options + response.status.should == 404 + end + end + end + + describe "PUT /projects/:id" do + let!(:project) { FactoryGirl.create(:project) } + let!(:project_info) { {name: "An updated name!" } } + + before do + options.merge!(project_info) + end + + it "should update a specific project's information" do + put api("/projects/#{project.id}"), options + response.status.should == 200 + json_response["name"].should == project_info[:name] + end + + it "fails to update a non-existing project" do + put api("/projects/non-existant-id"), options + response.status.should == 404 + end + + it "non-manager is not authorized" do + User.any_instance.stub(:can_manage_project?).and_return(false) + put api("/projects/#{project.id}"), options + response.status.should == 401 + end + end + + describe "DELETE /projects/:id" do + let!(:project) { FactoryGirl.create(:project) } + + it "should delete a specific project" do + delete api("/projects/#{project.id}"), options + response.status.should == 200 + + expect { project.reload }.to raise_error + end + + it "non-manager is not authorized" do + User.any_instance.stub(:can_manage_project?).and_return(false) + delete api("/projects/#{project.id}"), options + response.status.should == 401 + end + + it "is getting not found error" do + delete api("/projects/not-existing_id"), options + response.status.should == 404 + end + end + + describe "POST /projects" do + let(:project_info) { + { + name: "My project", + gitlab_id: 1, + path: "testing/testing", + ssh_url_to_repo: "ssh://example.com/testing/testing.git" + } + } + + let(:invalid_project_info) { {} } + + context "with valid project info" do + before do + options.merge!(project_info) + end + + it "should create a project with valid data" do + post api("/projects"), options + response.status.should == 201 + json_response['name'].should == project_info[:name] + end + end + + context "with invalid project info" do + before do + options.merge!(invalid_project_info) + end + + it "should error with invalid data" do + post api("/projects"), options + response.status.should == 400 + end + end + + describe "POST /projects/:id/runners/:id" do + let(:project) { FactoryGirl.create(:project) } + let(:runner) { FactoryGirl.create(:runner) } + + it "should add the project to the runner" do + post api("/projects/#{project.id}/runners/#{runner.id}"), options + response.status.should == 201 + + project.reload + project.runners.first.id.should == runner.id + end + + it "should fail if it tries to link a non-existing project or runner" do + post api("/projects/#{project.id}/runners/non-existing"), options + response.status.should == 404 + + post api("/projects/non-existing/runners/#{runner.id}"), options + response.status.should == 404 + end + + it "non-manager is not authorized" do + User.any_instance.stub(:can_manage_project?).and_return(false) + post api("/projects/#{project.id}/runners/#{runner.id}"), options + response.status.should == 401 + end + end + + describe "DELETE /projects/:id/runners/:id" do + let(:project) { FactoryGirl.create(:project) } + let(:runner) { FactoryGirl.create(:runner) } + + before do + post api("/projects/#{project.id}/runners/#{runner.id}"), options + end + + it "should remove the project from the runner" do + project.runners.should be_present + delete api("/projects/#{project.id}/runners/#{runner.id}"), options + response.status.should == 200 + + project.reload + project.runners.should be_empty + end + + it "non-manager is not authorized" do + User.any_instance.stub(:can_manage_project?).and_return(false) + post api("/projects/#{project.id}/runners/#{runner.id}"), options + response.status.should == 401 + end + end + end +end diff --git a/spec/requests/ci/api/runners_spec.rb b/spec/requests/ci/api/runners_spec.rb new file mode 100644 index 00000000000..3faebd40bae --- /dev/null +++ b/spec/requests/ci/api/runners_spec.rb @@ -0,0 +1,83 @@ +require 'spec_helper' + +describe Ci::API::API do + include ApiHelpers + include StubGitlabCalls + + before { + stub_gitlab_calls + } + + describe "GET /runners" do + let(:gitlab_url) { GitlabCi.config.gitlab_server.url } + let(:private_token) { Network.new.authenticate(access_token: "some_token")["private_token"] } + let(:options) { + { + :private_token => private_token, + :url => gitlab_url + } + } + + before do + 5.times { FactoryGirl.create(:runner) } + end + + it "should retrieve a list of all runners" do + get api("/runners"), options + response.status.should == 200 + json_response.count.should == 5 + json_response.last.should have_key("id") + json_response.last.should have_key("token") + end + end + + describe "POST /runners/register" do + describe "should create a runner if token provided" do + before { post api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN } + + it { response.status.should == 201 } + end + + describe "should create a runner with description" do + before { post api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, description: "server.hostname" } + + it { response.status.should == 201 } + it { Runner.first.description.should == "server.hostname" } + end + + describe "should create a runner with tags" do + before { post api("/runners/register"), token: GitlabCi::REGISTRATION_TOKEN, tag_list: "tag1, tag2" } + + it { response.status.should == 201 } + it { Runner.first.tag_list.sort.should == ["tag1", "tag2"] } + end + + describe "should create a runner if project token provided" do + let(:project) { FactoryGirl.create(:project) } + before { post api("/runners/register"), token: project.token } + + it { response.status.should == 201 } + it { project.runners.size.should == 1 } + end + + it "should return 403 error if token is invalid" do + post api("/runners/register"), token: 'invalid' + + response.status.should == 403 + end + + it "should return 400 error if no token" do + post api("/runners/register") + + response.status.should == 400 + end + end + + describe "DELETE /runners/delete" do + let!(:runner) { FactoryGirl.create(:runner) } + before { delete api("/runners/delete"), token: runner.token } + + it { response.status.should == 200 } + it { Runner.count.should == 0 } + end +end diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb new file mode 100644 index 00000000000..5da40a69991 --- /dev/null +++ b/spec/requests/ci/api/triggers_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' + +describe Ci::API::API do + include ApiHelpers + + describe 'POST /projects/:project_id/refs/:ref/trigger' do + let!(:trigger_token) { 'secure token' } + let!(:project) { FactoryGirl.create(:project) } + let!(:project2) { FactoryGirl.create(:project) } + let!(:trigger) { FactoryGirl.create(:trigger, project: project, token: trigger_token) } + let(:options) { + { + token: trigger_token + } + } + + context 'Handles errors' do + it 'should return bad request if token is missing' do + post api("/projects/#{project.id}/refs/master/trigger") + response.status.should == 400 + end + + it 'should return not found if project is not found' do + post api('/projects/0/refs/master/trigger'), options + response.status.should == 404 + end + + it 'should return unauthorized if token is for different project' do + post api("/projects/#{project2.id}/refs/master/trigger"), options + response.status.should == 401 + end + end + + context 'Have a commit' do + before do + @commit = FactoryGirl.create(:commit, project: project) + end + + it 'should create builds' do + post api("/projects/#{project.id}/refs/master/trigger"), options + response.status.should == 201 + @commit.builds.reload + @commit.builds.size.should == 2 + end + + it 'should return bad request with no builds created if there\'s no commit for that ref' do + post api("/projects/#{project.id}/refs/other-branch/trigger"), options + response.status.should == 400 + json_response['message'].should == 'No builds created' + end + + context 'Validates variables' do + let(:variables) { + {'TRIGGER_KEY' => 'TRIGGER_VALUE'} + } + + it 'should validate variables to be a hash' do + post api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: 'value') + response.status.should == 400 + json_response['message'].should == 'variables needs to be a hash' + end + + it 'should validate variables needs to be a map of key-valued strings' do + post api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: {key: %w(1 2)}) + response.status.should == 400 + json_response['message'].should == 'variables needs to be a map of key-valued strings' + end + + it 'create trigger request with variables' do + post api("/projects/#{project.id}/refs/master/trigger"), options.merge(variables: variables) + response.status.should == 201 + @commit.builds.reload + @commit.builds.first.trigger_request.variables.should == variables + end + end + end + end +end diff --git a/spec/requests/ci/builds_spec.rb b/spec/requests/ci/builds_spec.rb new file mode 100644 index 00000000000..73d540e372a --- /dev/null +++ b/spec/requests/ci/builds_spec.rb @@ -0,0 +1,18 @@ +require 'spec_helper' + +describe "Builds" do + before do + @project = FactoryGirl.create :project + @commit = FactoryGirl.create :commit, project: @project + @build = FactoryGirl.create :build, commit: @commit + end + + describe "GET /:project/builds/:id/status.json" do + before do + get status_project_build_path(@project, @build), format: :json + end + + it { response.status.should == 200 } + it { response.body.should include(@build.sha) } + end +end diff --git a/spec/requests/ci/commits_spec.rb b/spec/requests/ci/commits_spec.rb new file mode 100644 index 00000000000..e9d8366c41a --- /dev/null +++ b/spec/requests/ci/commits_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe "Commits" do + before do + @project = FactoryGirl.create :project + @commit = FactoryGirl.create :commit, project: @project + end + + describe "GET /:project/refs/:ref_name/commits/:id/status.json" do + before do + get status_project_ref_commit_path(@project, @commit.ref, @commit.sha), format: :json + end + + it { response.status.should == 200 } + it { response.body.should include(@commit.sha) } + end +end diff --git a/spec/services/ci/create_commit_service_spec.rb b/spec/services/ci/create_commit_service_spec.rb new file mode 100644 index 00000000000..34e00d5b3c0 --- /dev/null +++ b/spec/services/ci/create_commit_service_spec.rb @@ -0,0 +1,130 @@ +require 'spec_helper' + +describe CreateCommitService do + let(:service) { CreateCommitService.new } + let(:project) { FactoryGirl.create(:project) } + + describe :execute do + context 'valid params' do + let(:commit) do + service.execute(project, + ref: 'refs/heads/master', + before: '00000000', + after: '31das312', + ci_yaml_file: gitlab_ci_yaml, + commits: [ { message: "Message" } ] + ) + end + + it { commit.should be_kind_of(Commit) } + it { commit.should be_valid } + it { commit.should be_persisted } + it { commit.should == project.commits.last } + it { commit.builds.first.should be_kind_of(Build) } + end + + context "skip tag if there is no build for it" do + it "creates commit if there is appropriate job" do + result = service.execute(project, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + ci_yaml_file: gitlab_ci_yaml, + commits: [ { message: "Message" } ] + ) + result.should be_persisted + end + + it "creates commit if there is no appropriate job but deploy job has right ref setting" do + config = YAML.dump({deploy: {deploy: "ls", only: ["0_1"]}}) + + result = service.execute(project, + ref: 'refs/heads/0_1', + before: '00000000', + after: '31das312', + ci_yaml_file: config, + commits: [ { message: "Message" } ] + ) + result.should be_persisted + end + end + + describe :ci_skip? do + it "skips builds creation if there is [ci skip] tag in commit message" do + commits = [{message: "some message[ci skip]"}] + commit = service.execute(project, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits, + ci_yaml_file: gitlab_ci_yaml + ) + commit.builds.any?.should be_false + commit.status.should == "skipped" + end + + it "does not skips builds creation if there is no [ci skip] tag in commit message" do + commits = [{message: "some message"}] + + commit = service.execute(project, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits, + ci_yaml_file: gitlab_ci_yaml + ) + + commit.builds.first.name.should == "staging" + end + + it "skips builds creation if there is [ci skip] tag in commit message and yaml is invalid" do + commits = [{message: "some message[ci skip]"}] + commit = service.execute(project, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits, + ci_yaml_file: "invalid: file" + ) + commit.builds.any?.should be_false + commit.status.should == "skipped" + end + end + + it "skips build creation if there are already builds" do + commits = [{message: "message"}] + commit = service.execute(project, + ref: 'refs/heads/master', + before: '00000000', + after: '31das312', + commits: commits, + ci_yaml_file: gitlab_ci_yaml + ) + commit.builds.count(:all).should == 2 + + commit = service.execute(project, + ref: 'refs/heads/master', + before: '00000000', + after: '31das312', + commits: commits, + ci_yaml_file: gitlab_ci_yaml + ) + commit.builds.count(:all).should == 2 + end + + it "creates commit with failed status if yaml is invalid" do + commits = [{message: "some message"}] + + commit = service.execute(project, + ref: 'refs/tags/0_1', + before: '00000000', + after: '31das312', + commits: commits, + ci_yaml_file: "invalid: file" + ) + + commit.status.should == "failed" + commit.builds.any?.should be_false + end + end +end diff --git a/spec/services/ci/create_project_service_spec.rb b/spec/services/ci/create_project_service_spec.rb new file mode 100644 index 00000000000..31614968d55 --- /dev/null +++ b/spec/services/ci/create_project_service_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe CreateProjectService do + let(:service) { CreateProjectService.new } + let(:current_user) { double.as_null_object } + let(:project_dump) { YAML.load File.read(Rails.root.join('spec/support/gitlab_stubs/raw_project.yml')) } + + before { Network.any_instance.stub(enable_ci: true) } + + describe :execute do + context 'valid params' do + let(:project) { service.execute(current_user, project_dump, 'http://localhost/projects/:project_id') } + + it { project.should be_kind_of(Project) } + it { project.should be_persisted } + end + + context 'without project dump' do + it 'should raise exception' do + expect { service.execute(current_user, '', '') }.to raise_error + end + end + + context "forking" do + it "uses project as a template for settings and jobs" do + origin_project = FactoryGirl.create(:project) + origin_project.shared_runners_enabled = true + origin_project.public = true + origin_project.allow_git_fetch = true + origin_project.save! + + project = service.execute(current_user, project_dump, 'http://localhost/projects/:project_id', origin_project) + + project.shared_runners_enabled.should be_true + project.public.should be_true + project.allow_git_fetch.should be_true + end + end + end +end diff --git a/spec/services/ci/create_trigger_request_service_spec.rb b/spec/services/ci/create_trigger_request_service_spec.rb new file mode 100644 index 00000000000..41db01c2235 --- /dev/null +++ b/spec/services/ci/create_trigger_request_service_spec.rb @@ -0,0 +1,52 @@ +require 'spec_helper' + +describe CreateTriggerRequestService do + let(:service) { CreateTriggerRequestService.new } + let(:project) { FactoryGirl.create :project } + let(:trigger) { FactoryGirl.create :trigger, project: project } + + describe :execute do + context 'valid params' do + subject { service.execute(project, trigger, 'master') } + + before do + @commit = FactoryGirl.create :commit, project: project + end + + it { subject.should be_kind_of(TriggerRequest) } + it { subject.commit.should == @commit } + end + + context 'no commit for ref' do + subject { service.execute(project, trigger, 'other-branch') } + + it { subject.should be_nil } + end + + context 'no builds created' do + subject { service.execute(project, trigger, 'master') } + + before do + FactoryGirl.create :commit_without_jobs, project: project + end + + it { subject.should be_nil } + end + + context 'for multiple commits' do + subject { service.execute(project, trigger, 'master') } + + before do + @commit1 = FactoryGirl.create :commit, committed_at: 2.hour.ago, project: project + @commit2 = FactoryGirl.create :commit, committed_at: 1.hour.ago, project: project + @commit3 = FactoryGirl.create :commit, committed_at: 3.hour.ago, project: project + end + + context 'retries latest one' do + it { subject.should be_kind_of(TriggerRequest) } + it { subject.should be_persisted } + it { subject.commit.should == @commit2 } + end + end + end +end diff --git a/spec/services/ci/event_service_spec.rb b/spec/services/ci/event_service_spec.rb new file mode 100644 index 00000000000..f7b9bf58127 --- /dev/null +++ b/spec/services/ci/event_service_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe EventService do + let (:project) { FactoryGirl.create :project, name: "GitLab / gitlab-shell" } + let (:user) { double(username: "root", id: 1) } + + before do + Event.destroy_all + end + + describe :remove_project do + it "creates event" do + EventService.new.remove_project(user, project) + + Event.admin.last.description.should == "Project \"GitLab / gitlab-shell\" has been removed by root" + end + end + + describe :create_project do + it "creates event" do + EventService.new.create_project(user, project) + + Event.admin.last.description.should == "Project \"GitLab / gitlab-shell\" has been created by root" + end + end + + describe :change_project_settings do + it "creates event" do + EventService.new.change_project_settings(user, project) + + Event.last.description.should == "User \"root\" updated projects settings" + end + end +end \ No newline at end of file diff --git a/spec/services/ci/image_for_build_service_spec.rb b/spec/services/ci/image_for_build_service_spec.rb new file mode 100644 index 00000000000..4c7094146bb --- /dev/null +++ b/spec/services/ci/image_for_build_service_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe ImageForBuildService do + let(:service) { ImageForBuildService.new } + let(:project) { FactoryGirl.create(:project) } + let(:commit) { FactoryGirl.create(:commit, project: project, ref: 'master') } + let(:build) { FactoryGirl.create(:build, commit: commit) } + + describe :execute do + before { build } + + context 'branch name' do + before { build.run! } + let(:image) { service.execute(project, ref: 'master') } + + it { image.should be_kind_of(OpenStruct) } + it { image.path.to_s.should include('public/build-running.svg') } + it { image.name.should == 'build-running.svg' } + end + + context 'unknown branch name' do + let(:image) { service.execute(project, ref: 'feature') } + + it { image.should be_kind_of(OpenStruct) } + it { image.path.to_s.should include('public/build-unknown.svg') } + it { image.name.should == 'build-unknown.svg' } + end + + context 'commit sha' do + before { build.run! } + let(:image) { service.execute(project, sha: build.sha) } + + it { image.should be_kind_of(OpenStruct) } + it { image.path.to_s.should include('public/build-running.svg') } + it { image.name.should == 'build-running.svg' } + end + + context 'unknown commit sha' do + let(:image) { service.execute(project, sha: '0000000') } + + it { image.should be_kind_of(OpenStruct) } + it { image.path.to_s.should include('public/build-unknown.svg') } + it { image.name.should == 'build-unknown.svg' } + end + end +end diff --git a/spec/services/ci/register_build_service_spec.rb b/spec/services/ci/register_build_service_spec.rb new file mode 100644 index 00000000000..b5af777dd1d --- /dev/null +++ b/spec/services/ci/register_build_service_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe RegisterBuildService do + let!(:service) { RegisterBuildService.new } + let!(:project) { FactoryGirl.create :project } + let!(:commit) { FactoryGirl.create :commit, project: project } + let!(:pending_build) { FactoryGirl.create :build, project: project, commit: commit } + let!(:shared_runner) { FactoryGirl.create(:runner, is_shared: true) } + let!(:specific_runner) { FactoryGirl.create(:runner, is_shared: false) } + + before do + specific_runner.assign_to(project) + end + + describe :execute do + context 'runner follow tag list' do + it "picks build with the same tag" do + pending_build.tag_list = ["linux"] + pending_build.save + specific_runner.tag_list = ["linux"] + service.execute(specific_runner).should == pending_build + end + + it "does not pick build with different tag" do + pending_build.tag_list = ["linux"] + pending_build.save + specific_runner.tag_list = ["win32"] + service.execute(specific_runner).should be_false + end + + it "picks build without tag" do + service.execute(specific_runner).should == pending_build + end + + it "does not pick build with tag" do + pending_build.tag_list = ["linux"] + pending_build.save + service.execute(specific_runner).should be_false + end + + it "pick build without tag" do + specific_runner.tag_list = ["win32"] + service.execute(specific_runner).should == pending_build + end + end + + context 'allow shared runners' do + before do + project.shared_runners_enabled = true + project.save + end + + context 'shared runner' do + let(:build) { service.execute(shared_runner) } + + it { build.should be_kind_of(Build) } + it { build.should be_valid } + it { build.should be_running } + it { build.runner.should == shared_runner } + end + + context 'specific runner' do + let(:build) { service.execute(specific_runner) } + + it { build.should be_kind_of(Build) } + it { build.should be_valid } + it { build.should be_running } + it { build.runner.should == specific_runner } + end + end + + context 'disallow shared runners' do + context 'shared runner' do + let(:build) { service.execute(shared_runner) } + + it { build.should be_nil } + end + + context 'specific runner' do + let(:build) { service.execute(specific_runner) } + + it { build.should be_kind_of(Build) } + it { build.should be_valid } + it { build.should be_running } + it { build.runner.should == specific_runner } + end + end + end +end diff --git a/spec/services/ci/web_hook_service_spec.rb b/spec/services/ci/web_hook_service_spec.rb new file mode 100644 index 00000000000..2bb153942e8 --- /dev/null +++ b/spec/services/ci/web_hook_service_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe WebHookService do + let (:project) { FactoryGirl.create :project } + let (:commit) { FactoryGirl.create :commit, project: project } + let (:build) { FactoryGirl.create :build, commit: commit } + let (:hook) { FactoryGirl.create :web_hook, project: project } + + describe :execute do + it "should execute successfully" do + stub_request(:post, hook.url).to_return(status: 200) + WebHookService.new.build_end(build).should be_true + end + end + + context 'build_data' do + it "contains all needed fields" do + build_data(build).should include( + :build_id, + :project_id, + :ref, + :build_status, + :build_started_at, + :build_finished_at, + :before_sha, + :project_name, + :gitlab_url, + :build_name + ) + end + end + + def build_data(build) + WebHookService.new.send :build_data, build + end +end -- cgit v1.2.1