summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
Diffstat (limited to 'spec')
-rw-r--r--spec/features/admin/admin_groups_spec.rb35
-rw-r--r--spec/features/merge_requests/diff_notes_resolve_spec.rb2
-rw-r--r--spec/features/merge_requests/merge_when_build_succeeds_spec.rb4
-rw-r--r--spec/features/projects/commits/cherry_pick_spec.rb2
-rw-r--r--spec/features/projects/pipelines_spec.rb3
-rw-r--r--spec/finders/group_projects_finder_spec.rb5
-rw-r--r--spec/fixtures/emails/outlook_html.eml140
-rw-r--r--spec/helpers/application_helper_spec.rb4
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb2
-rw-r--r--spec/javascripts/build_spec.js.es615
-rw-r--r--spec/javascripts/fixtures/build.html.haml5
-rw-r--r--spec/lib/gitlab/chat_commands/command_spec.rb55
-rw-r--r--spec/lib/gitlab/chat_commands/issue_create_spec.rb52
-rw-r--r--spec/lib/gitlab/chat_commands/issue_show_spec.rb40
-rw-r--r--spec/lib/gitlab/cycle_analytics/code_event_spec.rb10
-rw-r--r--spec/lib/gitlab/cycle_analytics/events_spec.rb326
-rw-r--r--spec/lib/gitlab/cycle_analytics/issue_event_spec.rb10
-rw-r--r--spec/lib/gitlab/cycle_analytics/plan_event_spec.rb10
-rw-r--r--spec/lib/gitlab/cycle_analytics/production_event_spec.rb10
-rw-r--r--spec/lib/gitlab/cycle_analytics/review_event_spec.rb10
-rw-r--r--spec/lib/gitlab/cycle_analytics/shared_event_spec.rb21
-rw-r--r--spec/lib/gitlab/cycle_analytics/staging_event_spec.rb10
-rw-r--r--spec/lib/gitlab/cycle_analytics/test_event_spec.rb10
-rw-r--r--spec/lib/gitlab/cycle_analytics/updater_spec.rb25
-rw-r--r--spec/lib/gitlab/email/reply_parser_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/all_models.yml4
-rw-r--r--spec/lib/gitlab/middleware/go_spec.rb2
-rw-r--r--spec/lib/light_url_builder_spec.rb119
-rw-r--r--spec/mailers/emails/profile_spec.rb2
-rw-r--r--spec/models/build_spec.rb128
-rw-r--r--spec/models/ci/build_spec.rb6
-rw-r--r--spec/models/key_spec.rb2
-rw-r--r--spec/models/member_spec.rb22
-rw-r--r--spec/models/project_group_link_spec.rb16
-rw-r--r--spec/models/project_services/chat_service_spec.rb15
-rw-r--r--spec/models/project_services/gitlab_issue_tracker_service_spec.rb6
-rw-r--r--spec/models/project_services/jira_service_spec.rb44
-rw-r--r--spec/models/project_services/mattermost_slash_commands_service_spec.rb99
-rw-r--r--spec/models/project_services/slack_service/pipeline_message_spec.rb4
-rw-r--r--spec/models/project_spec.rb12
-rw-r--r--spec/models/repository_spec.rb22
-rw-r--r--spec/models/user_spec.rb76
-rw-r--r--spec/requests/api/internal_spec.rb4
-rw-r--r--spec/requests/api/services_spec.rb57
-rw-r--r--spec/requests/projects/cycle_analytics_events_spec.rb140
-rw-r--r--spec/serializers/analytics_build_entity_spec.rb27
-rw-r--r--spec/serializers/analytics_build_serializer_spec.rb22
-rw-r--r--spec/serializers/analytics_generic_entity_spec.rb39
-rw-r--r--spec/serializers/analytics_issue_serializer_spec.rb33
-rw-r--r--spec/serializers/analytics_merge_request_serializer_spec.rb34
-rw-r--r--spec/serializers/entity_date_helper_spec.rb45
-rw-r--r--spec/services/chat_names/find_user_service_spec.rb2
-rw-r--r--spec/services/destroy_group_service_spec.rb40
-rw-r--r--spec/services/git_push_service_spec.rb12
-rw-r--r--spec/services/merge_requests/get_urls_service_spec.rb6
-rw-r--r--spec/services/merge_requests/merge_service_spec.rb6
-rw-r--r--spec/services/projects/create_service_spec.rb3
-rw-r--r--spec/services/system_note_service_spec.rb45
-rw-r--r--spec/spec_helper.rb7
-rw-r--r--spec/support/database_connection_helpers.rb9
-rw-r--r--spec/support/db_cleaner.rb4
-rw-r--r--spec/support/jira_service_helper.rb5
-rw-r--r--spec/views/projects/builds/show.html.haml_spec.rb133
-rw-r--r--spec/workers/authorized_projects_worker_spec.rb22
-rw-r--r--spec/workers/pipeline_metrics_worker_spec.rb18
65 files changed, 2052 insertions, 50 deletions
diff --git a/spec/features/admin/admin_groups_spec.rb b/spec/features/admin/admin_groups_spec.rb
new file mode 100644
index 00000000000..f6d625fa7f6
--- /dev/null
+++ b/spec/features/admin/admin_groups_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+
+feature 'Admin Groups', feature: true do
+ let(:internal) { Gitlab::VisibilityLevel::INTERNAL }
+
+ before do
+ login_as(:admin)
+
+ stub_application_setting(default_group_visibility: internal)
+ end
+
+ describe 'create a group' do
+ scenario 'shows the visibility level radio populated with the default value' do
+ visit new_admin_group_path
+
+ expect_selected_visibility(internal)
+ end
+ end
+
+ describe 'group edit' do
+ scenario 'shows the visibility level radio populated with the group visibility_level value' do
+ group = create(:group, :private)
+
+ visit edit_admin_group_path(group)
+
+ expect_selected_visibility(group.visibility_level)
+ end
+ end
+
+ def expect_selected_visibility(level)
+ selector = "#group_visibility_level_#{level}[checked=checked]"
+
+ expect(page).to have_selector(selector, count: 1)
+ end
+end
diff --git a/spec/features/merge_requests/diff_notes_resolve_spec.rb b/spec/features/merge_requests/diff_notes_resolve_spec.rb
index d5e3d8e7eff..eab64bd4b54 100644
--- a/spec/features/merge_requests/diff_notes_resolve_spec.rb
+++ b/spec/features/merge_requests/diff_notes_resolve_spec.rb
@@ -201,7 +201,7 @@ feature 'Diff notes resolve', feature: true, js: true do
expect(first('.line-resolve-btn')['data-original-title']).to eq("Resolved by #{user.name}")
end
- expect(page).to have_content('Last updated')
+ expect(page).not_to have_content('Last updated')
page.within '.line-resolve-all-container' do
expect(page).to have_content('0/1 discussion resolved')
diff --git a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
index c3c3ab33872..8eceaad2457 100644
--- a/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
+++ b/spec/features/merge_requests/merge_when_build_succeeds_spec.rb
@@ -73,7 +73,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
expect(page).to have_button "Merge When Build Succeeds"
visit_merge_request(merge_request) # refresh the page
- expect(page).to have_content "Canceled the automatic merge"
+ expect(page).to have_content "canceled the automatic merge"
end
it "allows the user to remove the source branch" do
@@ -101,7 +101,7 @@ feature 'Merge When Build Succeeds', feature: true, js: true do
expect(page).not_to have_link "Merge When Build Succeeds"
end
end
-
+
def visit_merge_request(merge_request)
visit namespace_project_merge_request_path(merge_request.project.namespace, merge_request.project, merge_request)
end
diff --git a/spec/features/projects/commits/cherry_pick_spec.rb b/spec/features/projects/commits/cherry_pick_spec.rb
index e45e3a36d01..d46d9e9399e 100644
--- a/spec/features/projects/commits/cherry_pick_spec.rb
+++ b/spec/features/projects/commits/cherry_pick_spec.rb
@@ -64,7 +64,7 @@ describe 'Cherry-pick Commits' do
context "I cherry-pick a commit from a different branch", js: true do
it do
- find('.commit-action-buttons a.dropdown-toggle').click
+ find('.header-action-buttons a.dropdown-toggle').click
find(:css, "a[href='#modal-cherry-pick-commit']").click
page.within('#modal-cherry-pick-commit') do
diff --git a/spec/features/projects/pipelines_spec.rb b/spec/features/projects/pipelines_spec.rb
index db56a50e058..002c6f6b359 100644
--- a/spec/features/projects/pipelines_spec.rb
+++ b/spec/features/projects/pipelines_spec.rb
@@ -146,7 +146,8 @@ describe "Pipelines" do
end
describe 'GET /:project/pipelines/:id' do
- let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
+ let(:project) { create(:project) }
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master', sha: project.commit.id) }
before do
@success = create(:ci_build, :success, pipeline: pipeline, stage: 'build', name: 'build')
diff --git a/spec/finders/group_projects_finder_spec.rb b/spec/finders/group_projects_finder_spec.rb
index fbe09b28b3c..00eec3f3f4c 100644
--- a/spec/finders/group_projects_finder_spec.rb
+++ b/spec/finders/group_projects_finder_spec.rb
@@ -38,7 +38,10 @@ describe GroupProjectsFinder do
end
describe 'without group member current_user' do
- before { shared_project_2.team << [current_user, Gitlab::Access::MASTER] }
+ before do
+ shared_project_2.team << [current_user, Gitlab::Access::MASTER]
+ current_user.reload
+ end
context "only shared" do
context "without external user" do
diff --git a/spec/fixtures/emails/outlook_html.eml b/spec/fixtures/emails/outlook_html.eml
new file mode 100644
index 00000000000..506d69efe83
--- /dev/null
+++ b/spec/fixtures/emails/outlook_html.eml
@@ -0,0 +1,140 @@
+
+MIME-Version: 1.0
+Received: by 10.25.161.144 with HTTP; Tue, 7 Oct 2014 22:17:17 -0700 (PDT)
+X-Originating-IP: [117.207.85.84]
+In-Reply-To: <5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
+References: <topic/35@discourse.techapj.com>
+ <5434c8b52bb3a_623ff09fec70f049749@discourse-app.mail>
+Date: Wed, 8 Oct 2014 10:47:17 +0530
+Delivered-To: arpit@techapj.com
+Message-ID: <CAOJeqne=SJ_LwN4sb-0Y95ejc2OpreVhdmcPn0TnmwSvTCYzzQ@mail.gmail.com>
+Subject: Re: [Discourse] [Meta] Welcome to techAPJ's Discourse!
+From: Arpit Jalan <arpit@techapj.com>
+To: Discourse <mail+e1c7f2a380e33840aeb654f075490bad@arpitjalan.com>Accept-Language: en-US
+Content-Language: en-US
+X-MS-Has-Attach:
+X-MS-TNEF-Correlator:
+x-originating-ip: [134.68.31.227]
+Content-Type: multipart/alternative;
+ boundary="_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_"
+MIME-Version: 1.0
+
+--_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: base64
+
+PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy
+bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt
+YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj
+cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv
+VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg
+Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv
+ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTQgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPCEtLVtp
+ZiAhbXNvXT48c3R5bGU+dlw6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kb1w6KiB7
+YmVoYXZpb3I6dXJsKCNkZWZhdWx0I1ZNTCk7fQ0Kd1w6KiB7YmVoYXZpb3I6dXJsKCNkZWZhdWx0
+I1ZNTCk7fQ0KLnNoYXBlIHtiZWhhdmlvcjp1cmwoI2RlZmF1bHQjVk1MKTt9DQo8L3N0eWxlPjwh
+W2VuZGlmXS0tPjxzdHlsZT48IS0tDQovKiBGb250IERlZmluaXRpb25zICovDQpAZm9udC1mYWNl
+DQoJe2ZvbnQtZmFtaWx5OkNhbGlicmk7DQoJcGFub3NlLTE6MiAxNSA1IDIgMiAyIDQgMyAyIDQ7
+fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpUYWhvbWE7DQoJcGFub3NlLTE6MiAxMSA2IDQg
+MyA1IDQgNCAyIDQ7fQ0KLyogU3R5bGUgRGVmaW5pdGlvbnMgKi8NCnAuTXNvTm9ybWFsLCBsaS5N
+c29Ob3JtYWwsIGRpdi5Nc29Ob3JtYWwNCgl7bWFyZ2luOjBpbjsNCgltYXJnaW4tYm90dG9tOi4w
+MDAxcHQ7DQoJZm9udC1zaXplOjEyLjBwdDsNCglmb250LWZhbWlseToiVGltZXMgTmV3IFJvbWFu
+Iiwic2VyaWYiO30NCmE6bGluaywgc3Bhbi5Nc29IeXBlcmxpbmsNCgl7bXNvLXN0eWxlLXByaW9y
+aXR5Ojk5Ow0KCWNvbG9yOmJsdWU7DQoJdGV4dC1kZWNvcmF0aW9uOnVuZGVybGluZTt9DQphOnZp
+c2l0ZWQsIHNwYW4uTXNvSHlwZXJsaW5rRm9sbG93ZWQNCgl7bXNvLXN0eWxlLXByaW9yaXR5Ojk5
+Ow0KCWNvbG9yOnB1cnBsZTsNCgl0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lO30NCnANCgl7bXNv
+LXN0eWxlLXByaW9yaXR5Ojk5Ow0KCW1zby1tYXJnaW4tdG9wLWFsdDphdXRvOw0KCW1hcmdpbi1y
+aWdodDowaW47DQoJbXNvLW1hcmdpbi1ib3R0b20tYWx0OmF1dG87DQoJbWFyZ2luLWxlZnQ6MGlu
+Ow0KCWZvbnQtc2l6ZToxMi4wcHQ7DQoJZm9udC1mYW1pbHk6IlRpbWVzIE5ldyBSb21hbiIsInNl
+cmlmIjt9DQpzcGFuLkVtYWlsU3R5bGUxOA0KCXttc28tc3R5bGUtdHlwZTpwZXJzb25hbC1yZXBs
+eTsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsInNhbnMtc2VyaWYiOw0KCWNvbG9yOiMxRjQ5N0Q7
+fQ0KLk1zb0NocERlZmF1bHQNCgl7bXNvLXN0eWxlLXR5cGU6ZXhwb3J0LW9ubHk7DQoJZm9udC1m
+YW1pbHk6IkNhbGlicmkiLCJzYW5zLXNlcmlmIjt9DQpAcGFnZSBXb3JkU2VjdGlvbjENCgl7c2l6
+ZTo4LjVpbiAxMS4waW47DQoJbWFyZ2luOjEuMGluIDEuMGluIDEuMGluIDEuMGluO30NCmRpdi5X
+b3JkU2VjdGlvbjENCgl7cGFnZTpXb3JkU2VjdGlvbjE7fQ0KLS0+PC9zdHlsZT48IS0tW2lmIGd0
+ZSBtc28gOV0+PHhtbD4NCjxvOnNoYXBlZGVmYXVsdHMgdjpleHQ9ImVkaXQiIHNwaWRtYXg9IjEw
+MjYiIC8+DQo8L3htbD48IVtlbmRpZl0tLT48IS0tW2lmIGd0ZSBtc28gOV0+PHhtbD4NCjxvOnNo
+YXBlbGF5b3V0IHY6ZXh0PSJlZGl0Ij4NCjxvOmlkbWFwIHY6ZXh0PSJlZGl0IiBkYXRhPSIxIiAv
+Pg0KPC9vOnNoYXBlbGF5b3V0PjwveG1sPjwhW2VuZGlmXS0tPg0KPC9oZWFkPg0KPGJvZHkgbGFu
+Zz0iRU4tVVMiIGxpbms9ImJsdWUiIHZsaW5rPSJwdXJwbGUiPg0KPGRpdiBjbGFzcz0iV29yZFNl
+Y3Rpb24xIj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTEu
+MHB0O2ZvbnQtZmFtaWx5OiZxdW90O0NhbGlicmkmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90
+Oztjb2xvcjojMUY0OTdEIj5NaWNyb3NvZnQgT3V0bG9vayAyMDEwPG86cD48L286cD48L3NwYW4+
+PC9wPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCI+PHNwYW4gc3R5bGU9ImZvbnQtc2l6ZToxMS4wcHQ7
+Zm9udC1mYW1pbHk6JnF1b3Q7Q2FsaWJyaSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7O2Nv
+bG9yOiMxRjQ5N0QiPjxvOnA+Jm5ic3A7PC9vOnA+PC9zcGFuPjwvcD4NCjxwIGNsYXNzPSJNc29O
+b3JtYWwiPjxiPjxzcGFuIHN0eWxlPSJmb250LXNpemU6MTAuMHB0O2ZvbnQtZmFtaWx5OiZxdW90
+O1RhaG9tYSZxdW90OywmcXVvdDtzYW5zLXNlcmlmJnF1b3Q7Ij5Gcm9tOjwvc3Bhbj48L2I+PHNw
+YW4gc3R5bGU9ImZvbnQtc2l6ZToxMC4wcHQ7Zm9udC1mYW1pbHk6JnF1b3Q7VGFob21hJnF1b3Q7
+LCZxdW90O3NhbnMtc2VyaWYmcXVvdDsiPiBtaWNoYWVsIFttYWlsdG86dGFsa0BvcGVubXJzLm9y
+Z10NCjxicj4NCjxiPlNlbnQ6PC9iPiBNb25kYXksIE9jdG9iZXIgMTMsIDIwMTQgOTozOCBBTTxi
+cj4NCjxiPlRvOjwvYj4gUG93ZXIsIENocmlzPGJyPg0KPGI+U3ViamVjdDo8L2I+IFtQTV0gWW91
+ciBwb3N0IGluICZxdW90O0J1cmdlcmhhdXM6IE5ldyByZXN0YXVyYW50IC8gbHVuY2ggdmVudWUm
+cXVvdDs8bzpwPjwvbzpwPjwvc3Bhbj48L3A+DQo8cCBjbGFzcz0iTXNvTm9ybWFsIj48bzpwPiZu
+YnNwOzwvbzpwPjwvcD4NCjxkaXY+DQo8dGFibGUgY2xhc3M9Ik1zb05vcm1hbFRhYmxlIiBib3Jk
+ZXI9IjAiIGNlbGxzcGFjaW5nPSIwIiBjZWxscGFkZGluZz0iMCI+DQo8dGJvZHk+DQo8dHI+DQo8
+dGQgdmFsaWduPSJ0b3AiIHN0eWxlPSJwYWRkaW5nOjBpbiAwaW4gMGluIDBpbiI+PC90ZD4NCjx0
+ZCBzdHlsZT0icGFkZGluZzowaW4gMGluIDBpbiAwaW4iPg0KPHAgY2xhc3M9Ik1zb05vcm1hbCIg
+c3R5bGU9Im1hcmdpbi1ib3R0b206MTguNzVwdCI+PGEgaHJlZj0iaHR0cDovL2NsLm9wZW5tcnMu
+b3JnL3RyYWNrL2NsaWNrLzMwMDM5OTA1L3RhbGsub3Blbm1ycy5vcmc/cD1leUp6SWpvaWJHbFph
+MVYwZVhoQ1kwMU1SVEZzVURKbVl6VlFNMFpsZWpFNElpd2lkaUk2TVN3aWNDSTZJbnRjSW5WY0lq
+b3pNREF6T1Rrd05TeGNJblpjSWpveExGd2lkWEpzWENJNlhDSm9kSFJ3Y3pwY1hGd3ZYRnhjTDNS
+aGJHc3ViM0JsYm0xeWN5NXZjbWRjWEZ3dmRYTmxjbk5jWEZ3dmJXbGphR0ZsYkZ3aUxGd2lhV1Jj
+SWpwY0ltUTFZbU13TjJOa05EUmpaRFE0TUdNNFlUZzJNemxqWldJMU56Z3pZbVkyWENJc1hDSjFj
+bXhmYVdSelhDSTZXMXdpWWpoa09EZzFNams1TnpkbVpqWTFaV1l5TlRFM09XUmlOR1l5TVdJM056
+RmpOemhqWmpoa09Gd2lYWDBpZlEiIHRhcmdldD0iX2JsYW5rIj48Yj48c3BhbiBzdHlsZT0iZm9u
+dC1zaXplOjEwLjBwdDtmb250LWZhbWlseTomcXVvdDtUYWhvbWEmcXVvdDssJnF1b3Q7c2Fucy1z
+ZXJpZiZxdW90Oztjb2xvcjojMDA2Njk5O3RleHQtZGVjb3JhdGlvbjpub25lIj5taWNoYWVsPC9z
+cGFuPjwvYj48L2E+PGJyPg0KPHNwYW4gc3R5bGU9ImZvbnQtc2l6ZTo4LjVwdDtmb250LWZhbWls
+eTomcXVvdDtUYWhvbWEmcXVvdDssJnF1b3Q7c2Fucy1zZXJpZiZxdW90Oztjb2xvcjojOTk5OTk5
+Ij5PY3RvYmVyIDEzPC9zcGFuPg0KPG86cD48L286cD48L3A+DQo8L3RkPg0KPC90cj4NCjx0cj4N
+Cjx0ZCBjb2xzcGFuPSIyIiBzdHlsZT0icGFkZGluZzozLjc1cHQgMGluIDBpbiAwaW4iPg0KPHAg
+Y2xhc3M9Ik1zb05vcm1hbCIgc3R5bGU9Im1hcmdpbi1ib3R0b206MTguNzVwdCI+PGEgaHJlZj0i
+aHR0cDovL2NsLm9wZW5tcnMub3JnL3RyYWNrL2NsaWNrLzMwMDM5OTA1L3RhbGsub3Blbm1ycy5v
+cmc/cD1leUp6SWpvaVVFUklTVU55UjNsVk1EZEJWVmhwV25SM1dXeDRNV05zVFc1Wklpd2lkaUk2
+TVN3aWNDSTZJbnRjSW5WY0lqb3pNREF6T1Rrd05TeGNJblpjSWpveExGd2lkWEpzWENJNlhDSm9k
+SFJ3Y3pwY1hGd3ZYRnhjTDNSaGJHc3ViM0JsYm0xeWN5NXZjbWRjWEZ3dmRGeGNYQzlpZFhKblpY
+Sm9ZWFZ6TFc1bGR5MXlaWE4wWVhWeVlXNTBMV3gxYm1Ob0xYWmxiblZsWEZ4Y0x6WTNNbHhjWEM4
+elhDSXNYQ0pwWkZ3aU9sd2laRFZpWXpBM1kyUTBOR05rTkRnd1l6aGhPRFl6T1dObFlqVTNPRE5p
+WmpaY0lpeGNJblZ5YkY5cFpITmNJanBiWENKaU56WmlZamswWlRGaU56STVaVGsyWlRSbFpXTTRO
+R1JtTWpRNE1ETXdZall5WVdZeU1HTTBYQ0pkZlNKOSI+PGI+PHNwYW4gc3R5bGU9ImNvbG9yOiMw
+MDY2OTk7dGV4dC1kZWNvcmF0aW9uOm5vbmUiPmh0dHBzOi8vdGFsay5vcGVubXJzLm9yZy90L2J1
+cmdlcmhhdXMtbmV3LXJlc3RhdXJhbnQtbHVuY2gtdmVudWUvNjcyLzM8L3NwYW4+PC9iPjwvYT4N
+CjxvOnA+PC9vOnA+PC9wPg0KPHAgc3R5bGU9Im1hcmdpbi10b3A6MGluIj5Mb29rcyBsaWtlIHlv
+dXIgcmVwbHktYnktZW1haWwgd2Fzbid0IHByb2Nlc3NlZCBjb3JyZWN0bHkgYnkgb3VyIHNvZnR3
+YXJlLiBDYW4geW91IGxldCBtZSBrbm93IHdoYXQgdmVyc2lvbi9PUyBvZiB3aGF0IGVtYWlsIHBy
+b2dyYW0geW91J3JlIHVzaW5nPyBXZSB3aWxsIHdhbnQgdG8gdHJ5IHRvIGZpeCB0aGUgYnVnLiA6
+c21pbGU6PG86cD48L286cD48L3A+DQo8cCBzdHlsZT0ibWFyZ2luLXRvcDowaW4iPlRoYW5rcyE8
+bzpwPjwvbzpwPjwvcD4NCjwvdGQ+DQo8L3RyPg0KPC90Ym9keT4NCjwvdGFibGU+DQo8ZGl2IGNs
+YXNzPSJNc29Ob3JtYWwiIGFsaWduPSJjZW50ZXIiIHN0eWxlPSJ0ZXh0LWFsaWduOmNlbnRlciI+
+DQo8aHIgc2l6ZT0iMSIgd2lkdGg9IjEwMCUiIGFsaWduPSJjZW50ZXIiPg0KPC9kaXY+DQo8ZGl2
+Pg0KPHA+PHNwYW4gc3R5bGU9ImNvbG9yOiM2NjY2NjYiPlRvIHJlc3BvbmQsIHJlcGx5IHRvIHRo
+aXMgZW1haWwgb3IgdmlzaXQgPGEgaHJlZj0iaHR0cDovL2NsLm9wZW5tcnMub3JnL3RyYWNrL2Ns
+aWNrLzMwMDM5OTA1L3RhbGsub3Blbm1ycy5vcmc/cD1leUp6SWpvaWVYaDJWbnBGTUhSMU1uRm5a
+RWR1TlhFd01GcFFPVlp0VFZvNElpd2lkaUk2TVN3aWNDSTZJbnRjSW5WY0lqb3pNREF6T1Rrd05T
+eGNJblpjSWpveExGd2lkWEpzWENJNlhDSm9kSFJ3Y3pwY1hGd3ZYRnhjTDNSaGJHc3ViM0JsYm0x
+eWN5NXZjbWRjWEZ3dmRGeGNYQzk1YjNWeUxYQnZjM1F0YVc0dFluVnlaMlZ5YUdGMWN5MXVaWGN0
+Y21WemRHRjFjbUZ1ZEMxc2RXNWphQzEyWlc1MVpWeGNYQzgyTnpSY1hGd3ZNVndpTEZ3aWFXUmNJ
+anBjSW1RMVltTXdOMk5rTkRSalpEUTRNR000WVRnMk16bGpaV0kxTnpnelltWTJYQ0lzWENKMWNt
+eGZhV1J6WENJNlcxd2lZamMyWW1JNU5HVXhZamN5T1dVNU5tVTBaV1ZqT0RSa1pqSTBPREF6TUdJ
+Mk1tRm1NakJqTkZ3aVhYMGlmUSI+DQo8Yj48c3BhbiBzdHlsZT0iY29sb3I6IzAwNjY5OTt0ZXh0
+LWRlY29yYXRpb246bm9uZSI+aHR0cHM6Ly90YWxrLm9wZW5tcnMub3JnL3QveW91ci1wb3N0LWlu
+LWJ1cmdlcmhhdXMtbmV3LXJlc3RhdXJhbnQtbHVuY2gtdmVudWUvNjc0LzE8L3NwYW4+PC9iPjwv
+YT4gaW4geW91ciBicm93c2VyLjxvOnA+PC9vOnA+PC9zcGFuPjwvcD4NCjwvZGl2Pg0KPGRpdj4N
+CjxwPjxzcGFuIHN0eWxlPSJjb2xvcjojNjY2NjY2Ij5UbyB1bnN1YnNjcmliZSBmcm9tIHRoZXNl
+IGVtYWlscywgdmlzaXQgeW91ciA8YSBocmVmPSJodHRwOi8vY2wub3Blbm1ycy5vcmcvdHJhY2sv
+Y2xpY2svMzAwMzk5MDUvdGFsay5vcGVubXJzLm9yZz9wPWV5SnpJam9pZFV4dVdsZzVWRmMwT1da
+V1MwWTRiRmRMZG1seVdHc3hUVjl6SWl3aWRpSTZNU3dpY0NJNkludGNJblZjSWpvek1EQXpPVGt3
+TlN4Y0luWmNJam94TEZ3aWRYSnNYQ0k2WENKb2RIUndjenBjWEZ3dlhGeGNMM1JoYkdzdWIzQmxi
+bTF5Y3k1dmNtZGNYRnd2YlhsY1hGd3ZjSEpsWm1WeVpXNWpaWE5jSWl4Y0ltbGtYQ0k2WENKa05X
+SmpNRGRqWkRRMFkyUTBPREJqT0dFNE5qTTVZMlZpTlRjNE0ySm1ObHdpTEZ3aWRYSnNYMmxrYzF3
+aU9sdGNJbUk0TVdVd1pqQTFORFk1TkRNME56Z3lNMkZtTWpBMk5qRmpaamMzWkdOaU4yTmhZemRt
+TWpKY0lsMTlJbjAiPg0KPGI+PHNwYW4gc3R5bGU9ImNvbG9yOiMwMDY2OTk7dGV4dC1kZWNvcmF0
+aW9uOm5vbmUiPnVzZXIgcHJlZmVyZW5jZXM8L3NwYW4+PC9iPjwvYT4uPG86cD48L286cD48L3Nw
+YW4+PC9wPg0KPC9kaXY+DQo8L2Rpdj4NCjxwIGNsYXNzPSJNc29Ob3JtYWwiPjxpbWcgYm9yZGVy
+PSIwIiB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBpZD0iX3gwMDAwX2kxMDI2IiBzcmM9Imh0dHA6Ly9j
+bC5vcGVubXJzLm9yZy90cmFjay9vcGVuLnBocD91PTMwMDM5OTA1JmFtcDtpZD1kNWJjMDdjZDQ0
+Y2Q0ODBjOGE4NjM5Y2ViNTc4M2JmNiI+PG86cD48L286cD48L3A+DQo8L2Rpdj4NCjwvYm9keT4N
+CjwvaHRtbD4NCg==
+
+--_000_B0DFE1BEB3739743BC9B639D0E6BC8FF217A6341IUMSSGMBX104ads_--
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index c706e418d26..15863d444f8 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -57,7 +57,7 @@ describe ApplicationHelper do
it 'returns an url for the avatar' do
project = create(:project, avatar: File.open(avatar_file_path))
- avatar_url = "http://localhost/uploads/project/avatar/#{project.id}/banana_sample.gif"
+ avatar_url = "http://#{Gitlab.config.gitlab.host}/uploads/project/avatar/#{project.id}/banana_sample.gif"
expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).
to eq "<img src=\"#{avatar_url}\" alt=\"Banana sample\" />"
end
@@ -67,7 +67,7 @@ describe ApplicationHelper do
allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true)
- avatar_url = 'http://localhost' + namespace_project_avatar_path(project.namespace, project)
+ avatar_url = "http://#{Gitlab.config.gitlab.host}#{namespace_project_avatar_path(project.namespace, project)}"
expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).to match(
image_tag(avatar_url))
end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index 5368e5fab06..1d494edcd3b 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -113,7 +113,7 @@ describe GitlabMarkdownHelper do
it 'replaces commit message with emoji to link' do
actual = link_to_gfm(':book:Book', '/foo')
expect(actual).
- to eq %Q(<img class="emoji" title=":book:" alt=":book:" src="http://localhost/assets/1F4D6.png" height="20" width="20" align="absmiddle"><a href="/foo">Book</a>)
+ to eq %Q(<img class="emoji" title=":book:" alt=":book:" src="http://#{Gitlab.config.gitlab.host}/assets/1F4D6.png" height="20" width="20" align="absmiddle"><a href="/foo">Book</a>)
end
end
diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6
index 370944b6a8c..e21e5844a26 100644
--- a/spec/javascripts/build_spec.js.es6
+++ b/spec/javascripts/build_spec.js.es6
@@ -1,5 +1,7 @@
/* global Build */
/* eslint-disable no-new */
+//= require lib/utils/timeago
+//= require lib/utils/datetime_utility
//= require build
//= require breakpoints
//= require jquery.nicescroll
@@ -24,7 +26,15 @@
});
describe('setup', function () {
+ const removeDate = new Date();
+ removeDate.setUTCFullYear(removeDate.getUTCFullYear() + 1);
+ // give the test three days to run
+ removeDate.setTime(removeDate.getTime() + (3 * 24 * 60 * 60 * 1000));
+
beforeEach(function () {
+ const removeDateElement = document.querySelector('.js-artifacts-remove');
+ removeDateElement.innerText = removeDate.toString();
+
this.build = new Build();
});
@@ -54,6 +64,11 @@
expect($('.build-job[data-stage="test"]').is(':visible')).toBe(false);
expect($('.build-job[data-stage="deploy"]').is(':visible')).toBe(false);
});
+
+ it('displays the remove date correctly', function () {
+ const removeDateElement = document.querySelector('.js-artifacts-remove');
+ expect(removeDateElement.innerText.trim()).toBe('1 year');
+ });
});
describe('initial build trace', function () {
diff --git a/spec/javascripts/fixtures/build.html.haml b/spec/javascripts/fixtures/build.html.haml
index a2bc81c6be7..27136beb14c 100644
--- a/spec/javascripts/fixtures/build.html.haml
+++ b/spec/javascripts/fixtures/build.html.haml
@@ -55,3 +55,8 @@
build_status: 'passed',
build_stage: 'test',
state1: 'buildstate' }}
+
+%p.build-detail-row
+ The artifacts will be removed in
+ %span.js-artifacts-remove
+ 2016-12-19 09:02:12 UTC
diff --git a/spec/lib/gitlab/chat_commands/command_spec.rb b/spec/lib/gitlab/chat_commands/command_spec.rb
new file mode 100644
index 00000000000..8cedbb0240f
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/command_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::Command, service: true do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+
+ subject { described_class.new(project, user, params).execute }
+
+ describe '#execute' do
+ context 'when no command is available' do
+ let(:params) { { text: 'issue show 1' } }
+ let(:project) { create(:project, has_external_issue_tracker: true) }
+
+ it 'displays 404 messages' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to start_with('404 not found')
+ end
+ end
+
+ context 'when an unknown command is triggered' do
+ let(:params) { { command: '/gitlab', text: "unknown command 123" } }
+
+ it 'displays the help message' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to start_with('Available commands')
+ expect(subject[:text]).to match('/gitlab issue show')
+ end
+ end
+
+ context 'the user can not create an issue' do
+ let(:params) { { text: "issue create my new issue" } }
+
+ it 'rejects the actions' do
+ expect(subject[:response_type]).to be(:ephemeral)
+ expect(subject[:text]).to start_with('Whoops! That action is not allowed')
+ end
+ end
+
+ context 'issue is successfully created' do
+ let(:params) { { text: "issue create my new issue" } }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ it 'presents the issue' do
+ expect(subject[:text]).to match("my new issue")
+ end
+
+ it 'shows a link to the new issue' do
+ expect(subject[:text]).to match(/\/issues\/\d+/)
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/chat_commands/issue_create_spec.rb b/spec/lib/gitlab/chat_commands/issue_create_spec.rb
new file mode 100644
index 00000000000..df0c317ccea
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/issue_create_spec.rb
@@ -0,0 +1,52 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::IssueCreate, service: true do
+ describe '#execute' do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+ let(:regex_match) { described_class.match("issue create bird is the word") }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ subject do
+ described_class.new(project, user).execute(regex_match)
+ end
+
+ context 'without description' do
+ it 'creates the issue' do
+ expect { subject }.to change { project.issues.count }.by(1)
+
+ expect(subject.title).to eq('bird is the word')
+ end
+ end
+
+ context 'with description' do
+ let(:description) { "Surfin bird" }
+ let(:regex_match) { described_class.match("issue create bird is the word\n#{description}") }
+
+ it 'creates the issue with description' do
+ subject
+
+ expect(Issue.last.description).to eq(description)
+ end
+ end
+ end
+
+ describe '.match' do
+ it 'matches the title without description' do
+ match = described_class.match("issue create my title")
+
+ expect(match[:title]).to eq('my title')
+ expect(match[:description]).to eq("")
+ end
+
+ it 'matches the title with description' do
+ match = described_class.match("issue create my title\n\ndescription")
+
+ expect(match[:title]).to eq('my title')
+ expect(match[:description]).to eq('description')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/chat_commands/issue_show_spec.rb b/spec/lib/gitlab/chat_commands/issue_show_spec.rb
new file mode 100644
index 00000000000..331a4604e9b
--- /dev/null
+++ b/spec/lib/gitlab/chat_commands/issue_show_spec.rb
@@ -0,0 +1,40 @@
+require 'spec_helper'
+
+describe Gitlab::ChatCommands::IssueShow, service: true do
+ describe '#execute' do
+ let(:issue) { create(:issue) }
+ let(:project) { issue.project }
+ let(:user) { issue.author }
+ let(:regex_match) { described_class.match("issue show #{issue.iid}") }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ subject do
+ described_class.new(project, user).execute(regex_match)
+ end
+
+ context 'the issue exists' do
+ it 'returns the issue' do
+ expect(subject.iid).to be issue.iid
+ end
+ end
+
+ context 'the issue does not exist' do
+ let(:regex_match) { described_class.match("issue show 2343242") }
+
+ it "returns nil" do
+ expect(subject).to be_nil
+ end
+ end
+ end
+
+ describe 'self.match' do
+ it 'matches the iid' do
+ match = described_class.match("issue show 123")
+
+ expect(match[:iid]).to eq("123")
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/code_event_spec.rb b/spec/lib/gitlab/cycle_analytics/code_event_spec.rb
new file mode 100644
index 00000000000..43f42d1bde8
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/code_event_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+require 'lib/gitlab/cycle_analytics/shared_event_spec'
+
+describe Gitlab::CycleAnalytics::CodeEvent do
+ it_behaves_like 'default query config' do
+ it 'does not have the default order' do
+ expect(event.order).not_to eq(event.start_time_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/events_spec.rb b/spec/lib/gitlab/cycle_analytics/events_spec.rb
new file mode 100644
index 00000000000..9aeaa6b3ee8
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/events_spec.rb
@@ -0,0 +1,326 @@
+require 'spec_helper'
+
+describe Gitlab::CycleAnalytics::Events do
+ let(:project) { create(:project) }
+ let(:from_date) { 10.days.ago }
+ let(:user) { create(:user, :admin) }
+ let!(:context) { create(:issue, project: project, created_at: 2.days.ago) }
+
+ subject { described_class.new(project: project, options: { from: from_date, current_user: user }) }
+
+ before do
+ allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([context])
+
+ setup(context)
+ end
+
+ describe '#issue_events' do
+ it 'has the total time' do
+ expect(subject.issue_events.first[:total_time]).not_to be_empty
+ end
+
+ it 'has a title' do
+ expect(subject.issue_events.first[:title]).to eq(context.title)
+ end
+
+ it 'has the URL' do
+ expect(subject.issue_events.first[:url]).not_to be_nil
+ end
+
+ it 'has an iid' do
+ expect(subject.issue_events.first[:iid]).to eq(context.iid.to_s)
+ end
+
+ it 'has a created_at timestamp' do
+ expect(subject.issue_events.first[:created_at]).to end_with('ago')
+ end
+
+ it "has the author's URL" do
+ expect(subject.issue_events.first[:author][:web_url]).not_to be_nil
+ end
+
+ it "has the author's avatar URL" do
+ expect(subject.issue_events.first[:author][:avatar_url]).not_to be_nil
+ end
+
+ it "has the author's name" do
+ expect(subject.issue_events.first[:author][:name]).to eq(context.author.name)
+ end
+ end
+
+ describe '#plan_events' do
+ it 'has a title' do
+ expect(subject.plan_events.first[:title]).not_to be_nil
+ end
+
+ it 'has a sha short ID' do
+ expect(subject.plan_events.first[:short_sha]).not_to be_nil
+ end
+
+ it 'has the URL' do
+ expect(subject.plan_events.first[:commit_url]).not_to be_nil
+ end
+
+ it 'has the total time' do
+ expect(subject.plan_events.first[:total_time]).not_to be_empty
+ end
+
+ it "has the author's URL" do
+ expect(subject.plan_events.first[:author][:web_url]).not_to be_nil
+ end
+
+ it "has the author's avatar URL" do
+ expect(subject.plan_events.first[:author][:avatar_url]).not_to be_nil
+ end
+
+ it "has the author's name" do
+ expect(subject.plan_events.first[:author][:name]).not_to be_nil
+ end
+ end
+
+ describe '#code_events' do
+ before do
+ create_commit_referencing_issue(context)
+ end
+
+ it 'has the total time' do
+ expect(subject.code_events.first[:total_time]).not_to be_empty
+ end
+
+ it 'has a title' do
+ expect(subject.code_events.first[:title]).to eq('Awesome merge_request')
+ end
+
+ it 'has an iid' do
+ expect(subject.code_events.first[:iid]).to eq(context.iid.to_s)
+ end
+
+ it 'has a created_at timestamp' do
+ expect(subject.code_events.first[:created_at]).to end_with('ago')
+ end
+
+ it "has the author's URL" do
+ expect(subject.code_events.first[:author][:web_url]).not_to be_nil
+ end
+
+ it "has the author's avatar URL" do
+ expect(subject.code_events.first[:author][:avatar_url]).not_to be_nil
+ end
+
+ it "has the author's name" do
+ expect(subject.code_events.first[:author][:name]).to eq(MergeRequest.first.author.name)
+ end
+ end
+
+ describe '#test_events' do
+ let(:merge_request) { MergeRequest.first }
+ let!(:pipeline) do
+ create(:ci_pipeline,
+ ref: merge_request.source_branch,
+ sha: merge_request.diff_head_sha,
+ project: context.project)
+ end
+
+ before do
+ create(:ci_build, pipeline: pipeline, status: :success, author: user)
+ create(:ci_build, pipeline: pipeline, status: :success, author: user)
+
+ pipeline.run!
+ pipeline.succeed!
+ end
+
+ it 'has the name' do
+ expect(subject.test_events.first[:name]).not_to be_nil
+ end
+
+ it 'has the ID' do
+ expect(subject.test_events.first[:id]).not_to be_nil
+ end
+
+ it 'has the URL' do
+ expect(subject.test_events.first[:url]).not_to be_nil
+ end
+
+ it 'has the branch name' do
+ expect(subject.test_events.first[:branch]).not_to be_nil
+ end
+
+ it 'has the branch URL' do
+ expect(subject.test_events.first[:branch][:url]).not_to be_nil
+ end
+
+ it 'has the short SHA' do
+ expect(subject.test_events.first[:short_sha]).not_to be_nil
+ end
+
+ it 'has the commit URL' do
+ expect(subject.test_events.first[:commit_url]).not_to be_nil
+ end
+
+ it 'has the date' do
+ expect(subject.test_events.first[:date]).not_to be_nil
+ end
+
+ it 'has the total time' do
+ expect(subject.test_events.first[:total_time]).not_to be_empty
+ end
+ end
+
+ describe '#review_events' do
+ let!(:context) { create(:issue, project: project, created_at: 2.days.ago) }
+
+ it 'has the total time' do
+ expect(subject.review_events.first[:total_time]).not_to be_empty
+ end
+
+ it 'has a title' do
+ expect(subject.review_events.first[:title]).to eq('Awesome merge_request')
+ end
+
+ it 'has an iid' do
+ expect(subject.review_events.first[:iid]).to eq(context.iid.to_s)
+ end
+
+ it 'has the URL' do
+ expect(subject.review_events.first[:url]).not_to be_nil
+ end
+
+ it 'has a state' do
+ expect(subject.review_events.first[:state]).not_to be_nil
+ end
+
+ it 'has a created_at timestamp' do
+ expect(subject.review_events.first[:created_at]).not_to be_nil
+ end
+
+ it "has the author's URL" do
+ expect(subject.review_events.first[:author][:web_url]).not_to be_nil
+ end
+
+ it "has the author's avatar URL" do
+ expect(subject.review_events.first[:author][:avatar_url]).not_to be_nil
+ end
+
+ it "has the author's name" do
+ expect(subject.review_events.first[:author][:name]).to eq(MergeRequest.first.author.name)
+ end
+ end
+
+ describe '#staging_events' do
+ let(:merge_request) { MergeRequest.first }
+ let!(:pipeline) do
+ create(:ci_pipeline,
+ ref: merge_request.source_branch,
+ sha: merge_request.diff_head_sha,
+ project: context.project)
+ end
+
+ before do
+ create(:ci_build, pipeline: pipeline, status: :success, author: user)
+ create(:ci_build, pipeline: pipeline, status: :success, author: user)
+
+ pipeline.run!
+ pipeline.succeed!
+
+ merge_merge_requests_closing_issue(context)
+ deploy_master
+ end
+
+ it 'has the name' do
+ expect(subject.staging_events.first[:name]).not_to be_nil
+ end
+
+ it 'has the ID' do
+ expect(subject.staging_events.first[:id]).not_to be_nil
+ end
+
+ it 'has the URL' do
+ expect(subject.staging_events.first[:url]).not_to be_nil
+ end
+
+ it 'has the branch name' do
+ expect(subject.staging_events.first[:branch]).not_to be_nil
+ end
+
+ it 'has the branch URL' do
+ expect(subject.staging_events.first[:branch][:url]).not_to be_nil
+ end
+
+ it 'has the short SHA' do
+ expect(subject.staging_events.first[:short_sha]).not_to be_nil
+ end
+
+ it 'has the commit URL' do
+ expect(subject.staging_events.first[:commit_url]).not_to be_nil
+ end
+
+ it 'has the date' do
+ expect(subject.staging_events.first[:date]).not_to be_nil
+ end
+
+ it 'has the total time' do
+ expect(subject.staging_events.first[:total_time]).not_to be_empty
+ end
+
+ it "has the author's URL" do
+ expect(subject.staging_events.first[:author][:web_url]).not_to be_nil
+ end
+
+ it "has the author's avatar URL" do
+ expect(subject.staging_events.first[:author][:avatar_url]).not_to be_nil
+ end
+
+ it "has the author's name" do
+ expect(subject.staging_events.first[:author][:name]).to eq(MergeRequest.first.author.name)
+ end
+ end
+
+ describe '#production_events' do
+ let!(:context) { create(:issue, project: project, created_at: 2.days.ago) }
+
+ before do
+ merge_merge_requests_closing_issue(context)
+ deploy_master
+ end
+
+ it 'has the total time' do
+ expect(subject.production_events.first[:total_time]).not_to be_empty
+ end
+
+ it 'has a title' do
+ expect(subject.production_events.first[:title]).to eq(context.title)
+ end
+
+ it 'has the URL' do
+ expect(subject.production_events.first[:url]).not_to be_nil
+ end
+
+ it 'has an iid' do
+ expect(subject.production_events.first[:iid]).to eq(context.iid.to_s)
+ end
+
+ it 'has a created_at timestamp' do
+ expect(subject.production_events.first[:created_at]).to end_with('ago')
+ end
+
+ it "has the author's URL" do
+ expect(subject.production_events.first[:author][:web_url]).not_to be_nil
+ end
+
+ it "has the author's avatar URL" do
+ expect(subject.production_events.first[:author][:avatar_url]).not_to be_nil
+ end
+
+ it "has the author's name" do
+ expect(subject.production_events.first[:author][:name]).to eq(context.author.name)
+ end
+ end
+
+ def setup(context)
+ milestone = create(:milestone, project: project)
+ context.update(milestone: milestone)
+ mr = create_merge_request_closing_issue(context)
+
+ ProcessCommitWorker.new.perform(project.id, user.id, mr.commits.last.sha)
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/issue_event_spec.rb b/spec/lib/gitlab/cycle_analytics/issue_event_spec.rb
new file mode 100644
index 00000000000..1c5c308da7d
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/issue_event_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+require 'lib/gitlab/cycle_analytics/shared_event_spec'
+
+describe Gitlab::CycleAnalytics::IssueEvent do
+ it_behaves_like 'default query config' do
+ it 'has the default order' do
+ expect(event.order).to eq(event.start_time_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/plan_event_spec.rb b/spec/lib/gitlab/cycle_analytics/plan_event_spec.rb
new file mode 100644
index 00000000000..d76a255acf5
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/plan_event_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+require 'lib/gitlab/cycle_analytics/shared_event_spec'
+
+describe Gitlab::CycleAnalytics::PlanEvent do
+ it_behaves_like 'default query config' do
+ it 'has the default order' do
+ expect(event.order).to eq(event.start_time_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/production_event_spec.rb b/spec/lib/gitlab/cycle_analytics/production_event_spec.rb
new file mode 100644
index 00000000000..ac17e3b4287
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/production_event_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+require 'lib/gitlab/cycle_analytics/shared_event_spec'
+
+describe Gitlab::CycleAnalytics::ProductionEvent do
+ it_behaves_like 'default query config' do
+ it 'has the default order' do
+ expect(event.order).to eq(event.start_time_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/review_event_spec.rb b/spec/lib/gitlab/cycle_analytics/review_event_spec.rb
new file mode 100644
index 00000000000..1ff53aa0227
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/review_event_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+require 'lib/gitlab/cycle_analytics/shared_event_spec'
+
+describe Gitlab::CycleAnalytics::ReviewEvent do
+ it_behaves_like 'default query config' do
+ it 'has the default order' do
+ expect(event.order).to eq(event.start_time_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb
new file mode 100644
index 00000000000..7019e4c3351
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/shared_event_spec.rb
@@ -0,0 +1,21 @@
+require 'spec_helper'
+
+shared_examples 'default query config' do
+ let(:event) { described_class.new(project: double, options: {}) }
+
+ it 'has the start attributes' do
+ expect(event.start_time_attrs).not_to be_nil
+ end
+
+ it 'has the stage attribute' do
+ expect(event.stage).not_to be_nil
+ end
+
+ it 'has the end attributes' do
+ expect(event.end_time_attrs).not_to be_nil
+ end
+
+ it 'has the projection attributes' do
+ expect(event.projections).not_to be_nil
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/staging_event_spec.rb b/spec/lib/gitlab/cycle_analytics/staging_event_spec.rb
new file mode 100644
index 00000000000..4862d4765f2
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/staging_event_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+require 'lib/gitlab/cycle_analytics/shared_event_spec'
+
+describe Gitlab::CycleAnalytics::StagingEvent do
+ it_behaves_like 'default query config' do
+ it 'does not have the default order' do
+ expect(event.order).not_to eq(event.start_time_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/test_event_spec.rb b/spec/lib/gitlab/cycle_analytics/test_event_spec.rb
new file mode 100644
index 00000000000..e249db69fc6
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/test_event_spec.rb
@@ -0,0 +1,10 @@
+require 'spec_helper'
+require 'lib/gitlab/cycle_analytics/shared_event_spec'
+
+describe Gitlab::CycleAnalytics::TestEvent do
+ it_behaves_like 'default query config' do
+ it 'does not have the default order' do
+ expect(event.order).not_to eq(event.start_time_attrs)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/cycle_analytics/updater_spec.rb b/spec/lib/gitlab/cycle_analytics/updater_spec.rb
new file mode 100644
index 00000000000..eff54cd3692
--- /dev/null
+++ b/spec/lib/gitlab/cycle_analytics/updater_spec.rb
@@ -0,0 +1,25 @@
+require 'spec_helper'
+
+describe Gitlab::CycleAnalytics::Updater do
+ describe 'updates authors' do
+ let(:user) { create(:user) }
+ let(:events) { [{ 'author_id' => user.id }] }
+
+ it 'maps the correct user' do
+ described_class.update!(events, from: 'author_id', to: 'author', klass: User)
+
+ expect(events.first['author']).to eq(user)
+ end
+ end
+
+ describe 'updates builds' do
+ let(:build) { create(:ci_build) }
+ let(:events) { [{ 'id' => build.id }] }
+
+ it 'maps the correct build' do
+ described_class.update!(events, from: 'id', to: 'build', klass: ::Ci::Build)
+
+ expect(events.first['build']).to eq(build)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/reply_parser_spec.rb b/spec/lib/gitlab/email/reply_parser_spec.rb
index 6f8e9a4be64..c7a0139d32a 100644
--- a/spec/lib/gitlab/email/reply_parser_spec.rb
+++ b/spec/lib/gitlab/email/reply_parser_spec.rb
@@ -206,5 +206,9 @@ describe Gitlab::Email::ReplyParser, lib: true do
it "properly renders email reply from MS Outlook client" do
expect(test_parse_body(fixture_file("emails/outlook.eml"))).to eq("Microsoft Outlook 2010")
end
+
+ it "properly renders html-only email from MS Outlook" do
+ expect(test_parse_body(fixture_file("emails/outlook_html.eml"))).to eq("Microsoft Outlook 2010")
+ end
end
end
diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml
index 02b11bd999a..fe3c39e38db 100644
--- a/spec/lib/gitlab/import_export/all_models.yml
+++ b/spec/lib/gitlab/import_export/all_models.yml
@@ -116,6 +116,7 @@ project:
- base_tags
- tag_taggings
- tags
+- chat_services
- creator
- group
- namespace
@@ -127,6 +128,7 @@ project:
- emails_on_push_service
- builds_email_service
- pipelines_email_service
+- mattermost_slash_commands_service
- irker_service
- pivotaltracker_service
- hipchat_service
@@ -188,4 +190,4 @@ award_emoji:
- awardable
- user
priorities:
-- label \ No newline at end of file
+- label
diff --git a/spec/lib/gitlab/middleware/go_spec.rb b/spec/lib/gitlab/middleware/go_spec.rb
index 117a15264da..fd3769d75b5 100644
--- a/spec/lib/gitlab/middleware/go_spec.rb
+++ b/spec/lib/gitlab/middleware/go_spec.rb
@@ -22,7 +22,7 @@ describe Gitlab::Middleware::Go, lib: true do
resp = middleware.call(env)
expect(resp[0]).to eq(200)
expect(resp[1]['Content-Type']).to eq('text/html')
- expected_body = "<!DOCTYPE html><html><head><meta content='localhost/group/project git http://localhost/group/project.git' name='go-import'></head></html>\n"
+ expected_body = "<!DOCTYPE html><html><head><meta content='#{Gitlab.config.gitlab.host}/group/project git http://#{Gitlab.config.gitlab.host}/group/project.git' name='go-import'></head></html>\n"
expect(resp[2].body).to eq([expected_body])
end
end
diff --git a/spec/lib/light_url_builder_spec.rb b/spec/lib/light_url_builder_spec.rb
new file mode 100644
index 00000000000..a826b24419a
--- /dev/null
+++ b/spec/lib/light_url_builder_spec.rb
@@ -0,0 +1,119 @@
+require 'spec_helper'
+
+describe Gitlab::UrlBuilder, lib: true do
+ describe '.build' do
+ context 'when passing a Commit' do
+ it 'returns a proper URL' do
+ commit = build_stubbed(:commit)
+
+ url = described_class.build(commit)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{commit.project.path_with_namespace}/commit/#{commit.id}"
+ end
+ end
+
+ context 'when passing an Issue' do
+ it 'returns a proper URL' do
+ issue = build_stubbed(:issue, iid: 42)
+
+ url = described_class.build(issue)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}"
+ end
+ end
+
+ context 'when passing a MergeRequest' do
+ it 'returns a proper URL' do
+ merge_request = build_stubbed(:merge_request, iid: 42)
+
+ url = described_class.build(merge_request)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}"
+ end
+ end
+
+ context 'when passing a Note' do
+ context 'on a Commit' do
+ it 'returns a proper URL' do
+ note = build_stubbed(:note_on_commit)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ end
+ end
+
+ context 'on a Commit Diff' do
+ it 'returns a proper URL' do
+ note = build_stubbed(:diff_note_on_commit)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{note.project.path_with_namespace}/commit/#{note.commit_id}#note_#{note.id}"
+ end
+ end
+
+ context 'on an Issue' do
+ it 'returns a proper URL' do
+ issue = create(:issue, iid: 42)
+ note = build_stubbed(:note_on_issue, noteable: issue)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.path_with_namespace}/issues/#{issue.iid}#note_#{note.id}"
+ end
+ end
+
+ context 'on a MergeRequest' do
+ it 'returns a proper URL' do
+ merge_request = create(:merge_request, iid: 42)
+ note = build_stubbed(:note_on_merge_request, noteable: merge_request)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ end
+ end
+
+ context 'on a MergeRequest Diff' do
+ it 'returns a proper URL' do
+ merge_request = create(:merge_request, iid: 42)
+ note = build_stubbed(:diff_note_on_merge_request, noteable: merge_request)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{merge_request.project.path_with_namespace}/merge_requests/#{merge_request.iid}#note_#{note.id}"
+ end
+ end
+
+ context 'on a ProjectSnippet' do
+ it 'returns a proper URL' do
+ project_snippet = create(:project_snippet)
+ note = build_stubbed(:note_on_project_snippet, noteable: project_snippet)
+
+ url = described_class.build(note)
+
+ expect(url).to eq "#{Settings.gitlab['url']}/#{project_snippet.project.path_with_namespace}/snippets/#{note.noteable_id}#note_#{note.id}"
+ end
+ end
+
+ context 'on another object' do
+ it 'returns a proper URL' do
+ project = build_stubbed(:project)
+
+ expect { described_class.build(project) }.
+ to raise_error(NotImplementedError, 'No URL builder defined for Project')
+ end
+ end
+ end
+
+ context 'when passing a WikiPage' do
+ it 'returns a proper URL' do
+ wiki_page = build(:wiki_page)
+ url = described_class.build(wiki_page)
+
+ expect(url).to eq "#{Gitlab.config.gitlab.url}#{wiki_page.wiki.wiki_base_path}/#{wiki_page.slug}"
+ end
+ end
+ end
+end
diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb
index 14bc062ef12..e1877d5fde0 100644
--- a/spec/mailers/emails/profile_spec.rb
+++ b/spec/mailers/emails/profile_spec.rb
@@ -25,7 +25,7 @@ describe Notify do
it 'includes a link for user to set password' do
params = "reset_password_token=#{token}"
is_expected.to have_body_text(
- %r{http://localhost(:\d+)?/users/password/edit\?#{params}}
+ %r{http://#{Gitlab.config.gitlab.host}(:\d+)?/users/password/edit\?#{params}}
)
end
diff --git a/spec/models/build_spec.rb b/spec/models/build_spec.rb
index ae185de9ca3..ef07f2275b1 100644
--- a/spec/models/build_spec.rb
+++ b/spec/models/build_spec.rb
@@ -1052,4 +1052,132 @@ describe Ci::Build, models: true do
end
end
end
+
+ describe '#has_environment?' do
+ subject { build.has_environment? }
+
+ context 'when environment is defined' do
+ before do
+ build.update(environment: 'review')
+ end
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'when environment is not defined' do
+ before do
+ build.update(environment: nil)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#starts_environment?' do
+ subject { build.starts_environment? }
+
+ context 'when environment is defined' do
+ before do
+ build.update(environment: 'review')
+ end
+
+ context 'no action is defined' do
+ it { is_expected.to be_truthy }
+ end
+
+ context 'and start action is defined' do
+ before do
+ build.update(options: { environment: { action: 'start' } } )
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'when environment is not defined' do
+ before do
+ build.update(environment: nil)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#stops_environment?' do
+ subject { build.stops_environment? }
+
+ context 'when environment is defined' do
+ before do
+ build.update(environment: 'review')
+ end
+
+ context 'no action is defined' do
+ it { is_expected.to be_falsey }
+ end
+
+ context 'and stop action is defined' do
+ before do
+ build.update(options: { environment: { action: 'stop' } } )
+ end
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'when environment is not defined' do
+ before do
+ build.update(environment: nil)
+ end
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#last_deployment' do
+ subject { build.last_deployment }
+
+ context 'when multiple deployments are created' do
+ let!(:deployment1) { create(:deployment, deployable: build) }
+ let!(:deployment2) { create(:deployment, deployable: build) }
+
+ it 'returns the latest one' do
+ is_expected.to eq(deployment2)
+ end
+ end
+ end
+
+ describe '#outdated_deployment?' do
+ subject { build.outdated_deployment? }
+
+ context 'when build succeeded' do
+ let(:build) { create(:ci_build, :success) }
+ let!(:deployment) { create(:deployment, deployable: build) }
+
+ context 'current deployment is latest' do
+ it { is_expected.to be_falsey }
+ end
+
+ context 'current deployment is not latest on environment' do
+ let!(:deployment2) { create(:deployment, environment: deployment.environment) }
+
+ it { is_expected.to be_truthy }
+ end
+ end
+
+ context 'when build failed' do
+ let(:build) { create(:ci_build, :failed) }
+
+ it { is_expected.to be_falsey }
+ end
+ end
+
+ describe '#expanded_environment_name' do
+ subject { build.expanded_environment_name }
+
+ context 'when environment uses variables' do
+ let(:build) { create(:ci_build, ref: 'master', environment: 'review/$CI_BUILD_REF_NAME') }
+
+ it { is_expected.to eq('review/master') }
+ end
+ end
end
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index a37a00f461a..a7e90c8a381 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -4,6 +4,12 @@ describe Ci::Build, models: true do
let(:build) { create(:ci_build) }
let(:test_trace) { 'This is a test' }
+ it { is_expected.to belong_to(:runner) }
+ it { is_expected.to belong_to(:trigger_request) }
+ it { is_expected.to belong_to(:erased_by) }
+
+ it { is_expected.to have_many(:deployments) }
+
describe '#trace' do
it 'obfuscates project runners token' do
allow(build).to receive(:raw_trace).and_return("Test: #{build.project.runners_token}")
diff --git a/spec/models/key_spec.rb b/spec/models/key_spec.rb
index 1a26cee9f3d..90731f55470 100644
--- a/spec/models/key_spec.rb
+++ b/spec/models/key_spec.rb
@@ -19,7 +19,7 @@ describe Key, models: true do
describe "#publishable_keys" do
it 'replaces SSH key comment with simple identifier of username + hostname' do
- expect(build(:key, user: user).publishable_key).to include("#{user.name} (localhost)")
+ expect(build(:key, user: user).publishable_key).to include("#{user.name} (#{Gitlab.config.gitlab.host})")
end
end
end
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index 12419d6fd5a..4f7c8a36cb5 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -443,6 +443,16 @@ describe Member, models: true do
member.accept_invite!(user)
end
+
+ it "refreshes user's authorized projects", truncate: true do
+ project = member.source
+
+ expect(user.authorized_projects).not_to include(project)
+
+ member.accept_invite!(user)
+
+ expect(user.authorized_projects.reload).to include(project)
+ end
end
describe "#decline_invite!" do
@@ -468,4 +478,16 @@ describe Member, models: true do
expect { member.generate_invite_token }.to change { member.invite_token}
end
end
+
+ describe "destroying a record", truncate: true do
+ it "refreshes user's authorized projects" do
+ project = create(:project, :private)
+ user = create(:user)
+ member = project.team << [user, :reporter]
+
+ member.destroy
+
+ expect(user.authorized_projects).not_to include(project)
+ end
+ end
end
diff --git a/spec/models/project_group_link_spec.rb b/spec/models/project_group_link_spec.rb
index c5ff1941378..47397a822c1 100644
--- a/spec/models/project_group_link_spec.rb
+++ b/spec/models/project_group_link_spec.rb
@@ -14,4 +14,20 @@ describe ProjectGroupLink do
it { should validate_presence_of(:group) }
it { should validate_presence_of(:group_access) }
end
+
+ describe "destroying a record", truncate: true do
+ it "refreshes group users' authorized projects" do
+ project = create(:project, :private)
+ group = create(:group)
+ reporter = create(:user)
+ group_users = group.users
+
+ group.add_reporter(reporter)
+ project.project_group_links.create(group: group)
+ group_users.each { |user| expect(user.authorized_projects).to include(project) }
+
+ project.project_group_links.destroy_all
+ group_users.each { |user| expect(user.authorized_projects).not_to include(project) }
+ end
+ end
end
diff --git a/spec/models/project_services/chat_service_spec.rb b/spec/models/project_services/chat_service_spec.rb
new file mode 100644
index 00000000000..c6a45a3e1be
--- /dev/null
+++ b/spec/models/project_services/chat_service_spec.rb
@@ -0,0 +1,15 @@
+require 'spec_helper'
+
+describe ChatService, models: true do
+ describe "Associations" do
+ it { is_expected.to have_many :chat_names }
+ end
+
+ describe '#valid_token?' do
+ subject { described_class.new }
+
+ it 'is false as it has no token' do
+ expect(subject.valid_token?('wer')).to be_falsey
+ end
+ end
+end
diff --git a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
index 652804fb444..9b80f0e7296 100644
--- a/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
+++ b/spec/models/project_services/gitlab_issue_tracker_service_spec.rb
@@ -35,9 +35,9 @@ describe GitlabIssueTrackerService, models: true do
end
it 'gives the correct path' do
- expect(@service.project_url).to eq("http://localhost/gitlab/root/#{project.path_with_namespace}/issues")
- expect(@service.new_issue_url).to eq("http://localhost/gitlab/root/#{project.path_with_namespace}/issues/new")
- expect(@service.issue_url(432)).to eq("http://localhost/gitlab/root/#{project.path_with_namespace}/issues/432")
+ expect(@service.project_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues")
+ expect(@service.new_issue_url).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/new")
+ expect(@service.issue_url(432)).to eq("http://#{Gitlab.config.gitlab.host}/gitlab/root/#{project.path_with_namespace}/issues/432")
end
end
diff --git a/spec/models/project_services/jira_service_spec.rb b/spec/models/project_services/jira_service_spec.rb
index 2a87a411e9d..d8c47322220 100644
--- a/spec/models/project_services/jira_service_spec.rb
+++ b/spec/models/project_services/jira_service_spec.rb
@@ -86,17 +86,30 @@ describe JiraService, models: true do
project_key: 'GitLabProject'
)
+ # These stubs are needed to test JiraService#close_issue.
+ # We close the issue then do another request to API to check if it got closed.
+ # Here is stubbed the API return with a closed and an opened issues.
+ open_issue = JIRA::Resource::Issue.new(@jira_service.client, attrs: { "id" => "JIRA-123" })
+ closed_issue = open_issue.dup
+ allow(open_issue).to receive(:resolution).and_return(false)
+ allow(closed_issue).to receive(:resolution).and_return(true)
+ allow(JIRA::Resource::Issue).to receive(:find).and_return(open_issue, closed_issue)
+
+ allow_any_instance_of(JIRA::Resource::Issue).to receive(:key).and_return("JIRA-123")
+
@jira_service.save
project_issues_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123'
@project_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/project/GitLabProject'
@transitions_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/transitions'
@comment_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/comment'
+ @remote_link_url = 'http://gitlab_jira_username:gitlab_jira_password@jira.example.com/rest/api/2/issue/JIRA-123/remotelink'
WebMock.stub_request(:get, @project_url)
WebMock.stub_request(:get, project_issues_url)
WebMock.stub_request(:post, @transitions_url)
WebMock.stub_request(:post, @comment_url)
+ WebMock.stub_request(:post, @remote_link_url)
end
it "calls JIRA API" do
@@ -107,6 +120,37 @@ describe JiraService, models: true do
).once
end
+ # Check https://developer.atlassian.com/jiradev/jira-platform/guides/other/guide-jira-remote-issue-links/fields-in-remote-issue-links
+ # for more information
+ it "creates Remote Link reference in JIRA for comment" do
+ @jira_service.execute(merge_request, ExternalIssue.new("JIRA-123", project))
+
+ # Creates comment
+ expect(WebMock).to have_requested(:post, @comment_url)
+
+ # Creates Remote Link in JIRA issue fields
+ expect(WebMock).to have_requested(:post, @remote_link_url).with(
+ body: hash_including(
+ GlobalID: "GitLab",
+ object: {
+ url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{merge_request.diff_head_sha}",
+ title: "GitLab: Solved by commit #{merge_request.diff_head_sha}.",
+ icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+ status: { resolved: true, icon: { url16x16: "http://www.openwebgraphics.com/resources/data/1768/16x16_apply.png", title: "Closed" } }
+ }
+ )
+ ).once
+ end
+
+ it "does not send comment or remote links to issues already closed" do
+ allow_any_instance_of(JIRA::Resource::Issue).to receive(:resolution).and_return(true)
+
+ @jira_service.execute(merge_request, ExternalIssue.new("JIRA-123", project))
+
+ expect(WebMock).not_to have_requested(:post, @comment_url)
+ expect(WebMock).not_to have_requested(:post, @remote_link_url)
+ end
+
it "references the GitLab commit/merge request" do
stub_config_setting(base_url: custom_base_url)
diff --git a/spec/models/project_services/mattermost_slash_commands_service_spec.rb b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
new file mode 100644
index 00000000000..4a1037e950b
--- /dev/null
+++ b/spec/models/project_services/mattermost_slash_commands_service_spec.rb
@@ -0,0 +1,99 @@
+require 'spec_helper'
+
+describe MattermostSlashCommandsService, models: true do
+ describe "Associations" do
+ it { is_expected.to respond_to :token }
+ end
+
+ describe '#valid_token?' do
+ subject { described_class.new }
+
+ context 'when the token is empty' do
+ it 'is false' do
+ expect(subject.valid_token?('wer')).to be_falsey
+ end
+ end
+
+ context 'when there is a token' do
+ before do
+ subject.token = '123'
+ end
+
+ it 'accepts equal tokens' do
+ expect(subject.valid_token?('123')).to be_truthy
+ end
+ end
+ end
+
+ describe '#trigger' do
+ subject { described_class.new }
+
+ context 'no token is passed' do
+ let(:params) { Hash.new }
+
+ it 'returns nil' do
+ expect(subject.trigger(params)).to be_nil
+ end
+ end
+
+ context 'with a token passed' do
+ let(:project) { create(:empty_project) }
+ let(:params) { { token: 'token' } }
+
+ before do
+ allow(subject).to receive(:token).and_return('token')
+ end
+
+ context 'no user can be found' do
+ context 'when no url can be generated' do
+ it 'responds with the authorize url' do
+ response = subject.trigger(params)
+
+ expect(response[:response_type]).to eq :ephemeral
+ expect(response[:text]).to start_with ":sweat_smile: Couldn't identify you"
+ end
+ end
+
+ context 'when an auth url can be generated' do
+ let(:params) do
+ {
+ team_domain: 'http://domain.tld',
+ team_id: 'T3423423',
+ user_id: 'U234234',
+ user_name: 'mepmep',
+ token: 'token'
+ }
+ end
+
+ let(:service) do
+ project.create_mattermost_slash_commands_service(
+ properties: { token: 'token' }
+ )
+ end
+
+ it 'generates the url' do
+ response = service.trigger(params)
+
+ expect(response[:text]).to start_with(':wave: Hi there!')
+ end
+ end
+ end
+
+ context 'when the user is authenticated' do
+ let!(:chat_name) { create(:chat_name, service: service) }
+ let(:service) do
+ project.create_mattermost_slash_commands_service(
+ properties: { token: 'token' }
+ )
+ end
+ let(:params) { { token: 'token', team_id: chat_name.team_id, user_id: chat_name.chat_id } }
+
+ it 'triggers the command' do
+ expect_any_instance_of(Gitlab::ChatCommands::Command).to receive(:execute)
+
+ service.trigger(params)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/models/project_services/slack_service/pipeline_message_spec.rb b/spec/models/project_services/slack_service/pipeline_message_spec.rb
index babb3909f56..363138a9454 100644
--- a/spec/models/project_services/slack_service/pipeline_message_spec.rb
+++ b/spec/models/project_services/slack_service/pipeline_message_spec.rb
@@ -15,7 +15,7 @@ describe SlackService::PipelineMessage do
},
project: { path_with_namespace: 'project_name',
web_url: 'example.gitlab.com' },
- commit: { author_name: 'hacker' }
+ user: { name: 'hacker' }
}
end
@@ -48,7 +48,7 @@ describe SlackService::PipelineMessage do
def build_message(status_text = status)
"<example.gitlab.com|project_name>:" \
- " Pipeline <example.gitlab.com/pipelines/123|97de212e>" \
+ " Pipeline <example.gitlab.com/pipelines/123|#123>" \
" of <example.gitlab.com/commits/develop|develop> branch" \
" by hacker #{status_text} in #{duration} #{'second'.pluralize(duration)}"
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 46fa00a79c4..25458e20618 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -20,6 +20,7 @@ describe Project, models: true do
it { is_expected.to have_many(:deploy_keys) }
it { is_expected.to have_many(:hooks).dependent(:destroy) }
it { is_expected.to have_many(:protected_branches).dependent(:destroy) }
+ it { is_expected.to have_many(:chat_services) }
it { is_expected.to have_one(:forked_project_link).dependent(:destroy) }
it { is_expected.to have_one(:slack_service).dependent(:destroy) }
it { is_expected.to have_one(:pushover_service).dependent(:destroy) }
@@ -35,6 +36,7 @@ describe Project, models: true do
it { is_expected.to have_one(:hipchat_service).dependent(:destroy) }
it { is_expected.to have_one(:flowdock_service).dependent(:destroy) }
it { is_expected.to have_one(:assembla_service).dependent(:destroy) }
+ it { is_expected.to have_one(:mattermost_slash_commands_service).dependent(:destroy) }
it { is_expected.to have_one(:gemnasium_service).dependent(:destroy) }
it { is_expected.to have_one(:buildkite_service).dependent(:destroy) }
it { is_expected.to have_one(:bamboo_service).dependent(:destroy) }
@@ -700,7 +702,7 @@ describe Project, models: true do
"/uploads/project/avatar/#{project.id}/uploads/avatar.png"
end
- it { should eq "http://localhost#{avatar_path}" }
+ it { should eq "http://#{Gitlab.config.gitlab.host}#{avatar_path}" }
end
context 'When avatar file in git' do
@@ -712,7 +714,7 @@ describe Project, models: true do
"/#{project.namespace.name}/#{project.path}/avatar"
end
- it { should eq "http://localhost#{avatar_path}" }
+ it { should eq "http://#{Gitlab.config.gitlab.host}#{avatar_path}" }
end
context 'when git repo is empty' do
@@ -1514,7 +1516,7 @@ describe Project, models: true do
members_project.team << [developer, :developer]
members_project.team << [master, :master]
- create(:project_group_link, project: shared_project, group: group)
+ create(:project_group_link, project: shared_project, group: group, group_access: Gitlab::Access::DEVELOPER)
end
it 'returns false for no user' do
@@ -1543,7 +1545,9 @@ describe Project, models: true do
expect(members_project.authorized_for_user?(developer, Gitlab::Access::MASTER)).to be(false)
expect(members_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true)
expect(shared_project.authorized_for_user?(developer, Gitlab::Access::MASTER)).to be(false)
- expect(shared_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(true)
+ expect(shared_project.authorized_for_user?(master, Gitlab::Access::MASTER)).to be(false)
+ expect(shared_project.authorized_for_user?(developer, Gitlab::Access::DEVELOPER)).to be(true)
+ expect(shared_project.authorized_for_user?(master, Gitlab::Access::DEVELOPER)).to be(true)
end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 2470d504c68..72ac41f3472 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1354,6 +1354,28 @@ describe Repository, models: true do
repository.add_tag(user, '8.5', 'master', 'foo')
end
+ it 'does not create a tag when a pre-hook fails' do
+ allow_any_instance_of(Gitlab::Git::Hook).to receive(:trigger).and_return([false, ''])
+
+ expect do
+ repository.add_tag(user, '8.5', 'master', 'foo')
+ end.to raise_error(GitHooksService::PreReceiveError)
+
+ repository.expire_tags_cache
+ expect(repository.find_tag('8.5')).to be_nil
+ end
+
+ it 'passes tag SHA to hooks' do
+ spy = GitHooksService.new
+ allow(GitHooksService).to receive(:new).and_return(spy)
+ allow(spy).to receive(:execute).and_call_original
+
+ tag = repository.add_tag(user, '8.5', 'master', 'foo')
+
+ expect(spy).to have_received(:execute).
+ with(anything, anything, anything, tag.target, anything)
+ end
+
it 'returns a Gitlab::Git::Tag object' do
tag = repository.add_tag(user, '8.5', 'master', 'foo')
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 0994159e210..e84042f8063 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -1073,7 +1073,7 @@ describe User, models: true do
it { is_expected.to eq([private_group]) }
end
- describe '#authorized_projects' do
+ describe '#authorized_projects', truncate: true do
context 'with a minimum access level' do
it 'includes projects for which the user is an owner' do
user = create(:user)
@@ -1093,6 +1093,80 @@ describe User, models: true do
.to contain_exactly(project)
end
end
+
+ it "includes user's personal projects" do
+ user = create(:user)
+ project = create(:project, :private, namespace: user.namespace)
+
+ expect(user.authorized_projects).to include(project)
+ end
+
+ it "includes personal projects user has been given access to" do
+ user1 = create(:user)
+ user2 = create(:user)
+ project = create(:project, :private, namespace: user1.namespace)
+
+ project.team << [user2, Gitlab::Access::DEVELOPER]
+
+ expect(user2.authorized_projects).to include(project)
+ end
+
+ it "includes projects of groups user has been added to" do
+ group = create(:group)
+ project = create(:project, group: group)
+ user = create(:user)
+
+ group.add_developer(user)
+
+ expect(user.authorized_projects).to include(project)
+ end
+
+ it "does not include projects of groups user has been removed from" do
+ group = create(:group)
+ project = create(:project, group: group)
+ user = create(:user)
+
+ member = group.add_developer(user)
+ expect(user.authorized_projects).to include(project)
+
+ member.destroy
+ expect(user.authorized_projects).not_to include(project)
+ end
+
+ it "includes projects shared with user's group" do
+ user = create(:user)
+ project = create(:project, :private)
+ group = create(:group)
+
+ group.add_reporter(user)
+ project.project_group_links.create(group: group)
+
+ expect(user.authorized_projects).to include(project)
+ end
+
+ it "does not include destroyed projects user had access to" do
+ user1 = create(:user)
+ user2 = create(:user)
+ project = create(:project, :private, namespace: user1.namespace)
+
+ project.team << [user2, Gitlab::Access::DEVELOPER]
+ expect(user2.authorized_projects).to include(project)
+
+ project.destroy
+ expect(user2.authorized_projects).not_to include(project)
+ end
+
+ it "does not include projects of destroyed groups user had access to" do
+ group = create(:group)
+ project = create(:project, namespace: group)
+ user = create(:user)
+
+ group.add_developer(user)
+ expect(user.authorized_projects).to include(project)
+
+ group.destroy
+ expect(user.authorized_projects).not_to include(project)
+ end
end
describe '#projects_where_can_admin_issues' do
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 8f1a1f9e827..e88a7e27d45 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -5,7 +5,7 @@ describe API::API, api: true do
let(:user) { create(:user) }
let(:key) { create(:key, user: user) }
let(:project) { create(:project) }
- let(:secret_token) { File.read Gitlab.config.gitlab_shell.secret_file }
+ let(:secret_token) { Gitlab::Shell.secret_token }
describe "GET /internal/check", no_db: true do
it do
@@ -406,7 +406,7 @@ describe API::API, api: true do
it 'returns link to create new merge request' do
expect(json_response).to match [{
"branch_name" => "new_branch",
- "url" => "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
+ "url" => "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
"new_merge_request" => true
}]
end
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 2aadab3cbe1..ce9c96ace21 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -88,4 +88,61 @@ describe API::API, api: true do
end
end
end
+
+ describe 'POST /projects/:id/services/:slug/trigger' do
+ let!(:project) { create(:empty_project) }
+ let(:service_name) { 'mattermost_slash_commands' }
+
+ context 'no service is available' do
+ it 'returns a not found message' do
+ post api("/projects/#{project.id}/services/idonotexist/trigger")
+
+ expect(response).to have_http_status(404)
+ expect(json_response["message"]).to eq("404 Service Not Found")
+ end
+ end
+
+ context 'the service exists' do
+ let(:params) { { token: 'token' } }
+
+ context 'the service is not active' do
+ let!(:inactive_service) do
+ project.create_mattermost_slash_commands_service(
+ active: false,
+ properties: { token: 'token' }
+ )
+ end
+
+ it 'when the service is inactive' do
+ post api("/projects/#{project.id}/services/mattermost_slash_commands/trigger")
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'the service is active' do
+ let!(:active_service) do
+ project.create_mattermost_slash_commands_service(
+ active: true,
+ properties: { token: 'token' }
+ )
+ end
+
+ it 'retusn status 200' do
+ post api("/projects/#{project.id}/services/mattermost_slash_commands/trigger"), params
+
+ expect(response).to have_http_status(200)
+ end
+ end
+
+ context 'when the project can not be found' do
+ it 'returns a generic 404' do
+ post api("/projects/404/services/mattermost_slash_commands/trigger"), params
+
+ expect(response).to have_http_status(404)
+ expect(json_response["message"]).to eq("404 Service Not Found")
+ end
+ end
+ end
+ end
end
diff --git a/spec/requests/projects/cycle_analytics_events_spec.rb b/spec/requests/projects/cycle_analytics_events_spec.rb
new file mode 100644
index 00000000000..705dbb7d1c0
--- /dev/null
+++ b/spec/requests/projects/cycle_analytics_events_spec.rb
@@ -0,0 +1,140 @@
+require 'spec_helper'
+
+describe 'cycle analytics events' do
+ let(:user) { create(:user) }
+ let(:project) { create(:project) }
+ let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
+
+ describe 'GET /:namespace/:project/cycle_analytics/events/issues' do
+ before do
+ project.team << [user, :developer]
+
+ allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return([issue])
+
+ 3.times { create_cycle }
+ deploy_master
+
+ login_as(user)
+ end
+
+ it 'lists the issue events' do
+ get namespace_project_cycle_analytics_issue_path(project.namespace, project, format: :json)
+
+ expect(json_response['events']).not_to be_empty
+
+ first_issue_iid = Issue.order(created_at: :desc).pluck(:iid).first.to_s
+
+ expect(json_response['events'].first['iid']).to eq(first_issue_iid)
+ end
+
+ it 'lists the plan events' do
+ get namespace_project_cycle_analytics_plan_path(project.namespace, project, format: :json)
+
+ expect(json_response['events']).not_to be_empty
+
+ expect(json_response['events'].first['short_sha']).to eq(MergeRequest.last.commits.first.short_id)
+ end
+
+ it 'lists the code events' do
+ get namespace_project_cycle_analytics_code_path(project.namespace, project, format: :json)
+
+ expect(json_response['events']).not_to be_empty
+
+ first_mr_iid = MergeRequest.order(created_at: :desc).pluck(:iid).first.to_s
+
+ expect(json_response['events'].first['iid']).to eq(first_mr_iid)
+ end
+
+ it 'lists the test events' do
+ get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json)
+
+ expect(json_response['events']).not_to be_empty
+
+ expect(json_response['events'].first['date']).not_to be_empty
+ end
+
+ it 'lists the review events' do
+ get namespace_project_cycle_analytics_review_path(project.namespace, project, format: :json)
+
+ expect(json_response['events']).not_to be_empty
+
+ first_mr_iid = MergeRequest.order(created_at: :desc).pluck(:iid).first.to_s
+
+ expect(json_response['events'].first['iid']).to eq(first_mr_iid)
+ end
+
+ it 'lists the staging events' do
+ get namespace_project_cycle_analytics_staging_path(project.namespace, project, format: :json)
+
+ expect(json_response['events']).not_to be_empty
+
+ expect(json_response['events'].first['date']).not_to be_empty
+ end
+
+ it 'lists the production events' do
+ get namespace_project_cycle_analytics_production_path(project.namespace, project, format: :json)
+
+ expect(json_response['events']).not_to be_empty
+
+ first_issue_iid = Issue.order(created_at: :desc).pluck(:iid).first.to_s
+
+ expect(json_response['events'].first['iid']).to eq(first_issue_iid)
+ end
+
+ context 'specific branch' do
+ it 'lists the test events' do
+ branch = MergeRequest.first.source_branch
+
+ get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json, branch: branch)
+
+ expect(json_response['events']).not_to be_empty
+
+ expect(json_response['events'].first['date']).not_to be_empty
+ end
+ end
+
+ context 'with private project and builds' do
+ before do
+ ProjectMember.first.update(access_level: Gitlab::Access::GUEST)
+ end
+
+ it 'does not list the test events' do
+ get namespace_project_cycle_analytics_test_path(project.namespace, project, format: :json)
+
+ expect(response).to have_http_status(:not_found)
+ end
+
+ it 'does not list the staging events' do
+ get namespace_project_cycle_analytics_staging_path(project.namespace, project, format: :json)
+
+ expect(response).to have_http_status(:not_found)
+ end
+
+ it 'lists the issue events' do
+ get namespace_project_cycle_analytics_issue_path(project.namespace, project, format: :json)
+
+ expect(response).to have_http_status(:ok)
+ end
+ end
+ end
+
+ def json_response
+ JSON.parse(response.body)
+ end
+
+ def create_cycle
+ milestone = create(:milestone, project: project)
+ issue.update(milestone: milestone)
+ mr = create_merge_request_closing_issue(issue)
+
+ pipeline = create(:ci_empty_pipeline, status: 'created', project: project, ref: mr.source_branch, sha: mr.source_branch_sha)
+ pipeline.run
+
+ create(:ci_build, pipeline: pipeline, status: :success, author: user)
+ create(:ci_build, pipeline: pipeline, status: :success, author: user)
+
+ merge_merge_requests_closing_issue(issue)
+
+ ProcessCommitWorker.new.perform(project.id, user.id, mr.commits.last.sha)
+ end
+end
diff --git a/spec/serializers/analytics_build_entity_spec.rb b/spec/serializers/analytics_build_entity_spec.rb
new file mode 100644
index 00000000000..9ac6f20fd3c
--- /dev/null
+++ b/spec/serializers/analytics_build_entity_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe AnalyticsBuildEntity do
+ let(:entity) do
+ described_class.new(build, request: double)
+ end
+
+ context 'build with an author' do
+ let(:user) { create(:user) }
+ let(:build) { create(:ci_build, author: user) }
+
+ subject { entity.as_json }
+
+ it 'contains the URL' do
+ expect(subject).to include(:url)
+ end
+
+ it 'contains the author' do
+ expect(subject).to include(:author)
+ end
+
+ it 'does not contain sensitive information' do
+ expect(subject).not_to include(/token/)
+ expect(subject).not_to include(/variables/)
+ end
+ end
+end
diff --git a/spec/serializers/analytics_build_serializer_spec.rb b/spec/serializers/analytics_build_serializer_spec.rb
new file mode 100644
index 00000000000..a0a9d9a5f12
--- /dev/null
+++ b/spec/serializers/analytics_build_serializer_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe AnalyticsBuildSerializer do
+ let(:serializer) do
+ described_class
+ .new.represent(resource)
+ end
+
+ let(:json) { serializer.as_json }
+ let(:resource) { create(:ci_build) }
+
+ context 'when there is a single object provided' do
+ it 'it generates payload for single object' do
+ expect(json).to be_an_instance_of Hash
+ end
+
+ it 'contains important elements of analyticsBuild' do
+ expect(json)
+ .to include(:name, :branch, :short_sha, :date, :total_time, :url, :author)
+ end
+ end
+end
diff --git a/spec/serializers/analytics_generic_entity_spec.rb b/spec/serializers/analytics_generic_entity_spec.rb
new file mode 100644
index 00000000000..68086216ba9
--- /dev/null
+++ b/spec/serializers/analytics_generic_entity_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe AnalyticsIssueEntity do
+ let(:user) { create(:user) }
+ let(:entity_hash) do
+ {
+ total_time: "172802.724419",
+ title: "Eos voluptatem inventore in sed.",
+ iid: "1",
+ id: "1",
+ created_at: "2016-11-12 15:04:02.948604",
+ author: user,
+ }
+ end
+
+ let(:project) { create(:empty_project) }
+ let(:request) { EntityRequest.new(project: project, entity: :merge_request) }
+
+ let(:entity) do
+ described_class.new(entity_hash, request: request, project: project)
+ end
+
+ context 'generic entity' do
+ subject { entity.as_json }
+
+ it 'contains the entity URL' do
+ expect(subject).to include(:url)
+ end
+
+ it 'contains the author' do
+ expect(subject).to include(:author)
+ end
+
+ it 'does not contain sensitive information' do
+ expect(subject).not_to include(/token/)
+ expect(subject).not_to include(/variables/)
+ end
+ end
+end
diff --git a/spec/serializers/analytics_issue_serializer_spec.rb b/spec/serializers/analytics_issue_serializer_spec.rb
new file mode 100644
index 00000000000..2842e1ba52f
--- /dev/null
+++ b/spec/serializers/analytics_issue_serializer_spec.rb
@@ -0,0 +1,33 @@
+require 'spec_helper'
+
+describe AnalyticsIssueSerializer do
+ let(:serializer) do
+ described_class
+ .new(project: project, entity: :merge_request)
+ .represent(resource)
+ end
+
+ let(:user) { create(:user) }
+ let(:json) { serializer.as_json }
+ let(:project) { create(:project) }
+ let(:resource) do
+ {
+ total_time: "172802.724419",
+ title: "Eos voluptatem inventore in sed.",
+ iid: "1",
+ id: "1",
+ created_at: "2016-11-12 15:04:02.948604",
+ author: user,
+ }
+ end
+
+ context 'when there is a single object provided' do
+ it 'it generates payload for single object' do
+ expect(json).to be_an_instance_of Hash
+ end
+
+ it 'contains important elements of the issue' do
+ expect(json).to include(:title, :iid, :created_at, :total_time, :url, :author)
+ end
+ end
+end
diff --git a/spec/serializers/analytics_merge_request_serializer_spec.rb b/spec/serializers/analytics_merge_request_serializer_spec.rb
new file mode 100644
index 00000000000..564207984df
--- /dev/null
+++ b/spec/serializers/analytics_merge_request_serializer_spec.rb
@@ -0,0 +1,34 @@
+require 'spec_helper'
+
+describe AnalyticsMergeRequestSerializer do
+ let(:serializer) do
+ described_class
+ .new(project: project, entity: :merge_request)
+ .represent(resource)
+ end
+
+ let(:user) { create(:user) }
+ let(:json) { serializer.as_json }
+ let(:project) { create(:project) }
+ let(:resource) do
+ {
+ total_time: "172802.724419",
+ title: "Eos voluptatem inventore in sed.",
+ iid: "1",
+ id: "1",
+ state: 'open',
+ created_at: "2016-11-12 15:04:02.948604",
+ author: user
+ }
+ end
+
+ context 'when there is a single object provided' do
+ it 'it generates payload for single object' do
+ expect(json).to be_an_instance_of Hash
+ end
+
+ it 'contains important elements of the merge request' do
+ expect(json).to include(:title, :iid, :created_at, :total_time, :url, :author, :state)
+ end
+ end
+end
diff --git a/spec/serializers/entity_date_helper_spec.rb b/spec/serializers/entity_date_helper_spec.rb
new file mode 100644
index 00000000000..b9cc2f64831
--- /dev/null
+++ b/spec/serializers/entity_date_helper_spec.rb
@@ -0,0 +1,45 @@
+require 'spec_helper'
+
+describe EntityDateHelper do
+ let(:date_helper_class) { Class.new { include EntityDateHelper }.new }
+
+ it 'converts 0 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(0)).to eq(seconds: 0)
+ end
+
+ it 'converts 40 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(40)).to eq(seconds: 40)
+ end
+
+ it 'converts 60 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(60)).to eq(mins: 1)
+ end
+
+ it 'converts 70 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(70)).to eq(mins: 1, seconds: 10)
+ end
+
+ it 'converts 3600 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(3600)).to eq(hours: 1)
+ end
+
+ it 'converts 3750 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(3750)).to eq(hours: 1, mins: 2, seconds: 30)
+ end
+
+ it 'converts 86400 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(86400)).to eq(days: 1)
+ end
+
+ it 'converts 86560 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(86560)).to eq(days: 1, mins: 2, seconds: 40)
+ end
+
+ it 'converts 86760 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(99760)).to eq(days: 1, hours: 3, mins: 42, seconds: 40)
+ end
+
+ it 'converts 986760 seconds' do
+ expect(date_helper_class.distance_of_time_as_hash(986760)).to eq(days: 11, hours: 10, mins: 6)
+ end
+end
diff --git a/spec/services/chat_names/find_user_service_spec.rb b/spec/services/chat_names/find_user_service_spec.rb
index 5b885b2c657..51441e8f3be 100644
--- a/spec/services/chat_names/find_user_service_spec.rb
+++ b/spec/services/chat_names/find_user_service_spec.rb
@@ -13,7 +13,7 @@ describe ChatNames::FindUserService, services: true do
context 'when existing user is requested' do
let(:params) { { team_id: chat_name.team_id, user_id: chat_name.chat_id } }
- it 'returns existing user' do
+ it 'returns the existing user' do
is_expected.to eq(user)
end
diff --git a/spec/services/destroy_group_service_spec.rb b/spec/services/destroy_group_service_spec.rb
index da724643604..538e85cdc89 100644
--- a/spec/services/destroy_group_service_spec.rb
+++ b/spec/services/destroy_group_service_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe DestroyGroupService, services: true do
+ include DatabaseConnectionHelpers
+
let!(:user) { create(:user) }
let!(:group) { create(:group) }
let!(:project) { create(:project, namespace: group) }
@@ -50,6 +52,44 @@ describe DestroyGroupService, services: true do
describe 'asynchronous delete' do
it_behaves_like 'group destruction', true
+
+ context 'potential race conditions' do
+ context "when the `GroupDestroyWorker` task runs immediately" do
+ it "deletes the group" do
+ # Commit the contents of this spec's transaction so far
+ # so subsequent db connections can see it.
+ #
+ # DO NOT REMOVE THIS LINE, even if you see a WARNING with "No
+ # transaction is currently in progress". Without this, this
+ # spec will always be green, since the group created in setup
+ # cannot be seen by any other connections / threads in this spec.
+ Group.connection.commit_db_transaction
+
+ group_record = run_with_new_database_connection do |conn|
+ conn.execute("SELECT * FROM namespaces WHERE id = #{group.id}").first
+ end
+
+ expect(group_record).not_to be_nil
+
+ # Execute the contents of `GroupDestroyWorker` in a separate thread, to
+ # simulate data manipulation by the Sidekiq worker (different database
+ # connection / transaction).
+ expect(GroupDestroyWorker).to receive(:perform_async).and_wrap_original do |m, group_id, user_id|
+ Thread.new { m[group_id, user_id] }.join(5)
+ end
+
+ # Kick off the initial group destroy in a new thread, so that
+ # it doesn't share this spec's database transaction.
+ Thread.new { DestroyGroupService.new(group, user).async_execute }.join(5)
+
+ group_record = run_with_new_database_connection do |conn|
+ conn.execute("SELECT * FROM namespaces WHERE id = #{group.id}").first
+ end
+
+ expect(group_record).to be_nil
+ end
+ end
+ end
end
describe 'synchronous delete' do
diff --git a/spec/services/git_push_service_spec.rb b/spec/services/git_push_service_spec.rb
index cea7e6429f9..62f9982e840 100644
--- a/spec/services/git_push_service_spec.rb
+++ b/spec/services/git_push_service_spec.rb
@@ -490,7 +490,17 @@ describe GitPushService, services: true do
context "closing an issue" do
let(:message) { "this is some work.\n\ncloses JIRA-1" }
- let(:comment_body) { { body: "Issue solved with [#{closing_commit.id}|http://localhost/#{project.path_with_namespace}/commit/#{closing_commit.id}]." }.to_json }
+ let(:comment_body) { { body: "Issue solved with [#{closing_commit.id}|http://#{Gitlab.config.gitlab.host}/#{project.path_with_namespace}/commit/#{closing_commit.id}]." }.to_json }
+
+ before do
+ open_issue = JIRA::Resource::Issue.new(jira_tracker.client, attrs: { "id" => "JIRA-1" })
+ closed_issue = open_issue.dup
+ allow(open_issue).to receive(:resolution).and_return(false)
+ allow(closed_issue).to receive(:resolution).and_return(true)
+ allow(JIRA::Resource::Issue).to receive(:find).and_return(open_issue, closed_issue)
+
+ allow_any_instance_of(JIRA::Resource::Issue).to receive(:key).and_return("JIRA-1")
+ end
context "using right markdown" do
it "initiates one api call to jira server to close the issue" do
diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb
index 3a71776e81f..08829e4be70 100644
--- a/spec/services/merge_requests/get_urls_service_spec.rb
+++ b/spec/services/merge_requests/get_urls_service_spec.rb
@@ -4,8 +4,8 @@ describe MergeRequests::GetUrlsService do
let(:project) { create(:project, :public) }
let(:service) { MergeRequests::GetUrlsService.new(project) }
let(:source_branch) { "my_branch" }
- let(:new_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{source_branch}" }
- let(:show_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/#{merge_request.iid}" }
+ let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{source_branch}" }
+ let(:show_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/#{merge_request.iid}" }
let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
let(:deleted_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 #{Gitlab::Git::BLANK_SHA} refs/heads/#{source_branch}" }
let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
@@ -115,7 +115,7 @@ describe MergeRequests::GetUrlsService do
let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" }
let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/existing_branch" }
let(:changes) { "#{new_branch_changes}\n#{existing_branch_changes}" }
- let(:new_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" }
+ let(:new_merge_request_url) { "http://#{Gitlab.config.gitlab.host}/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" }
it 'returns 2 urls for both creating new and showing merge request' do
result = service.execute(changes)
diff --git a/spec/services/merge_requests/merge_service_spec.rb b/spec/services/merge_requests/merge_service_spec.rb
index f93d7732a9a..1fd9f5a4910 100644
--- a/spec/services/merge_requests/merge_service_spec.rb
+++ b/spec/services/merge_requests/merge_service_spec.rb
@@ -67,17 +67,19 @@ describe MergeRequests::MergeService, services: true do
it 'closes issues on JIRA issue tracker' do
jira_issue = ExternalIssue.new('JIRA-123', project)
+ stub_jira_urls(jira_issue)
commit = double('commit', safe_message: "Fixes #{jira_issue.to_reference}")
allow(merge_request).to receive(:commits).and_return([commit])
- expect_any_instance_of(JiraService).to receive(:close_issue).with(merge_request, jira_issue).once
+ expect_any_instance_of(JiraService).to receive(:close_issue).with(merge_request, an_instance_of(JIRA::Resource::Issue)).once
service.execute(merge_request)
end
context "wrong issue markdown" do
it 'does not close issues on JIRA issue tracker' do
- jira_issue = ExternalIssue.new('#123', project)
+ jira_issue = ExternalIssue.new('#JIRA-123', project)
+ stub_jira_urls(jira_issue)
commit = double('commit', safe_message: "Fixes #{jira_issue.to_reference}")
allow(merge_request).to receive(:commits).and_return([commit])
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 2cf9883113c..fbd22560d6e 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -34,6 +34,8 @@ describe Projects::CreateService, services: true do
@group = create :group
@group.add_owner(@user)
+ @user.refresh_authorized_projects # Ensure cache is warm
+
@opts.merge!(namespace_id: @group.id)
@project = create_project(@user, @opts)
end
@@ -41,6 +43,7 @@ describe Projects::CreateService, services: true do
it { expect(@project).to be_valid }
it { expect(@project.owner).to eq(@group) }
it { expect(@project.namespace).to eq(@group) }
+ it { expect(@user.authorized_projects).to include(@project) }
end
context 'error handling' do
diff --git a/spec/services/system_note_service_spec.rb b/spec/services/system_note_service_spec.rb
index 5bb107fdd85..56d39e9a005 100644
--- a/spec/services/system_note_service_spec.rb
+++ b/spec/services/system_note_service_spec.rb
@@ -1,6 +1,8 @@
require 'spec_helper'
describe SystemNoteService, services: true do
+ include Gitlab::Routing.url_helpers
+
let(:project) { create(:project) }
let(:author) { create(:user) }
let(:noteable) { create(:issue, project: project) }
@@ -543,23 +545,55 @@ describe SystemNoteService, services: true do
before { stub_jira_urls(jira_issue.id) }
- context 'in JIRA issue tracker' do
+ context 'in issue' do
before { jira_service_settings }
describe "new reference" do
subject { described_class.cross_reference(jira_issue, commit, author) }
it { is_expected.to eq(success_message) }
+
+ it "creates remote link" do
+ subject
+
+ expect(WebMock).to have_requested(:post, jira_api_remote_link_url(jira_issue)).with(
+ body: hash_including(
+ GlobalID: "GitLab",
+ object: {
+ url: namespace_project_commit_url(project.namespace, project, commit),
+ title: "GitLab: Mentioned on commit - #{commit.title}",
+ icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+ status: { resolved: false }
+ }
+ )
+ ).once
+ end
end
end
- context 'issue from an issue' do
+ context 'in commit' do
context 'in JIRA issue tracker' do
before { jira_service_settings }
subject { described_class.cross_reference(jira_issue, issue, author) }
it { is_expected.to eq(success_message) }
+
+ it "creates remote link" do
+ subject
+
+ expect(WebMock).to have_requested(:post, jira_api_remote_link_url(jira_issue)).with(
+ body: hash_including(
+ GlobalID: "GitLab",
+ object: {
+ url: namespace_project_issue_url(project.namespace, project, issue),
+ title: "GitLab: Mentioned on issue - #{issue.title}",
+ icon: { title: "GitLab", url16x16: "https://gitlab.com/favicon.ico" },
+ status: { resolved: false }
+ }
+ )
+ ).once
+ end
end
end
@@ -572,6 +606,13 @@ describe SystemNoteService, services: true do
subject { described_class.cross_reference(jira_issue, commit, author) }
it { is_expected.not_to eq(success_message) }
+
+ it 'does not try to create comment and remote link' do
+ subject
+
+ expect(WebMock).not_to have_requested(:post, jira_api_comment_url(jira_issue))
+ expect(WebMock).not_to have_requested(:post, jira_api_remote_link_url(jira_issue))
+ end
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 73cf4c9a24c..bead1a006d1 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -26,10 +26,11 @@ RSpec.configure do |config|
config.verbose_retry = true
config.display_try_failure_messages = true
- config.include Devise::Test::ControllerHelpers, type: :controller
+ config.include Devise::Test::ControllerHelpers, type: :controller
+ config.include Devise::Test::ControllerHelpers, type: :view
config.include Warden::Test::Helpers, type: :request
- config.include LoginHelpers, type: :feature
- config.include SearchHelpers, type: :feature
+ config.include LoginHelpers, type: :feature
+ config.include SearchHelpers, type: :feature
config.include StubConfiguration
config.include EmailHelpers
config.include TestEnv
diff --git a/spec/support/database_connection_helpers.rb b/spec/support/database_connection_helpers.rb
new file mode 100644
index 00000000000..763329499f0
--- /dev/null
+++ b/spec/support/database_connection_helpers.rb
@@ -0,0 +1,9 @@
+module DatabaseConnectionHelpers
+ def run_with_new_database_connection
+ pool = ActiveRecord::Base.connection_pool
+ conn = pool.checkout
+ yield conn
+ ensure
+ pool.checkin(conn)
+ end
+end
diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb
index ac38e31b77e..247f0954221 100644
--- a/spec/support/db_cleaner.rb
+++ b/spec/support/db_cleaner.rb
@@ -11,6 +11,10 @@ RSpec.configure do |config|
DatabaseCleaner.strategy = :truncation
end
+ config.before(:each, truncate: true) do
+ DatabaseCleaner.strategy = :truncation
+ end
+
config.before(:each) do
DatabaseCleaner.start
end
diff --git a/spec/support/jira_service_helper.rb b/spec/support/jira_service_helper.rb
index 96e0dad6b55..7437ba2688d 100644
--- a/spec/support/jira_service_helper.rb
+++ b/spec/support/jira_service_helper.rb
@@ -57,6 +57,10 @@ module JiraServiceHelper
JIRA_API + "/issue/#{issue_id}/comment"
end
+ def jira_api_remote_link_url(issue_id)
+ JIRA_API + "/issue/#{issue_id}/remotelink"
+ end
+
def jira_api_transition_url(issue_id)
JIRA_API + "/issue/#{issue_id}/transitions"
end
@@ -75,6 +79,7 @@ module JiraServiceHelper
WebMock.stub_request(:get, jira_issue_url(issue_id))
WebMock.stub_request(:get, jira_api_test_url)
WebMock.stub_request(:post, jira_api_comment_url(issue_id))
+ WebMock.stub_request(:post, jira_api_remote_link_url(issue_id))
WebMock.stub_request(:post, jira_api_transition_url(issue_id))
end
end
diff --git a/spec/views/projects/builds/show.html.haml_spec.rb b/spec/views/projects/builds/show.html.haml_spec.rb
index da43622d3f9..e0c77201116 100644
--- a/spec/views/projects/builds/show.html.haml_spec.rb
+++ b/spec/views/projects/builds/show.html.haml_spec.rb
@@ -1,14 +1,12 @@
require 'spec_helper'
-describe 'projects/builds/show' do
- include Devise::Test::ControllerHelpers
-
+describe 'projects/builds/show', :view do
let(:project) { create(:project) }
+ let(:build) { create(:ci_build, pipeline: pipeline) }
+
let(:pipeline) do
- create(:ci_pipeline, project: project,
- sha: project.commit.id)
+ create(:ci_pipeline, project: project, sha: project.commit.id)
end
- let(:build) { create(:ci_build, pipeline: pipeline) }
before do
assign(:build, build)
@@ -17,6 +15,129 @@ describe 'projects/builds/show' do
allow(view).to receive(:can?).and_return(true)
end
+ describe 'environment info in build view' do
+ context 'build with latest deployment' do
+ let(:build) do
+ create(:ci_build, :success, environment: 'staging')
+ end
+
+ before do
+ create(:environment, name: 'staging')
+ create(:deployment, deployable: build)
+ end
+
+ it 'shows deployment message' do
+ expected_text = 'This build is the most recent deployment'
+ render
+
+ expect(rendered).to have_css(
+ '.environment-information', text: expected_text)
+ end
+ end
+
+ context 'build with outdated deployment' do
+ let(:build) do
+ create(:ci_build, :success, environment: 'staging', pipeline: pipeline)
+ end
+
+ let(:second_build) do
+ create(:ci_build, :success, environment: 'staging', pipeline: pipeline)
+ end
+
+ let(:environment) do
+ create(:environment, name: 'staging', project: project)
+ end
+
+ let!(:first_deployment) do
+ create(:deployment, environment: environment, deployable: build)
+ end
+
+ let!(:second_deployment) do
+ create(:deployment, environment: environment, deployable: second_build)
+ end
+
+ it 'shows deployment message' do
+ expected_text = 'This build is an out-of-date deployment ' \
+ "to staging.\nView the most recent deployment ##{second_deployment.iid}."
+ render
+
+ expect(rendered).to have_css('.environment-information', text: expected_text)
+ end
+ end
+
+ context 'build failed to deploy' do
+ let(:build) do
+ create(:ci_build, :failed, environment: 'staging', pipeline: pipeline)
+ end
+
+ let!(:environment) do
+ create(:environment, name: 'staging', project: project)
+ end
+
+ it 'shows deployment message' do
+ expected_text = 'The deployment of this build to staging did not succeed.'
+ render
+
+ expect(rendered).to have_css(
+ '.environment-information', text: expected_text)
+ end
+ end
+
+ context 'build will deploy' do
+ let(:build) do
+ create(:ci_build, :running, environment: 'staging', pipeline: pipeline)
+ end
+
+ let!(:environment) do
+ create(:environment, name: 'staging', project: project)
+ end
+
+ it 'shows deployment message' do
+ expected_text = 'This build is creating a deployment to staging'
+ render
+
+ expect(rendered).to have_css(
+ '.environment-information', text: expected_text)
+ end
+ end
+
+ context 'build that failed to deploy and environment has not been created' do
+ let(:build) do
+ create(:ci_build, :failed, environment: 'staging', pipeline: pipeline)
+ end
+
+ let!(:environment) do
+ create(:environment, name: 'staging', project: project)
+ end
+
+ it 'shows deployment message' do
+ expected_text = 'The deployment of this build to staging did not succeed'
+ render
+
+ expect(rendered).to have_css(
+ '.environment-information', text: expected_text)
+ end
+ end
+
+ context 'build that will deploy and environment has not been created' do
+ let(:build) do
+ create(:ci_build, :running, environment: 'staging', pipeline: pipeline)
+ end
+
+ let!(:environment) do
+ create(:environment, name: 'staging', project: project)
+ end
+
+ it 'shows deployment message' do
+ expected_text = 'This build is creating a deployment to staging'
+ render
+
+ expect(rendered).to have_css(
+ '.environment-information', text: expected_text)
+ end
+ end
+ end
+
context 'when build is running' do
before do
build.run!
diff --git a/spec/workers/authorized_projects_worker_spec.rb b/spec/workers/authorized_projects_worker_spec.rb
new file mode 100644
index 00000000000..18a1aab766c
--- /dev/null
+++ b/spec/workers/authorized_projects_worker_spec.rb
@@ -0,0 +1,22 @@
+require 'spec_helper'
+
+describe AuthorizedProjectsWorker do
+ describe '#perform' do
+ it "refreshes user's authorized projects" do
+ user = create(:user)
+
+ expect(User).to receive(:find_by).with(id: user.id).and_return(user)
+ expect(user).to receive(:refresh_authorized_projects)
+
+ described_class.new.perform(user.id)
+ end
+
+ context "when user is not found" do
+ it "does nothing" do
+ expect_any_instance_of(User).not_to receive(:refresh_authorized_projects)
+
+ described_class.new.perform(999_999)
+ end
+ end
+ end
+end
diff --git a/spec/workers/pipeline_metrics_worker_spec.rb b/spec/workers/pipeline_metrics_worker_spec.rb
index 2c9e7c2cd02..2d47d93acec 100644
--- a/spec/workers/pipeline_metrics_worker_spec.rb
+++ b/spec/workers/pipeline_metrics_worker_spec.rb
@@ -15,32 +15,36 @@ describe PipelineMetricsWorker do
end
describe '#perform' do
- subject { described_class.new.perform(pipeline.id) }
+ before do
+ described_class.new.perform(pipeline.id)
+ end
context 'when pipeline is running' do
let(:status) { 'running' }
it 'records the build start time' do
- subject
-
expect(merge_request.reload.metrics.latest_build_started_at).to be_like_time(pipeline.started_at)
end
it 'clears the build end time' do
- subject
-
expect(merge_request.reload.metrics.latest_build_finished_at).to be_nil
end
+
+ it 'records the pipeline' do
+ expect(merge_request.reload.metrics.pipeline).to eq(pipeline)
+ end
end
context 'when pipeline succeeded' do
let(:status) { 'success' }
it 'records the build end time' do
- subject
-
expect(merge_request.reload.metrics.latest_build_finished_at).to be_like_time(pipeline.finished_at)
end
+
+ it 'records the pipeline' do
+ expect(merge_request.reload.metrics.pipeline).to eq(pipeline)
+ end
end
end
end