summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorPhil Hughes <me@iamphill.com>2017-05-03 17:04:47 +0100
committerPhil Hughes <me@iamphill.com>2017-05-03 17:04:47 +0100
commitf29e5d4d93123ea73e5f58be46020781af2ef7cb (patch)
treed08a8f8e5a9cf30dd4f238c187673ffe30ac39b3 /spec
parent4134d700623404948f163349882caf4a6d940cf3 (diff)
parent8f29bf96b9306fd95b9b98019e80173b47b3a6b8 (diff)
downloadgitlab-ce-f29e5d4d93123ea73e5f58be46020781af2ef7cb.tar.gz
Merge branch 'master' into deploy-keys-load-async
Diffstat (limited to 'spec')
-rw-r--r--spec/controllers/application_controller_spec.rb8
-rw-r--r--spec/controllers/blob_controller_spec.rb67
-rw-r--r--spec/controllers/groups/milestones_controller_spec.rb12
-rw-r--r--spec/controllers/oauth/authorizations_controller_spec.rb55
-rw-r--r--spec/controllers/profiles/personal_access_tokens_controller_spec.rb (renamed from spec/controllers/profiles/personal_access_tokens_spec.rb)0
-rw-r--r--spec/controllers/projects/blob_controller_spec.rb51
-rw-r--r--spec/controllers/projects/deployments_controller_spec.rb42
-rw-r--r--spec/controllers/projects/milestones_controller_spec.rb3
-rw-r--r--spec/controllers/projects/notes_controller_spec.rb41
-rw-r--r--spec/controllers/projects/todos_controller_spec.rb (renamed from spec/controllers/projects/todo_controller_spec.rb)0
-rw-r--r--spec/controllers/snippets/notes_controller_spec.rb196
-rw-r--r--spec/controllers/snippets_controller_spec.rb180
-rw-r--r--spec/factories/notes.rb2
-rw-r--r--spec/factories/project_hooks.rb2
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/features/admin/admin_hooks_spec.rb43
-rw-r--r--spec/features/admin/admin_requests_profiles_spec.rb69
-rw-r--r--spec/features/atom/users_spec.rb2
-rw-r--r--spec/features/explore/groups_list_spec.rb28
-rw-r--r--spec/features/issues/form_spec.rb38
-rw-r--r--spec/features/issues/issue_sidebar_spec.rb11
-rw-r--r--spec/features/merge_requests/create_new_mr_spec.rb2
-rw-r--r--spec/features/milestones/milestones_spec.rb3
-rw-r--r--spec/features/projects/blobs/blob_show_spec.rb39
-rw-r--r--spec/features/projects/commit/cherry_pick_spec.rb6
-rw-r--r--spec/features/projects/environments/environment_spec.rb2
-rw-r--r--spec/features/projects/merge_request_button_spec.rb4
-rw-r--r--spec/features/projects/milestones/milestone_spec.rb5
-rw-r--r--spec/features/projects/settings/integration_settings_spec.rb94
-rw-r--r--spec/features/projects/snippets/show_spec.rb144
-rw-r--r--spec/features/protected_branches/access_control_ce_spec.rb2
-rw-r--r--spec/features/protected_branches_spec.rb2
-rw-r--r--spec/features/protected_tags/access_control_ce_spec.rb1
-rw-r--r--spec/features/security/project/internal_access_spec.rb15
-rw-r--r--spec/features/security/project/private_access_spec.rb15
-rw-r--r--spec/features/security/project/public_access_spec.rb15
-rw-r--r--spec/features/snippets/create_snippet_spec.rb8
-rw-r--r--spec/features/snippets/notes_on_personal_snippets_spec.rb39
-rw-r--r--spec/features/snippets/public_snippets_spec.rb3
-rw-r--r--spec/features/snippets/show_spec.rb138
-rw-r--r--spec/features/todos/todos_filtering_spec.rb4
-rw-r--r--spec/features/todos/todos_spec.rb77
-rw-r--r--spec/features/triggers_spec.rb18
-rw-r--r--spec/finders/issues_finder_spec.rb8
-rw-r--r--spec/finders/merge_requests_finder_spec.rb8
-rw-r--r--spec/finders/notes_finder_spec.rb9
-rw-r--r--spec/finders/snippets_finder_spec.rb32
-rw-r--r--spec/fixtures/api/schemas/deployments.json58
-rw-r--r--spec/helpers/award_emoji_helper_spec.rb61
-rw-r--r--spec/helpers/blob_helper_spec.rb1
-rw-r--r--spec/helpers/events_helper_spec.rb2
-rw-r--r--spec/helpers/markup_helper_spec.rb2
-rw-r--r--spec/helpers/merge_requests_helper_spec.rb46
-rw-r--r--spec/javascripts/blob/pdf/index_spec.js6
-rw-r--r--spec/javascripts/blob/pdf/test.pdfbin11956 -> 0 bytes
-rw-r--r--spec/javascripts/fixtures/environments.rb30
-rw-r--r--spec/javascripts/fixtures/environments/metrics.html.haml62
-rw-r--r--spec/javascripts/fixtures/line_highlighter.html.haml2
-rw-r--r--spec/javascripts/fixtures/pdf.rb18
-rw-r--r--spec/javascripts/landing_spec.js160
-rw-r--r--spec/javascripts/monitoring/deployments_spec.js133
-rw-r--r--spec/javascripts/monitoring/prometheus_graph_spec.js4
-rw-r--r--spec/javascripts/pdf/index_spec.js61
-rw-r--r--spec/javascripts/pdf/page_spec.js57
-rw-r--r--spec/lib/banzai/renderer_spec.rb2
-rw-r--r--spec/lib/constraints/group_url_constrainer_spec.rb7
-rw-r--r--spec/lib/gitlab/changes_list_spec.rb2
-rw-r--r--spec/lib/gitlab/checks/force_push_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/build/credentials/factory_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/build/credentials/registry_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/cron_parser_spec.rb88
-rw-r--r--spec/lib/gitlab/current_settings_spec.rb4
-rw-r--r--spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb2
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb33
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb197
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb171
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb102
-rw-r--r--spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb54
-rw-r--r--spec/lib/gitlab/email/receiver_spec.rb10
-rw-r--r--spec/lib/gitlab/git/repository_spec.rb119
-rw-r--r--spec/lib/gitlab/git/util_spec.rb2
-rw-r--r--spec/lib/gitlab/git_ref_validator_spec.rb (renamed from spec/lib/git_ref_validator_spec.rb)0
-rw-r--r--spec/lib/gitlab/gitaly_client/ref_spec.rb2
-rw-r--r--spec/lib/gitlab/health_checks/db_check_spec.rb (renamed from spec/lib/gitlab/healthchecks/db_check_spec.rb)0
-rw-r--r--spec/lib/gitlab/health_checks/fs_shards_check_spec.rb (renamed from spec/lib/gitlab/healthchecks/fs_shards_check_spec.rb)0
-rw-r--r--spec/lib/gitlab/health_checks/redis_check_spec.rb (renamed from spec/lib/gitlab/healthchecks/redis_check_spec.rb)0
-rw-r--r--spec/lib/gitlab/health_checks/simple_check_shared.rb (renamed from spec/lib/gitlab/healthchecks/simple_check_shared.rb)0
-rw-r--r--spec/lib/gitlab/import_export/fork_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/project.json1
-rw-r--r--spec/lib/gitlab/import_export/project_tree_restorer_spec.rb4
-rw-r--r--spec/lib/gitlab/import_export/project_tree_saver_spec.rb11
-rw-r--r--spec/lib/gitlab/import_export/reader_spec.rb2
-rw-r--r--spec/lib/gitlab/import_export/safe_model_attributes.yml22
-rw-r--r--spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb (renamed from spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb)0
-rw-r--r--spec/lib/gitlab/ldap/person_spec.rb6
-rw-r--r--spec/lib/gitlab/metrics_spec.rb28
-rw-r--r--spec/lib/gitlab/regex_spec.rb4
-rw-r--r--spec/lib/gitlab/request_profiler_spec.rb27
-rw-r--r--spec/lib/gitlab/shell_spec.rb (renamed from spec/lib/gitlab/backend/shell_spec.rb)0
-rw-r--r--spec/lib/gitlab/sidekiq_throttler_spec.rb4
-rw-r--r--spec/lib/gitlab/slash_commands/dsl_spec.rb2
-rw-r--r--spec/lib/gitlab/template/gitignore_template_spec.rb2
-rw-r--r--spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb2
-rw-r--r--spec/lib/gitlab/template/issue_template_spec.rb2
-rw-r--r--spec/lib/gitlab/template/merge_request_template_spec.rb2
-rw-r--r--spec/lib/gitlab/usage_data_spec.rb4
-rw-r--r--spec/lib/gitlab/user_access_spec.rb4
-rw-r--r--spec/lib/light_url_builder_spec.rb119
-rw-r--r--spec/mailers/emails/merge_requests_spec.rb2
-rw-r--r--spec/mailers/emails/profile_spec.rb146
-rw-r--r--spec/mailers/notify_spec.rb82
-rw-r--r--spec/migrations/active_record/schema_spec.rb (renamed from spec/migrations/schema_spec.rb)0
-rw-r--r--spec/models/ci/trigger_schedule_spec.rb32
-rw-r--r--spec/models/concerns/awardable_spec.rb4
-rw-r--r--spec/models/concerns/cache_markdown_field_spec.rb6
-rw-r--r--spec/models/concerns/discussion_on_diff_spec.rb6
-rw-r--r--spec/models/concerns/issuable_spec.rb35
-rw-r--r--spec/models/concerns/noteable_spec.rb2
-rw-r--r--spec/models/concerns/relative_positioning_spec.rb2
-rw-r--r--spec/models/concerns/spammable_spec.rb4
-rw-r--r--spec/models/concerns/strip_attribute_spec.rb2
-rw-r--r--spec/models/group_spec.rb26
-rw-r--r--spec/models/member_spec.rb6
-rw-r--r--spec/models/namespace_spec.rb8
-rw-r--r--spec/models/project_services/pipelines_email_service_spec.rb (renamed from spec/models/project_services/pipeline_email_service_spec.rb)0
-rw-r--r--spec/models/project_spec.rb62
-rw-r--r--spec/models/repository_spec.rb34
-rw-r--r--spec/models/snippet_blob_spec.rb47
-rw-r--r--spec/models/snippet_spec.rb13
-rw-r--r--spec/models/todo_spec.rb46
-rw-r--r--spec/models/user_spec.rb12
-rw-r--r--spec/policies/issue_policy_spec.rb246
-rw-r--r--spec/policies/issues_policy_spec.rb193
-rw-r--r--spec/requests/api/doorkeeper_access_spec.rb2
-rw-r--r--spec/requests/api/helpers/internal_helpers_spec.rb (renamed from spec/requests/api/api_internal_helpers_spec.rb)2
-rw-r--r--spec/requests/api/helpers_spec.rb2
-rw-r--r--spec/requests/api/merge_requests_spec.rb13
-rw-r--r--spec/requests/api/oauth_tokens_spec.rb2
-rw-r--r--spec/requests/api/v3/merge_requests_spec.rb13
-rw-r--r--spec/requests/request_profiler_spec.rb44
-rw-r--r--spec/routing/admin_routing_spec.rb14
-rw-r--r--spec/routing/environments_spec.rb2
-rw-r--r--spec/routing/notifications_routing_spec.rb14
-rw-r--r--spec/routing/project_routing_spec.rb6
-rw-r--r--spec/rubocop/cop/migration/add_column_with_default_to_large_table_spec.rb44
-rw-r--r--spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb (renamed from spec/rubocop/cop/migration/add_column_with_default_spec.rb)4
-rw-r--r--spec/serializers/analytics_issue_entity_spec.rb (renamed from spec/serializers/analytics_generic_entity_spec.rb)0
-rw-r--r--spec/serializers/deployment_entity_spec.rb16
-rw-r--r--spec/serializers/status_entity_spec.rb6
-rw-r--r--spec/services/issues/resolve_discussions_spec.rb24
-rw-r--r--spec/services/merge_requests/build_service_spec.rb10
-rw-r--r--spec/services/merge_requests/get_urls_service_spec.rb4
-rw-r--r--spec/services/merge_requests/merge_request_diff_cache_service_spec.rb2
-rw-r--r--spec/services/merge_requests/resolve_service_spec.rb12
-rw-r--r--spec/services/merge_requests/resolved_discussion_notification_service_spec.rb (renamed from spec/services/merge_requests/resolved_discussion_notification_service.rb)0
-rw-r--r--spec/services/projects/enable_deploy_key_service_spec.rb10
-rw-r--r--spec/services/projects/housekeeping_service_spec.rb2
-rw-r--r--spec/spec_helper.rb5
-rw-r--r--spec/support/fake_migration_classes.rb3
-rw-r--r--spec/support/import_export/import_export.yml8
-rw-r--r--spec/support/milestone_tabs_examples.rb68
-rw-r--r--spec/support/test_env.rb3
-rw-r--r--spec/support/wait_for_requests.rb6
-rw-r--r--spec/tasks/config_lint_spec.rb4
-rw-r--r--spec/tasks/gitlab/backup_rake_spec.rb6
-rw-r--r--spec/validators/dynamic_path_validator_spec.rb266
-rw-r--r--spec/views/projects/blob/_viewer.html.haml_spec.rb1
-rw-r--r--spec/views/projects/commit/show.html.haml_spec.rb44
-rw-r--r--spec/workers/delete_user_worker_spec.rb4
-rw-r--r--spec/workers/emails_on_push_worker_spec.rb2
-rw-r--r--spec/workers/expire_build_instance_artifacts_worker_spec.rb6
-rw-r--r--spec/workers/git_garbage_collect_worker_spec.rb2
-rw-r--r--spec/workers/gitlab_usage_ping_worker_spec.rb2
-rw-r--r--spec/workers/group_destroy_worker_spec.rb2
-rw-r--r--spec/workers/merge_worker_spec.rb2
-rw-r--r--spec/workers/pipeline_process_worker_spec.rb (renamed from spec/workers/pipeline_proccess_worker_spec.rb)0
-rw-r--r--spec/workers/post_receive_spec.rb18
-rw-r--r--spec/workers/project_destroy_worker_spec.rb2
-rw-r--r--spec/workers/remove_expired_members_worker_spec.rb2
-rw-r--r--spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb2
-rw-r--r--spec/workers/repository_fork_worker_spec.rb2
181 files changed, 3970 insertions, 1063 deletions
diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb
index 760f33b09c1..1bf0533ca24 100644
--- a/spec/controllers/application_controller_spec.rb
+++ b/spec/controllers/application_controller_spec.rb
@@ -4,7 +4,7 @@ describe ApplicationController do
let(:user) { create(:user) }
describe '#check_password_expiration' do
- let(:controller) { ApplicationController.new }
+ let(:controller) { described_class.new }
it 'redirects if the user is over their password expiry' do
user.password_expires_at = Time.new(2002)
@@ -34,7 +34,7 @@ describe ApplicationController do
describe "#authenticate_user_from_token!" do
describe "authenticating a user from a private token" do
- controller(ApplicationController) do
+ controller(described_class) do
def index
render text: "authenticated"
end
@@ -66,7 +66,7 @@ describe ApplicationController do
end
describe "authenticating a user from a personal access token" do
- controller(ApplicationController) do
+ controller(described_class) do
def index
render text: 'authenticated'
end
@@ -115,7 +115,7 @@ describe ApplicationController do
end
context 'two-factor authentication' do
- let(:controller) { ApplicationController.new }
+ let(:controller) { described_class.new }
describe '#check_two_factor_requirement' do
subject { controller.send :check_two_factor_requirement }
diff --git a/spec/controllers/blob_controller_spec.rb b/spec/controllers/blob_controller_spec.rb
deleted file mode 100644
index 44e011fd3a8..00000000000
--- a/spec/controllers/blob_controller_spec.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-require 'spec_helper'
-
-describe Projects::BlobController do
- let(:project) { create(:project, :repository) }
- let(:user) { create(:user) }
-
- before do
- sign_in(user)
-
- project.team << [user, :master]
-
- allow(project).to receive(:branches).and_return(['master', 'foo/bar/baz'])
- allow(project).to receive(:tags).and_return(['v1.0.0', 'v2.0.0'])
- controller.instance_variable_set(:@project, project)
- end
-
- describe "GET show" do
- render_views
-
- before do
- get(:show,
- namespace_id: project.namespace,
- project_id: project,
- id: id)
- end
-
- context "valid branch, valid file" do
- let(:id) { 'master/README.md' }
- it { is_expected.to respond_with(:success) }
- end
-
- context "valid branch, invalid file" do
- let(:id) { 'master/invalid-path.rb' }
- it { is_expected.to respond_with(:not_found) }
- end
-
- context "invalid branch, valid file" do
- let(:id) { 'invalid-branch/README.md' }
- it { is_expected.to respond_with(:not_found) }
- end
-
- context "binary file" do
- let(:id) { 'binary-encoding/encoding/binary-1.bin' }
- it { is_expected.to respond_with(:success) }
- end
- end
-
- describe 'GET show with tree path' do
- render_views
-
- before do
- get(:show,
- namespace_id: project.namespace,
- project_id: project,
- id: id)
- controller.instance_variable_set(:@blob, nil)
- end
-
- context 'redirect to tree' do
- let(:id) { 'markdown/doc' }
- it 'redirects' do
- expect(subject).
- to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc")
- end
- end
- end
-end
diff --git a/spec/controllers/groups/milestones_controller_spec.rb b/spec/controllers/groups/milestones_controller_spec.rb
index 6e4b5f78e33..7cf2996ffd0 100644
--- a/spec/controllers/groups/milestones_controller_spec.rb
+++ b/spec/controllers/groups/milestones_controller_spec.rb
@@ -6,6 +6,16 @@ describe Groups::MilestonesController do
let(:project2) { create(:empty_project, group: group) }
let(:user) { create(:user) }
let(:title) { '肯定不是中文的问题' }
+ let(:milestone) do
+ project_milestone = create(:milestone, project: project)
+
+ GroupMilestone.build(
+ group,
+ [project],
+ project_milestone.title
+ )
+ end
+ let(:milestone_path) { group_milestone_path(group, milestone.safe_title, title: milestone.title) }
before do
sign_in(user)
@@ -14,6 +24,8 @@ describe Groups::MilestonesController do
controller.instance_variable_set(:@group, group)
end
+ it_behaves_like 'milestone tabs'
+
describe "#create" do
it "creates group milestone with Chinese title" do
post :create,
diff --git a/spec/controllers/oauth/authorizations_controller_spec.rb b/spec/controllers/oauth/authorizations_controller_spec.rb
new file mode 100644
index 00000000000..d321bfcea9d
--- /dev/null
+++ b/spec/controllers/oauth/authorizations_controller_spec.rb
@@ -0,0 +1,55 @@
+require 'spec_helper'
+
+describe Oauth::AuthorizationsController do
+ let(:user) { create(:user) }
+
+ let(:doorkeeper) do
+ Doorkeeper::Application.create(
+ name: "MyApp",
+ redirect_uri: 'http://example.com',
+ scopes: "")
+ end
+
+ let(:params) do
+ {
+ response_type: "code",
+ client_id: doorkeeper.uid,
+ redirect_uri: doorkeeper.redirect_uri,
+ state: 'state'
+ }
+ end
+
+ before do
+ sign_in(user)
+ end
+
+ describe 'GET #new' do
+ context 'without valid params' do
+ it 'returns 200 code and renders error view' do
+ get :new
+
+ expect(response).to have_http_status(200)
+ expect(response).to render_template('doorkeeper/authorizations/error')
+ end
+ end
+
+ context 'with valid params' do
+ it 'returns 200 code and renders view' do
+ get :new, params
+
+ expect(response).to have_http_status(200)
+ expect(response).to render_template('doorkeeper/authorizations/new')
+ end
+
+ it 'deletes session.user_return_to and redirects when skip authorization' do
+ request.session['user_return_to'] = 'http://example.com'
+ allow(controller).to receive(:skip_authorization?).and_return(true)
+
+ get :new, params
+
+ expect(request.session['user_return_to']).to be_nil
+ expect(response).to have_http_status(302)
+ end
+ end
+ end
+end
diff --git a/spec/controllers/profiles/personal_access_tokens_spec.rb b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
index 98a43e278b2..98a43e278b2 100644
--- a/spec/controllers/profiles/personal_access_tokens_spec.rb
+++ b/spec/controllers/profiles/personal_access_tokens_controller_spec.rb
diff --git a/spec/controllers/projects/blob_controller_spec.rb b/spec/controllers/projects/blob_controller_spec.rb
index 0fd09d156c4..3b3caa9d3e6 100644
--- a/spec/controllers/projects/blob_controller_spec.rb
+++ b/spec/controllers/projects/blob_controller_spec.rb
@@ -3,6 +3,57 @@ require 'rails_helper'
describe Projects::BlobController do
let(:project) { create(:project, :public, :repository) }
+ describe "GET show" do
+ render_views
+
+ context 'with file path' do
+ before do
+ get(:show,
+ namespace_id: project.namespace,
+ project_id: project,
+ id: id)
+ end
+
+ context "valid branch, valid file" do
+ let(:id) { 'master/README.md' }
+ it { is_expected.to respond_with(:success) }
+ end
+
+ context "valid branch, invalid file" do
+ let(:id) { 'master/invalid-path.rb' }
+ it { is_expected.to respond_with(:not_found) }
+ end
+
+ context "invalid branch, valid file" do
+ let(:id) { 'invalid-branch/README.md' }
+ it { is_expected.to respond_with(:not_found) }
+ end
+
+ context "binary file" do
+ let(:id) { 'binary-encoding/encoding/binary-1.bin' }
+ it { is_expected.to respond_with(:success) }
+ end
+ end
+
+ context 'with tree path' do
+ before do
+ get(:show,
+ namespace_id: project.namespace,
+ project_id: project,
+ id: id)
+ controller.instance_variable_set(:@blob, nil)
+ end
+
+ context 'redirect to tree' do
+ let(:id) { 'markdown/doc' }
+ it 'redirects' do
+ expect(subject).
+ to redirect_to("/#{project.path_with_namespace}/tree/markdown/doc")
+ end
+ end
+ end
+ end
+
describe 'GET diff' do
let(:user) { create(:user) }
diff --git a/spec/controllers/projects/deployments_controller_spec.rb b/spec/controllers/projects/deployments_controller_spec.rb
new file mode 100644
index 00000000000..89692b601b2
--- /dev/null
+++ b/spec/controllers/projects/deployments_controller_spec.rb
@@ -0,0 +1,42 @@
+require 'spec_helper'
+
+describe Projects::DeploymentsController do
+ include ApiHelpers
+
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project) }
+ let(:environment) { create(:environment, name: 'production', project: project) }
+
+ before do
+ project.add_master(user)
+
+ sign_in(user)
+ end
+
+ describe 'GET #index' do
+ it 'returns list of deployments from last 8 hours' do
+ create(:deployment, environment: environment, created_at: 9.hours.ago)
+ create(:deployment, environment: environment, created_at: 7.hours.ago)
+ create(:deployment, environment: environment)
+
+ get :index, environment_params(after: 8.hours.ago)
+
+ expect(response).to be_ok
+
+ expect(json_response['deployments'].count).to eq(2)
+ end
+
+ it 'returns a list with deployments information' do
+ create(:deployment, environment: environment)
+
+ get :index, environment_params
+
+ expect(response).to be_ok
+ expect(response).to match_response_schema('deployments')
+ end
+ end
+
+ def environment_params(opts = {})
+ opts.reverse_merge(namespace_id: project.namespace, project_id: project, environment_id: environment.id)
+ end
+end
diff --git a/spec/controllers/projects/milestones_controller_spec.rb b/spec/controllers/projects/milestones_controller_spec.rb
index 47e61c3cea8..84a61b2784e 100644
--- a/spec/controllers/projects/milestones_controller_spec.rb
+++ b/spec/controllers/projects/milestones_controller_spec.rb
@@ -7,6 +7,7 @@ describe Projects::MilestonesController do
let(:issue) { create(:issue, project: project, milestone: milestone) }
let!(:label) { create(:label, project: project, title: 'Issue Label', issues: [issue]) }
let!(:merge_request) { create(:merge_request, source_project: project, target_project: project, milestone: milestone) }
+ let(:milestone_path) { namespace_project_milestone_path }
before do
sign_in(user)
@@ -14,6 +15,8 @@ describe Projects::MilestonesController do
controller.instance_variable_set(:@project, project)
end
+ it_behaves_like 'milestone tabs'
+
describe "#show" do
render_views
diff --git a/spec/controllers/projects/notes_controller_spec.rb b/spec/controllers/projects/notes_controller_spec.rb
index f140eaef5d5..45f4cf9180d 100644
--- a/spec/controllers/projects/notes_controller_spec.rb
+++ b/spec/controllers/projects/notes_controller_spec.rb
@@ -167,6 +167,47 @@ describe Projects::NotesController do
end
end
+ describe 'DELETE destroy' do
+ let(:request_params) do
+ {
+ namespace_id: project.namespace,
+ project_id: project,
+ id: note,
+ format: :js
+ }
+ end
+
+ context 'user is the author of a note' do
+ before do
+ sign_in(note.author)
+ project.team << [note.author, :developer]
+ end
+
+ it "returns status 200 for html" do
+ delete :destroy, request_params
+
+ expect(response).to have_http_status(200)
+ end
+
+ it "deletes the note" do
+ expect { delete :destroy, request_params }.to change { Note.count }.from(1).to(0)
+ end
+ end
+
+ context 'user is not the author of a note' do
+ before do
+ sign_in(user)
+ project.team << [user, :developer]
+ end
+
+ it "returns status 404" do
+ delete :destroy, request_params
+
+ expect(response).to have_http_status(404)
+ end
+ end
+ end
+
describe 'POST toggle_award_emoji' do
before do
sign_in(user)
diff --git a/spec/controllers/projects/todo_controller_spec.rb b/spec/controllers/projects/todos_controller_spec.rb
index c5a4153d991..c5a4153d991 100644
--- a/spec/controllers/projects/todo_controller_spec.rb
+++ b/spec/controllers/projects/todos_controller_spec.rb
diff --git a/spec/controllers/snippets/notes_controller_spec.rb b/spec/controllers/snippets/notes_controller_spec.rb
new file mode 100644
index 00000000000..1c494b8c7ab
--- /dev/null
+++ b/spec/controllers/snippets/notes_controller_spec.rb
@@ -0,0 +1,196 @@
+require 'spec_helper'
+
+describe Snippets::NotesController do
+ let(:user) { create(:user) }
+
+ let(:private_snippet) { create(:personal_snippet, :private) }
+ let(:internal_snippet) { create(:personal_snippet, :internal) }
+ let(:public_snippet) { create(:personal_snippet, :public) }
+
+ let(:note_on_private) { create(:note_on_personal_snippet, noteable: private_snippet) }
+ let(:note_on_internal) { create(:note_on_personal_snippet, noteable: internal_snippet) }
+ let(:note_on_public) { create(:note_on_personal_snippet, noteable: public_snippet) }
+
+ describe 'GET index' do
+ context 'when a snippet is public' do
+ before do
+ note_on_public
+
+ get :index, { snippet_id: public_snippet }
+ end
+
+ it "returns status 200" do
+ expect(response).to have_http_status(200)
+ end
+
+ it "returns not empty array of notes" do
+ expect(JSON.parse(response.body)["notes"].empty?).to be_falsey
+ end
+ end
+
+ context 'when a snippet is internal' do
+ before do
+ note_on_internal
+ end
+
+ context 'when user not logged in' do
+ it "returns status 404" do
+ get :index, { snippet_id: internal_snippet }
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when user logged in' do
+ before do
+ sign_in(user)
+ end
+
+ it "returns status 200" do
+ get :index, { snippet_id: internal_snippet }
+
+ expect(response).to have_http_status(200)
+ end
+ end
+ end
+
+ context 'when a snippet is private' do
+ before do
+ note_on_private
+ end
+
+ context 'when user not logged in' do
+ it "returns status 404" do
+ get :index, { snippet_id: private_snippet }
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when user other than author logged in' do
+ before do
+ sign_in(user)
+ end
+
+ it "returns status 404" do
+ get :index, { snippet_id: private_snippet }
+
+ expect(response).to have_http_status(404)
+ end
+ end
+
+ context 'when author logged in' do
+ before do
+ note_on_private
+
+ sign_in(private_snippet.author)
+ end
+
+ it "returns status 200" do
+ get :index, { snippet_id: private_snippet }
+
+ expect(response).to have_http_status(200)
+ end
+
+ it "returns 1 note" do
+ get :index, { snippet_id: private_snippet }
+
+ expect(JSON.parse(response.body)['notes'].count).to eq(1)
+ end
+ end
+ end
+
+ context 'dont show non visible notes' do
+ before do
+ note_on_public
+
+ sign_in(user)
+
+ expect_any_instance_of(Note).to receive(:cross_reference_not_visible_for?).and_return(true)
+ end
+
+ it "does not return any note" do
+ get :index, { snippet_id: public_snippet }
+
+ expect(JSON.parse(response.body)['notes'].count).to eq(0)
+ end
+ end
+ end
+
+ describe 'DELETE destroy' do
+ let(:request_params) do
+ {
+ snippet_id: public_snippet,
+ id: note_on_public,
+ format: :js
+ }
+ end
+
+ context 'when user is the author of a note' do
+ before do
+ sign_in(note_on_public.author)
+ end
+
+ it "returns status 200" do
+ delete :destroy, request_params
+
+ expect(response).to have_http_status(200)
+ end
+
+ it "deletes the note" do
+ expect{ delete :destroy, request_params }.to change{ Note.count }.from(1).to(0)
+ end
+
+ context 'system note' do
+ before do
+ expect_any_instance_of(Note).to receive(:system?).and_return(true)
+ end
+
+ it "does not delete the note" do
+ expect{ delete :destroy, request_params }.not_to change{ Note.count }
+ end
+ end
+ end
+
+ context 'when user is not the author of a note' do
+ before do
+ sign_in(user)
+
+ note_on_public
+ end
+
+ it "returns status 404" do
+ delete :destroy, request_params
+
+ expect(response).to have_http_status(404)
+ end
+
+ it "does not update the note" do
+ expect{ delete :destroy, request_params }.not_to change{ Note.count }
+ end
+ end
+ end
+
+ describe 'POST toggle_award_emoji' do
+ let(:note) { create(:note_on_personal_snippet, noteable: public_snippet) }
+ before do
+ sign_in(user)
+ end
+
+ subject { post(:toggle_award_emoji, snippet_id: public_snippet, id: note.id, name: "thumbsup") }
+
+ it "toggles the award emoji" do
+ expect { subject }.to change { note.award_emoji.count }.by(1)
+
+ expect(response).to have_http_status(200)
+ end
+
+ it "removes the already awarded emoji when it exists" do
+ note.toggle_award_emoji('thumbsup', user) # create award emoji before
+
+ expect { subject }.to change { AwardEmoji.count }.by(-1)
+
+ expect(response).to have_http_status(200)
+ end
+ end
+end
diff --git a/spec/controllers/snippets_controller_spec.rb b/spec/controllers/snippets_controller_spec.rb
index 234f3edd3d8..41cd5bdcdd8 100644
--- a/spec/controllers/snippets_controller_spec.rb
+++ b/spec/controllers/snippets_controller_spec.rb
@@ -350,144 +350,138 @@ describe SnippetsController do
end
end
- %w(raw download).each do |action|
- describe "GET #{action}" do
- context 'when the personal snippet is private' do
- let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
+ describe "GET #raw" do
+ context 'when the personal snippet is private' do
+ let(:personal_snippet) { create(:personal_snippet, :private, author: user) }
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
- context 'when signed in user is not the author' do
- let(:other_author) { create(:author) }
- let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
+ context 'when signed in user is not the author' do
+ let(:other_author) { create(:author) }
+ let(:other_personal_snippet) { create(:personal_snippet, :private, author: other_author) }
- it 'responds with status 404' do
- get action, id: other_personal_snippet.to_param
+ it 'responds with status 404' do
+ get :raw, id: other_personal_snippet.to_param
- expect(response).to have_http_status(404)
- end
+ expect(response).to have_http_status(404)
end
+ end
- context 'when signed in user is the author' do
- before { get action, id: personal_snippet.to_param }
+ context 'when signed in user is the author' do
+ before { get :raw, id: personal_snippet.to_param }
- it 'responds with status 200' do
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ it 'responds with status 200' do
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
+ end
- it 'has expected headers' do
- expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
+ it 'has expected headers' do
+ expect(response.header['Content-Type']).to eq('text/plain; charset=utf-8')
- if action == :download
- expect(response.header['Content-Disposition']).to match(/attachment/)
- elsif action == :raw
- expect(response.header['Content-Disposition']).to match(/inline/)
- end
- end
+ expect(response.header['Content-Disposition']).to match(/inline/)
end
end
+ end
- context 'when not signed in' do
- it 'redirects to the sign in page' do
- get action, id: personal_snippet.to_param
+ context 'when not signed in' do
+ it 'redirects to the sign in page' do
+ get :raw, id: personal_snippet.to_param
- expect(response).to redirect_to(new_user_session_path)
- end
+ expect(response).to redirect_to(new_user_session_path)
end
end
+ end
- context 'when the personal snippet is internal' do
- let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
+ context 'when the personal snippet is internal' do
+ let(:personal_snippet) { create(:personal_snippet, :internal, author: user) }
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
- it 'responds with status 200' do
- get action, id: personal_snippet.to_param
+ it 'responds with status 200' do
+ get :raw, id: personal_snippet.to_param
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
end
+ end
- context 'when not signed in' do
- it 'redirects to the sign in page' do
- get action, id: personal_snippet.to_param
+ context 'when not signed in' do
+ it 'redirects to the sign in page' do
+ get :raw, id: personal_snippet.to_param
- expect(response).to redirect_to(new_user_session_path)
- end
+ expect(response).to redirect_to(new_user_session_path)
end
end
+ end
- context 'when the personal snippet is public' do
- let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
+ context 'when the personal snippet is public' do
+ let(:personal_snippet) { create(:personal_snippet, :public, author: user) }
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
- it 'responds with status 200' do
- get action, id: personal_snippet.to_param
+ it 'responds with status 200' do
+ get :raw, id: personal_snippet.to_param
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
+ end
- context 'CRLF line ending' do
- let(:personal_snippet) do
- create(:personal_snippet, :public, author: user, content: "first line\r\nsecond line\r\nthird line")
- end
+ context 'CRLF line ending' do
+ let(:personal_snippet) do
+ create(:personal_snippet, :public, author: user, content: "first line\r\nsecond line\r\nthird line")
+ end
- it 'returns LF line endings by default' do
- get action, id: personal_snippet.to_param
+ it 'returns LF line endings by default' do
+ get :raw, id: personal_snippet.to_param
- expect(response.body).to eq("first line\nsecond line\nthird line")
- end
+ expect(response.body).to eq("first line\nsecond line\nthird line")
+ end
- it 'does not convert line endings when parameter present' do
- get action, id: personal_snippet.to_param, line_ending: :raw
+ it 'does not convert line endings when parameter present' do
+ get :raw, id: personal_snippet.to_param, line_ending: :raw
- expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
- end
+ expect(response.body).to eq("first line\r\nsecond line\r\nthird line")
end
end
+ end
- context 'when not signed in' do
- it 'responds with status 200' do
- get action, id: personal_snippet.to_param
+ context 'when not signed in' do
+ it 'responds with status 200' do
+ get :raw, id: personal_snippet.to_param
- expect(assigns(:snippet)).to eq(personal_snippet)
- expect(response).to have_http_status(200)
- end
+ expect(assigns(:snippet)).to eq(personal_snippet)
+ expect(response).to have_http_status(200)
end
end
+ end
- context 'when the personal snippet does not exist' do
- context 'when signed in' do
- before do
- sign_in(user)
- end
+ context 'when the personal snippet does not exist' do
+ context 'when signed in' do
+ before do
+ sign_in(user)
+ end
- it 'responds with status 404' do
- get action, id: 'doesntexist'
+ it 'responds with status 404' do
+ get :raw, id: 'doesntexist'
- expect(response).to have_http_status(404)
- end
+ expect(response).to have_http_status(404)
end
+ end
- context 'when not signed in' do
- it 'responds with status 404' do
- get action, id: 'doesntexist'
+ context 'when not signed in' do
+ it 'responds with status 404' do
+ get :raw, id: 'doesntexist'
- expect(response).to have_http_status(404)
- end
+ expect(response).to have_http_status(404)
end
end
end
diff --git a/spec/factories/notes.rb b/spec/factories/notes.rb
index 93f4903119c..44c3186d813 100644
--- a/spec/factories/notes.rb
+++ b/spec/factories/notes.rb
@@ -5,7 +5,7 @@ include ActionDispatch::TestProcess
FactoryGirl.define do
factory :note do
project factory: :empty_project
- note "Note"
+ note { generate(:title) }
author
on_issue
diff --git a/spec/factories/project_hooks.rb b/spec/factories/project_hooks.rb
index 39c2a9dd1fb..0210e871a63 100644
--- a/spec/factories/project_hooks.rb
+++ b/spec/factories/project_hooks.rb
@@ -1,6 +1,7 @@
FactoryGirl.define do
factory :project_hook do
url { generate(:url) }
+ enable_ssl_verification false
trait :token do
token { SecureRandom.hex(10) }
@@ -11,6 +12,7 @@ FactoryGirl.define do
merge_requests_events true
tag_push_events true
issues_events true
+ confidential_issues_events true
note_events true
build_events true
pipeline_events true
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index 0db2fe04edd..3580752a805 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -32,6 +32,10 @@ FactoryGirl.define do
request_access_enabled true
end
+ trait :with_avatar do
+ avatar { File.open(Rails.root.join('spec/fixtures/dk.png')) }
+ end
+
trait :repository do
# no-op... for now!
end
diff --git a/spec/features/admin/admin_hooks_spec.rb b/spec/features/admin/admin_hooks_spec.rb
index fb519a9bf12..c5f24d412d7 100644
--- a/spec/features/admin/admin_hooks_spec.rb
+++ b/spec/features/admin/admin_hooks_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe "Admin::Hooks", feature: true do
+describe 'Admin::Hooks', feature: true do
before do
@project = create(:project)
login_as :admin
@@ -8,24 +8,24 @@ describe "Admin::Hooks", feature: true do
@system_hook = create(:system_hook)
end
- describe "GET /admin/hooks" do
- it "is ok" do
+ describe 'GET /admin/hooks' do
+ it 'is ok' do
visit admin_root_path
- page.within ".layout-nav" do
- click_on "Hooks"
+ page.within '.layout-nav' do
+ click_on 'Hooks'
end
expect(current_path).to eq(admin_hooks_path)
end
- it "has hooks list" do
+ it 'has hooks list' do
visit admin_hooks_path
expect(page).to have_content(@system_hook.url)
end
end
- describe "New Hook" do
+ describe 'New Hook' do
let(:url) { generate(:url) }
it 'adds new hook' do
@@ -40,11 +40,36 @@ describe "Admin::Hooks", feature: true do
end
end
- describe "Test" do
+ describe 'Update existing hook' do
+ let(:new_url) { generate(:url) }
+
+ it 'updates existing hook' do
+ visit admin_hooks_path
+
+ click_link 'Edit'
+ fill_in 'hook_url', with: new_url
+ check 'Enable SSL verification'
+ click_button 'Save changes'
+
+ expect(page).to have_content 'SSL Verification: enabled'
+ expect(current_path).to eq(admin_hooks_path)
+ expect(page).to have_content(new_url)
+ end
+ end
+
+ describe 'Remove existing hook' do
+ it 'remove existing hook' do
+ visit admin_hooks_path
+
+ expect { click_link 'Remove' }.to change(SystemHook, :count).by(-1)
+ end
+ end
+
+ describe 'Test' do
before do
WebMock.stub_request(:post, @system_hook.url)
visit admin_hooks_path
- click_link "Test hook"
+ click_link 'Test hook'
end
it { expect(current_path).to eq(admin_hooks_path) }
diff --git a/spec/features/admin/admin_requests_profiles_spec.rb b/spec/features/admin/admin_requests_profiles_spec.rb
new file mode 100644
index 00000000000..e8ecb70306b
--- /dev/null
+++ b/spec/features/admin/admin_requests_profiles_spec.rb
@@ -0,0 +1,69 @@
+require 'spec_helper'
+
+describe 'Admin::RequestsProfilesController', feature: true do
+ before do
+ FileUtils.mkdir_p(Gitlab::RequestProfiler::PROFILES_DIR)
+ login_as(:admin)
+ end
+
+ after do
+ Gitlab::RequestProfiler.remove_all_profiles
+ end
+
+ describe 'GET /admin/requests_profiles' do
+ it 'shows the current profile token' do
+ allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new)
+
+ visit admin_requests_profiles_path
+
+ expect(page).to have_content("X-Profile-Token: #{Gitlab::RequestProfiler.profile_token}")
+ end
+
+ it 'lists all available profiles' do
+ time1 = 1.hour.ago
+ time2 = 2.hours.ago
+ time3 = 3.hours.ago
+ profile1 = "|gitlab-org|gitlab-ce_#{time1.to_i}.html"
+ profile2 = "|gitlab-org|gitlab-ce_#{time2.to_i}.html"
+ profile3 = "|gitlab-com|infrastructure_#{time3.to_i}.html"
+
+ FileUtils.touch("#{Gitlab::RequestProfiler::PROFILES_DIR}/#{profile1}")
+ FileUtils.touch("#{Gitlab::RequestProfiler::PROFILES_DIR}/#{profile2}")
+ FileUtils.touch("#{Gitlab::RequestProfiler::PROFILES_DIR}/#{profile3}")
+
+ visit admin_requests_profiles_path
+
+ within('.panel', text: '/gitlab-org/gitlab-ce') do
+ expect(page).to have_selector("a[href='#{admin_requests_profile_path(profile1)}']", text: time1.to_s(:long))
+ expect(page).to have_selector("a[href='#{admin_requests_profile_path(profile2)}']", text: time2.to_s(:long))
+ end
+
+ within('.panel', text: '/gitlab-com/infrastructure') do
+ expect(page).to have_selector("a[href='#{admin_requests_profile_path(profile3)}']", text: time3.to_s(:long))
+ end
+ end
+ end
+
+ describe 'GET /admin/requests_profiles/:profile' do
+ context 'when a profile exists' do
+ it 'displays the content of the profile' do
+ content = 'This is a request profile'
+ profile = "|gitlab-org|gitlab-ce_#{Time.now.to_i}.html"
+
+ File.write("#{Gitlab::RequestProfiler::PROFILES_DIR}/#{profile}", content)
+
+ visit admin_requests_profile_path(profile)
+
+ expect(page).to have_content(content)
+ end
+ end
+
+ context 'when a profile does not exist' do
+ it 'shows an error message' do
+ visit admin_requests_profile_path('|non|existent_12345.html')
+
+ expect(page).to have_content('Profile not found')
+ end
+ end
+ end
+end
diff --git a/spec/features/atom/users_spec.rb b/spec/features/atom/users_spec.rb
index 55e10a1a89b..7a2987e815d 100644
--- a/spec/features/atom/users_spec.rb
+++ b/spec/features/atom/users_spec.rb
@@ -53,7 +53,7 @@ describe "User Feed", feature: true do
end
it 'has XHTML summaries in issue descriptions' do
- expect(body).to match /we have a bug!<\/p>\n\n<hr ?\/>\n\n<p dir="auto">I guess/
+ expect(body).to match /<hr ?\/>/
end
it 'has XHTML summaries in notes' do
diff --git a/spec/features/explore/groups_list_spec.rb b/spec/features/explore/groups_list_spec.rb
index 8e5421a984b..9828cb179a7 100644
--- a/spec/features/explore/groups_list_spec.rb
+++ b/spec/features/explore/groups_list_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe 'Explore Groups page', js: true, feature: true do
+describe 'Explore Groups page', :js, :feature do
let!(:user) { create :user }
let!(:group) { create(:group) }
let!(:public_group) { create(:group, :public) }
@@ -46,19 +46,39 @@ describe 'Explore Groups page', js: true, feature: true do
it 'shows non-archived projects count' do
# Initially project is not archived
expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("1")
-
+
# Archive project
empty_project.archive!
visit explore_groups_path
# Check project count
expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("0")
-
+
# Unarchive project
empty_project.unarchive!
visit explore_groups_path
# Check project count
- expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("1")
+ expect(find('.js-groups-list-holder .content-list li:first-child .stats span:first-child')).to have_text("1")
+ end
+
+ describe 'landing component' do
+ it 'should show a landing component' do
+ expect(page).to have_content('Below you will find all the groups that are public.')
+ end
+
+ it 'should be dismissable' do
+ find('.dismiss-button').click
+
+ expect(page).not_to have_content('Below you will find all the groups that are public.')
+ end
+
+ it 'should persistently not show once dismissed' do
+ find('.dismiss-button').click
+
+ visit explore_groups_path
+
+ expect(page).not_to have_content('Below you will find all the groups that are public.')
+ end
end
end
diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb
index 755992069ff..21b8cf3add5 100644
--- a/spec/features/issues/form_spec.rb
+++ b/spec/features/issues/form_spec.rb
@@ -2,6 +2,7 @@ require 'rails_helper'
describe 'New/edit issue', feature: true, js: true do
include GitlabRoutingHelper
+ include ActionView::Helpers::JavaScriptHelper
let!(:project) { create(:project) }
let!(:user) { create(:user)}
@@ -105,6 +106,33 @@ describe 'New/edit issue', feature: true, js: true do
expect(find('.js-label-select')).to have_content('Labels')
end
+
+ it 'correctly updates the selected user when changing assignee' do
+ click_button 'Assignee'
+ page.within '.dropdown-menu-user' do
+ click_link user.name
+ end
+
+ expect(find('input[name="issue[assignee_id]"]', visible: false).value).to match(user.id.to_s)
+
+ click_button user.name
+
+ expect(find('.dropdown-menu-user a.is-active').first(:xpath, '..')['data-user-id']).to eq(user.id.to_s)
+
+ # check the ::before pseudo element to ensure checkmark icon is present
+ expect(before_for_selector('.dropdown-menu-selectable a.is-active')).not_to eq('')
+ expect(before_for_selector('.dropdown-menu-selectable a:not(.is-active)')).to eq('')
+
+ page.within '.dropdown-menu-user' do
+ click_link user2.name
+ end
+
+ expect(find('input[name="issue[assignee_id]"]', visible: false).value).to match(user2.id.to_s)
+
+ click_button user2.name
+
+ expect(find('.dropdown-menu-user a.is-active').first(:xpath, '..')['data-user-id']).to eq(user2.id.to_s)
+ end
end
context 'edit issue' do
@@ -154,4 +182,14 @@ describe 'New/edit issue', feature: true, js: true do
end
end
end
+
+ def before_for_selector(selector)
+ js = <<-JS.strip_heredoc
+ (function(selector) {
+ var el = document.querySelector(selector);
+ return window.getComputedStyle(el, '::before').getPropertyValue('content');
+ })("#{escape_javascript(selector)}")
+ JS
+ page.evaluate_script(js)
+ end
end
diff --git a/spec/features/issues/issue_sidebar_spec.rb b/spec/features/issues/issue_sidebar_spec.rb
index baacd7edb86..82b80a69bed 100644
--- a/spec/features/issues/issue_sidebar_spec.rb
+++ b/spec/features/issues/issue_sidebar_spec.rb
@@ -3,7 +3,8 @@ require 'rails_helper'
feature 'Issue Sidebar', feature: true do
include MobileHelpers
- let(:project) { create(:project, :public) }
+ let(:group) { create(:group, :nested) }
+ let(:project) { create(:project, :public, namespace: group) }
let(:issue) { create(:issue, project: project) }
let!(:user) { create(:user)}
let!(:label) { create(:label, project: project, title: 'bug') }
@@ -55,10 +56,12 @@ feature 'Issue Sidebar', feature: true do
# Resize the window
resize_screen_sm
# Make sure the sidebar is collapsed
+ find(sidebar_selector)
expect(page).to have_css(sidebar_selector)
# Once is collapsed let's open the sidebard and reload
open_issue_sidebar
refresh
+ find(sidebar_selector)
expect(page).to have_css(sidebar_selector)
# Restore the window size as it was including the sidebar
restore_window_size
@@ -149,9 +152,7 @@ feature 'Issue Sidebar', feature: true do
end
def open_issue_sidebar
- page.within('aside.right-sidebar.right-sidebar-collapsed') do
- find('.js-sidebar-toggle').click
- sleep 1
- end
+ find('aside.right-sidebar.right-sidebar-collapsed .js-sidebar-toggle').click
+ find('aside.right-sidebar.right-sidebar-expanded')
end
end
diff --git a/spec/features/merge_requests/create_new_mr_spec.rb b/spec/features/merge_requests/create_new_mr_spec.rb
index 16b09933bda..f1b3e7f158c 100644
--- a/spec/features/merge_requests/create_new_mr_spec.rb
+++ b/spec/features/merge_requests/create_new_mr_spec.rb
@@ -34,7 +34,7 @@ feature 'Create New Merge Request', feature: true, js: true do
expect(page).to have_content('Target branch')
first('.js-target-branch').click
- first('.dropdown-target-branch .dropdown-content a', text: 'v1.1.0').click
+ find('.dropdown-target-branch .dropdown-content a', text: 'v1.1.0', match: :first).click
expect(page).to have_content "b83d6e3"
end
diff --git a/spec/features/milestones/milestones_spec.rb b/spec/features/milestones/milestones_spec.rb
index 50d7ca39045..9eec3d7f270 100644
--- a/spec/features/milestones/milestones_spec.rb
+++ b/spec/features/milestones/milestones_spec.rb
@@ -86,6 +86,9 @@ describe 'Milestone draggable', feature: true, js: true do
visit namespace_project_milestone_path(project.namespace, project, milestone)
page.find("a[href='#tab-merge-requests']").click
+
+ wait_for_ajax
+
scroll_into_view('.milestone-content')
drag_to(selector: '.merge_requests-sortable-list', list_to_index: 1)
diff --git a/spec/features/projects/blobs/blob_show_spec.rb b/spec/features/projects/blobs/blob_show_spec.rb
index cc11cb7a55f..8dba2ccbafa 100644
--- a/spec/features/projects/blobs/blob_show_spec.rb
+++ b/spec/features/projects/blobs/blob_show_spec.rb
@@ -1,13 +1,10 @@
require 'spec_helper'
feature 'File blob', :js, feature: true do
- include TreeHelper
- include WaitForAjax
-
let(:project) { create(:project, :public) }
def visit_blob(path, fragment = nil)
- visit namespace_project_blob_path(project.namespace, project, tree_join('master', path), anchor: fragment)
+ visit namespace_project_blob_path(project.namespace, project, File.join('master', path), anchor: fragment)
end
context 'Ruby file' do
@@ -27,6 +24,9 @@ feature 'File blob', :js, feature: true do
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
end
@@ -39,7 +39,7 @@ feature 'File blob', :js, feature: true do
wait_for_ajax
end
- it 'displays the blob' do
+ it 'displays the blob using the rich viewer' do
aggregate_failures do
# hides the simple viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
@@ -53,6 +53,9 @@ feature 'File blob', :js, feature: true do
# shows a disabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
@@ -63,7 +66,7 @@ feature 'File blob', :js, feature: true do
wait_for_ajax
end
- it 'displays the blob' do
+ it 'displays the blob using the simple viewer' do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
@@ -84,7 +87,7 @@ feature 'File blob', :js, feature: true do
wait_for_ajax
end
- it 'displays the blob' do
+ it 'displays the blob using the rich viewer' do
aggregate_failures do
# hides the simple viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
@@ -105,7 +108,7 @@ feature 'File blob', :js, feature: true do
wait_for_ajax
end
- it 'displays the blob' do
+ it 'displays the blob using the simple viewer' do
aggregate_failures do
# hides the rich viewer
expect(page).to have_selector('.blob-viewer[data-type="simple"]')
@@ -163,6 +166,9 @@ feature 'File blob', :js, feature: true do
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
@@ -206,6 +212,9 @@ feature 'File blob', :js, feature: true do
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
end
@@ -222,7 +231,7 @@ feature 'File blob', :js, feature: true do
branch_name: 'master',
commit_message: "Add PDF",
file_path: 'files/test.pdf',
- file_content: File.read(Rails.root.join('spec/javascripts/blob/pdf/test.pdf'))
+ file_content: project.repository.blob_at('add-pdf-file', 'files/pdf/test.pdf').data
).execute
visit_blob('files/test.pdf')
@@ -240,6 +249,9 @@ feature 'File blob', :js, feature: true do
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
end
end
end
@@ -265,6 +277,9 @@ feature 'File blob', :js, feature: true do
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
end
end
end
@@ -286,6 +301,9 @@ feature 'File blob', :js, feature: true do
# shows an enabled copy button
expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
end
end
end
@@ -308,6 +326,9 @@ feature 'File blob', :js, feature: true do
# does not show a copy button
expect(page).not_to have_selector('.js-copy-blob-source-btn')
+
+ # shows a download button
+ expect(page).to have_link('Download')
end
end
end
diff --git a/spec/features/projects/commit/cherry_pick_spec.rb b/spec/features/projects/commit/cherry_pick_spec.rb
index 5d64d42fd61..fa67d390c47 100644
--- a/spec/features/projects/commit/cherry_pick_spec.rb
+++ b/spec/features/projects/commit/cherry_pick_spec.rb
@@ -74,8 +74,10 @@ describe 'Cherry-pick Commits' do
wait_for_ajax
- page.within('#modal-cherry-pick-commit .dropdown-menu .dropdown-content') do
- click_link 'feature'
+ page.within('#modal-cherry-pick-commit .dropdown-menu') do
+ find('.dropdown-input input').set('feature')
+ wait_for_ajax
+ click_link "feature"
end
page.within('#modal-cherry-pick-commit') do
diff --git a/spec/features/projects/environments/environment_spec.rb b/spec/features/projects/environments/environment_spec.rb
index acc3efe04e6..1e12f8542e2 100644
--- a/spec/features/projects/environments/environment_spec.rb
+++ b/spec/features/projects/environments/environment_spec.rb
@@ -200,7 +200,7 @@ feature 'Environment', :feature do
end
scenario 'user deletes the branch with running environment' do
- visit namespace_project_branches_path(project.namespace, project)
+ visit namespace_project_branches_path(project.namespace, project, search: 'feature')
remove_branch_with_hooks(project, user, 'feature') do
page.within('.js-branch-feature') { find('a.btn-remove').click }
diff --git a/spec/features/projects/merge_request_button_spec.rb b/spec/features/projects/merge_request_button_spec.rb
index 05f3162f13c..1370ab1c521 100644
--- a/spec/features/projects/merge_request_button_spec.rb
+++ b/spec/features/projects/merge_request_button_spec.rb
@@ -85,8 +85,8 @@ feature 'Merge Request button', feature: true do
context 'on branches page' do
it_behaves_like 'Merge request button only shown when allowed' do
let(:label) { 'Merge request' }
- let(:url) { namespace_project_branches_path(project.namespace, project) }
- let(:fork_url) { namespace_project_branches_path(forked_project.namespace, forked_project) }
+ let(:url) { namespace_project_branches_path(project.namespace, project, search: 'feature') }
+ let(:fork_url) { namespace_project_branches_path(forked_project.namespace, forked_project, search: 'feature') }
end
end
diff --git a/spec/features/projects/milestones/milestone_spec.rb b/spec/features/projects/milestones/milestone_spec.rb
index 5e19907eef9..b4fc0edbde8 100644
--- a/spec/features/projects/milestones/milestone_spec.rb
+++ b/spec/features/projects/milestones/milestone_spec.rb
@@ -78,11 +78,10 @@ feature 'Project milestone', :feature do
it 'shows the total MR and issue counts' do
find('.milestone-sidebar .block', match: :first)
- blocks = all('.milestone-sidebar .block')
aggregate_failures 'MR and issue blocks' do
- expect(blocks[3]).to have_content 1
- expect(blocks[4]).to have_content 0
+ expect(find('.milestone-sidebar .block.issues')).to have_content 1
+ expect(find('.milestone-sidebar .block.merge-requests')).to have_content 0
end
end
end
diff --git a/spec/features/projects/settings/integration_settings_spec.rb b/spec/features/projects/settings/integration_settings_spec.rb
new file mode 100644
index 00000000000..7909234556e
--- /dev/null
+++ b/spec/features/projects/settings/integration_settings_spec.rb
@@ -0,0 +1,94 @@
+require 'spec_helper'
+
+feature 'Integration settings', feature: true do
+ let(:project) { create(:empty_project) }
+ let(:user) { create(:user) }
+ let(:role) { :developer }
+ let(:integrations_path) { namespace_project_settings_integrations_path(project.namespace, project) }
+
+ background do
+ login_as(user)
+ project.team << [user, role]
+ end
+
+ context 'for developer' do
+ given(:role) { :developer }
+
+ scenario 'to be disallowed to view' do
+ visit integrations_path
+
+ expect(page.status_code).to eq(404)
+ end
+ end
+
+ context 'for master' do
+ given(:role) { :master }
+
+ context 'Webhooks' do
+ let(:hook) { create(:project_hook, :all_events_enabled, enable_ssl_verification: true, project: project) }
+ let(:url) { generate(:url) }
+
+ scenario 'show list of webhooks' do
+ hook
+
+ visit integrations_path
+
+ expect(page.status_code).to eq(200)
+ expect(page).to have_content(hook.url)
+ expect(page).to have_content('SSL Verification: enabled')
+ expect(page).to have_content('Push Events')
+ expect(page).to have_content('Tag Push Events')
+ expect(page).to have_content('Issues Events')
+ expect(page).to have_content('Confidential Issues Events')
+ expect(page).to have_content('Note Events')
+ expect(page).to have_content('Merge Requests Events')
+ expect(page).to have_content('Pipeline Events')
+ expect(page).to have_content('Wiki Page Events')
+ end
+
+ scenario 'create webhook' do
+ visit integrations_path
+
+ fill_in 'hook_url', with: url
+ check 'Tag push events'
+ check 'Enable SSL verification'
+
+ click_button 'Add webhook'
+
+ expect(page).to have_content(url)
+ expect(page).to have_content('SSL Verification: enabled')
+ expect(page).to have_content('Push Events')
+ expect(page).to have_content('Tag Push Events')
+ end
+
+ scenario 'edit existing webhook' do
+ hook
+ visit integrations_path
+
+ click_link 'Edit'
+ fill_in 'hook_url', with: url
+ check 'Enable SSL verification'
+ click_button 'Save changes'
+
+ expect(page).to have_content 'SSL Verification: enabled'
+ expect(page).to have_content(url)
+ end
+
+ scenario 'test existing webhook' do
+ WebMock.stub_request(:post, hook.url)
+ visit integrations_path
+
+ click_link 'Test'
+
+ expect(current_path).to eq(integrations_path)
+ end
+
+ scenario 'remove existing webhook' do
+ hook
+ visit integrations_path
+
+ expect { click_link 'Remove' }.to change(ProjectHook, :count).by(-1)
+ end
+ end
+ end
+end
diff --git a/spec/features/projects/snippets/show_spec.rb b/spec/features/projects/snippets/show_spec.rb
new file mode 100644
index 00000000000..cedf3778c7e
--- /dev/null
+++ b/spec/features/projects/snippets/show_spec.rb
@@ -0,0 +1,144 @@
+require 'spec_helper'
+
+feature 'Project snippet', :js, feature: true do
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :repository) }
+ let(:snippet) { create(:project_snippet, project: project, file_name: file_name, content: content) }
+
+ before do
+ project.team << [user, :master]
+ login_as(user)
+ end
+
+ context 'Ruby file' do
+ let(:file_name) { 'popen.rb' }
+ let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
+
+ before do
+ visit namespace_project_snippet_path(project.namespace, project, snippet)
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows highlighted Ruby code
+ expect(page).to have_content("require 'fileutils'")
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'Markdown file' do
+ let(:file_name) { 'ruby-style-guide.md' }
+ let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data }
+
+ context 'visiting directly' do
+ before do
+ visit namespace_project_snippet_path(project.namespace, project, snippet)
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows rendered Markdown
+ expect(page).to have_link("PEP-8")
+
+ # shows a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+
+ context 'switching to the simple viewer' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the simple viewer' do
+ aggregate_failures do
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+
+ # shows highlighted Markdown code
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+
+ context 'switching to the rich viewer again' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+ end
+ end
+ end
+
+ context 'visiting with a line number anchor' do
+ before do
+ visit namespace_project_snippet_path(project.namespace, project, snippet, anchor: 'L1')
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the simple viewer' do
+ aggregate_failures do
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+
+ # highlights the line in question
+ expect(page).to have_selector('#LC1.hll')
+
+ # shows highlighted Markdown code
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/protected_branches/access_control_ce_spec.rb b/spec/features/protected_branches/access_control_ce_spec.rb
index eb3cea775da..d30e7947106 100644
--- a/spec/features/protected_branches/access_control_ce_spec.rb
+++ b/spec/features/protected_branches/access_control_ce_spec.rb
@@ -9,7 +9,7 @@ RSpec.shared_examples "protected branches > access control > CE" do
allowed_to_push_button = find(".js-allowed-to-push")
unless allowed_to_push_button.text == access_type_name
- allowed_to_push_button.click
+ allowed_to_push_button.trigger('click')
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
end
end
diff --git a/spec/features/protected_branches_spec.rb b/spec/features/protected_branches_spec.rb
index acc5641f930..fc9b293c393 100644
--- a/spec/features/protected_branches_spec.rb
+++ b/spec/features/protected_branches_spec.rb
@@ -8,7 +8,7 @@ feature 'Projected Branches', feature: true, js: true do
before { login_as(user) }
def set_protected_branch_name(branch_name)
- find(".js-protected-branch-select").click
+ find(".js-protected-branch-select").trigger('click')
find(".dropdown-input-field").set(branch_name)
click_on("Create wildcard #{branch_name}")
end
diff --git a/spec/features/protected_tags/access_control_ce_spec.rb b/spec/features/protected_tags/access_control_ce_spec.rb
index 5b2baf8616c..5b24ac0292b 100644
--- a/spec/features/protected_tags/access_control_ce_spec.rb
+++ b/spec/features/protected_tags/access_control_ce_spec.rb
@@ -10,6 +10,7 @@ RSpec.shared_examples "protected tags > access control > CE" do
unless allowed_to_create_button.text == access_type_name
allowed_to_create_button.click
+ find('.dropdown.open .dropdown-menu li', match: :first)
within(".dropdown.open .dropdown-menu") { click_on access_type_name }
end
end
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index a1a36931824..26879a77c48 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -466,6 +466,21 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_denied_for(:visitor) }
end
+ describe "GET /:project_path/environments/:id/deployments" do
+ let(:environment) { create(:environment, project: project) }
+ subject { namespace_project_environment_deployments_path(project.namespace, project, environment) }
+
+ it { is_expected.to be_allowed_for(:admin) }
+ it { is_expected.to be_allowed_for(:owner).of(project) }
+ it { is_expected.to be_allowed_for(:master).of(project) }
+ it { is_expected.to be_allowed_for(:developer).of(project) }
+ it { is_expected.to be_allowed_for(:reporter).of(project) }
+ it { is_expected.to be_denied_for(:guest).of(project) }
+ it { is_expected.to be_denied_for(:user) }
+ it { is_expected.to be_denied_for(:external) }
+ it { is_expected.to be_denied_for(:visitor) }
+ end
+
describe "GET /:project_path/environments/new" do
subject { new_namespace_project_environment_path(project.namespace, project) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index 5d58494a22a..699ca4f724c 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -449,6 +449,21 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for(:visitor) }
end
+ describe "GET /:project_path/environments/:id/deployments" do
+ let(:environment) { create(:environment, project: project) }
+ subject { namespace_project_environment_deployments_path(project.namespace, project, environment) }
+
+ it { is_expected.to be_allowed_for(:admin) }
+ it { is_expected.to be_allowed_for(:owner).of(project) }
+ it { is_expected.to be_allowed_for(:master).of(project) }
+ it { is_expected.to be_allowed_for(:developer).of(project) }
+ it { is_expected.to be_allowed_for(:reporter).of(project) }
+ it { is_expected.to be_denied_for(:guest).of(project) }
+ it { is_expected.to be_denied_for(:user) }
+ it { is_expected.to be_denied_for(:external) }
+ it { is_expected.to be_denied_for(:visitor) }
+ end
+
describe "GET /:project_path/environments/new" do
subject { new_namespace_project_environment_path(project.namespace, project) }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 5df5b710dc4..624f0d0f485 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -286,6 +286,21 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_denied_for(:visitor) }
end
+ describe "GET /:project_path/environments/:id/deployments" do
+ let(:environment) { create(:environment, project: project) }
+ subject { namespace_project_environment_deployments_path(project.namespace, project, environment) }
+
+ it { is_expected.to be_allowed_for(:admin) }
+ it { is_expected.to be_allowed_for(:owner).of(project) }
+ it { is_expected.to be_allowed_for(:master).of(project) }
+ it { is_expected.to be_allowed_for(:developer).of(project) }
+ it { is_expected.to be_allowed_for(:reporter).of(project) }
+ it { is_expected.to be_denied_for(:guest).of(project) }
+ it { is_expected.to be_denied_for(:user) }
+ it { is_expected.to be_denied_for(:external) }
+ it { is_expected.to be_denied_for(:visitor) }
+ end
+
describe "GET /:project_path/environments/new" do
subject { new_namespace_project_environment_path(project.namespace, project) }
diff --git a/spec/features/snippets/create_snippet_spec.rb b/spec/features/snippets/create_snippet_spec.rb
index 5470276bf06..9409c323288 100644
--- a/spec/features/snippets/create_snippet_spec.rb
+++ b/spec/features/snippets/create_snippet_spec.rb
@@ -1,6 +1,6 @@
require 'rails_helper'
-feature 'Create Snippet', feature: true do
+feature 'Create Snippet', :js, feature: true do
before do
login_as :user
visit new_snippet_path
@@ -9,10 +9,11 @@ feature 'Create Snippet', feature: true do
scenario 'Authenticated user creates a snippet' do
fill_in 'personal_snippet_title', with: 'My Snippet Title'
page.within('.file-editor') do
- find(:xpath, "//input[@id='personal_snippet_content']").set 'Hello World!'
+ find('.ace_editor').native.send_keys 'Hello World!'
end
click_button 'Create snippet'
+ wait_for_ajax
expect(page).to have_content('My Snippet Title')
expect(page).to have_content('Hello World!')
@@ -22,10 +23,11 @@ feature 'Create Snippet', feature: true do
fill_in 'personal_snippet_title', with: 'My Snippet Title'
page.within('.file-editor') do
find(:xpath, "//input[@id='personal_snippet_file_name']").set 'snippet+file+name'
- find(:xpath, "//input[@id='personal_snippet_content']").set 'Hello World!'
+ find('.ace_editor').native.send_keys 'Hello World!'
end
click_button 'Create snippet'
+ wait_for_ajax
expect(page).to have_content('My Snippet Title')
expect(page).to have_content('snippet+file+name')
diff --git a/spec/features/snippets/notes_on_personal_snippets_spec.rb b/spec/features/snippets/notes_on_personal_snippets_spec.rb
new file mode 100644
index 00000000000..c646039e0b1
--- /dev/null
+++ b/spec/features/snippets/notes_on_personal_snippets_spec.rb
@@ -0,0 +1,39 @@
+require 'spec_helper'
+
+describe 'Comments on personal snippets', feature: true do
+ let!(:user) { create(:user) }
+ let!(:snippet) { create(:personal_snippet, :public) }
+ let!(:snippet_notes) do
+ [
+ create(:note_on_personal_snippet, noteable: snippet, author: user),
+ create(:note_on_personal_snippet, noteable: snippet)
+ ]
+ end
+ let!(:other_note) { create(:note_on_personal_snippet) }
+
+ before do
+ login_as user
+ visit snippet_path(snippet)
+ end
+
+ subject { page }
+
+ context 'viewing the snippet detail page' do
+ it 'contains notes for a snippet with correct action icons' do
+ expect(page).to have_selector('#notes-list li', count: 2)
+
+ # comment authored by current user
+ page.within("#notes-list li#note_#{snippet_notes[0].id}") do
+ expect(page).to have_content(snippet_notes[0].note)
+ expect(page).to have_selector('.js-note-delete')
+ expect(page).to have_selector('.note-emoji-button')
+ end
+
+ page.within("#notes-list li#note_#{snippet_notes[1].id}") do
+ expect(page).to have_content(snippet_notes[1].note)
+ expect(page).not_to have_selector('.js-note-delete')
+ expect(page).to have_selector('.note-emoji-button')
+ end
+ end
+ end
+end
diff --git a/spec/features/snippets/public_snippets_spec.rb b/spec/features/snippets/public_snippets_spec.rb
index 34300ccb940..2df483818c3 100644
--- a/spec/features/snippets/public_snippets_spec.rb
+++ b/spec/features/snippets/public_snippets_spec.rb
@@ -1,10 +1,11 @@
require 'rails_helper'
-feature 'Public Snippets', feature: true do
+feature 'Public Snippets', :js, feature: true do
scenario 'Unauthenticated user should see public snippets' do
public_snippet = create(:personal_snippet, :public)
visit snippet_path(public_snippet)
+ wait_for_ajax
expect(page).to have_content(public_snippet.content)
end
diff --git a/spec/features/snippets/show_spec.rb b/spec/features/snippets/show_spec.rb
new file mode 100644
index 00000000000..e36cf547f80
--- /dev/null
+++ b/spec/features/snippets/show_spec.rb
@@ -0,0 +1,138 @@
+require 'spec_helper'
+
+feature 'Snippet', :js, feature: true do
+ let(:project) { create(:project, :repository) }
+ let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content) }
+
+ context 'Ruby file' do
+ let(:file_name) { 'popen.rb' }
+ let(:content) { project.repository.blob_at('master', 'files/ruby/popen.rb').data }
+
+ before do
+ visit snippet_path(snippet)
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob' do
+ aggregate_failures do
+ # shows highlighted Ruby code
+ expect(page).to have_content("require 'fileutils'")
+
+ # does not show a viewer switcher
+ expect(page).not_to have_selector('.js-blob-viewer-switcher')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+ end
+
+ context 'Markdown file' do
+ let(:file_name) { 'ruby-style-guide.md' }
+ let(:content) { project.repository.blob_at('master', 'files/markdown/ruby-style-guide.md').data }
+
+ context 'visiting directly' do
+ before do
+ visit snippet_path(snippet)
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows rendered Markdown
+ expect(page).to have_link("PEP-8")
+
+ # shows a viewer switcher
+ expect(page).to have_selector('.js-blob-viewer-switcher')
+
+ # shows a disabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn.disabled')
+
+ # shows a raw button
+ expect(page).to have_link('Open raw')
+
+ # shows a download button
+ expect(page).to have_link('Download')
+ end
+ end
+
+ context 'switching to the simple viewer' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=simple]').click
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the simple viewer' do
+ aggregate_failures do
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+
+ # shows highlighted Markdown code
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+
+ context 'switching to the rich viewer again' do
+ before do
+ find('.js-blob-viewer-switch-btn[data-viewer=rich]').click
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the rich viewer' do
+ aggregate_failures do
+ # hides the simple viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]', visible: false)
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]')
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+ end
+ end
+ end
+
+ context 'visiting with a line number anchor' do
+ before do
+ visit snippet_path(snippet, anchor: 'L1')
+
+ wait_for_ajax
+ end
+
+ it 'displays the blob using the simple viewer' do
+ aggregate_failures do
+ # hides the rich viewer
+ expect(page).to have_selector('.blob-viewer[data-type="simple"]')
+ expect(page).to have_selector('.blob-viewer[data-type="rich"]', visible: false)
+
+ # highlights the line in question
+ expect(page).to have_selector('#LC1.hll')
+
+ # shows highlighted Markdown code
+ expect(page).to have_content("[PEP-8](http://www.python.org/dev/peps/pep-0008/)")
+
+ # shows an enabled copy button
+ expect(page).to have_selector('.js-copy-blob-source-btn:not(.disabled)')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/features/todos/todos_filtering_spec.rb b/spec/features/todos/todos_filtering_spec.rb
index cecb98641a6..f32e70c2c3f 100644
--- a/spec/features/todos/todos_filtering_spec.rb
+++ b/spec/features/todos/todos_filtering_spec.rb
@@ -45,8 +45,8 @@ describe 'Dashboard > User filters todos', feature: true, js: true do
wait_for_ajax
- expect(find('.todos-list')).to have_content user_1.name
- expect(find('.todos-list')).not_to have_content user_2.name
+ expect(find('.todos-list')).to have_content 'merge request'
+ expect(find('.todos-list')).not_to have_content 'issue'
end
it "shows only authors of existing todos" do
diff --git a/spec/features/todos/todos_spec.rb b/spec/features/todos/todos_spec.rb
index 50c207fb9cb..be5b3af417f 100644
--- a/spec/features/todos/todos_spec.rb
+++ b/spec/features/todos/todos_spec.rb
@@ -99,6 +99,83 @@ describe 'Dashboard Todos', feature: true do
end
end
+ context 'User created todos for themself' do
+ before do
+ login_as(user)
+ end
+
+ context 'issue assigned todo' do
+ before do
+ create(:todo, :assigned, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows issue assigned to yourself message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You assigned issue #{issue.to_reference(full: true)} to yourself")
+ end
+ end
+ end
+
+ context 'marked todo' do
+ before do
+ create(:todo, :marked, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you added a todo message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You added a todo for issue #{issue.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+
+ context 'mentioned todo' do
+ before do
+ create(:todo, :mentioned, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you mentioned yourself message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You mentioned yourself on issue #{issue.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+
+ context 'directly_addressed todo' do
+ before do
+ create(:todo, :directly_addressed, user: user, project: project, target: issue, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you directly addressed yourself message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You directly addressed yourself on issue #{issue.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+
+ context 'approval todo' do
+ let(:merge_request) { create(:merge_request) }
+
+ before do
+ create(:todo, :approval_required, user: user, project: project, target: merge_request, author: user)
+ visit dashboard_todos_path
+ end
+
+ it 'shows you set yourself as an approver message' do
+ page.within('.js-todos-all') do
+ expect(page).to have_content("You set yourself as an approver for merge request #{merge_request.to_reference(full: true)}")
+ expect(page).not_to have_content('to yourself')
+ end
+ end
+ end
+ end
+
context 'User has done todos', js: true do
before do
create(:todo, :mentioned, :done, user: user, project: project, target: issue, author: author)
diff --git a/spec/features/triggers_spec.rb b/spec/features/triggers_spec.rb
index 81fa2de1cc3..783f330221c 100644
--- a/spec/features/triggers_spec.rb
+++ b/spec/features/triggers_spec.rb
@@ -104,6 +104,24 @@ feature 'Triggers', feature: true, js: true do
expect(page).to have_content 'The form contains the following errors'
end
+
+ context 'when GitLab time_zone is ActiveSupport::TimeZone format' do
+ before do
+ allow(Time).to receive(:zone)
+ .and_return(ActiveSupport::TimeZone['Eastern Time (US & Canada)'])
+ end
+
+ scenario 'do fill form with valid data and save' do
+ find('#trigger_trigger_schedule_attributes_active').click
+ fill_in 'trigger_trigger_schedule_attributes_cron', with: '1 * * * *'
+ fill_in 'trigger_trigger_schedule_attributes_cron_timezone', with: 'UTC'
+ fill_in 'trigger_trigger_schedule_attributes_ref', with: 'master'
+ click_button 'Save trigger'
+
+ expect(page.find('.flash-notice'))
+ .to have_content 'Trigger was successfully updated.'
+ end
+ end
end
context 'disabling schedule' do
diff --git a/spec/finders/issues_finder_spec.rb b/spec/finders/issues_finder_spec.rb
index a1ae1d746af..a5f717e6233 100644
--- a/spec/finders/issues_finder_spec.rb
+++ b/spec/finders/issues_finder_spec.rb
@@ -16,7 +16,7 @@ describe IssuesFinder do
set(:label_link) { create(:label_link, label: label, target: issue2) }
let(:search_user) { user }
let(:params) { {} }
- let(:issues) { IssuesFinder.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute }
+ let(:issues) { described_class.new(search_user, params.reverse_merge(scope: scope, state: 'opened')).execute }
before(:context) do
project1.team << [user, :master]
@@ -282,15 +282,15 @@ describe IssuesFinder do
let!(:confidential_issue) { create(:issue, project: project, confidential: true) }
it 'returns non confidential issues for nil user' do
- expect(IssuesFinder.send(:not_restricted_by_confidentiality, nil)).to include(public_issue)
+ expect(described_class.send(:not_restricted_by_confidentiality, nil)).to include(public_issue)
end
it 'returns non confidential issues for user not authorized for the issues projects' do
- expect(IssuesFinder.send(:not_restricted_by_confidentiality, user)).to include(public_issue)
+ expect(described_class.send(:not_restricted_by_confidentiality, user)).to include(public_issue)
end
it 'returns all issues for user authorized for the issues projects' do
- expect(IssuesFinder.send(:not_restricted_by_confidentiality, authorized_user)).to include(public_issue, confidential_issue)
+ expect(described_class.send(:not_restricted_by_confidentiality, authorized_user)).to include(public_issue, confidential_issue)
end
end
end
diff --git a/spec/finders/merge_requests_finder_spec.rb b/spec/finders/merge_requests_finder_spec.rb
index 21ef94ac5d1..58b7cd5e098 100644
--- a/spec/finders/merge_requests_finder_spec.rb
+++ b/spec/finders/merge_requests_finder_spec.rb
@@ -23,26 +23,26 @@ describe MergeRequestsFinder do
describe "#execute" do
it 'filters by scope' do
params = { scope: 'authored', state: 'opened' }
- merge_requests = MergeRequestsFinder.new(user, params).execute
+ merge_requests = described_class.new(user, params).execute
expect(merge_requests.size).to eq(3)
end
it 'filters by project' do
params = { project_id: project1.id, scope: 'authored', state: 'opened' }
- merge_requests = MergeRequestsFinder.new(user, params).execute
+ merge_requests = described_class.new(user, params).execute
expect(merge_requests.size).to eq(1)
end
it 'filters by non_archived' do
params = { non_archived: true }
- merge_requests = MergeRequestsFinder.new(user, params).execute
+ merge_requests = described_class.new(user, params).execute
expect(merge_requests.size).to eq(3)
end
it 'filters by iid' do
params = { project_id: project1.id, iids: merge_request1.iid }
- merge_requests = MergeRequestsFinder.new(user, params).execute
+ merge_requests = described_class.new(user, params).execute
expect(merge_requests).to contain_exactly(merge_request1)
end
diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb
index 765bf44d863..ba6bbb3bce0 100644
--- a/spec/finders/notes_finder_spec.rb
+++ b/spec/finders/notes_finder_spec.rb
@@ -110,6 +110,15 @@ describe NotesFinder do
expect(notes.count).to eq(1)
end
+ it 'finds notes on personal snippets' do
+ note = create(:note_on_personal_snippet)
+ params = { target_type: 'personal_snippet', target_id: note.noteable_id }
+
+ notes = described_class.new(project, user, params).execute
+
+ expect(notes.count).to eq(1)
+ end
+
it 'raises an exception for an invalid target_type' do
params[:target_type] = 'invalid'
expect { described_class.new(project, user, params).execute }.to raise_error('invalid target_type')
diff --git a/spec/finders/snippets_finder_spec.rb b/spec/finders/snippets_finder_spec.rb
index 975e99c5807..cb6c80d1bd0 100644
--- a/spec/finders/snippets_finder_spec.rb
+++ b/spec/finders/snippets_finder_spec.rb
@@ -14,13 +14,13 @@ describe SnippetsFinder do
let!(:snippet3) { create(:personal_snippet, :public) }
it "returns all private and internal snippets" do
- snippets = SnippetsFinder.new.execute(user, filter: :all)
+ snippets = described_class.new.execute(user, filter: :all)
expect(snippets).to include(snippet2, snippet3)
expect(snippets).not_to include(snippet1)
end
it "returns all public snippets" do
- snippets = SnippetsFinder.new.execute(nil, filter: :all)
+ snippets = described_class.new.execute(nil, filter: :all)
expect(snippets).to include(snippet3)
expect(snippets).not_to include(snippet1, snippet2)
end
@@ -32,7 +32,7 @@ describe SnippetsFinder do
let!(:snippet3) { create(:personal_snippet, :public) }
it "returns public public snippets" do
- snippets = SnippetsFinder.new.execute(nil, filter: :public)
+ snippets = described_class.new.execute(nil, filter: :public)
expect(snippets).to include(snippet3)
expect(snippets).not_to include(snippet1, snippet2)
@@ -45,36 +45,36 @@ describe SnippetsFinder do
let!(:snippet3) { create(:personal_snippet, :public, author: user) }
it "returns all public and internal snippets" do
- snippets = SnippetsFinder.new.execute(user1, filter: :by_user, user: user)
+ snippets = described_class.new.execute(user1, filter: :by_user, user: user)
expect(snippets).to include(snippet2, snippet3)
expect(snippets).not_to include(snippet1)
end
it "returns internal snippets" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_internal")
+ snippets = described_class.new.execute(user, filter: :by_user, user: user, scope: "are_internal")
expect(snippets).to include(snippet2)
expect(snippets).not_to include(snippet1, snippet3)
end
it "returns private snippets" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_private")
+ snippets = described_class.new.execute(user, filter: :by_user, user: user, scope: "are_private")
expect(snippets).to include(snippet1)
expect(snippets).not_to include(snippet2, snippet3)
end
it "returns public snippets" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user, scope: "are_public")
+ snippets = described_class.new.execute(user, filter: :by_user, user: user, scope: "are_public")
expect(snippets).to include(snippet3)
expect(snippets).not_to include(snippet1, snippet2)
end
it "returns all snippets" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_user, user: user)
+ snippets = described_class.new.execute(user, filter: :by_user, user: user)
expect(snippets).to include(snippet1, snippet2, snippet3)
end
it "returns only public snippets if unauthenticated user" do
- snippets = SnippetsFinder.new.execute(nil, filter: :by_user, user: user)
+ snippets = described_class.new.execute(nil, filter: :by_user, user: user)
expect(snippets).to include(snippet3)
expect(snippets).not_to include(snippet2, snippet1)
end
@@ -88,43 +88,43 @@ describe SnippetsFinder do
end
it "returns public snippets for unauthorized user" do
- snippets = SnippetsFinder.new.execute(nil, filter: :by_project, project: project1)
+ snippets = described_class.new.execute(nil, filter: :by_project, project: project1)
expect(snippets).to include(@snippet3)
expect(snippets).not_to include(@snippet1, @snippet2)
end
it "returns public and internal snippets for non project members" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+ snippets = described_class.new.execute(user, filter: :by_project, project: project1)
expect(snippets).to include(@snippet2, @snippet3)
expect(snippets).not_to include(@snippet1)
end
it "returns public snippets for non project members" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_public")
+ snippets = described_class.new.execute(user, filter: :by_project, project: project1, scope: "are_public")
expect(snippets).to include(@snippet3)
expect(snippets).not_to include(@snippet1, @snippet2)
end
it "returns internal snippets for non project members" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_internal")
+ snippets = described_class.new.execute(user, filter: :by_project, project: project1, scope: "are_internal")
expect(snippets).to include(@snippet2)
expect(snippets).not_to include(@snippet1, @snippet3)
end
it "does not return private snippets for non project members" do
- snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_private")
+ snippets = described_class.new.execute(user, filter: :by_project, project: project1, scope: "are_private")
expect(snippets).not_to include(@snippet1, @snippet2, @snippet3)
end
it "returns all snippets for project members" do
project1.team << [user, :developer]
- snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1)
+ snippets = described_class.new.execute(user, filter: :by_project, project: project1)
expect(snippets).to include(@snippet1, @snippet2, @snippet3)
end
it "returns private snippets for project members" do
project1.team << [user, :developer]
- snippets = SnippetsFinder.new.execute(user, filter: :by_project, project: project1, scope: "are_private")
+ snippets = described_class.new.execute(user, filter: :by_project, project: project1, scope: "are_private")
expect(snippets).to include(@snippet1)
end
end
diff --git a/spec/fixtures/api/schemas/deployments.json b/spec/fixtures/api/schemas/deployments.json
new file mode 100644
index 00000000000..1112f23aab2
--- /dev/null
+++ b/spec/fixtures/api/schemas/deployments.json
@@ -0,0 +1,58 @@
+{
+ "additionalProperties": false,
+ "properties": {
+ "deployments": {
+ "items": {
+ "additionalProperties": false,
+ "properties": {
+ "created_at": {
+ "type": "string"
+ },
+ "id": {
+ "type": "integer"
+ },
+ "iid": {
+ "type": "integer"
+ },
+ "last?": {
+ "type": "boolean"
+ },
+ "ref": {
+ "additionalProperties": false,
+ "properties": {
+ "name": {
+ "type": "string"
+ }
+ },
+ "required": [
+ "name"
+ ],
+ "type": "object"
+ },
+ "sha": {
+ "type": "string"
+ },
+ "tag": {
+ "type": "boolean"
+ }
+ },
+ "required": [
+ "sha",
+ "created_at",
+ "iid",
+ "tag",
+ "last?",
+ "ref",
+ "id"
+ ],
+ "type": "object"
+ },
+ "minItems": 1,
+ "type": "array"
+ }
+ },
+ "required": [
+ "deployments"
+ ],
+ "type": "object"
+}
diff --git a/spec/helpers/award_emoji_helper_spec.rb b/spec/helpers/award_emoji_helper_spec.rb
new file mode 100644
index 00000000000..7dfd6a3f6b4
--- /dev/null
+++ b/spec/helpers/award_emoji_helper_spec.rb
@@ -0,0 +1,61 @@
+require 'spec_helper'
+
+describe AwardEmojiHelper do
+ describe '.toggle_award_url' do
+ context 'note on personal snippet' do
+ let(:note) { create(:note_on_personal_snippet) }
+
+ it 'returns correct url' do
+ expected_url = "/snippets/#{note.noteable.id}/notes/#{note.id}/toggle_award_emoji"
+
+ expect(helper.toggle_award_url(note)).to eq(expected_url)
+ end
+ end
+
+ context 'note on project item' do
+ let(:note) { create(:note_on_project_snippet) }
+
+ it 'returns correct url' do
+ @project = note.noteable.project
+
+ expected_url = "/#{@project.namespace.path}/#{@project.path}/notes/#{note.id}/toggle_award_emoji"
+
+ expect(helper.toggle_award_url(note)).to eq(expected_url)
+ end
+ end
+
+ context 'personal snippet' do
+ let(:snippet) { create(:personal_snippet) }
+
+ it 'returns correct url' do
+ expected_url = "/snippets/#{snippet.id}/toggle_award_emoji"
+
+ expect(helper.toggle_award_url(snippet)).to eq(expected_url)
+ end
+ end
+
+ context 'merge request' do
+ let(:merge_request) { create(:merge_request) }
+
+ it 'returns correct url' do
+ @project = merge_request.project
+
+ expected_url = "/#{@project.namespace.path}/#{@project.path}/merge_requests/#{merge_request.id}/toggle_award_emoji"
+
+ expect(helper.toggle_award_url(merge_request)).to eq(expected_url)
+ end
+ end
+
+ context 'issue' do
+ let(:issue) { create(:issue) }
+
+ it 'returns correct url' do
+ @project = issue.project
+
+ expected_url = "/#{@project.namespace.path}/#{@project.path}/issues/#{issue.id}/toggle_award_emoji"
+
+ expect(helper.toggle_award_url(issue)).to eq(expected_url)
+ end
+ end
+ end
+end
diff --git a/spec/helpers/blob_helper_spec.rb b/spec/helpers/blob_helper_spec.rb
index 379f62f73e1..075f1887d91 100644
--- a/spec/helpers/blob_helper_spec.rb
+++ b/spec/helpers/blob_helper_spec.rb
@@ -157,6 +157,7 @@ describe BlobHelper do
describe '#blob_render_error_options' do
before do
assign(:project, project)
+ assign(:blob, blob)
assign(:id, File.join('master', blob.path))
controller.params[:controller] = 'projects/blob'
diff --git a/spec/helpers/events_helper_spec.rb b/spec/helpers/events_helper_spec.rb
index a7c3c281083..c3bd0cb3542 100644
--- a/spec/helpers/events_helper_spec.rb
+++ b/spec/helpers/events_helper_spec.rb
@@ -56,7 +56,7 @@ describe EventsHelper do
it 'preserves code color scheme' do
input = "```ruby\ndef test\n 'hello world'\nend\n```"
- expected = '<pre class="code highlight js-syntax-highlight ruby">' \
+ expected = "\n<pre class=\"code highlight js-syntax-highlight ruby\">" \
"<code><span class=\"line\"><span class=\"k\">def</span> <span class=\"nf\">test</span>...</span>\n" \
"</code></pre>"
expect(helper.event_note(input)).to eq(expected)
diff --git a/spec/helpers/markup_helper_spec.rb b/spec/helpers/markup_helper_spec.rb
index c10f4b09b5b..2a0de0b0656 100644
--- a/spec/helpers/markup_helper_spec.rb
+++ b/spec/helpers/markup_helper_spec.rb
@@ -111,7 +111,7 @@ describe MarkupHelper do
it 'replaces commit message with emoji to link' do
actual = link_to_gfm(':book: Book', '/foo')
expect(actual).
- to eq '<gl-emoji data-name="book" data-unicode-version="6.0">📖</gl-emoji><a href="/foo"> Book</a>'
+ to eq '<gl-emoji title="open book" data-name="book" data-unicode-version="6.0">📖</gl-emoji><a href="/foo"> Book</a>'
end
end
diff --git a/spec/helpers/merge_requests_helper_spec.rb b/spec/helpers/merge_requests_helper_spec.rb
index e9037749ef2..10681af5f7e 100644
--- a/spec/helpers/merge_requests_helper_spec.rb
+++ b/spec/helpers/merge_requests_helper_spec.rb
@@ -64,7 +64,7 @@ describe MergeRequestsHelper do
it do
@project = project
-
+
is_expected.to eq("#1, #2, and #{other_project.namespace.path}/#{other_project.path}#3")
end
end
@@ -149,6 +149,50 @@ describe MergeRequestsHelper do
end
end
+ describe '#target_projects' do
+ let(:project) { create(:empty_project) }
+ let(:fork_project) { create(:empty_project, forked_from_project: project) }
+
+ context 'when target project has enabled merge requests' do
+ it 'returns the forked_from project' do
+ expect(target_projects(fork_project)).to contain_exactly(project, fork_project)
+ end
+ end
+
+ context 'when target project has disabled merge requests' do
+ it 'returns the forked project' do
+ project.project_feature.update(merge_requests_access_level: 0)
+
+ expect(target_projects(fork_project)).to contain_exactly(fork_project)
+ end
+ end
+ end
+
+ describe '#new_mr_path_from_push_event' do
+ subject(:url_params) { URI.decode_www_form(new_mr_path_from_push_event(event)).to_h }
+ let(:user) { create(:user) }
+ let(:project) { create(:empty_project, creator: user) }
+ let(:fork_project) { create(:project, forked_from_project: project, creator: user) }
+ let(:event) do
+ push_data = Gitlab::DataBuilder::Push.build_sample(fork_project, user)
+ create(:event, :pushed, project: fork_project, target: fork_project, author: user, data: push_data)
+ end
+
+ context 'when target project has enabled merge requests' do
+ it 'returns link to create merge request on source project' do
+ expect(url_params['merge_request[target_project_id]'].to_i).to eq(project.id)
+ end
+ end
+
+ context 'when target project has disabled merge requests' do
+ it 'returns link to create merge request on forked project' do
+ project.project_feature.update(merge_requests_access_level: 0)
+
+ expect(url_params['merge_request[target_project_id]'].to_i).to eq(fork_project.id)
+ end
+ end
+ end
+
describe '#mr_issues_mentioned_but_not_closing' do
let(:user_1) { create(:user) }
let(:user_2) { create(:user) }
diff --git a/spec/javascripts/blob/pdf/index_spec.js b/spec/javascripts/blob/pdf/index_spec.js
index d3a4d04345b..bbeaf95e68d 100644
--- a/spec/javascripts/blob/pdf/index_spec.js
+++ b/spec/javascripts/blob/pdf/index_spec.js
@@ -1,5 +1,7 @@
+/* eslint-disable import/no-unresolved */
+
import renderPDF from '~/blob/pdf';
-import testPDF from './test.pdf';
+import testPDF from '../../fixtures/blob/pdf/test.pdf';
describe('PDF renderer', () => {
let viewer;
@@ -59,7 +61,7 @@ describe('PDF renderer', () => {
describe('error getting file', () => {
beforeEach((done) => {
- viewer.dataset.endpoint = 'invalid/endpoint';
+ viewer.dataset.endpoint = 'invalid/path/to/file.pdf';
app = renderPDF();
checkLoaded(done);
diff --git a/spec/javascripts/blob/pdf/test.pdf b/spec/javascripts/blob/pdf/test.pdf
deleted file mode 100644
index eb3d147fde3..00000000000
--- a/spec/javascripts/blob/pdf/test.pdf
+++ /dev/null
Binary files differ
diff --git a/spec/javascripts/fixtures/environments.rb b/spec/javascripts/fixtures/environments.rb
new file mode 100644
index 00000000000..3474f4696ef
--- /dev/null
+++ b/spec/javascripts/fixtures/environments.rb
@@ -0,0 +1,30 @@
+require 'spec_helper'
+
+describe Projects::EnvironmentsController, '(JavaScript fixtures)', type: :controller do
+ include JavaScriptFixturesHelpers
+
+ let(:admin) { create(:admin) }
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
+ let(:project) { create(:project_empty_repo, namespace: namespace, path: 'environments-project') }
+ let(:environment) { create(:environment, name: 'production', project: project) }
+
+ render_views
+
+ before(:all) do
+ clean_frontend_fixtures('environments/metrics')
+ end
+
+ before(:each) do
+ sign_in(admin)
+ end
+
+ it 'environments/metrics/metrics.html.raw' do |example|
+ get :metrics,
+ namespace_id: project.namespace,
+ project_id: project,
+ id: environment.id
+
+ expect(response).to be_success
+ store_frontend_fixture(response, example.description)
+ end
+end
diff --git a/spec/javascripts/fixtures/environments/metrics.html.haml b/spec/javascripts/fixtures/environments/metrics.html.haml
deleted file mode 100644
index e2dd9519898..00000000000
--- a/spec/javascripts/fixtures/environments/metrics.html.haml
+++ /dev/null
@@ -1,62 +0,0 @@
-.prometheus-container{ 'data-has-metrics': "false", 'data-doc-link': '/help/administration/monitoring/prometheus/index.md', 'data-prometheus-integration': '/root/hello-prometheus/services/prometheus/edit' }
- .top-area
- .row
- .col-sm-6
- %h3.page-title
- Metrics for environment
- .prometheus-state
- .js-getting-started.hidden
- .row
- .col-md-4.col-md-offset-4.state-svg
- %svg
- .row
- .col-md-6.col-md-offset-3
- %h4.text-center.state-title
- Get started with performance monitoring
- .row
- .col-md-6.col-md-offset-3
- .description-text.text-center.state-description
- Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments. Learn more about performance monitoring
- .row.state-button-section
- .col-md-4.col-md-offset-4.text-center.state-button
- %a.btn.btn-success
- Configure Prometheus
- .js-loading.hidden
- .row
- .col-md-4.col-md-offset-4.state-svg
- %svg
- .row
- .col-md-6.col-md-offset-3
- %h4.text-center.state-title
- Waiting for performance data
- .row
- .col-md-6.col-md-offset-3
- .description-text.text-center.state-description
- Creating graphs uses the data from the Prometheus server. If this takes a long time, ensure that data is available.
- .row.state-button-section
- .col-md-4.col-md-offset-4.text-center.state-button
- %a.btn.btn-success
- View documentation
- .js-unable-to-connect.hidden
- .row
- .col-md-4.col-md-offset-4.state-svg
- %svg
- .row
- .col-md-6.col-md-offset-3
- %h4.text-center.state-title
- Unable to connect to Prometheus server
- .row
- .col-md-6.col-md-offset-3
- .description-text.text-center.state-description
- Ensure connectivity is available from the GitLab server to the Prometheus server
- .row.state-button-section
- .col-md-4.col-md-offset-4.text-center.state-button
- %a.btn.btn-success
- View documentation
- .prometheus-graphs
- .row
- .col-sm-12
- %svg.prometheus-graph{ 'graph-type' => 'cpu_values' }
- .row
- .col-sm-12
- %svg.prometheus-graph{ 'graph-type' => 'memory_values' }
diff --git a/spec/javascripts/fixtures/line_highlighter.html.haml b/spec/javascripts/fixtures/line_highlighter.html.haml
index 514877340e4..2782c50e298 100644
--- a/spec/javascripts/fixtures/line_highlighter.html.haml
+++ b/spec/javascripts/fixtures/line_highlighter.html.haml
@@ -1,4 +1,4 @@
-#blob-content-holder
+.file-holder
.file-content
.line-numbers
- 1.upto(25) do |i|
diff --git a/spec/javascripts/fixtures/pdf.rb b/spec/javascripts/fixtures/pdf.rb
new file mode 100644
index 00000000000..6b2422a7986
--- /dev/null
+++ b/spec/javascripts/fixtures/pdf.rb
@@ -0,0 +1,18 @@
+require 'spec_helper'
+
+describe 'PDF file', '(JavaScript fixtures)', type: :controller do
+ include JavaScriptFixturesHelpers
+
+ let(:namespace) { create(:namespace, name: 'frontend-fixtures' )}
+ let(:project) { create(:project, namespace: namespace, path: 'pdf-project') }
+
+ before(:all) do
+ clean_frontend_fixtures('blob/pdf/')
+ end
+
+ it 'blob/pdf/test.pdf' do |example|
+ blob = project.repository.blob_at('e774ebd33', 'files/pdf/test.pdf')
+
+ store_frontend_fixture(blob.data.force_encoding("utf-8"), example.description)
+ end
+end
diff --git a/spec/javascripts/landing_spec.js b/spec/javascripts/landing_spec.js
new file mode 100644
index 00000000000..7916073190a
--- /dev/null
+++ b/spec/javascripts/landing_spec.js
@@ -0,0 +1,160 @@
+import Landing from '~/landing';
+import Cookies from 'js-cookie';
+
+describe('Landing', function () {
+ describe('class constructor', function () {
+ beforeEach(function () {
+ this.landingElement = {};
+ this.dismissButton = {};
+ this.cookieName = 'cookie_name';
+
+ this.landing = new Landing(this.landingElement, this.dismissButton, this.cookieName);
+ });
+
+ it('should set .landing', function () {
+ expect(this.landing.landingElement).toBe(this.landingElement);
+ });
+
+ it('should set .cookieName', function () {
+ expect(this.landing.cookieName).toBe(this.cookieName);
+ });
+
+ it('should set .dismissButton', function () {
+ expect(this.landing.dismissButton).toBe(this.dismissButton);
+ });
+
+ it('should set .eventWrapper', function () {
+ expect(this.landing.eventWrapper).toEqual({});
+ });
+ });
+
+ describe('toggle', function () {
+ beforeEach(function () {
+ this.isDismissed = false;
+ this.landingElement = { classList: jasmine.createSpyObj('classList', ['toggle']) };
+ this.landing = {
+ isDismissed: () => {},
+ addEvents: () => {},
+ landingElement: this.landingElement,
+ };
+
+ spyOn(this.landing, 'isDismissed').and.returnValue(this.isDismissed);
+ spyOn(this.landing, 'addEvents');
+
+ Landing.prototype.toggle.call(this.landing);
+ });
+
+ it('should call .isDismissed', function () {
+ expect(this.landing.isDismissed).toHaveBeenCalled();
+ });
+
+ it('should call .classList.toggle', function () {
+ expect(this.landingElement.classList.toggle).toHaveBeenCalledWith('hidden', this.isDismissed);
+ });
+
+ it('should call .addEvents', function () {
+ expect(this.landing.addEvents).toHaveBeenCalled();
+ });
+
+ describe('if isDismissed is true', function () {
+ beforeEach(function () {
+ this.isDismissed = true;
+ this.landingElement = { classList: jasmine.createSpyObj('classList', ['toggle']) };
+ this.landing = {
+ isDismissed: () => {},
+ addEvents: () => {},
+ landingElement: this.landingElement,
+ };
+
+ spyOn(this.landing, 'isDismissed').and.returnValue(this.isDismissed);
+ spyOn(this.landing, 'addEvents');
+
+ this.landing.isDismissed.calls.reset();
+
+ Landing.prototype.toggle.call(this.landing);
+ });
+
+ it('should not call .addEvents', function () {
+ expect(this.landing.addEvents).not.toHaveBeenCalled();
+ });
+ });
+ });
+
+ describe('addEvents', function () {
+ beforeEach(function () {
+ this.dismissButton = jasmine.createSpyObj('dismissButton', ['addEventListener']);
+ this.eventWrapper = {};
+ this.landing = {
+ eventWrapper: this.eventWrapper,
+ dismissButton: this.dismissButton,
+ dismissLanding: () => {},
+ };
+
+ Landing.prototype.addEvents.call(this.landing);
+ });
+
+ it('should set .eventWrapper.dismissLanding', function () {
+ expect(this.eventWrapper.dismissLanding).toEqual(jasmine.any(Function));
+ });
+
+ it('should call .addEventListener', function () {
+ expect(this.dismissButton.addEventListener).toHaveBeenCalledWith('click', this.eventWrapper.dismissLanding);
+ });
+ });
+
+ describe('removeEvents', function () {
+ beforeEach(function () {
+ this.dismissButton = jasmine.createSpyObj('dismissButton', ['removeEventListener']);
+ this.eventWrapper = { dismissLanding: () => {} };
+ this.landing = {
+ eventWrapper: this.eventWrapper,
+ dismissButton: this.dismissButton,
+ };
+
+ Landing.prototype.removeEvents.call(this.landing);
+ });
+
+ it('should call .removeEventListener', function () {
+ expect(this.dismissButton.removeEventListener).toHaveBeenCalledWith('click', this.eventWrapper.dismissLanding);
+ });
+ });
+
+ describe('dismissLanding', function () {
+ beforeEach(function () {
+ this.landingElement = { classList: jasmine.createSpyObj('classList', ['add']) };
+ this.cookieName = 'cookie_name';
+ this.landing = { landingElement: this.landingElement, cookieName: this.cookieName };
+
+ spyOn(Cookies, 'set');
+
+ Landing.prototype.dismissLanding.call(this.landing);
+ });
+
+ it('should call .classList.add', function () {
+ expect(this.landingElement.classList.add).toHaveBeenCalledWith('hidden');
+ });
+
+ it('should call Cookies.set', function () {
+ expect(Cookies.set).toHaveBeenCalledWith(this.cookieName, 'true', { expires: 365 });
+ });
+ });
+
+ describe('isDismissed', function () {
+ beforeEach(function () {
+ this.cookieName = 'cookie_name';
+ this.landing = { cookieName: this.cookieName };
+
+ spyOn(Cookies, 'get').and.returnValue('true');
+
+ this.isDismissed = Landing.prototype.isDismissed.call(this.landing);
+ });
+
+ it('should call Cookies.get', function () {
+ expect(Cookies.get).toHaveBeenCalledWith(this.cookieName);
+ });
+
+ it('should return a boolean', function () {
+ expect(typeof this.isDismissed).toEqual('boolean');
+ });
+ });
+});
diff --git a/spec/javascripts/monitoring/deployments_spec.js b/spec/javascripts/monitoring/deployments_spec.js
new file mode 100644
index 00000000000..19bc11d0f24
--- /dev/null
+++ b/spec/javascripts/monitoring/deployments_spec.js
@@ -0,0 +1,133 @@
+import d3 from 'd3';
+import PrometheusGraph from '~/monitoring/prometheus_graph';
+import Deployments from '~/monitoring/deployments';
+import { prometheusMockData } from './prometheus_mock_data';
+
+describe('Metrics deployments', () => {
+ const fixtureName = 'environments/metrics/metrics.html.raw';
+ let deployment;
+ let prometheusGraph;
+
+ const graphElement = () => document.querySelector('.prometheus-graph');
+
+ preloadFixtures(fixtureName);
+
+ beforeEach((done) => {
+ // Setup the view
+ loadFixtures(fixtureName);
+
+ d3.selectAll('.prometheus-graph')
+ .append('g')
+ .attr('class', 'graph-container');
+
+ prometheusGraph = new PrometheusGraph();
+ deployment = new Deployments(1000, 500);
+
+ spyOn(prometheusGraph, 'init');
+ spyOn($, 'ajax').and.callFake(() => {
+ const d = $.Deferred();
+ d.resolve({
+ deployments: [{
+ id: 1,
+ created_at: deployment.chartData[10].time,
+ sha: 'testing',
+ tag: false,
+ ref: {
+ name: 'testing',
+ },
+ }, {
+ id: 2,
+ created_at: deployment.chartData[15].time,
+ sha: '',
+ tag: true,
+ ref: {
+ name: 'tag',
+ },
+ }],
+ });
+
+ setTimeout(done);
+
+ return d.promise();
+ });
+
+ prometheusGraph.configureGraph();
+ prometheusGraph.transformData(prometheusMockData.metrics);
+
+ deployment.init(prometheusGraph.graphSpecificProperties.memory_values.data);
+ });
+
+ it('creates line on graph for deploment', () => {
+ expect(
+ graphElement().querySelectorAll('.deployment-line').length,
+ ).toBe(2);
+ });
+
+ it('creates hidden deploy boxes', () => {
+ expect(
+ graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box').length,
+ ).toBe(2);
+ });
+
+ it('hides the info boxes by default', () => {
+ expect(
+ graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box.hidden').length,
+ ).toBe(2);
+ });
+
+ it('shows sha short code when tag is false', () => {
+ expect(
+ graphElement().querySelector('.deploy-info-1-cpu_values .js-deploy-info-box').textContent.trim(),
+ ).toContain('testin');
+ });
+
+ it('shows ref name when tag is true', () => {
+ expect(
+ graphElement().querySelector('.deploy-info-2-cpu_values .js-deploy-info-box').textContent.trim(),
+ ).toContain('tag');
+ });
+
+ it('shows info box when moving mouse over line', () => {
+ deployment.mouseOverDeployInfo(deployment.data[0].xPos, 'cpu_values');
+
+ expect(
+ graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box.hidden').length,
+ ).toBe(1);
+
+ expect(
+ graphElement().querySelector('.deploy-info-1-cpu_values .js-deploy-info-box.hidden'),
+ ).toBeNull();
+ });
+
+ it('hides previously visible info box when moving mouse away', () => {
+ deployment.mouseOverDeployInfo(500, 'cpu_values');
+
+ expect(
+ graphElement().querySelectorAll('.prometheus-graph .js-deploy-info-box.hidden').length,
+ ).toBe(2);
+
+ expect(
+ graphElement().querySelector('.deploy-info-1-cpu_values .js-deploy-info-box.hidden'),
+ ).not.toBeNull();
+ });
+
+ describe('refText', () => {
+ it('returns shortened SHA', () => {
+ expect(
+ Deployments.refText({
+ tag: false,
+ sha: '123456789',
+ }),
+ ).toBe('123456');
+ });
+
+ it('returns tag name', () => {
+ expect(
+ Deployments.refText({
+ tag: true,
+ ref: 'v1.0',
+ }),
+ ).toBe('v1.0');
+ });
+ });
+});
diff --git a/spec/javascripts/monitoring/prometheus_graph_spec.js b/spec/javascripts/monitoring/prometheus_graph_spec.js
index 4b904fc2960..25578bf1c6e 100644
--- a/spec/javascripts/monitoring/prometheus_graph_spec.js
+++ b/spec/javascripts/monitoring/prometheus_graph_spec.js
@@ -3,7 +3,7 @@ import PrometheusGraph from '~/monitoring/prometheus_graph';
import { prometheusMockData } from './prometheus_mock_data';
describe('PrometheusGraph', () => {
- const fixtureName = 'static/environments/metrics.html.raw';
+ const fixtureName = 'environments/metrics/metrics.html.raw';
const prometheusGraphContainer = '.prometheus-graph';
const prometheusGraphContents = `${prometheusGraphContainer}[graph-type=cpu_values]`;
@@ -77,7 +77,7 @@ describe('PrometheusGraph', () => {
});
describe('PrometheusGraphs UX states', () => {
- const fixtureName = 'static/environments/metrics.html.raw';
+ const fixtureName = 'environments/metrics/metrics.html.raw';
preloadFixtures(fixtureName);
beforeEach(() => {
diff --git a/spec/javascripts/pdf/index_spec.js b/spec/javascripts/pdf/index_spec.js
new file mode 100644
index 00000000000..f661fae5fe2
--- /dev/null
+++ b/spec/javascripts/pdf/index_spec.js
@@ -0,0 +1,61 @@
+/* eslint-disable import/no-unresolved */
+
+import Vue from 'vue';
+import { PDFJS } from 'pdfjs-dist';
+import workerSrc from 'vendor/pdf.worker';
+
+import PDFLab from '~/pdf/index.vue';
+import pdf from '../fixtures/blob/pdf/test.pdf';
+
+PDFJS.workerSrc = workerSrc;
+const Component = Vue.extend(PDFLab);
+
+describe('PDF component', () => {
+ let vm;
+
+ const checkLoaded = (done) => {
+ if (vm.loading) {
+ setTimeout(() => {
+ checkLoaded(done);
+ }, 100);
+ } else {
+ done();
+ }
+ };
+
+ describe('without PDF data', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ pdf: '',
+ },
+ });
+
+ vm.$mount();
+
+ checkLoaded(done);
+ });
+
+ it('does not render', () => {
+ expect(vm.$el.tagName).toBeUndefined();
+ });
+ });
+
+ describe('with PDF data', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ pdf,
+ },
+ });
+
+ vm.$mount();
+
+ checkLoaded(done);
+ });
+
+ it('renders pdf component', () => {
+ expect(vm.$el.tagName).toBeDefined();
+ });
+ });
+});
diff --git a/spec/javascripts/pdf/page_spec.js b/spec/javascripts/pdf/page_spec.js
new file mode 100644
index 00000000000..ac76ebbfbe6
--- /dev/null
+++ b/spec/javascripts/pdf/page_spec.js
@@ -0,0 +1,57 @@
+/* eslint-disable import/no-unresolved */
+
+import Vue from 'vue';
+import pdfjsLib from 'pdfjs-dist';
+import workerSrc from 'vendor/pdf.worker';
+
+import PageComponent from '~/pdf/page/index.vue';
+import testPDF from '../fixtures/blob/pdf/test.pdf';
+
+const Component = Vue.extend(PageComponent);
+
+describe('Page component', () => {
+ let vm;
+ let testPage;
+ pdfjsLib.PDFJS.workerSrc = workerSrc;
+
+ const checkRendered = (done) => {
+ if (vm.rendering) {
+ setTimeout(() => {
+ checkRendered(done);
+ }, 100);
+ } else {
+ done();
+ }
+ };
+
+ beforeEach((done) => {
+ pdfjsLib.getDocument(testPDF)
+ .then(pdf => pdf.getPage(1))
+ .then((page) => {
+ testPage = page;
+ done();
+ })
+ .catch((error) => {
+ console.error(error);
+ });
+ });
+
+ describe('render', () => {
+ beforeEach((done) => {
+ vm = new Component({
+ propsData: {
+ page: testPage,
+ number: 1,
+ },
+ });
+
+ vm.$mount();
+
+ checkRendered(done);
+ });
+
+ it('renders first page', () => {
+ expect(vm.$el.tagName).toBeDefined();
+ });
+ });
+});
diff --git a/spec/lib/banzai/renderer_spec.rb b/spec/lib/banzai/renderer_spec.rb
index e6f8d2a1fed..0e094405e33 100644
--- a/spec/lib/banzai/renderer_spec.rb
+++ b/spec/lib/banzai/renderer_spec.rb
@@ -11,7 +11,7 @@ describe Banzai::Renderer do
end
describe '#render_field' do
- let(:renderer) { Banzai::Renderer }
+ let(:renderer) { described_class }
subject { renderer.render_field(object, :field) }
context 'with a stale cache' do
diff --git a/spec/lib/constraints/group_url_constrainer_spec.rb b/spec/lib/constraints/group_url_constrainer_spec.rb
index 96dacdc5cd2..f95adf3a84b 100644
--- a/spec/lib/constraints/group_url_constrainer_spec.rb
+++ b/spec/lib/constraints/group_url_constrainer_spec.rb
@@ -17,6 +17,13 @@ describe GroupUrlConstrainer, lib: true do
it { expect(subject.matches?(request)).to be_truthy }
end
+ context 'valid request for nested group with reserved top level name' do
+ let!(:nested_group) { create(:group, path: 'api', parent: group) }
+ let!(:request) { build_request('gitlab/api') }
+
+ it { expect(subject.matches?(request)).to be_truthy }
+ end
+
context 'invalid request' do
let(:request) { build_request('foo') }
diff --git a/spec/lib/gitlab/changes_list_spec.rb b/spec/lib/gitlab/changes_list_spec.rb
index 69d86144e32..464508fcd73 100644
--- a/spec/lib/gitlab/changes_list_spec.rb
+++ b/spec/lib/gitlab/changes_list_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::ChangesList do
let(:invalid_changes) { 1 }
context 'when changes is a valid string' do
- let(:changes_list) { Gitlab::ChangesList.new(valid_changes_string) }
+ let(:changes_list) { described_class.new(valid_changes_string) }
it 'splits elements by newline character' do
expect(changes_list).to contain_exactly({
diff --git a/spec/lib/gitlab/checks/force_push_spec.rb b/spec/lib/gitlab/checks/force_push_spec.rb
index 7a84bbebd02..bc66ce83d4a 100644
--- a/spec/lib/gitlab/checks/force_push_spec.rb
+++ b/spec/lib/gitlab/checks/force_push_spec.rb
@@ -1,19 +1,19 @@
require 'spec_helper'
-describe Gitlab::Checks::ChangeAccess, lib: true do
+describe Gitlab::Checks::ForcePush, lib: true do
let(:project) { create(:project, :repository) }
context "exit code checking" do
it "does not raise a runtime error if the `popen` call to git returns a zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['normal output', 0])
- expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
+ expect { described_class.force_push?(project, 'oldrev', 'newrev') }.not_to raise_error
end
it "raises a runtime error if the `popen` call to git returns a non-zero exit code" do
allow(Gitlab::Popen).to receive(:popen).and_return(['error', 1])
- expect { Gitlab::Checks::ForcePush.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError)
+ expect { described_class.force_push?(project, 'oldrev', 'newrev') }.to raise_error(RuntimeError)
end
end
end
diff --git a/spec/lib/gitlab/ci/build/credentials/factory_spec.rb b/spec/lib/gitlab/ci/build/credentials/factory_spec.rb
index 10b4b7a8826..d53db05e5e6 100644
--- a/spec/lib/gitlab/ci/build/credentials/factory_spec.rb
+++ b/spec/lib/gitlab/ci/build/credentials/factory_spec.rb
@@ -3,14 +3,14 @@ require 'spec_helper'
describe Gitlab::Ci::Build::Credentials::Factory do
let(:build) { create(:ci_build, name: 'spinach', stage: 'test', stage_idx: 0) }
- subject { Gitlab::Ci::Build::Credentials::Factory.new(build).create! }
+ subject { described_class.new(build).create! }
class TestProvider
def initialize(build); end
end
before do
- allow_any_instance_of(Gitlab::Ci::Build::Credentials::Factory).to receive(:providers).and_return([TestProvider])
+ allow_any_instance_of(described_class).to receive(:providers).and_return([TestProvider])
end
context 'when provider is valid' do
diff --git a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb b/spec/lib/gitlab/ci/build/credentials/registry_spec.rb
index 84e44dd53e2..c6054138cde 100644
--- a/spec/lib/gitlab/ci/build/credentials/registry_spec.rb
+++ b/spec/lib/gitlab/ci/build/credentials/registry_spec.rb
@@ -4,14 +4,14 @@ describe Gitlab::Ci::Build::Credentials::Registry do
let(:build) { create(:ci_build, name: 'spinach', stage: 'test', stage_idx: 0) }
let(:registry_url) { 'registry.example.com:5005' }
- subject { Gitlab::Ci::Build::Credentials::Registry.new(build) }
+ subject { described_class.new(build) }
before do
stub_container_registry_config(host_port: registry_url)
end
it 'contains valid DockerRegistry credentials' do
- expect(subject).to be_kind_of(Gitlab::Ci::Build::Credentials::Registry)
+ expect(subject).to be_kind_of(described_class)
expect(subject.username).to eq 'gitlab-ci-token'
expect(subject.password).to eq build.token
@@ -20,7 +20,7 @@ describe Gitlab::Ci::Build::Credentials::Registry do
end
describe '.valid?' do
- subject { Gitlab::Ci::Build::Credentials::Registry.new(build).valid? }
+ subject { described_class.new(build).valid? }
context 'when registry is enabled' do
before do
diff --git a/spec/lib/gitlab/ci/cron_parser_spec.rb b/spec/lib/gitlab/ci/cron_parser_spec.rb
index 0864bc7258d..809fda11879 100644
--- a/spec/lib/gitlab/ci/cron_parser_spec.rb
+++ b/spec/lib/gitlab/ci/cron_parser_spec.rb
@@ -60,14 +60,60 @@ describe Gitlab::Ci::CronParser do
end
end
- context 'when cron_timezone is US/Pacific' do
- let(:cron) { '0 0 * * *' }
- let(:cron_timezone) { 'US/Pacific' }
+ context 'when cron_timezone is TZInfo format' do
+ before do
+ allow(Time).to receive(:zone)
+ .and_return(ActiveSupport::TimeZone['UTC'])
+ end
- it_behaves_like "returns time in the future"
+ let(:hour_in_utc) do
+ ActiveSupport::TimeZone[cron_timezone]
+ .now.change(hour: 0).in_time_zone('UTC').hour
+ end
+
+ context 'when cron_timezone is US/Pacific' do
+ let(:cron) { '* 0 * * *' }
+ let(:cron_timezone) { 'US/Pacific' }
+
+ it_behaves_like "returns time in the future"
+
+ it 'converts time in server time zone' do
+ expect(subject.hour).to eq(hour_in_utc)
+ end
+ end
+ end
+
+ context 'when cron_timezone is ActiveSupport::TimeZone format' do
+ before do
+ allow(Time).to receive(:zone)
+ .and_return(ActiveSupport::TimeZone['UTC'])
+ end
+
+ let(:hour_in_utc) do
+ ActiveSupport::TimeZone[cron_timezone]
+ .now.change(hour: 0).in_time_zone('UTC').hour
+ end
+
+ context 'when cron_timezone is Berlin' do
+ let(:cron) { '* 0 * * *' }
+ let(:cron_timezone) { 'Berlin' }
+
+ it_behaves_like "returns time in the future"
+
+ it 'converts time in server time zone' do
+ expect(subject.hour).to eq(hour_in_utc)
+ end
+ end
- it 'converts time in server time zone' do
- expect(subject.hour).to eq((Time.zone.now.in_time_zone(cron_timezone).utc_offset / 60 / 60).abs)
+ context 'when cron_timezone is Eastern Time (US & Canada)' do
+ let(:cron) { '* 0 * * *' }
+ let(:cron_timezone) { 'Eastern Time (US & Canada)' }
+
+ it_behaves_like "returns time in the future"
+
+ it 'converts time in server time zone' do
+ expect(subject.hour).to eq(hour_in_utc)
+ end
end
end
end
@@ -76,9 +122,21 @@ describe Gitlab::Ci::CronParser do
let(:cron) { 'invalid_cron' }
let(:cron_timezone) { 'invalid_cron_timezone' }
- it 'returns nil' do
- is_expected.to be_nil
- end
+ it { is_expected.to be_nil }
+ end
+
+ context 'when cron syntax is quoted' do
+ let(:cron) { "'0 * * * *'" }
+ let(:cron_timezone) { 'UTC' }
+
+ it { expect(subject).to be_nil }
+ end
+
+ context 'when cron syntax is rufus-scheduler syntax' do
+ let(:cron) { 'every 3h' }
+ let(:cron_timezone) { 'UTC' }
+
+ it { expect(subject).to be_nil }
end
end
@@ -96,6 +154,12 @@ describe Gitlab::Ci::CronParser do
it { is_expected.to eq(false) }
end
+
+ context 'when cron syntax is quoted' do
+ let(:cron) { "'0 * * * *'" }
+
+ it { is_expected.to eq(false) }
+ end
end
describe '#cron_timezone_valid?' do
@@ -112,5 +176,11 @@ describe Gitlab::Ci::CronParser do
it { is_expected.to eq(false) }
end
+
+ context 'when cron_timezone is ActiveSupport::TimeZone format' do
+ let(:cron_timezone) { 'Eastern Time (US & Canada)' }
+
+ it { is_expected.to eq(true) }
+ end
end
end
diff --git a/spec/lib/gitlab/current_settings_spec.rb b/spec/lib/gitlab/current_settings_spec.rb
index b01c4805a34..c796c98ec9f 100644
--- a/spec/lib/gitlab/current_settings_spec.rb
+++ b/spec/lib/gitlab/current_settings_spec.rb
@@ -10,7 +10,7 @@ describe Gitlab::CurrentSettings do
describe '#current_application_settings' do
context 'with DB available' do
before do
- allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(true)
+ allow_any_instance_of(described_class).to receive(:connect_to_db?).and_return(true)
end
it 'attempts to use cached values first' do
@@ -36,7 +36,7 @@ describe Gitlab::CurrentSettings do
context 'with DB unavailable' do
before do
- allow_any_instance_of(Gitlab::CurrentSettings).to receive(:connect_to_db?).and_return(false)
+ allow_any_instance_of(described_class).to receive(:connect_to_db?).and_return(false)
end
it 'returns an in-memory ApplicationSetting object' do
diff --git a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
index c455cd9b942..d8757c601ab 100644
--- a/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
+++ b/spec/lib/gitlab/cycle_analytics/base_event_fetcher_spec.rb
@@ -20,7 +20,7 @@ describe Gitlab::CycleAnalytics::BaseEventFetcher do
before do
allow_any_instance_of(Gitlab::ReferenceExtractor).to receive(:issues).and_return(Issue.all)
- allow_any_instance_of(Gitlab::CycleAnalytics::BaseEventFetcher).to receive(:serialize) do |event|
+ allow_any_instance_of(described_class).to receive(:serialize) do |event|
event
end
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index a044b871730..737fac14f92 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -726,4 +726,37 @@ describe Gitlab::Database::MigrationHelpers, lib: true do
expect(model.column_for(:users, :kittens)).to be_nil
end
end
+
+ describe '#replace_sql' do
+ context 'using postgres' do
+ before do
+ allow(Gitlab::Database).to receive(:mysql?).and_return(false)
+ end
+
+ it 'builds the sql with correct functions' do
+ expect(model.replace_sql(Arel::Table.new(:users)[:first_name], "Alice", "Eve").to_s).
+ to include('regexp_replace')
+ end
+ end
+
+ context 'using mysql' do
+ before do
+ allow(Gitlab::Database).to receive(:mysql?).and_return(true)
+ end
+
+ it 'builds the sql with the correct functions' do
+ expect(model.replace_sql(Arel::Table.new(:users)[:first_name], "Alice", "Eve").to_s).
+ to include('locate', 'insert')
+ end
+ end
+
+ describe 'results' do
+ let!(:user) { create(:user, name: 'Kathy Alice Aliceson') }
+
+ it 'replaces the correct part of the string' do
+ model.update_column_in_batches(:users, :name, model.replace_sql(Arel::Table.new(:users)[:name], 'Alice', 'Eve'))
+ expect(user.reload.name).to eq('Kathy Eve Aliceson')
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
new file mode 100644
index 00000000000..64bc5fc0429
--- /dev/null
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_base_spec.rb
@@ -0,0 +1,197 @@
+require 'spec_helper'
+
+describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameBase do
+ let(:migration) { FakeRenameReservedPathMigrationV1.new }
+ let(:subject) { described_class.new(['the-path'], migration) }
+
+ before do
+ allow(migration).to receive(:say)
+ end
+
+ def migration_namespace(namespace)
+ Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::
+ Namespace.find(namespace.id)
+ end
+
+ def migration_project(project)
+ Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::
+ Project.find(project.id)
+ end
+
+ describe "#remove_last_ocurrence" do
+ it "removes only the last occurance of a string" do
+ input = "this/is/a-word-to-replace/namespace/with/a-word-to-replace"
+
+ expect(subject.remove_last_occurrence(input, "a-word-to-replace"))
+ .to eq("this/is/a-word-to-replace/namespace/with/")
+ end
+ end
+
+ describe '#remove_cached_html_for_projects' do
+ let(:project) { create(:empty_project, description_html: 'Project description') }
+
+ it 'removes description_html from projects' do
+ subject.remove_cached_html_for_projects([project.id])
+
+ expect(project.reload.description_html).to be_nil
+ end
+
+ it 'removes issue descriptions' do
+ issue = create(:issue, project: project, description_html: 'Issue description')
+
+ subject.remove_cached_html_for_projects([project.id])
+
+ expect(issue.reload.description_html).to be_nil
+ end
+
+ it 'removes merge request descriptions' do
+ merge_request = create(:merge_request,
+ source_project: project,
+ target_project: project,
+ description_html: 'MergeRequest description')
+
+ subject.remove_cached_html_for_projects([project.id])
+
+ expect(merge_request.reload.description_html).to be_nil
+ end
+
+ it 'removes note html' do
+ note = create(:note,
+ project: project,
+ noteable: create(:issue, project: project),
+ note_html: 'note description')
+
+ subject.remove_cached_html_for_projects([project.id])
+
+ expect(note.reload.note_html).to be_nil
+ end
+
+ it 'removes milestone description' do
+ milestone = create(:milestone,
+ project: project,
+ description_html: 'milestone description')
+
+ subject.remove_cached_html_for_projects([project.id])
+
+ expect(milestone.reload.description_html).to be_nil
+ end
+ end
+
+ describe '#rename_path_for_routable' do
+ context 'for namespaces' do
+ let(:namespace) { create(:namespace, path: 'the-path') }
+ it "renames namespaces called the-path" do
+ subject.rename_path_for_routable(migration_namespace(namespace))
+
+ expect(namespace.reload.path).to eq("the-path0")
+ end
+
+ it "renames the route to the namespace" do
+ subject.rename_path_for_routable(migration_namespace(namespace))
+
+ expect(Namespace.find(namespace.id).full_path).to eq("the-path0")
+ end
+
+ it "renames the route for projects of the namespace" do
+ project = create(:project, path: "project-path", namespace: namespace)
+
+ subject.rename_path_for_routable(migration_namespace(namespace))
+
+ expect(project.route.reload.path).to eq("the-path0/project-path")
+ end
+
+ it 'returns the old & the new path' do
+ old_path, new_path = subject.rename_path_for_routable(migration_namespace(namespace))
+
+ expect(old_path).to eq('the-path')
+ expect(new_path).to eq('the-path0')
+ end
+
+ context "the-path namespace -> subgroup -> the-path0 project" do
+ it "updates the route of the project correctly" do
+ subgroup = create(:group, path: "subgroup", parent: namespace)
+ project = create(:project, path: "the-path0", namespace: subgroup)
+
+ subject.rename_path_for_routable(migration_namespace(namespace))
+
+ expect(project.route.reload.path).to eq("the-path0/subgroup/the-path0")
+ end
+ end
+ end
+
+ context 'for projects' do
+ let(:parent) { create(:namespace, path: 'the-parent') }
+ let(:project) { create(:empty_project, path: 'the-path', namespace: parent) }
+
+ it 'renames the project called `the-path`' do
+ subject.rename_path_for_routable(migration_project(project))
+
+ expect(project.reload.path).to eq('the-path0')
+ end
+
+ it 'renames the route for the project' do
+ subject.rename_path_for_routable(project)
+
+ expect(project.reload.route.path).to eq('the-parent/the-path0')
+ end
+
+ it 'returns the old & new path' do
+ old_path, new_path = subject.rename_path_for_routable(migration_project(project))
+
+ expect(old_path).to eq('the-parent/the-path')
+ expect(new_path).to eq('the-parent/the-path0')
+ end
+ end
+ end
+
+ describe '#move_pages' do
+ it 'moves the pages directory' do
+ expect(subject).to receive(:move_folders)
+ .with(TestEnv.pages_path, 'old-path', 'new-path')
+
+ subject.move_pages('old-path', 'new-path')
+ end
+ end
+
+ describe "#move_uploads" do
+ let(:test_dir) { File.join(Rails.root, 'tmp', 'tests', 'rename_reserved_paths') }
+ let(:uploads_dir) { File.join(test_dir, 'public', 'uploads') }
+
+ it 'moves subdirectories in the uploads folder' do
+ expect(subject).to receive(:uploads_dir).and_return(uploads_dir)
+ expect(subject).to receive(:move_folders).with(uploads_dir, 'old_path', 'new_path')
+
+ subject.move_uploads('old_path', 'new_path')
+ end
+
+ it "doesn't move uploads when they are stored in object storage" do
+ expect(subject).to receive(:file_storage?).and_return(false)
+ expect(subject).not_to receive(:move_folders)
+
+ subject.move_uploads('old_path', 'new_path')
+ end
+ end
+
+ describe '#move_folders' do
+ let(:test_dir) { File.join(Rails.root, 'tmp', 'tests', 'rename_reserved_paths') }
+ let(:uploads_dir) { File.join(test_dir, 'public', 'uploads') }
+
+ before do
+ FileUtils.remove_dir(test_dir) if File.directory?(test_dir)
+ FileUtils.mkdir_p(uploads_dir)
+ allow(subject).to receive(:uploads_dir).and_return(uploads_dir)
+ end
+
+ it 'moves a folder with files' do
+ source = File.join(uploads_dir, 'parent-group', 'sub-group')
+ FileUtils.mkdir_p(source)
+ destination = File.join(uploads_dir, 'parent-group', 'moved-group')
+ FileUtils.touch(File.join(source, 'test.txt'))
+ expected_file = File.join(destination, 'test.txt')
+
+ subject.move_folders(uploads_dir, File.join('parent-group', 'sub-group'), File.join('parent-group', 'moved-group'))
+
+ expect(File.exist?(expected_file)).to be(true)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
new file mode 100644
index 00000000000..a25c5da488a
--- /dev/null
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_namespaces_spec.rb
@@ -0,0 +1,171 @@
+require 'spec_helper'
+
+describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameNamespaces do
+ let(:migration) { FakeRenameReservedPathMigrationV1.new }
+ let(:subject) { described_class.new(['the-path'], migration) }
+
+ before do
+ allow(migration).to receive(:say)
+ end
+
+ def migration_namespace(namespace)
+ Gitlab::Database::RenameReservedPathsMigration::V1::MigrationClasses::
+ Namespace.find(namespace.id)
+ end
+
+ describe '#namespaces_for_paths' do
+ context 'nested namespaces' do
+ let(:subject) { described_class.new(['parent/the-Path'], migration) }
+
+ it 'includes the namespace' do
+ parent = create(:namespace, path: 'parent')
+ child = create(:namespace, path: 'the-path', parent: parent)
+
+ found_ids = subject.namespaces_for_paths(type: :child).
+ map(&:id)
+ expect(found_ids).to contain_exactly(child.id)
+ end
+ end
+
+ context 'for child namespaces' do
+ it 'only returns child namespaces with the correct path' do
+ _root_namespace = create(:namespace, path: 'THE-path')
+ _other_path = create(:namespace,
+ path: 'other',
+ parent: create(:namespace))
+ namespace = create(:namespace,
+ path: 'the-path',
+ parent: create(:namespace))
+
+ found_ids = subject.namespaces_for_paths(type: :child).
+ map(&:id)
+ expect(found_ids).to contain_exactly(namespace.id)
+ end
+ end
+
+ context 'for top levelnamespaces' do
+ it 'only returns child namespaces with the correct path' do
+ root_namespace = create(:namespace, path: 'the-path')
+ _other_path = create(:namespace, path: 'other')
+ _child_namespace = create(:namespace,
+ path: 'the-path',
+ parent: create(:namespace))
+
+ found_ids = subject.namespaces_for_paths(type: :top_level).
+ map(&:id)
+ expect(found_ids).to contain_exactly(root_namespace.id)
+ end
+ end
+ end
+
+ describe '#move_repositories' do
+ let(:namespace) { create(:group, name: 'hello-group') }
+ it 'moves a project for a namespace' do
+ create(:project, namespace: namespace, path: 'hello-project')
+ expected_path = File.join(TestEnv.repos_path, 'bye-group', 'hello-project.git')
+
+ subject.move_repositories(namespace, 'hello-group', 'bye-group')
+
+ expect(File.directory?(expected_path)).to be(true)
+ end
+
+ it 'moves a namespace in a subdirectory correctly' do
+ child_namespace = create(:group, name: 'sub-group', parent: namespace)
+ create(:project, namespace: child_namespace, path: 'hello-project')
+
+ expected_path = File.join(TestEnv.repos_path, 'hello-group', 'renamed-sub-group', 'hello-project.git')
+
+ subject.move_repositories(child_namespace, 'hello-group/sub-group', 'hello-group/renamed-sub-group')
+
+ expect(File.directory?(expected_path)).to be(true)
+ end
+
+ it 'moves a parent namespace with subdirectories' do
+ child_namespace = create(:group, name: 'sub-group', parent: namespace)
+ create(:project, namespace: child_namespace, path: 'hello-project')
+ expected_path = File.join(TestEnv.repos_path, 'renamed-group', 'sub-group', 'hello-project.git')
+
+ subject.move_repositories(child_namespace, 'hello-group', 'renamed-group')
+
+ expect(File.directory?(expected_path)).to be(true)
+ end
+ end
+
+ describe "#child_ids_for_parent" do
+ it "collects child ids for all levels" do
+ parent = create(:namespace)
+ first_child = create(:namespace, parent: parent)
+ second_child = create(:namespace, parent: parent)
+ third_child = create(:namespace, parent: second_child)
+ all_ids = [parent.id, first_child.id, second_child.id, third_child.id]
+
+ collected_ids = subject.child_ids_for_parent(parent, ids: [parent.id])
+
+ expect(collected_ids).to contain_exactly(*all_ids)
+ end
+ end
+
+ describe "#rename_namespace" do
+ let(:namespace) { create(:namespace, path: 'the-path') }
+
+ it 'renames paths & routes for the namespace' do
+ expect(subject).to receive(:rename_path_for_routable).
+ with(namespace).
+ and_call_original
+
+ subject.rename_namespace(namespace)
+
+ expect(namespace.reload.path).to eq('the-path0')
+ end
+
+ it "moves the the repository for a project in the namespace" do
+ create(:project, namespace: namespace, path: "the-path-project")
+ expected_repo = File.join(TestEnv.repos_path, "the-path0", "the-path-project.git")
+
+ subject.rename_namespace(namespace)
+
+ expect(File.directory?(expected_repo)).to be(true)
+ end
+
+ it "moves the uploads for the namespace" do
+ expect(subject).to receive(:move_uploads).with("the-path", "the-path0")
+
+ subject.rename_namespace(namespace)
+ end
+
+ it "moves the pages for the namespace" do
+ expect(subject).to receive(:move_pages).with("the-path", "the-path0")
+
+ subject.rename_namespace(namespace)
+ end
+
+ it 'invalidates the markdown cache of related projects' do
+ project = create(:empty_project, namespace: namespace, path: "the-path-project")
+
+ expect(subject).to receive(:remove_cached_html_for_projects).with([project.id])
+
+ subject.rename_namespace(namespace)
+ end
+ end
+
+ describe '#rename_namespaces' do
+ let!(:top_level_namespace) { create(:namespace, path: 'the-path') }
+ let!(:child_namespace) do
+ create(:namespace, path: 'the-path', parent: create(:namespace))
+ end
+
+ it 'renames top level namespaces the namespace' do
+ expect(subject).to receive(:rename_namespace).
+ with(migration_namespace(top_level_namespace))
+
+ subject.rename_namespaces(type: :top_level)
+ end
+
+ it 'renames child namespaces' do
+ expect(subject).to receive(:rename_namespace).
+ with(migration_namespace(child_namespace))
+
+ subject.rename_namespaces(type: :child)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
new file mode 100644
index 00000000000..59e8de2712d
--- /dev/null
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1/rename_projects_spec.rb
@@ -0,0 +1,102 @@
+require 'spec_helper'
+
+describe Gitlab::Database::RenameReservedPathsMigration::V1::RenameProjects do
+ let(:migration) { FakeRenameReservedPathMigrationV1.new }
+ let(:subject) { described_class.new(['the-path'], migration) }
+
+ before do
+ allow(migration).to receive(:say)
+ end
+
+ describe '#projects_for_paths' do
+ it 'searches using nested paths' do
+ namespace = create(:namespace, path: 'hello')
+ project = create(:empty_project, path: 'THE-path', namespace: namespace)
+
+ result_ids = described_class.new(['Hello/the-path'], migration).
+ projects_for_paths.map(&:id)
+
+ expect(result_ids).to contain_exactly(project.id)
+ end
+
+ it 'includes the correct projects' do
+ project = create(:empty_project, path: 'THE-path')
+ _other_project = create(:empty_project)
+
+ result_ids = subject.projects_for_paths.map(&:id)
+
+ expect(result_ids).to contain_exactly(project.id)
+ end
+ end
+
+ describe '#rename_projects' do
+ let!(:projects) { create_list(:empty_project, 2, path: 'the-path') }
+
+ it 'renames each project' do
+ expect(subject).to receive(:rename_project).twice
+
+ subject.rename_projects
+ end
+
+ it 'invalidates the markdown cache of related projects' do
+ expect(subject).to receive(:remove_cached_html_for_projects).
+ with(projects.map(&:id))
+
+ subject.rename_projects
+ end
+ end
+
+ describe '#rename_project' do
+ let(:project) do
+ create(:empty_project,
+ path: 'the-path',
+ namespace: create(:namespace, path: 'known-parent' ))
+ end
+
+ it 'renames path & route for the project' do
+ expect(subject).to receive(:rename_path_for_routable).
+ with(project).
+ and_call_original
+
+ subject.rename_project(project)
+
+ expect(project.reload.path).to eq('the-path0')
+ end
+
+ it 'moves the wiki & the repo' do
+ expect(subject).to receive(:move_repository).
+ with(project, 'known-parent/the-path.wiki', 'known-parent/the-path0.wiki')
+ expect(subject).to receive(:move_repository).
+ with(project, 'known-parent/the-path', 'known-parent/the-path0')
+
+ subject.rename_project(project)
+ end
+
+ it 'moves uploads' do
+ expect(subject).to receive(:move_uploads).
+ with('known-parent/the-path', 'known-parent/the-path0')
+
+ subject.rename_project(project)
+ end
+
+ it 'moves pages' do
+ expect(subject).to receive(:move_pages).
+ with('known-parent/the-path', 'known-parent/the-path0')
+
+ subject.rename_project(project)
+ end
+ end
+
+ describe '#move_repository' do
+ let(:known_parent) { create(:namespace, path: 'known-parent') }
+ let(:project) { create(:project, path: 'the-path', namespace: known_parent) }
+
+ it 'moves the repository for a project' do
+ expected_path = File.join(TestEnv.repos_path, 'known-parent', 'new-repo.git')
+
+ subject.move_repository(project, 'known-parent/the-path', 'known-parent/new-repo')
+
+ expect(File.directory?(expected_path)).to be(true)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb
new file mode 100644
index 00000000000..f8cc1eb91ec
--- /dev/null
+++ b/spec/lib/gitlab/database/rename_reserved_paths_migration/v1_spec.rb
@@ -0,0 +1,54 @@
+require 'spec_helper'
+
+shared_examples 'renames child namespaces' do |type|
+ it 'renames namespaces' do
+ rename_namespaces = double
+ expect(described_class::RenameNamespaces).
+ to receive(:new).with(['first-path', 'second-path'], subject).
+ and_return(rename_namespaces)
+ expect(rename_namespaces).to receive(:rename_namespaces).
+ with(type: :child)
+
+ subject.rename_wildcard_paths(['first-path', 'second-path'])
+ end
+end
+
+describe Gitlab::Database::RenameReservedPathsMigration::V1 do
+ let(:subject) { FakeRenameReservedPathMigrationV1.new }
+
+ before do
+ allow(subject).to receive(:say)
+ end
+
+ describe '#rename_child_paths' do
+ it_behaves_like 'renames child namespaces'
+ end
+
+ describe '#rename_wildcard_paths' do
+ it_behaves_like 'renames child namespaces'
+
+ it 'should rename projects' do
+ rename_projects = double
+ expect(described_class::RenameProjects).
+ to receive(:new).with(['the-path'], subject).
+ and_return(rename_projects)
+
+ expect(rename_projects).to receive(:rename_projects)
+
+ subject.rename_wildcard_paths(['the-path'])
+ end
+ end
+
+ describe '#rename_root_paths' do
+ it 'should rename namespaces' do
+ rename_namespaces = double
+ expect(described_class::RenameNamespaces).
+ to receive(:new).with(['the-path'], subject).
+ and_return(rename_namespaces)
+ expect(rename_namespaces).to receive(:rename_namespaces).
+ with(type: :top_level)
+
+ subject.rename_root_paths('the-path')
+ end
+ end
+end
diff --git a/spec/lib/gitlab/email/receiver_spec.rb b/spec/lib/gitlab/email/receiver_spec.rb
index 2a86b427806..f127e45ae6a 100644
--- a/spec/lib/gitlab/email/receiver_spec.rb
+++ b/spec/lib/gitlab/email/receiver_spec.rb
@@ -7,9 +7,17 @@ describe Gitlab::Email::Receiver, lib: true do
context "when we cannot find a capable handler" do
let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "!!!") }
- it "raises a UnknownIncomingEmail" do
+ it "raises an UnknownIncomingEmail error" do
expect { receiver.execute }.to raise_error(Gitlab::Email::UnknownIncomingEmail)
end
+
+ context "and the email contains no references header" do
+ let(:email_raw) { fixture_file("emails/auto_reply.eml").gsub(mail_key, "!!!") }
+
+ it "raises an UnknownIncomingEmail error" do
+ expect { receiver.execute }.to raise_error(Gitlab::Email::UnknownIncomingEmail)
+ end
+ end
end
context "when the email is blank" do
diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb
index f88653cb1fe..ddedb7c3443 100644
--- a/spec/lib/gitlab/git/repository_spec.rb
+++ b/spec/lib/gitlab/git/repository_spec.rb
@@ -24,21 +24,26 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
end
- # TODO: Uncomment when feature is reenabled
- # context 'with gitaly enabled' do
- # before { stub_gitaly }
- #
- # it 'gets the branch name from GitalyClient' do
- # expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name)
- # repository.root_ref
- # end
- #
- # it 'wraps GRPC exceptions' do
- # expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name).
- # and_raise(GRPC::Unknown)
- # expect { repository.root_ref }.to raise_error(Gitlab::Git::CommandError)
- # end
- # end
+ context 'with gitaly enabled' do
+ before { stub_gitaly }
+
+ it 'gets the branch name from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name)
+ repository.root_ref
+ end
+
+ it 'wraps GRPC not found' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name).
+ and_raise(GRPC::NotFound)
+ expect { repository.root_ref }.to raise_error(Gitlab::Git::Repository::NoRepository)
+ end
+
+ it 'wraps GRPC exceptions' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:default_branch_name).
+ and_raise(GRPC::Unknown)
+ expect { repository.root_ref }.to raise_error(Gitlab::Git::CommandError)
+ end
+ end
end
describe "#rugged" do
@@ -113,21 +118,26 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.to include("master") }
it { is_expected.not_to include("branch-from-space") }
- # TODO: Uncomment when feature is reenabled
- # context 'with gitaly enabled' do
- # before { stub_gitaly }
- #
- # it 'gets the branch names from GitalyClient' do
- # expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names)
- # subject
- # end
- #
- # it 'wraps GRPC exceptions' do
- # expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names).
- # and_raise(GRPC::Unknown)
- # expect { subject }.to raise_error(Gitlab::Git::CommandError)
- # end
- # end
+ context 'with gitaly enabled' do
+ before { stub_gitaly }
+
+ it 'gets the branch names from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names)
+ subject
+ end
+
+ it 'wraps GRPC not found' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names).
+ and_raise(GRPC::NotFound)
+ expect { subject }.to raise_error(Gitlab::Git::Repository::NoRepository)
+ end
+
+ it 'wraps GRPC other exceptions' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:branch_names).
+ and_raise(GRPC::Unknown)
+ expect { subject }.to raise_error(Gitlab::Git::CommandError)
+ end
+ end
end
describe '#tag_names' do
@@ -145,21 +155,26 @@ describe Gitlab::Git::Repository, seed_helper: true do
it { is_expected.to include("v1.0.0") }
it { is_expected.not_to include("v5.0.0") }
- # TODO: Uncomment when feature is reenabled
- # context 'with gitaly enabled' do
- # before { stub_gitaly }
- #
- # it 'gets the tag names from GitalyClient' do
- # expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names)
- # subject
- # end
- #
- # it 'wraps GRPC exceptions' do
- # expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names).
- # and_raise(GRPC::Unknown)
- # expect { subject }.to raise_error(Gitlab::Git::CommandError)
- # end
- # end
+ context 'with gitaly enabled' do
+ before { stub_gitaly }
+
+ it 'gets the tag names from GitalyClient' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names)
+ subject
+ end
+
+ it 'wraps GRPC not found' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names).
+ and_raise(GRPC::NotFound)
+ expect { subject }.to raise_error(Gitlab::Git::Repository::NoRepository)
+ end
+
+ it 'wraps GRPC exceptions' do
+ expect_any_instance_of(Gitlab::GitalyClient::Ref).to receive(:tag_names).
+ and_raise(GRPC::Unknown)
+ expect { subject }.to raise_error(Gitlab::Git::CommandError)
+ end
+ end
end
shared_examples 'archive check' do |extenstion|
@@ -1074,20 +1089,8 @@ describe Gitlab::Git::Repository, seed_helper: true do
end
describe '#branch_count' do
- before(:each) do
- valid_ref = double(:ref)
- invalid_ref = double(:ref)
-
- allow(valid_ref).to receive_messages(name: 'master', target: double(:target))
-
- allow(invalid_ref).to receive_messages(name: 'bad-branch')
- allow(invalid_ref).to receive(:target) { raise Rugged::ReferenceError }
-
- allow(repository.rugged).to receive_messages(branches: [valid_ref, invalid_ref])
- end
-
it 'returns the number of branches' do
- expect(repository.branch_count).to eq(1)
+ expect(repository.branch_count).to eq(9)
end
end
diff --git a/spec/lib/gitlab/git/util_spec.rb b/spec/lib/gitlab/git/util_spec.rb
index bcca4d4c746..69d3ca55397 100644
--- a/spec/lib/gitlab/git/util_spec.rb
+++ b/spec/lib/gitlab/git/util_spec.rb
@@ -9,7 +9,7 @@ describe Gitlab::Git::Util do
["foo\n\n", 2],
].each do |string, line_count|
it "counts #{line_count} lines in #{string.inspect}" do
- expect(Gitlab::Git::Util.count_lines(string)).to eq(line_count)
+ expect(described_class.count_lines(string)).to eq(line_count)
end
end
end
diff --git a/spec/lib/git_ref_validator_spec.rb b/spec/lib/gitlab/git_ref_validator_spec.rb
index cc8daa535d6..cc8daa535d6 100644
--- a/spec/lib/git_ref_validator_spec.rb
+++ b/spec/lib/gitlab/git_ref_validator_spec.rb
diff --git a/spec/lib/gitlab/gitaly_client/ref_spec.rb b/spec/lib/gitlab/gitaly_client/ref_spec.rb
index 5405eafd281..255f23e6270 100644
--- a/spec/lib/gitlab/gitaly_client/ref_spec.rb
+++ b/spec/lib/gitlab/gitaly_client/ref_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::GitalyClient::Ref do
let(:project) { create(:empty_project) }
let(:repo_path) { project.repository.path_to_repo }
- let(:client) { Gitlab::GitalyClient::Ref.new(project.repository) }
+ let(:client) { described_class.new(project.repository) }
before do
allow(Gitlab.config.gitaly).to receive(:enabled).and_return(true)
diff --git a/spec/lib/gitlab/healthchecks/db_check_spec.rb b/spec/lib/gitlab/health_checks/db_check_spec.rb
index 33c6c24449c..33c6c24449c 100644
--- a/spec/lib/gitlab/healthchecks/db_check_spec.rb
+++ b/spec/lib/gitlab/health_checks/db_check_spec.rb
diff --git a/spec/lib/gitlab/healthchecks/fs_shards_check_spec.rb b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb
index 4cd8cf313a5..4cd8cf313a5 100644
--- a/spec/lib/gitlab/healthchecks/fs_shards_check_spec.rb
+++ b/spec/lib/gitlab/health_checks/fs_shards_check_spec.rb
diff --git a/spec/lib/gitlab/healthchecks/redis_check_spec.rb b/spec/lib/gitlab/health_checks/redis_check_spec.rb
index 734cdcb893e..734cdcb893e 100644
--- a/spec/lib/gitlab/healthchecks/redis_check_spec.rb
+++ b/spec/lib/gitlab/health_checks/redis_check_spec.rb
diff --git a/spec/lib/gitlab/healthchecks/simple_check_shared.rb b/spec/lib/gitlab/health_checks/simple_check_shared.rb
index 1fa6d0faef9..1fa6d0faef9 100644
--- a/spec/lib/gitlab/healthchecks/simple_check_shared.rb
+++ b/spec/lib/gitlab/health_checks/simple_check_shared.rb
diff --git a/spec/lib/gitlab/import_export/fork_spec.rb b/spec/lib/gitlab/import_export/fork_spec.rb
index c5ce06afd73..42f3fc59f04 100644
--- a/spec/lib/gitlab/import_export/fork_spec.rb
+++ b/spec/lib/gitlab/import_export/fork_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe 'forked project import', services: true do
let(:user) { create(:user) }
let!(:project_with_repo) { create(:project, :test_repo, name: 'test-repo-restorer', path: 'test-repo-restorer') }
- let!(:project) { create(:empty_project) }
+ let!(:project) { create(:empty_project, name: 'test-repo-restorer-no-repo', path: 'test-repo-restorer-no-repo') }
let(:export_path) { "#{Dir.tmpdir}/project_tree_saver_spec" }
let(:shared) { Gitlab::ImportExport::Shared.new(relative_path: project.path_with_namespace) }
let(:forked_from_project) { create(:project) }
diff --git a/spec/lib/gitlab/import_export/project.json b/spec/lib/gitlab/import_export/project.json
index bfecfa28ed1..fdbb6a0556d 100644
--- a/spec/lib/gitlab/import_export/project.json
+++ b/spec/lib/gitlab/import_export/project.json
@@ -2,6 +2,7 @@
"description": "Nisi et repellendus ut enim quo accusamus vel magnam.",
"visibility_level": 10,
"archived": false,
+ "description_html": "description",
"labels": [
{
"id": 2,
diff --git a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
index 0e9607c5bd3..14338515892 100644
--- a/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_restorer_spec.rb
@@ -30,6 +30,10 @@ describe Gitlab::ImportExport::ProjectTreeRestorer, services: true do
expect(project.project_feature.merge_requests_access_level).to eq(ProjectFeature::ENABLED)
end
+ it 'has the project html description' do
+ expect(Project.find_by_path('project').description_html).to eq('description')
+ end
+
it 'has the same label associated to two issues' do
expect(ProjectLabel.find_by_title('test2').issues.count).to eq(2)
end
diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
index d2d89e3b019..6e145947104 100644
--- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
+++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb
@@ -189,6 +189,16 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
end
end
end
+
+ context 'project attributes' do
+ it 'contains the html description' do
+ expect(saved_project_json).to include("description_html" => 'description')
+ end
+
+ it 'does not contain the runners token' do
+ expect(saved_project_json).not_to include("runners_token" => 'token')
+ end
+ end
end
end
@@ -209,6 +219,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do
releases: [release],
group: group
)
+ project.update(description_html: 'description')
project_label = create(:label, project: project)
group_label = create(:group_label, group: group)
create(:label_link, label: project_label, target: issue)
diff --git a/spec/lib/gitlab/import_export/reader_spec.rb b/spec/lib/gitlab/import_export/reader_spec.rb
index 48d74b07e27..d700af142be 100644
--- a/spec/lib/gitlab/import_export/reader_spec.rb
+++ b/spec/lib/gitlab/import_export/reader_spec.rb
@@ -5,7 +5,7 @@ describe Gitlab::ImportExport::Reader, lib: true do
let(:test_config) { 'spec/support/import_export/import_export.yml' }
let(:project_tree_hash) do
{
- only: [:name, :path],
+ except: [:id, :created_at],
include: [:issues, :labels,
{ merge_requests: {
only: [:id],
diff --git a/spec/lib/gitlab/import_export/safe_model_attributes.yml b/spec/lib/gitlab/import_export/safe_model_attributes.yml
index 0372e3f7dbf..ebfaab4eacd 100644
--- a/spec/lib/gitlab/import_export/safe_model_attributes.yml
+++ b/spec/lib/gitlab/import_export/safe_model_attributes.yml
@@ -329,6 +329,28 @@ Project:
- snippets_enabled
- visibility_level
- archived
+- created_at
+- updated_at
+- last_activity_at
+- star_count
+- ci_id
+- shared_runners_enabled
+- build_coverage_regex
+- build_allow_git_fetchs
+- build_timeout
+- pending_delete
+- public_builds
+- last_repository_check_failed
+- last_repository_check_at
+- container_registry_enabled
+- only_allow_merge_if_pipeline_succeeds
+- has_external_issue_tracker
+- request_access_enabled
+- has_external_wiki
+- only_allow_merge_if_all_discussions_are_resolved
+- auto_cancel_pending_pipelines
+- printing_merge_request_link_enabled
+- build_allow_git_fetch
Author:
- name
ProjectFeature:
diff --git a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
index 071e5fac3f0..071e5fac3f0 100644
--- a/spec/lib/gitlab/import_export/wiki_repo_bundler_spec.rb
+++ b/spec/lib/gitlab/import_export/wiki_repo_saver_spec.rb
diff --git a/spec/lib/gitlab/ldap/person_spec.rb b/spec/lib/gitlab/ldap/person_spec.rb
index 9a556cde5d5..087c4d8c92c 100644
--- a/spec/lib/gitlab/ldap/person_spec.rb
+++ b/spec/lib/gitlab/ldap/person_spec.rb
@@ -20,7 +20,7 @@ describe Gitlab::LDAP::Person do
it 'uses the configured name attribute and handles values as an array' do
name = 'John Doe'
entry['cn'] = [name]
- person = Gitlab::LDAP::Person.new(entry, 'ldapmain')
+ person = described_class.new(entry, 'ldapmain')
expect(person.name).to eq(name)
end
@@ -30,7 +30,7 @@ describe Gitlab::LDAP::Person do
it 'returns the value of mail, if present' do
mail = 'john@example.com'
entry['mail'] = mail
- person = Gitlab::LDAP::Person.new(entry, 'ldapmain')
+ person = described_class.new(entry, 'ldapmain')
expect(person.email).to eq([mail])
end
@@ -38,7 +38,7 @@ describe Gitlab::LDAP::Person do
it 'returns the value of userPrincipalName, if mail and email are not present' do
user_principal_name = 'john.doe@example.com'
entry['userPrincipalName'] = user_principal_name
- person = Gitlab::LDAP::Person.new(entry, 'ldapmain')
+ person = described_class.new(entry, 'ldapmain')
expect(person.email).to eq([user_principal_name])
end
diff --git a/spec/lib/gitlab/metrics_spec.rb b/spec/lib/gitlab/metrics_spec.rb
index ab6e311b1e8..208a8d028cd 100644
--- a/spec/lib/gitlab/metrics_spec.rb
+++ b/spec/lib/gitlab/metrics_spec.rb
@@ -20,7 +20,7 @@ describe Gitlab::Metrics do
expect(pool).to receive(:with).and_yield(connection)
expect(connection).to receive(:write_points).with(an_instance_of(Array))
- expect(Gitlab::Metrics).to receive(:pool).and_return(pool)
+ expect(described_class).to receive(:pool).and_return(pool)
described_class.submit_metrics([{ 'series' => 'kittens', 'tags' => {} }])
end
@@ -64,7 +64,7 @@ describe Gitlab::Metrics do
describe '.measure' do
context 'without a transaction' do
it 'returns the return value of the block' do
- val = Gitlab::Metrics.measure(:foo) { 10 }
+ val = described_class.measure(:foo) { 10 }
expect(val).to eq(10)
end
@@ -74,7 +74,7 @@ describe Gitlab::Metrics do
let(:transaction) { Gitlab::Metrics::Transaction.new }
before do
- allow(Gitlab::Metrics).to receive(:current_transaction).
+ allow(described_class).to receive(:current_transaction).
and_return(transaction)
end
@@ -88,11 +88,11 @@ describe Gitlab::Metrics do
expect(transaction).to receive(:increment).
with('foo_call_count', 1)
- Gitlab::Metrics.measure(:foo) { 10 }
+ described_class.measure(:foo) { 10 }
end
it 'returns the return value of the block' do
- val = Gitlab::Metrics.measure(:foo) { 10 }
+ val = described_class.measure(:foo) { 10 }
expect(val).to eq(10)
end
@@ -105,7 +105,7 @@ describe Gitlab::Metrics do
expect_any_instance_of(Gitlab::Metrics::Transaction).
not_to receive(:add_tag)
- Gitlab::Metrics.tag_transaction(:foo, 'bar')
+ described_class.tag_transaction(:foo, 'bar')
end
end
@@ -113,13 +113,13 @@ describe Gitlab::Metrics do
let(:transaction) { Gitlab::Metrics::Transaction.new }
it 'adds the tag to the transaction' do
- expect(Gitlab::Metrics).to receive(:current_transaction).
+ expect(described_class).to receive(:current_transaction).
and_return(transaction)
expect(transaction).to receive(:add_tag).
with(:foo, 'bar')
- Gitlab::Metrics.tag_transaction(:foo, 'bar')
+ described_class.tag_transaction(:foo, 'bar')
end
end
end
@@ -130,7 +130,7 @@ describe Gitlab::Metrics do
expect_any_instance_of(Gitlab::Metrics::Transaction).
not_to receive(:action=)
- Gitlab::Metrics.action = 'foo'
+ described_class.action = 'foo'
end
end
@@ -138,12 +138,12 @@ describe Gitlab::Metrics do
it 'sets the action of a transaction' do
trans = Gitlab::Metrics::Transaction.new
- expect(Gitlab::Metrics).to receive(:current_transaction).
+ expect(described_class).to receive(:current_transaction).
and_return(trans)
expect(trans).to receive(:action=).with('foo')
- Gitlab::Metrics.action = 'foo'
+ described_class.action = 'foo'
end
end
end
@@ -160,7 +160,7 @@ describe Gitlab::Metrics do
expect_any_instance_of(Gitlab::Metrics::Transaction).
not_to receive(:add_event)
- Gitlab::Metrics.add_event(:meow)
+ described_class.add_event(:meow)
end
end
@@ -170,10 +170,10 @@ describe Gitlab::Metrics do
expect(transaction).to receive(:add_event).with(:meow)
- expect(Gitlab::Metrics).to receive(:current_transaction).
+ expect(described_class).to receive(:current_transaction).
and_return(transaction)
- Gitlab::Metrics.add_event(:meow)
+ described_class.add_event(:meow)
end
end
end
diff --git a/spec/lib/gitlab/regex_spec.rb b/spec/lib/gitlab/regex_spec.rb
index 127cd8c78d8..72e947f2cc2 100644
--- a/spec/lib/gitlab/regex_spec.rb
+++ b/spec/lib/gitlab/regex_spec.rb
@@ -45,8 +45,8 @@ describe Gitlab::Regex, lib: true do
it { is_expected.not_to match('foo-') }
end
- describe 'FULL_NAMESPACE_REGEX_STR' do
- subject { %r{\A#{Gitlab::Regex::FULL_NAMESPACE_REGEX_STR}\z} }
+ describe '.full_namespace_regex' do
+ subject { described_class.full_namespace_regex }
it { is_expected.to match('gitlab.org') }
it { is_expected.to match('gitlab.org/gitlab-git') }
diff --git a/spec/lib/gitlab/request_profiler_spec.rb b/spec/lib/gitlab/request_profiler_spec.rb
new file mode 100644
index 00000000000..ae9c06ebb7d
--- /dev/null
+++ b/spec/lib/gitlab/request_profiler_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Gitlab::RequestProfiler, lib: true do
+ describe '.profile_token' do
+ it 'returns a token' do
+ expect(described_class.profile_token).to be_present
+ end
+
+ it 'caches the token' do
+ expect(Rails.cache).to receive(:fetch).with('profile-token')
+
+ described_class.profile_token
+ end
+ end
+
+ describe '.remove_all_profiles' do
+ it 'removes Gitlab::RequestProfiler::PROFILES_DIR directory' do
+ dir = described_class::PROFILES_DIR
+ FileUtils.mkdir_p(dir)
+
+ expect(Dir.exist?(dir)).to be true
+
+ described_class.remove_all_profiles
+ expect(Dir.exist?(dir)).to be false
+ end
+ end
+end
diff --git a/spec/lib/gitlab/backend/shell_spec.rb b/spec/lib/gitlab/shell_spec.rb
index 6675d26734e..6675d26734e 100644
--- a/spec/lib/gitlab/backend/shell_spec.rb
+++ b/spec/lib/gitlab/shell_spec.rb
diff --git a/spec/lib/gitlab/sidekiq_throttler_spec.rb b/spec/lib/gitlab/sidekiq_throttler_spec.rb
index ff32e0e699d..6374ac80207 100644
--- a/spec/lib/gitlab/sidekiq_throttler_spec.rb
+++ b/spec/lib/gitlab/sidekiq_throttler_spec.rb
@@ -13,14 +13,14 @@ describe Gitlab::SidekiqThrottler do
describe '#execute!' do
it 'sets limits on the selected queues' do
- Gitlab::SidekiqThrottler.execute!
+ described_class.execute!
expect(Sidekiq::Queue['build'].limit).to eq 4
expect(Sidekiq::Queue['project_cache'].limit).to eq 4
end
it 'does not set limits on other queues' do
- Gitlab::SidekiqThrottler.execute!
+ described_class.execute!
expect(Sidekiq::Queue['merge'].limit).to be_nil
end
diff --git a/spec/lib/gitlab/slash_commands/dsl_spec.rb b/spec/lib/gitlab/slash_commands/dsl_spec.rb
index 26217a0e3b2..2763d950716 100644
--- a/spec/lib/gitlab/slash_commands/dsl_spec.rb
+++ b/spec/lib/gitlab/slash_commands/dsl_spec.rb
@@ -3,7 +3,7 @@ require 'spec_helper'
describe Gitlab::SlashCommands::Dsl do
before :all do
DummyClass = Struct.new(:project) do
- include Gitlab::SlashCommands::Dsl
+ include Gitlab::SlashCommands::Dsl # rubocop:disable RSpec/DescribedClass
desc 'A command with no args'
command :no_args, :none do
diff --git a/spec/lib/gitlab/template/gitignore_template_spec.rb b/spec/lib/gitlab/template/gitignore_template_spec.rb
index 9750a012e22..97797f42aaa 100644
--- a/spec/lib/gitlab/template/gitignore_template_spec.rb
+++ b/spec/lib/gitlab/template/gitignore_template_spec.rb
@@ -24,7 +24,7 @@ describe Gitlab::Template::GitignoreTemplate do
it 'returns the Gitignore object of a valid file' do
ruby = subject.find('Ruby')
- expect(ruby).to be_a Gitlab::Template::GitignoreTemplate
+ expect(ruby).to be_a described_class
expect(ruby.name).to eq('Ruby')
end
end
diff --git a/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb b/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb
index e3b8321eda3..6541326d1de 100644
--- a/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb
+++ b/spec/lib/gitlab/template/gitlab_ci_yml_template_spec.rb
@@ -25,7 +25,7 @@ describe Gitlab::Template::GitlabCiYmlTemplate do
it 'returns the GitlabCiYml object of a valid file' do
ruby = subject.find('Ruby')
- expect(ruby).to be_a Gitlab::Template::GitlabCiYmlTemplate
+ expect(ruby).to be_a described_class
expect(ruby.name).to eq('Ruby')
end
end
diff --git a/spec/lib/gitlab/template/issue_template_spec.rb b/spec/lib/gitlab/template/issue_template_spec.rb
index 9213ced7b19..329d1d74970 100644
--- a/spec/lib/gitlab/template/issue_template_spec.rb
+++ b/spec/lib/gitlab/template/issue_template_spec.rb
@@ -37,7 +37,7 @@ describe Gitlab::Template::IssueTemplate do
it 'returns the issue object of a valid file' do
ruby = subject.find('bug', project)
- expect(ruby).to be_a Gitlab::Template::IssueTemplate
+ expect(ruby).to be_a described_class
expect(ruby.name).to eq('bug')
end
end
diff --git a/spec/lib/gitlab/template/merge_request_template_spec.rb b/spec/lib/gitlab/template/merge_request_template_spec.rb
index 77dd3079e22..2b0056d9bab 100644
--- a/spec/lib/gitlab/template/merge_request_template_spec.rb
+++ b/spec/lib/gitlab/template/merge_request_template_spec.rb
@@ -37,7 +37,7 @@ describe Gitlab::Template::MergeRequestTemplate do
it 'returns the merge request object of a valid file' do
ruby = subject.find('bug', project)
- expect(ruby).to be_a Gitlab::Template::MergeRequestTemplate
+ expect(ruby).to be_a described_class
expect(ruby.name).to eq('bug')
end
end
diff --git a/spec/lib/gitlab/usage_data_spec.rb b/spec/lib/gitlab/usage_data_spec.rb
index 7f21288cf88..bf1dfe7f412 100644
--- a/spec/lib/gitlab/usage_data_spec.rb
+++ b/spec/lib/gitlab/usage_data_spec.rb
@@ -6,7 +6,7 @@ describe Gitlab::UsageData do
let!(:board) { create(:board, project: project) }
describe '#data' do
- subject { Gitlab::UsageData.data }
+ subject { described_class.data }
it "gathers usage data" do
expect(subject.keys).to match_array(%i(
@@ -58,7 +58,7 @@ describe Gitlab::UsageData do
end
describe '#license_usage_data' do
- subject { Gitlab::UsageData.license_usage_data }
+ subject { described_class.license_usage_data }
it "gathers license data" do
expect(subject[:uuid]).to eq(current_application_settings.uuid)
diff --git a/spec/lib/gitlab/user_access_spec.rb b/spec/lib/gitlab/user_access_spec.rb
index 611cdbbc865..2b27ff66c09 100644
--- a/spec/lib/gitlab/user_access_spec.rb
+++ b/spec/lib/gitlab/user_access_spec.rb
@@ -87,10 +87,10 @@ describe Gitlab::UserAccess, lib: true do
expect(access.can_push_to_branch?(branch.name)).to be_falsey
end
- it 'returns true if branch does not exist and user has permission to merge' do
+ it 'returns false if branch does not exist' do
project.team << [user, :developer]
- expect(access.can_push_to_branch?(not_existing_branch.name)).to be_truthy
+ expect(access.can_push_to_branch?(not_existing_branch.name)).to be_falsey
end
end
diff --git a/spec/lib/light_url_builder_spec.rb b/spec/lib/light_url_builder_spec.rb
deleted file mode 100644
index 3fe8cf43934..00000000000
--- a/spec/lib/light_url_builder_spec.rb
+++ /dev/null
@@ -1,119 +0,0 @@
-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(:empty_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/merge_requests_spec.rb b/spec/mailers/emails/merge_requests_spec.rb
index e22858d1d8f..2ad572bb5c7 100644
--- a/spec/mailers/emails/merge_requests_spec.rb
+++ b/spec/mailers/emails/merge_requests_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'email_spec'
-describe Notify, "merge request notifications" do
+describe Emails::MergeRequests do
include EmailSpec::Matchers
describe "#resolved_all_discussions_email" do
diff --git a/spec/mailers/emails/profile_spec.rb b/spec/mailers/emails/profile_spec.rb
index 5ca936f28f0..8c1c9bf135f 100644
--- a/spec/mailers/emails/profile_spec.rb
+++ b/spec/mailers/emails/profile_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
require 'email_spec'
-describe Notify do
+describe Emails::Profile do
include EmailSpec::Matchers
include_context 'gitlab email notification'
@@ -15,106 +15,104 @@ describe Notify do
end
end
- describe 'profile notifications' do
- describe 'for new users, the email' do
- let(:example_site_path) { root_path }
- let(:new_user) { create(:user, email: new_user_address, created_by_id: 1) }
- let(:token) { 'kETLwRaayvigPq_x3SNM' }
+ describe 'for new users, the email' do
+ let(:example_site_path) { root_path }
+ let(:new_user) { create(:user, email: new_user_address, created_by_id: 1) }
+ let(:token) { 'kETLwRaayvigPq_x3SNM' }
- subject { Notify.new_user_email(new_user.id, token) }
+ subject { Notify.new_user_email(new_user.id, token) }
- it_behaves_like 'an email sent from GitLab'
- it_behaves_like 'a new user email'
- it_behaves_like 'it should not have Gmail Actions links'
- it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'a new user email'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- it 'contains the password text' do
- is_expected.to have_body_text /Click here to set your password/
- end
+ it 'contains the password text' do
+ is_expected.to have_body_text /Click here to set your password/
+ end
- it 'includes a link for user to set password' do
- params = "reset_password_token=#{token}"
- is_expected.to have_body_text(
- %r{http://#{Gitlab.config.gitlab.host}(:\d+)?/users/password/edit\?#{params}}
- )
- end
+ it 'includes a link for user to set password' do
+ params = "reset_password_token=#{token}"
+ is_expected.to have_body_text(
+ %r{http://#{Gitlab.config.gitlab.host}(:\d+)?/users/password/edit\?#{params}}
+ )
+ end
- it 'explains the reset link expiration' do
- is_expected.to have_body_text(/This link is valid for \d+ (hours?|days?)/)
- is_expected.to have_body_text(new_user_password_url)
- is_expected.to have_body_text(/\?user_email=.*%40.*/)
- end
+ it 'explains the reset link expiration' do
+ is_expected.to have_body_text(/This link is valid for \d+ (hours?|days?)/)
+ is_expected.to have_body_text(new_user_password_url)
+ is_expected.to have_body_text(/\?user_email=.*%40.*/)
end
+ end
- describe 'for users that signed up, the email' do
- let(:example_site_path) { root_path }
- let(:new_user) { create(:user, email: new_user_address, password: "securePassword") }
+ describe 'for users that signed up, the email' do
+ let(:example_site_path) { root_path }
+ let(:new_user) { create(:user, email: new_user_address, password: "securePassword") }
- subject { Notify.new_user_email(new_user.id) }
+ subject { Notify.new_user_email(new_user.id) }
- it_behaves_like 'an email sent from GitLab'
- it_behaves_like 'a new user email'
- it_behaves_like 'it should not have Gmail Actions links'
- it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'a new user email'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- it 'does not contain the new user\'s password' do
- is_expected.not_to have_body_text /password/
- end
+ it 'does not contain the new user\'s password' do
+ is_expected.not_to have_body_text /password/
end
+ end
- describe 'user added ssh key' do
- let(:key) { create(:personal_key) }
+ describe 'user added ssh key' do
+ let(:key) { create(:personal_key) }
- subject { Notify.new_ssh_key_email(key.id) }
+ subject { Notify.new_ssh_key_email(key.id) }
- it_behaves_like 'an email sent from GitLab'
- it_behaves_like 'it should not have Gmail Actions links'
- it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'an email sent from GitLab'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- it 'is sent to the new user' do
- is_expected.to deliver_to key.user.email
- end
+ it 'is sent to the new user' do
+ is_expected.to deliver_to key.user.email
+ end
- it 'has the correct subject' do
- is_expected.to have_subject /^SSH key was added to your account$/i
- end
+ it 'has the correct subject' do
+ is_expected.to have_subject /^SSH key was added to your account$/i
+ end
- it 'contains the new ssh key title' do
- is_expected.to have_body_text /#{key.title}/
- end
+ it 'contains the new ssh key title' do
+ is_expected.to have_body_text /#{key.title}/
+ end
- it 'includes a link to ssh keys page' do
- is_expected.to have_body_text /#{profile_keys_path}/
- end
+ it 'includes a link to ssh keys page' do
+ is_expected.to have_body_text /#{profile_keys_path}/
+ end
- context 'with SSH key that does not exist' do
- it { expect { Notify.new_ssh_key_email('foo') }.not_to raise_error }
- end
+ context 'with SSH key that does not exist' do
+ it { expect { Notify.new_ssh_key_email('foo') }.not_to raise_error }
end
+ end
- describe 'user added email' do
- let(:email) { create(:email) }
+ describe 'user added email' do
+ let(:email) { create(:email) }
- subject { Notify.new_email_email(email.id) }
+ subject { Notify.new_email_email(email.id) }
- it_behaves_like 'it should not have Gmail Actions links'
- it_behaves_like 'a user cannot unsubscribe through footer link'
+ it_behaves_like 'it should not have Gmail Actions links'
+ it_behaves_like 'a user cannot unsubscribe through footer link'
- it 'is sent to the new user' do
- is_expected.to deliver_to email.user.email
- end
+ it 'is sent to the new user' do
+ is_expected.to deliver_to email.user.email
+ end
- it 'has the correct subject' do
- is_expected.to have_subject /^Email was added to your account$/i
- end
+ it 'has the correct subject' do
+ is_expected.to have_subject /^Email was added to your account$/i
+ end
- it 'contains the new email address' do
- is_expected.to have_body_text /#{email.email}/
- end
+ it 'contains the new email address' do
+ is_expected.to have_body_text /#{email.email}/
+ end
- it 'includes a link to emails page' do
- is_expected.to have_body_text /#{profile_emails_path}/
- end
+ it 'includes a link to emails page' do
+ is_expected.to have_body_text /#{profile_emails_path}/
end
end
end
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index e6f0a3b5920..9f12e40d808 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -40,7 +40,7 @@ describe Notify do
let(:issue_with_description) { create(:issue, author: current_user, assignee: assignee, project: project, description: 'My awesome description') }
describe 'that are new' do
- subject { Notify.new_issue_email(issue.assignee_id, issue.id) }
+ subject { described_class.new_issue_email(issue.assignee_id, issue.id) }
it_behaves_like 'an assignee email'
it_behaves_like 'an email starting a new thread with reply-by-email enabled' do
@@ -69,7 +69,7 @@ describe Notify do
end
describe 'that are new with a description' do
- subject { Notify.new_issue_email(issue_with_description.assignee_id, issue_with_description.id) }
+ subject { described_class.new_issue_email(issue_with_description.assignee_id, issue_with_description.id) }
it_behaves_like 'it should show Gmail Actions View Issue link'
@@ -79,7 +79,7 @@ describe Notify do
end
describe 'that have been reassigned' do
- subject { Notify.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id, current_user.id) }
+ subject { described_class.reassigned_issue_email(recipient.id, issue.id, previous_assignee.id, current_user.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -105,7 +105,7 @@ describe Notify do
end
describe 'that have been relabeled' do
- subject { Notify.relabeled_issue_email(recipient.id, issue.id, %w[foo bar baz], current_user.id) }
+ subject { described_class.relabeled_issue_email(recipient.id, issue.id, %w[foo bar baz], current_user.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -132,7 +132,7 @@ describe Notify do
describe 'status changed' do
let(:status) { 'closed' }
- subject { Notify.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) }
+ subject { described_class.issue_status_changed_email(recipient.id, issue.id, status, current_user.id) }
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue }
@@ -158,7 +158,7 @@ describe Notify do
describe 'moved to another project' do
let(:new_issue) { create(:issue) }
- subject { Notify.issue_moved_email(recipient, issue, new_issue, current_user) }
+ subject { described_class.issue_moved_email(recipient, issue, new_issue, current_user) }
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { issue }
@@ -190,7 +190,7 @@ describe Notify do
let(:merge_request_with_description) { create(:merge_request, author: current_user, assignee: assignee, source_project: project, target_project: project, description: 'My awesome description') }
describe 'that are new' do
- subject { Notify.new_merge_request_email(merge_request.assignee_id, merge_request.id) }
+ subject { described_class.new_merge_request_email(merge_request.assignee_id, merge_request.id) }
it_behaves_like 'an assignee email'
it_behaves_like 'an email starting a new thread with reply-by-email enabled' do
@@ -221,7 +221,7 @@ describe Notify do
end
describe 'that are new with a description' do
- subject { Notify.new_merge_request_email(merge_request_with_description.assignee_id, merge_request_with_description.id) }
+ subject { described_class.new_merge_request_email(merge_request_with_description.assignee_id, merge_request_with_description.id) }
it_behaves_like 'it should show Gmail Actions View Merge request link'
it_behaves_like "an unsubscribeable thread"
@@ -232,7 +232,7 @@ describe Notify do
end
describe 'that are reassigned' do
- subject { Notify.reassigned_merge_request_email(recipient.id, merge_request.id, previous_assignee.id, current_user.id) }
+ subject { described_class.reassigned_merge_request_email(recipient.id, merge_request.id, previous_assignee.id, current_user.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -258,7 +258,7 @@ describe Notify do
end
describe 'that have been relabeled' do
- subject { Notify.relabeled_merge_request_email(recipient.id, merge_request.id, %w[foo bar baz], current_user.id) }
+ subject { described_class.relabeled_merge_request_email(recipient.id, merge_request.id, %w[foo bar baz], current_user.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -283,7 +283,7 @@ describe Notify do
describe 'status changed' do
let(:status) { 'reopened' }
- subject { Notify.merge_request_status_email(recipient.id, merge_request.id, status, current_user.id) }
+ subject { described_class.merge_request_status_email(recipient.id, merge_request.id, status, current_user.id) }
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
let(:model) { merge_request }
@@ -308,7 +308,7 @@ describe Notify do
end
describe 'that are merged' do
- subject { Notify.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) }
+ subject { described_class.merged_merge_request_email(recipient.id, merge_request.id, merge_author.id) }
it_behaves_like 'a multiple recipients email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -337,7 +337,7 @@ describe Notify do
describe 'project was moved' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
- subject { Notify.project_was_moved_email(project.id, user.id, "gitlab/gitlab") }
+ subject { described_class.project_was_moved_email(project.id, user.id, "gitlab/gitlab") }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -363,7 +363,7 @@ describe Notify do
project.request_access(user)
project.requesters.find_by(user_id: user.id)
end
- subject { Notify.member_access_requested_email('project', project_member.id) }
+ subject { described_class.member_access_requested_email('project', project_member.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -390,7 +390,7 @@ describe Notify do
project.request_access(user)
project.requesters.find_by(user_id: user.id)
end
- subject { Notify.member_access_requested_email('project', project_member.id) }
+ subject { described_class.member_access_requested_email('project', project_member.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -416,7 +416,7 @@ describe Notify do
project.request_access(user)
project.requesters.find_by(user_id: user.id)
end
- subject { Notify.member_access_denied_email('project', project.id, user.id) }
+ subject { described_class.member_access_denied_email('project', project.id, user.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -434,7 +434,7 @@ describe Notify do
let(:project) { create(:empty_project, :public, :access_requestable, namespace: owner.namespace) }
let(:user) { create(:user) }
let(:project_member) { create(:project_member, project: project, user: user) }
- subject { Notify.member_access_granted_email('project', project_member.id) }
+ subject { described_class.member_access_granted_email('project', project_member.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -465,7 +465,7 @@ describe Notify do
let(:master) { create(:user).tap { |u| project.team << [u, :master] } }
let(:project_member) { invite_to_project(project, inviter: master) }
- subject { Notify.member_invited_email('project', project_member.id, project_member.invite_token) }
+ subject { described_class.member_invited_email('project', project_member.id, project_member.invite_token) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -490,7 +490,7 @@ describe Notify do
invitee
end
- subject { Notify.member_invite_accepted_email('project', project_member.id) }
+ subject { described_class.member_invite_accepted_email('project', project_member.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -514,7 +514,7 @@ describe Notify do
invitee
end
- subject { Notify.member_invite_declined_email('project', project.id, project_member.invite_email, master.id) }
+ subject { described_class.member_invite_declined_email('project', project.id, project_member.invite_email, master.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -574,7 +574,7 @@ describe Notify do
before(:each) { allow(note).to receive(:noteable).and_return(commit) }
- subject { Notify.note_commit_email(recipient.id, note.id) }
+ subject { described_class.note_commit_email(recipient.id, note.id) }
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -596,7 +596,7 @@ describe Notify do
let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") }
before(:each) { allow(note).to receive(:noteable).and_return(merge_request) }
- subject { Notify.note_merge_request_email(recipient.id, note.id) }
+ subject { described_class.note_merge_request_email(recipient.id, note.id) }
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -618,7 +618,7 @@ describe Notify do
let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") }
before(:each) { allow(note).to receive(:noteable).and_return(issue) }
- subject { Notify.note_issue_email(recipient.id, note.id) }
+ subject { described_class.note_issue_email(recipient.id, note.id) }
it_behaves_like 'a note email'
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -680,7 +680,7 @@ describe Notify do
before(:each) { allow(note).to receive(:noteable).and_return(commit) }
- subject { Notify.note_commit_email(recipient.id, note.id) }
+ subject { described_class.note_commit_email(recipient.id, note.id) }
it_behaves_like 'a discussion note email', :discussion_note_on_commit
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -704,7 +704,7 @@ describe Notify do
let(:note_on_merge_request_path) { namespace_project_merge_request_path(project.namespace, project, merge_request, anchor: "note_#{note.id}") }
before(:each) { allow(note).to receive(:noteable).and_return(merge_request) }
- subject { Notify.note_merge_request_email(recipient.id, note.id) }
+ subject { described_class.note_merge_request_email(recipient.id, note.id) }
it_behaves_like 'a discussion note email', :discussion_note_on_merge_request
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -728,7 +728,7 @@ describe Notify do
let(:note_on_issue_path) { namespace_project_issue_path(project.namespace, project, issue, anchor: "note_#{note.id}") }
before(:each) { allow(note).to receive(:noteable).and_return(issue) }
- subject { Notify.note_issue_email(recipient.id, note.id) }
+ subject { described_class.note_issue_email(recipient.id, note.id) }
it_behaves_like 'a discussion note email', :discussion_note_on_issue
it_behaves_like 'an answer to an existing thread with reply-by-email enabled' do
@@ -798,7 +798,7 @@ describe Notify do
let(:commit) { project.commit }
let(:note) { create(:diff_note_on_commit) }
- subject { Notify.note_commit_email(recipient.id, note.id) }
+ subject { described_class.note_commit_email(recipient.id, note.id) }
it_behaves_like 'an email for a note on a diff discussion', :diff_note_on_commit
it_behaves_like 'it should show Gmail Actions View Commit link'
@@ -809,7 +809,7 @@ describe Notify do
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
let(:note) { create(:diff_note_on_merge_request) }
- subject { Notify.note_merge_request_email(recipient.id, note.id) }
+ subject { described_class.note_merge_request_email(recipient.id, note.id) }
it_behaves_like 'an email for a note on a diff discussion', :diff_note_on_merge_request
it_behaves_like 'it should show Gmail Actions View Merge request link'
@@ -826,7 +826,7 @@ describe Notify do
group.request_access(user)
group.requesters.find_by(user_id: user.id)
end
- subject { Notify.member_access_requested_email('group', group_member.id) }
+ subject { described_class.member_access_requested_email('group', group_member.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -847,7 +847,7 @@ describe Notify do
group.request_access(user)
group.requesters.find_by(user_id: user.id)
end
- subject { Notify.member_access_denied_email('group', group.id, user.id) }
+ subject { described_class.member_access_denied_email('group', group.id, user.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -865,7 +865,7 @@ describe Notify do
let(:user) { create(:user) }
let(:group_member) { create(:group_member, group: group, user: user) }
- subject { Notify.member_access_granted_email('group', group_member.id) }
+ subject { described_class.member_access_granted_email('group', group_member.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -896,7 +896,7 @@ describe Notify do
let(:owner) { create(:user).tap { |u| group.add_user(u, Gitlab::Access::OWNER) } }
let(:group_member) { invite_to_group(group, inviter: owner) }
- subject { Notify.member_invited_email('group', group_member.id, group_member.invite_token) }
+ subject { described_class.member_invited_email('group', group_member.id, group_member.invite_token) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -921,7 +921,7 @@ describe Notify do
invitee
end
- subject { Notify.member_invite_accepted_email('group', group_member.id) }
+ subject { described_class.member_invite_accepted_email('group', group_member.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -945,7 +945,7 @@ describe Notify do
invitee
end
- subject { Notify.member_invite_declined_email('group', group.id, group_member.invite_email, owner.id) }
+ subject { described_class.member_invite_declined_email('group', group.id, group_member.invite_email, owner.id) }
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
@@ -994,7 +994,7 @@ describe Notify do
let(:user) { create(:user) }
let(:tree_path) { namespace_project_tree_path(project.namespace, project, "empty-branch") }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/empty-branch', action: :create) }
+ subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/empty-branch', action: :create) }
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
@@ -1020,7 +1020,7 @@ describe Notify do
let(:user) { create(:user) }
let(:tree_path) { namespace_project_tree_path(project.namespace, project, "v1.0") }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/tags/v1.0', action: :create) }
+ subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/tags/v1.0', action: :create) }
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like "a user cannot unsubscribe through footer link"
@@ -1045,7 +1045,7 @@ describe Notify do
let(:example_site_path) { root_path }
let(:user) { create(:user) }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :delete) }
+ subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :delete) }
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
@@ -1067,7 +1067,7 @@ describe Notify do
let(:example_site_path) { root_path }
let(:user) { create(:user) }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/tags/v1.0', action: :delete) }
+ subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/tags/v1.0', action: :delete) }
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
@@ -1096,7 +1096,7 @@ describe Notify do
let(:send_from_committer_email) { false }
let(:diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: project.merge_base_commit(sample_image_commit.id, sample_commit.id).id, head_sha: sample_commit.id) }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, diff_refs: diff_refs, send_from_committer_email: send_from_committer_email) }
+ subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, reverse_compare: false, diff_refs: diff_refs, send_from_committer_email: send_from_committer_email) }
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
@@ -1189,7 +1189,7 @@ describe Notify do
let(:diff_path) { namespace_project_commit_path(project.namespace, project, commits.first) }
let(:diff_refs) { Gitlab::Diff::DiffRefs.new(base_sha: project.merge_base_commit(sample_image_commit.id, sample_commit.id).id, head_sha: sample_commit.id) }
- subject { Notify.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, diff_refs: diff_refs) }
+ subject { described_class.repository_push_email(project.id, author_id: user.id, ref: 'refs/heads/master', action: :push, compare: compare, diff_refs: diff_refs) }
it_behaves_like 'it should show Gmail Actions View Commit link'
it_behaves_like 'a user cannot unsubscribe through footer link'
@@ -1215,7 +1215,7 @@ describe Notify do
describe 'HTML emails setting' do
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
- let(:multipart_mail) { Notify.project_was_moved_email(project.id, user.id, "gitlab/gitlab") }
+ let(:multipart_mail) { described_class.project_was_moved_email(project.id, user.id, "gitlab/gitlab") }
context 'when disabled' do
it 'only sends the text template' do
diff --git a/spec/migrations/schema_spec.rb b/spec/migrations/active_record/schema_spec.rb
index e132529d8d8..e132529d8d8 100644
--- a/spec/migrations/schema_spec.rb
+++ b/spec/migrations/active_record/schema_spec.rb
diff --git a/spec/models/ci/trigger_schedule_spec.rb b/spec/models/ci/trigger_schedule_spec.rb
index 75d21541cee..92447564d7c 100644
--- a/spec/models/ci/trigger_schedule_spec.rb
+++ b/spec/models/ci/trigger_schedule_spec.rb
@@ -73,4 +73,36 @@ describe Ci::TriggerSchedule, models: true do
end
end
end
+
+ describe '#real_next_run' do
+ subject do
+ Ci::TriggerSchedule.last.real_next_run(worker_cron: worker_cron,
+ worker_time_zone: worker_time_zone)
+ end
+
+ context 'when GitLab time_zone is UTC' do
+ before do
+ allow(Time).to receive(:zone)
+ .and_return(ActiveSupport::TimeZone[worker_time_zone])
+ end
+
+ let(:worker_time_zone) { 'UTC' }
+
+ context 'when cron_timezone is Eastern Time (US & Canada)' do
+ before do
+ create(:ci_trigger_schedule, :nightly,
+ cron_timezone: 'Eastern Time (US & Canada)')
+ end
+
+ let(:worker_cron) { '0 1 2 3 *' }
+
+ it 'returns the next time worker executes' do
+ expect(subject.min).to eq(0)
+ expect(subject.hour).to eq(1)
+ expect(subject.day).to eq(2)
+ expect(subject.month).to eq(3)
+ end
+ end
+ end
+ end
end
diff --git a/spec/models/concerns/awardable_spec.rb b/spec/models/concerns/awardable_spec.rb
index de791abdf3d..63ad3a3630b 100644
--- a/spec/models/concerns/awardable_spec.rb
+++ b/spec/models/concerns/awardable_spec.rb
@@ -1,10 +1,12 @@
require 'spec_helper'
-describe Issue, "Awardable" do
+describe Awardable do
let!(:issue) { create(:issue) }
let!(:award_emoji) { create(:award_emoji, :downvote, awardable: issue) }
describe "Associations" do
+ subject { build(:issue) }
+
it { is_expected.to have_many(:award_emoji).dependent(:destroy) }
end
diff --git a/spec/models/concerns/cache_markdown_field_spec.rb b/spec/models/concerns/cache_markdown_field_spec.rb
index 4edafbc4e32..40bbb10eaac 100644
--- a/spec/models/concerns/cache_markdown_field_spec.rb
+++ b/spec/models/concerns/cache_markdown_field_spec.rb
@@ -170,6 +170,12 @@ describe CacheMarkdownField do
is_expected.to be_truthy
end
+
+ it 'returns false if the markdown field is set but the html is not' do
+ thing.foo_html = nil
+
+ is_expected.to be_falsy
+ end
end
describe '#refresh_markdown_cache!' do
diff --git a/spec/models/concerns/discussion_on_diff_spec.rb b/spec/models/concerns/discussion_on_diff_spec.rb
index 0002a00770f..8571e85627c 100644
--- a/spec/models/concerns/discussion_on_diff_spec.rb
+++ b/spec/models/concerns/discussion_on_diff_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe DiffDiscussion, DiscussionOnDiff, model: true do
+describe DiscussionOnDiff, model: true do
subject { create(:diff_note_on_merge_request).to_discussion }
describe "#truncated_diff_lines" do
@@ -8,9 +8,9 @@ describe DiffDiscussion, DiscussionOnDiff, model: true do
context "when diff is greater than allowed number of truncated diff lines " do
it "returns fewer lines" do
- expect(subject.diff_lines.count).to be > described_class::NUMBER_OF_TRUNCATED_DIFF_LINES
+ expect(subject.diff_lines.count).to be > DiffDiscussion::NUMBER_OF_TRUNCATED_DIFF_LINES
- expect(truncated_lines.count).to be <= described_class::NUMBER_OF_TRUNCATED_DIFF_LINES
+ expect(truncated_lines.count).to be <= DiffDiscussion::NUMBER_OF_TRUNCATED_DIFF_LINES
end
end
diff --git a/spec/models/concerns/issuable_spec.rb b/spec/models/concerns/issuable_spec.rb
index 4522206fab1..3ecba2e9687 100644
--- a/spec/models/concerns/issuable_spec.rb
+++ b/spec/models/concerns/issuable_spec.rb
@@ -1,10 +1,13 @@
require 'spec_helper'
-describe Issue, "Issuable" do
+describe Issuable do
+ let(:issuable_class) { Issue }
let(:issue) { create(:issue) }
let(:user) { create(:user) }
describe "Associations" do
+ subject { build(:issue) }
+
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:author) }
it { is_expected.to belong_to(:assignee) }
@@ -23,10 +26,14 @@ describe Issue, "Issuable" do
end
describe 'Included modules' do
+ let(:described_class) { issuable_class }
+
it { is_expected.to include_module(Awardable) }
end
describe "Validation" do
+ subject { build(:issue) }
+
before do
allow(subject).to receive(:set_iid).and_return(false)
end
@@ -39,9 +46,11 @@ describe Issue, "Issuable" do
end
describe "Scope" do
- it { expect(described_class).to respond_to(:opened) }
- it { expect(described_class).to respond_to(:closed) }
- it { expect(described_class).to respond_to(:assigned) }
+ subject { build(:issue) }
+
+ it { expect(issuable_class).to respond_to(:opened) }
+ it { expect(issuable_class).to respond_to(:closed) }
+ it { expect(issuable_class).to respond_to(:assigned) }
end
describe 'author_name' do
@@ -115,16 +124,16 @@ describe Issue, "Issuable" do
let!(:searchable_issue) { create(:issue, title: "Searchable issue") }
it 'returns notes with a matching title' do
- expect(described_class.search(searchable_issue.title)).
+ expect(issuable_class.search(searchable_issue.title)).
to eq([searchable_issue])
end
it 'returns notes with a partially matching title' do
- expect(described_class.search('able')).to eq([searchable_issue])
+ expect(issuable_class.search('able')).to eq([searchable_issue])
end
it 'returns notes with a matching title regardless of the casing' do
- expect(described_class.search(searchable_issue.title.upcase)).
+ expect(issuable_class.search(searchable_issue.title.upcase)).
to eq([searchable_issue])
end
end
@@ -135,31 +144,31 @@ describe Issue, "Issuable" do
end
it 'returns notes with a matching title' do
- expect(described_class.full_search(searchable_issue.title)).
+ expect(issuable_class.full_search(searchable_issue.title)).
to eq([searchable_issue])
end
it 'returns notes with a partially matching title' do
- expect(described_class.full_search('able')).to eq([searchable_issue])
+ expect(issuable_class.full_search('able')).to eq([searchable_issue])
end
it 'returns notes with a matching title regardless of the casing' do
- expect(described_class.full_search(searchable_issue.title.upcase)).
+ expect(issuable_class.full_search(searchable_issue.title.upcase)).
to eq([searchable_issue])
end
it 'returns notes with a matching description' do
- expect(described_class.full_search(searchable_issue.description)).
+ expect(issuable_class.full_search(searchable_issue.description)).
to eq([searchable_issue])
end
it 'returns notes with a partially matching description' do
- expect(described_class.full_search(searchable_issue.description)).
+ expect(issuable_class.full_search(searchable_issue.description)).
to eq([searchable_issue])
end
it 'returns notes with a matching description regardless of the casing' do
- expect(described_class.full_search(searchable_issue.description.upcase)).
+ expect(issuable_class.full_search(searchable_issue.description.upcase)).
to eq([searchable_issue])
end
end
diff --git a/spec/models/concerns/noteable_spec.rb b/spec/models/concerns/noteable_spec.rb
index 92cc8859a8c..bdae742ff1d 100644
--- a/spec/models/concerns/noteable_spec.rb
+++ b/spec/models/concerns/noteable_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe MergeRequest, Noteable, model: true do
+describe Noteable, model: true do
let!(:active_diff_note1) { create(:diff_note_on_merge_request) }
let(:project) { active_diff_note1.project }
subject { active_diff_note1.noteable }
diff --git a/spec/models/concerns/relative_positioning_spec.rb b/spec/models/concerns/relative_positioning_spec.rb
index 255b584a85e..494e6f1b6f6 100644
--- a/spec/models/concerns/relative_positioning_spec.rb
+++ b/spec/models/concerns/relative_positioning_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Issue, 'RelativePositioning' do
+describe RelativePositioning do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:issue1) { create(:issue, project: project) }
diff --git a/spec/models/concerns/spammable_spec.rb b/spec/models/concerns/spammable_spec.rb
index fd3b8307571..e698207166c 100644
--- a/spec/models/concerns/spammable_spec.rb
+++ b/spec/models/concerns/spammable_spec.rb
@@ -1,9 +1,11 @@
require 'spec_helper'
-describe Issue, 'Spammable' do
+describe Spammable do
let(:issue) { create(:issue, description: 'Test Desc.') }
describe 'Associations' do
+ subject { build(:issue) }
+
it { is_expected.to have_one(:user_agent_detail).dependent(:destroy) }
end
diff --git a/spec/models/concerns/strip_attribute_spec.rb b/spec/models/concerns/strip_attribute_spec.rb
index c3af7a0960f..8c945686b66 100644
--- a/spec/models/concerns/strip_attribute_spec.rb
+++ b/spec/models/concerns/strip_attribute_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Milestone, "StripAttribute" do
+describe StripAttribute do
let(:milestone) { create(:milestone) }
describe ".strip_attributes" do
diff --git a/spec/models/group_spec.rb b/spec/models/group_spec.rb
index 8ffde6f7fbb..a11805926cc 100644
--- a/spec/models/group_spec.rb
+++ b/spec/models/group_spec.rb
@@ -57,6 +57,32 @@ describe Group, models: true do
it { is_expected.not_to validate_presence_of :owner }
it { is_expected.to validate_presence_of :two_factor_grace_period }
it { is_expected.to validate_numericality_of(:two_factor_grace_period).is_greater_than_or_equal_to(0) }
+
+ describe 'path validation' do
+ it 'rejects paths reserved on the root namespace when the group has no parent' do
+ group = build(:group, path: 'api')
+
+ expect(group).not_to be_valid
+ end
+
+ it 'allows root paths when the group has a parent' do
+ group = build(:group, path: 'api', parent: create(:group))
+
+ expect(group).to be_valid
+ end
+
+ it 'rejects any wildcard paths when not a top level group' do
+ group = build(:group, path: 'tree', parent: create(:group))
+
+ expect(group).not_to be_valid
+ end
+
+ it 'rejects reserved group paths' do
+ group = build(:group, path: 'activity', parent: create(:group))
+
+ expect(group).not_to be_valid
+ end
+ end
end
describe '.visible_to_user' do
diff --git a/spec/models/member_spec.rb b/spec/models/member_spec.rb
index b0f3657d3b5..ccc3deac199 100644
--- a/spec/models/member_spec.rb
+++ b/spec/models/member_spec.rb
@@ -390,13 +390,15 @@ describe Member, models: true do
%w[project group].each do |source_type|
context "when source is a #{source_type}" do
let!(:source) { create(source_type, :public, :access_requestable) }
- let!(:user) { create(:user) }
let!(:admin) { create(:admin) }
+ let(:user1) { create(:user) }
+ let(:user2) { create(:user) }
it 'returns a <Source>Member objects' do
- members = described_class.add_users(source, [user], :master)
+ members = described_class.add_users(source, [user1, user2], :master)
expect(members).to be_a Array
+ expect(members.size).to eq(2)
expect(members.first).to be_a "#{source_type.classify}Member".constantize
expect(members.first).to be_persisted
end
diff --git a/spec/models/namespace_spec.rb b/spec/models/namespace_spec.rb
index e406d0a16bd..8624616316c 100644
--- a/spec/models/namespace_spec.rb
+++ b/spec/models/namespace_spec.rb
@@ -34,6 +34,13 @@ describe Namespace, models: true do
let(:group) { build(:group, :nested, path: 'tree') }
it { expect(group).not_to be_valid }
+
+ it 'rejects nested paths' do
+ parent = create(:group, :nested, path: 'environments')
+ namespace = build(:project, path: 'folders', namespace: parent)
+
+ expect(namespace).not_to be_valid
+ end
end
context 'top-level group' do
@@ -47,6 +54,7 @@ describe Namespace, models: true do
describe "Respond to" do
it { is_expected.to respond_to(:human_name) }
it { is_expected.to respond_to(:to_param) }
+ it { is_expected.to respond_to(:has_parent?) }
end
describe '#to_param' do
diff --git a/spec/models/project_services/pipeline_email_service_spec.rb b/spec/models/project_services/pipelines_email_service_spec.rb
index 03932895b0e..03932895b0e 100644
--- a/spec/models/project_services/pipeline_email_service_spec.rb
+++ b/spec/models/project_services/pipelines_email_service_spec.rb
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index 92d420337f9..36ce3070a6e 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -253,6 +253,34 @@ describe Project, models: true do
expect(new_project.errors.full_messages.first).to eq('The project is still being deleted. Please try again later.')
end
end
+
+ describe 'path validation' do
+ it 'allows paths reserved on the root namespace' do
+ project = build(:project, path: 'api')
+
+ expect(project).to be_valid
+ end
+
+ it 'rejects paths reserved on another level' do
+ project = build(:project, path: 'tree')
+
+ expect(project).not_to be_valid
+ end
+
+ it 'rejects nested paths' do
+ parent = create(:group, :nested, path: 'environments')
+ project = build(:project, path: 'folders', namespace: parent)
+
+ expect(project).not_to be_valid
+ end
+
+ it 'allows a reserved group name' do
+ parent = create(:group)
+ project = build(:project, path: 'avatar', namespace: parent)
+
+ expect(project).to be_valid
+ end
+ end
end
describe 'default_scope' do
@@ -781,17 +809,14 @@ describe Project, models: true do
let(:project) { create(:empty_project) }
- context 'When avatar file is uploaded' do
- before do
- project.update_columns(avatar: 'uploads/avatar.png')
- allow(project.avatar).to receive(:present?) { true }
- end
+ context 'when avatar file is uploaded' do
+ let(:project) { create(:empty_project, :with_avatar) }
- let(:avatar_path) do
- "/uploads/project/avatar/#{project.id}/uploads/avatar.png"
- end
+ it 'creates a correct avatar path' do
+ avatar_path = "/uploads/project/avatar/#{project.id}/dk.png"
- it { should eq "http://#{Gitlab.config.gitlab.host}#{avatar_path}" }
+ expect(project.avatar_url).to eq("http://#{Gitlab.config.gitlab.host}#{avatar_path}")
+ end
end
context 'When avatar file in git' do
@@ -1881,4 +1906,23 @@ describe Project, models: true do
expect(project.pipeline_status).to be_loaded
end
end
+
+ describe '#append_or_update_attribute' do
+ let(:project) { create(:project) }
+
+ it 'shows full error updating an invalid MR' do
+ error_message = 'Failed to replace merge_requests because one or more of the new records could not be saved.'\
+ ' Validate fork Source project is not a fork of the target project'
+
+ expect { project.append_or_update_attribute(:merge_requests, [create(:merge_request)]) }.
+ to raise_error(ActiveRecord::RecordNotSaved, error_message)
+ end
+
+ it 'updates the project succesfully' do
+ merge_request = create(:merge_request, target_project: project, source_project: project)
+
+ expect { project.append_or_update_attribute(:merge_requests, [merge_request]) }.
+ not_to raise_error
+ end
+ end
end
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index 98d0641443e..5216764a82d 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -1379,12 +1379,22 @@ describe Repository, models: true do
describe '#branch_count' do
it 'returns the number of branches' do
expect(repository.branch_count).to be_an(Integer)
+
+ # NOTE: Until rugged goes away, make sure rugged and gitaly are in sync
+ rugged_count = repository.raw_repository.rugged.branches.count
+
+ expect(repository.branch_count).to eq(rugged_count)
end
end
describe '#tag_count' do
it 'returns the number of tags' do
expect(repository.tag_count).to be_an(Integer)
+
+ # NOTE: Until rugged goes away, make sure rugged and gitaly are in sync
+ rugged_count = repository.raw_repository.rugged.tags.count
+
+ expect(repository.tag_count).to eq(rugged_count)
end
end
@@ -1849,17 +1859,15 @@ describe Repository, models: true do
end
end
- # TODO: Uncomment when feature is reenabled
- # describe '#is_ancestor?' do
- # context 'Gitaly is_ancestor feature enabled' do
- # it 'asks Gitaly server if it\'s an ancestor' do
- # commit = repository.commit
- # allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:is_ancestor).and_return(true)
- # expect(Gitlab::GitalyClient::Commit).to receive(:is_ancestor).
- # with(repository.raw_repository, commit.id, commit.id).and_return(true)
- #
- # expect(repository.is_ancestor?(commit.id, commit.id)).to be true
- # end
- # end
- # end
+ describe '#is_ancestor?' do
+ context 'Gitaly is_ancestor feature enabled' do
+ it "asks Gitaly server if it's an ancestor" do
+ commit = repository.commit
+ expect(repository.raw_repository).to receive(:is_ancestor?).and_call_original
+ allow(Gitlab::GitalyClient).to receive(:feature_enabled?).with(:is_ancestor).and_return(true)
+
+ expect(repository.is_ancestor?(commit.id, commit.id)).to be true
+ end
+ end
+ end
end
diff --git a/spec/models/snippet_blob_spec.rb b/spec/models/snippet_blob_spec.rb
new file mode 100644
index 00000000000..120b390586b
--- /dev/null
+++ b/spec/models/snippet_blob_spec.rb
@@ -0,0 +1,47 @@
+require 'spec_helper'
+
+describe SnippetBlob, models: true do
+ let(:snippet) { create(:snippet) }
+
+ subject { described_class.new(snippet) }
+
+ describe '#id' do
+ it 'returns the snippet ID' do
+ expect(subject.id).to eq(snippet.id)
+ end
+ end
+
+ describe '#name' do
+ it 'returns the snippet file name' do
+ expect(subject.name).to eq(snippet.file_name)
+ end
+ end
+
+ describe '#size' do
+ it 'returns the data size' do
+ expect(subject.size).to eq(subject.data.bytesize)
+ end
+ end
+
+ describe '#data' do
+ it 'returns the snippet content' do
+ expect(subject.data).to eq(snippet.content)
+ end
+ end
+
+ describe '#rendered_markup' do
+ context 'when the content is GFM' do
+ let(:snippet) { create(:snippet, file_name: 'file.md') }
+
+ it 'returns the rendered GFM' do
+ expect(subject.rendered_markup).to eq(snippet.content_html)
+ end
+ end
+
+ context 'when the content is not GFM' do
+ it 'returns nil' do
+ expect(subject.rendered_markup).to be_nil
+ end
+ end
+ end
+end
diff --git a/spec/models/snippet_spec.rb b/spec/models/snippet_spec.rb
index 8095d01b69e..75b1fc7e216 100644
--- a/spec/models/snippet_spec.rb
+++ b/spec/models/snippet_spec.rb
@@ -5,7 +5,6 @@ describe Snippet, models: true do
subject { described_class }
it { is_expected.to include_module(Gitlab::VisibilityLevel) }
- it { is_expected.to include_module(Linguist::BlobHelper) }
it { is_expected.to include_module(Participable) }
it { is_expected.to include_module(Referable) }
it { is_expected.to include_module(Sortable) }
@@ -241,4 +240,16 @@ describe Snippet, models: true do
end
end
end
+
+ describe '#blob' do
+ let(:snippet) { create(:snippet) }
+
+ it 'returns a blob representing the snippet data' do
+ blob = snippet.blob
+
+ expect(blob).to be_a(Blob)
+ expect(blob.path).to eq(snippet.file_name)
+ expect(blob.data).to eq(snippet.content)
+ end
+ end
end
diff --git a/spec/models/todo_spec.rb b/spec/models/todo_spec.rb
index 581305ad39f..3f80e1ac534 100644
--- a/spec/models/todo_spec.rb
+++ b/spec/models/todo_spec.rb
@@ -125,4 +125,50 @@ describe Todo, models: true do
expect(subject.target_reference).to eq issue.to_reference(full: true)
end
end
+
+ describe '#self_added?' do
+ let(:user_1) { build(:user) }
+
+ before do
+ subject.user = user_1
+ end
+
+ it 'is true when the user is the author' do
+ subject.author = user_1
+
+ expect(subject).to be_self_added
+ end
+
+ it 'is false when the user is not the author' do
+ subject.author = build(:user)
+
+ expect(subject).not_to be_self_added
+ end
+ end
+
+ describe '#self_assigned?' do
+ let(:user_1) { build(:user) }
+
+ before do
+ subject.user = user_1
+ subject.author = user_1
+ subject.action = Todo::ASSIGNED
+ end
+
+ it 'is true when todo is ASSIGNED and self_added' do
+ expect(subject).to be_self_assigned
+ end
+
+ it 'is false when the todo is not ASSIGNED' do
+ subject.action = Todo::MENTIONED
+
+ expect(subject).not_to be_self_assigned
+ end
+
+ it 'is false when todo is not self_added' do
+ subject.author = build(:user)
+
+ expect(subject).not_to be_self_assigned
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 0bcebc27598..1c2df4c9d97 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -97,6 +97,18 @@ describe User, models: true do
expect(user.errors.values).to eq [['dashboard is a reserved name']]
end
+ it 'allows child names' do
+ user = build(:user, username: 'avatar')
+
+ expect(user).to be_valid
+ end
+
+ it 'allows wildcard names' do
+ user = build(:user, username: 'blob')
+
+ expect(user).to be_valid
+ end
+
it 'validates uniqueness' do
expect(subject).to validate_uniqueness_of(:username).case_insensitive
end
diff --git a/spec/policies/issue_policy_spec.rb b/spec/policies/issue_policy_spec.rb
index 2905d5b26a5..9a870b7fda1 100644
--- a/spec/policies/issue_policy_spec.rb
+++ b/spec/policies/issue_policy_spec.rb
@@ -1,118 +1,192 @@
require 'spec_helper'
describe IssuePolicy, models: true do
- let(:user) { create(:user) }
-
- describe '#rules' do
- context 'using a regular issue' do
- let(:project) { create(:empty_project, :public) }
- let(:issue) { create(:issue, project: project) }
- let(:policies) { described_class.abilities(user, issue).to_set }
-
- context 'with a regular user' do
- it 'includes the read_issue permission' do
- expect(policies).to include(:read_issue)
- end
-
- it 'does not include the admin_issue permission' do
- expect(policies).not_to include(:admin_issue)
- end
-
- it 'does not include the update_issue permission' do
- expect(policies).not_to include(:update_issue)
- end
- end
+ let(:guest) { create(:user) }
+ let(:author) { create(:user) }
+ let(:assignee) { create(:user) }
+ let(:reporter) { create(:user) }
+ let(:group) { create(:group, :public) }
+ let(:reporter_from_group_link) { create(:user) }
+
+ def permissions(user, issue)
+ described_class.abilities(user, issue).to_set
+ end
+
+ context 'a private project' do
+ let(:non_member) { create(:user) }
+ let(:project) { create(:empty_project, :private) }
+ let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
+ let(:issue_no_assignee) { create(:issue, project: project) }
+
+ before do
+ project.team << [guest, :guest]
+ project.team << [author, :guest]
+ project.team << [assignee, :guest]
+ project.team << [reporter, :reporter]
+
+ group.add_reporter(reporter_from_group_link)
+
+ create(:project_group_link, group: group, project: project)
+ end
+
+ it 'does not allow non-members to read issues' do
+ expect(permissions(non_member, issue)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(non_member, issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ end
+
+ it 'allows guests to read issues' do
+ expect(permissions(guest, issue)).to include(:read_issue)
+ expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
+
+ expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
+ expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ end
+
+ it 'allows reporters to read, update, and admin issues' do
+ expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ end
+
+ it 'allows reporters from group links to read, update, and admin issues' do
+ expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ end
+
+ it 'allows issue authors to read and update their issues' do
+ expect(permissions(author, issue)).to include(:read_issue, :update_issue)
+ expect(permissions(author, issue)).not_to include(:admin_issue)
+
+ expect(permissions(author, issue_no_assignee)).to include(:read_issue)
+ expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ end
+
+ it 'allows issue assignees to read and update their issues' do
+ expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
+ expect(permissions(assignee, issue)).not_to include(:admin_issue)
+
+ expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
+ expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ end
- context 'with a user that is a project reporter' do
- before do
- project.team << [user, :reporter]
- end
+ context 'with confidential issues' do
+ let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
+ let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
- it 'includes the read_issue permission' do
- expect(policies).to include(:read_issue)
- end
+ it 'does not allow non-members to read confidential issues' do
+ expect(permissions(non_member, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(non_member, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ end
+
+ it 'does not allow guests to read confidential issues' do
+ expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ end
- it 'includes the admin_issue permission' do
- expect(policies).to include(:admin_issue)
- end
+ it 'allows reporters to read, update, and admin confidential issues' do
+ expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ end
- it 'includes the update_issue permission' do
- expect(policies).to include(:update_issue)
- end
+ it 'allows reporters from group links to read, update, and admin confidential issues' do
+ expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
end
- context 'with a user that is a project guest' do
- before do
- project.team << [user, :guest]
- end
+ it 'allows issue authors to read and update their confidential issues' do
+ expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
+ expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
- it 'includes the read_issue permission' do
- expect(policies).to include(:read_issue)
- end
+ expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ end
- it 'does not include the admin_issue permission' do
- expect(policies).not_to include(:admin_issue)
- end
+ it 'allows issue assignees to read and update their confidential issues' do
+ expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
+ expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
- it 'does not include the update_issue permission' do
- expect(policies).not_to include(:update_issue)
- end
+ expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
end
+ end
- context 'using a confidential issue' do
- let(:issue) { create(:issue, :confidential) }
+ context 'a public project' do
+ let(:project) { create(:empty_project, :public) }
+ let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
+ let(:issue_no_assignee) { create(:issue, project: project) }
- context 'with a regular user' do
- let(:policies) { described_class.abilities(user, issue).to_set }
+ before do
+ project.team << [guest, :guest]
+ project.team << [reporter, :reporter]
- it 'does not include the read_issue permission' do
- expect(policies).not_to include(:read_issue)
- end
+ group.add_reporter(reporter_from_group_link)
- it 'does not include the admin_issue permission' do
- expect(policies).not_to include(:admin_issue)
- end
+ create(:project_group_link, group: group, project: project)
+ end
- it 'does not include the update_issue permission' do
- expect(policies).not_to include(:update_issue)
- end
- end
+ it 'allows guests to read issues' do
+ expect(permissions(guest, issue)).to include(:read_issue)
+ expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
+
+ expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
+ expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ end
+
+ it 'allows reporters to read, update, and admin issues' do
+ expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ end
+
+ it 'allows reporters from group links to read, update, and admin issues' do
+ expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ end
- context 'with a user that is a project member' do
- let(:policies) { described_class.abilities(user, issue).to_set }
+ it 'allows issue authors to read and update their issues' do
+ expect(permissions(author, issue)).to include(:read_issue, :update_issue)
+ expect(permissions(author, issue)).not_to include(:admin_issue)
- before do
- issue.project.team << [user, :reporter]
- end
+ expect(permissions(author, issue_no_assignee)).to include(:read_issue)
+ expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ end
+
+ it 'allows issue assignees to read and update their issues' do
+ expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
+ expect(permissions(assignee, issue)).not_to include(:admin_issue)
- it 'includes the read_issue permission' do
- expect(policies).to include(:read_issue)
- end
+ expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
+ expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
+ end
- it 'includes the admin_issue permission' do
- expect(policies).to include(:admin_issue)
- end
+ context 'with confidential issues' do
+ let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
+ let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
- it 'includes the update_issue permission' do
- expect(policies).to include(:update_issue)
- end
+ it 'does not allow guests to read confidential issues' do
+ expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
- context 'without a user' do
- let(:policies) { described_class.abilities(nil, issue).to_set }
+ it 'allows reporters to read, update, and admin confidential issues' do
+ expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ end
+
+ it 'allows reporter from group links to read, update, and admin confidential issues' do
+ expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
+ expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
+ end
- it 'does not include the read_issue permission' do
- expect(policies).not_to include(:read_issue)
- end
+ it 'allows issue authors to read and update their confidential issues' do
+ expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
+ expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
+
+ expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
+ end
- it 'does not include the admin_issue permission' do
- expect(policies).not_to include(:admin_issue)
- end
+ it 'allows issue assignees to read and update their confidential issues' do
+ expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
+ expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
- it 'does not include the update_issue permission' do
- expect(policies).not_to include(:update_issue)
- end
+ expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
end
end
end
diff --git a/spec/policies/issues_policy_spec.rb b/spec/policies/issues_policy_spec.rb
deleted file mode 100644
index 2b7b6cad654..00000000000
--- a/spec/policies/issues_policy_spec.rb
+++ /dev/null
@@ -1,193 +0,0 @@
-require 'spec_helper'
-
-describe IssuePolicy, models: true do
- let(:guest) { create(:user) }
- let(:author) { create(:user) }
- let(:assignee) { create(:user) }
- let(:reporter) { create(:user) }
- let(:group) { create(:group, :public) }
- let(:reporter_from_group_link) { create(:user) }
-
- def permissions(user, issue)
- IssuePolicy.abilities(user, issue).to_set
- end
-
- context 'a private project' do
- let(:non_member) { create(:user) }
- let(:project) { create(:empty_project, :private) }
- let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
- let(:issue_no_assignee) { create(:issue, project: project) }
-
- before do
- project.team << [guest, :guest]
- project.team << [author, :guest]
- project.team << [assignee, :guest]
- project.team << [reporter, :reporter]
-
- group.add_reporter(reporter_from_group_link)
-
- create(:project_group_link, group: group, project: project)
- end
-
- it 'does not allow non-members to read issues' do
- expect(permissions(non_member, issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(non_member, issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows guests to read issues' do
- expect(permissions(guest, issue)).to include(:read_issue)
- expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
-
- expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
- expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
- end
-
- it 'allows reporters to read, update, and admin issues' do
- expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows reporters from group links to read, update, and admin issues' do
- expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows issue authors to read and update their issues' do
- expect(permissions(author, issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, issue)).not_to include(:admin_issue)
-
- expect(permissions(author, issue_no_assignee)).to include(:read_issue)
- expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
- end
-
- it 'allows issue assignees to read and update their issues' do
- expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, issue)).not_to include(:admin_issue)
-
- expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
- expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
- end
-
- context 'with confidential issues' do
- let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
- let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
-
- it 'does not allow non-members to read confidential issues' do
- expect(permissions(non_member, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(non_member, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'does not allow guests to read confidential issues' do
- expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows reporters to read, update, and admin confidential issues' do
- expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows reporters from group links to read, update, and admin confidential issues' do
- expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows issue authors to read and update their confidential issues' do
- expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
-
- expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows issue assignees to read and update their confidential issues' do
- expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
-
- expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
- end
- end
-
- context 'a public project' do
- let(:project) { create(:empty_project, :public) }
- let(:issue) { create(:issue, project: project, assignee: assignee, author: author) }
- let(:issue_no_assignee) { create(:issue, project: project) }
-
- before do
- project.team << [guest, :guest]
- project.team << [reporter, :reporter]
-
- group.add_reporter(reporter_from_group_link)
-
- create(:project_group_link, group: group, project: project)
- end
-
- it 'allows guests to read issues' do
- expect(permissions(guest, issue)).to include(:read_issue)
- expect(permissions(guest, issue)).not_to include(:update_issue, :admin_issue)
-
- expect(permissions(guest, issue_no_assignee)).to include(:read_issue)
- expect(permissions(guest, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
- end
-
- it 'allows reporters to read, update, and admin issues' do
- expect(permissions(reporter, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows reporters from group links to read, update, and admin issues' do
- expect(permissions(reporter_from_group_link, issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows issue authors to read and update their issues' do
- expect(permissions(author, issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, issue)).not_to include(:admin_issue)
-
- expect(permissions(author, issue_no_assignee)).to include(:read_issue)
- expect(permissions(author, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
- end
-
- it 'allows issue assignees to read and update their issues' do
- expect(permissions(assignee, issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, issue)).not_to include(:admin_issue)
-
- expect(permissions(assignee, issue_no_assignee)).to include(:read_issue)
- expect(permissions(assignee, issue_no_assignee)).not_to include(:update_issue, :admin_issue)
- end
-
- context 'with confidential issues' do
- let(:confidential_issue) { create(:issue, :confidential, project: project, assignee: assignee, author: author) }
- let(:confidential_issue_no_assignee) { create(:issue, :confidential, project: project) }
-
- it 'does not allow guests to read confidential issues' do
- expect(permissions(guest, confidential_issue)).not_to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(guest, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows reporters to read, update, and admin confidential issues' do
- expect(permissions(reporter, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows reporter from group links to read, update, and admin confidential issues' do
- expect(permissions(reporter_from_group_link, confidential_issue)).to include(:read_issue, :update_issue, :admin_issue)
- expect(permissions(reporter_from_group_link, confidential_issue_no_assignee)).to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows issue authors to read and update their confidential issues' do
- expect(permissions(author, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(author, confidential_issue)).not_to include(:admin_issue)
-
- expect(permissions(author, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
-
- it 'allows issue assignees to read and update their confidential issues' do
- expect(permissions(assignee, confidential_issue)).to include(:read_issue, :update_issue)
- expect(permissions(assignee, confidential_issue)).not_to include(:admin_issue)
-
- expect(permissions(assignee, confidential_issue_no_assignee)).not_to include(:read_issue, :update_issue, :admin_issue)
- end
- end
- end
-end
diff --git a/spec/requests/api/doorkeeper_access_spec.rb b/spec/requests/api/doorkeeper_access_spec.rb
index b5897b2e346..868fef65c1c 100644
--- a/spec/requests/api/doorkeeper_access_spec.rb
+++ b/spec/requests/api/doorkeeper_access_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::API do
+describe 'doorkeeper access' do
let!(:user) { create(:user) }
let!(:application) { Doorkeeper::Application.create!(name: "MyApp", redirect_uri: "https://app.com", owner: user) }
let!(:token) { Doorkeeper::AccessToken.create! application_id: application.id, resource_owner_id: user.id, scopes: "api" }
diff --git a/spec/requests/api/api_internal_helpers_spec.rb b/spec/requests/api/helpers/internal_helpers_spec.rb
index f5265ea60ff..db716b340f1 100644
--- a/spec/requests/api/api_internal_helpers_spec.rb
+++ b/spec/requests/api/helpers/internal_helpers_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe ::API::Helpers::InternalHelpers do
- include ::API::Helpers::InternalHelpers
+ include described_class
describe '.clean_project_path' do
project = 'namespace/project'
diff --git a/spec/requests/api/helpers_spec.rb b/spec/requests/api/helpers_spec.rb
index 06c8eb1d0b7..ed392acc607 100644
--- a/spec/requests/api/helpers_spec.rb
+++ b/spec/requests/api/helpers_spec.rb
@@ -2,7 +2,7 @@ require 'spec_helper'
describe API::Helpers do
include API::APIGuard::HelperMethods
- include API::Helpers
+ include described_class
include SentryHelper
let(:user) { create(:user) }
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index c4bff1647b5..16e5efb2f5b 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -434,6 +434,19 @@ describe API::MergeRequests do
expect(json_response['title']).to eq('Test merge_request')
end
+ it 'returns 422 when target project has disabled merge requests' do
+ project.project_feature.update(merge_requests_access_level: 0)
+
+ post api("/projects/#{fork_project.id}/merge_requests", user2),
+ title: 'Test',
+ target_branch: 'master',
+ source_branch: 'markdown',
+ author: user2,
+ target_project_id: project.id
+
+ expect(response).to have_http_status(422)
+ end
+
it "returns 400 when source_branch is missing" do
post api("/projects/#{fork_project.id}/merge_requests", user2),
title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id
diff --git a/spec/requests/api/oauth_tokens_spec.rb b/spec/requests/api/oauth_tokens_spec.rb
index 819df105960..0d56e1f732e 100644
--- a/spec/requests/api/oauth_tokens_spec.rb
+++ b/spec/requests/api/oauth_tokens_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe API::API do
+describe 'OAuth tokens' do
context 'Resource Owner Password Credentials' do
def request_oauth_token(user)
post '/oauth/token', username: user.username, password: user.password, grant_type: 'password'
diff --git a/spec/requests/api/v3/merge_requests_spec.rb b/spec/requests/api/v3/merge_requests_spec.rb
index 6c2950a6e6f..f6ff96be566 100644
--- a/spec/requests/api/v3/merge_requests_spec.rb
+++ b/spec/requests/api/v3/merge_requests_spec.rb
@@ -338,6 +338,19 @@ describe API::MergeRequests do
expect(json_response['title']).to eq('Test merge_request')
end
+ it "returns 422 when target project has disabled merge requests" do
+ project.project_feature.update(merge_requests_access_level: 0)
+
+ post v3_api("/projects/#{fork_project.id}/merge_requests", user2),
+ title: 'Test',
+ target_branch: "master",
+ source_branch: 'markdown',
+ author: user2,
+ target_project_id: project.id
+
+ expect(response).to have_http_status(422)
+ end
+
it "returns 400 when source_branch is missing" do
post v3_api("/projects/#{fork_project.id}/merge_requests", user2),
title: 'Test merge_request', target_branch: "master", author: user2, target_project_id: project.id
diff --git a/spec/requests/request_profiler_spec.rb b/spec/requests/request_profiler_spec.rb
new file mode 100644
index 00000000000..51fbfecec4b
--- /dev/null
+++ b/spec/requests/request_profiler_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe 'Request Profiler' do
+ let(:user) { create(:user) }
+
+ shared_examples 'profiling a request' do
+ before do
+ allow(Rails).to receive(:cache).and_return(ActiveSupport::Cache::MemoryStore.new)
+ allow(RubyProf::Profile).to receive(:profile) do |&blk|
+ blk.call
+ RubyProf::Profile.new
+ end
+ end
+
+ it 'creates a profile of the request' do
+ project = create(:project, namespace: user.namespace)
+ time = Time.now
+ path = "/#{project.path_with_namespace}"
+
+ Timecop.freeze(time) do
+ get path, nil, 'X-Profile-Token' => Gitlab::RequestProfiler.profile_token
+ end
+
+ profile_path = "#{Gitlab.config.shared.path}/tmp/requests_profiles/#{path.tr('/', '|')}_#{time.to_i}.html"
+ expect(File.exist?(profile_path)).to be true
+ end
+
+ after do
+ Gitlab::RequestProfiler.remove_all_profiles
+ end
+ end
+
+ context "when user is logged-in" do
+ before do
+ login_as(user)
+ end
+
+ include_examples 'profiling a request'
+ end
+
+ context "when user is not logged-in" do
+ include_examples 'profiling a request'
+ end
+end
diff --git a/spec/routing/admin_routing_spec.rb b/spec/routing/admin_routing_spec.rb
index 99c44bde151..e5fc0b676af 100644
--- a/spec/routing/admin_routing_spec.rb
+++ b/spec/routing/admin_routing_spec.rb
@@ -71,13 +71,15 @@ describe Admin::ProjectsController, "routing" do
end
end
-# admin_hook_test GET /admin/hooks/:hook_id/test(.:format) admin/hooks#test
+# admin_hook_test GET /admin/hooks/:id/test(.:format) admin/hooks#test
# admin_hooks GET /admin/hooks(.:format) admin/hooks#index
# POST /admin/hooks(.:format) admin/hooks#create
# admin_hook DELETE /admin/hooks/:id(.:format) admin/hooks#destroy
+# PUT /admin/hooks/:id(.:format) admin/hooks#update
+# edit_admin_hook GET /admin/hooks/:id(.:format) admin/hooks#edit
describe Admin::HooksController, "routing" do
it "to #test" do
- expect(get("/admin/hooks/1/test")).to route_to('admin/hooks#test', hook_id: '1')
+ expect(get("/admin/hooks/1/test")).to route_to('admin/hooks#test', id: '1')
end
it "to #index" do
@@ -88,6 +90,14 @@ describe Admin::HooksController, "routing" do
expect(post("/admin/hooks")).to route_to('admin/hooks#create')
end
+ it "to #edit" do
+ expect(get("/admin/hooks/1/edit")).to route_to('admin/hooks#edit', id: '1')
+ end
+
+ it "to #update" do
+ expect(put("/admin/hooks/1")).to route_to('admin/hooks#update', id: '1')
+ end
+
it "to #destroy" do
expect(delete("/admin/hooks/1")).to route_to('admin/hooks#destroy', id: '1')
end
diff --git a/spec/routing/environments_spec.rb b/spec/routing/environments_spec.rb
index ba124de70bb..624f3c43f0a 100644
--- a/spec/routing/environments_spec.rb
+++ b/spec/routing/environments_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-describe Projects::EnvironmentsController, :routing do
+describe 'environments routing', :routing do
let(:project) { create(:empty_project) }
let(:environment) do
diff --git a/spec/routing/notifications_routing_spec.rb b/spec/routing/notifications_routing_spec.rb
index 24592942a96..54ed87b5520 100644
--- a/spec/routing/notifications_routing_spec.rb
+++ b/spec/routing/notifications_routing_spec.rb
@@ -1,13 +1,11 @@
require "spec_helper"
-describe Profiles::NotificationsController do
- describe "routing" do
- it "routes to #show" do
- expect(get("/profile/notifications")).to route_to("profiles/notifications#show")
- end
+describe "notifications routing" do
+ it "routes to #show" do
+ expect(get("/profile/notifications")).to route_to("profiles/notifications#show")
+ end
- it "routes to #update" do
- expect(put("/profile/notifications")).to route_to("profiles/notifications#update")
- end
+ it "routes to #update" do
+ expect(put("/profile/notifications")).to route_to("profiles/notifications#update")
end
end
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index a3de022d242..163df072cf6 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -340,14 +340,16 @@ describe 'project routing' do
# test_project_hook GET /:project_id/hooks/:id/test(.:format) hooks#test
# project_hooks GET /:project_id/hooks(.:format) hooks#index
# POST /:project_id/hooks(.:format) hooks#create
- # project_hook DELETE /:project_id/hooks/:id(.:format) hooks#destroy
+ # edit_project_hook GET /:project_id/hooks/:id/edit(.:format) hooks#edit
+ # project_hook PUT /:project_id/hooks/:id(.:format) hooks#update
+ # DELETE /:project_id/hooks/:id(.:format) hooks#destroy
describe Projects::HooksController, 'routing' do
it 'to #test' do
expect(get('/gitlab/gitlabhq/hooks/1/test')).to route_to('projects/hooks#test', namespace_id: 'gitlab', project_id: 'gitlabhq', id: '1')
end
it_behaves_like 'RESTful project resources' do
- let(:actions) { [:index, :create, :destroy] }
+ let(:actions) { [:index, :create, :destroy, :edit, :update] }
let(:controller) { 'hooks' }
end
end
diff --git a/spec/rubocop/cop/migration/add_column_with_default_to_large_table_spec.rb b/spec/rubocop/cop/migration/add_column_with_default_to_large_table_spec.rb
new file mode 100644
index 00000000000..07cb3fc4a2e
--- /dev/null
+++ b/spec/rubocop/cop/migration/add_column_with_default_to_large_table_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+require 'rubocop'
+require 'rubocop/rspec/support'
+
+require_relative '../../../../rubocop/cop/migration/add_column_with_default_to_large_table'
+
+describe RuboCop::Cop::Migration::AddColumnWithDefaultToLargeTable do
+ include CopHelper
+
+ subject(:cop) { described_class.new }
+
+ context 'in migration' do
+ before do
+ allow(cop).to receive(:in_migration?).and_return(true)
+ end
+
+ described_class::LARGE_TABLES.each do |table|
+ it "registers an offense for the #{table} table" do
+ inspect_source(cop, "add_column_with_default :#{table}, :column, default: true")
+
+ aggregate_failures do
+ expect(cop.offenses.size).to eq(1)
+ expect(cop.offenses.map(&:line)).to eq([1])
+ end
+ end
+ end
+
+ it 'registers no offense for non-blacklisted tables' do
+ inspect_source(cop, "add_column_with_default :table, :column, default: true")
+
+ expect(cop.offenses).to be_empty
+ end
+ end
+
+ context 'outside of migration' do
+ it 'registers no offense' do
+ table = described_class::LARGE_TABLES.sample
+ inspect_source(cop, "add_column_with_default :#{table}, :column, default: true")
+
+ expect(cop.offenses).to be_empty
+ end
+ end
+end
diff --git a/spec/rubocop/cop/migration/add_column_with_default_spec.rb b/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb
index 6b9b6b19650..3723d635083 100644
--- a/spec/rubocop/cop/migration/add_column_with_default_spec.rb
+++ b/spec/rubocop/cop/migration/reversible_add_column_with_default_spec.rb
@@ -3,9 +3,9 @@ require 'spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
-require_relative '../../../../rubocop/cop/migration/add_column_with_default'
+require_relative '../../../../rubocop/cop/migration/reversible_add_column_with_default'
-describe RuboCop::Cop::Migration::AddColumnWithDefault do
+describe RuboCop::Cop::Migration::ReversibleAddColumnWithDefault do
include CopHelper
subject(:cop) { described_class.new }
diff --git a/spec/serializers/analytics_generic_entity_spec.rb b/spec/serializers/analytics_issue_entity_spec.rb
index 68086216ba9..68086216ba9 100644
--- a/spec/serializers/analytics_generic_entity_spec.rb
+++ b/spec/serializers/analytics_issue_entity_spec.rb
diff --git a/spec/serializers/deployment_entity_spec.rb b/spec/serializers/deployment_entity_spec.rb
index 95eca5463eb..69355bcde42 100644
--- a/spec/serializers/deployment_entity_spec.rb
+++ b/spec/serializers/deployment_entity_spec.rb
@@ -3,25 +3,23 @@ require 'spec_helper'
describe DeploymentEntity do
let(:user) { create(:user) }
let(:request) { double('request') }
+ let(:deployment) { create(:deployment) }
+ let(:entity) { described_class.new(deployment, request: request) }
+ subject { entity.as_json }
before do
allow(request).to receive(:user).and_return(user)
end
- let(:entity) do
- described_class.new(deployment, request: request)
- end
-
- let(:deployment) { create(:deployment) }
-
- subject { entity.as_json }
-
it 'exposes internal deployment id' do
expect(subject).to include(:iid)
end
it 'exposes nested information about branch' do
expect(subject[:ref][:name]).to eq 'master'
- expect(subject[:ref][:ref_path]).not_to be_empty
+ end
+
+ it 'exposes creation date' do
+ expect(subject).to include(:created_at)
end
end
diff --git a/spec/serializers/status_entity_spec.rb b/spec/serializers/status_entity_spec.rb
index c94902dbab8..3964b998084 100644
--- a/spec/serializers/status_entity_spec.rb
+++ b/spec/serializers/status_entity_spec.rb
@@ -18,6 +18,12 @@ describe StatusEntity do
it 'contains status details' do
expect(subject).to include :text, :icon, :favicon, :label, :group
expect(subject).to include :has_details, :details_path
+ expect(subject[:favicon]).to eq('/assets/ci_favicons/favicon_status_success.ico')
+ end
+
+ it 'contains a dev namespaced favicon if dev env' do
+ allow(Rails.env).to receive(:development?) { true }
+ expect(entity.as_json[:favicon]).to eq('/assets/ci_favicons/dev/favicon_status_success.ico')
end
end
end
diff --git a/spec/services/issues/resolve_discussions_spec.rb b/spec/services/issues/resolve_discussions_spec.rb
index 4a4929daefc..c3b4c2176ee 100644
--- a/spec/services/issues/resolve_discussions_spec.rb
+++ b/spec/services/issues/resolve_discussions_spec.rb
@@ -1,15 +1,15 @@
require 'spec_helper.rb'
-class DummyService < Issues::BaseService
- include ::Issues::ResolveDiscussions
+describe Issues::ResolveDiscussions, services: true do
+ class DummyService < Issues::BaseService
+ include ::Issues::ResolveDiscussions
- def initialize(*args)
- super
- filter_resolve_discussion_params
+ def initialize(*args)
+ super
+ filter_resolve_discussion_params
+ end
end
-end
-describe DummyService, services: true do
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
@@ -23,7 +23,7 @@ describe DummyService, services: true do
let(:other_merge_request) { create(:merge_request, source_project: project, source_branch: "other") }
describe "#merge_request_for_resolving_discussion" do
- let(:service) { described_class.new(project, user, merge_request_to_resolve_discussions_of: merge_request.iid) }
+ let(:service) { DummyService.new(project, user, merge_request_to_resolve_discussions_of: merge_request.iid) }
it "finds the merge request" do
expect(service.merge_request_to_resolve_discussions_of).to eq(merge_request)
@@ -43,7 +43,7 @@ describe DummyService, services: true do
describe "#discussions_to_resolve" do
it "contains a single discussion when matching merge request and discussion are passed" do
- service = described_class.new(
+ service = DummyService.new(
project,
user,
discussion_to_resolve: discussion.id,
@@ -61,7 +61,7 @@ describe DummyService, services: true do
noteable: merge_request,
project: merge_request.target_project,
line_number: 15)])
- service = described_class.new(
+ service = DummyService.new(
project,
user,
merge_request_to_resolve_discussions_of: merge_request.iid
@@ -79,7 +79,7 @@ describe DummyService, services: true do
project: merge_request.target_project,
line_number: 15,
)])
- service = described_class.new(
+ service = DummyService.new(
project,
user,
merge_request_to_resolve_discussions_of: merge_request.iid
@@ -92,7 +92,7 @@ describe DummyService, services: true do
end
it "is empty when a discussion and another merge request are passed" do
- service = described_class.new(
+ service = DummyService.new(
project,
user,
discussion_to_resolve: discussion.id,
diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb
index be9f9ea2dec..6f9d1208b1d 100644
--- a/spec/services/merge_requests/build_service_spec.rb
+++ b/spec/services/merge_requests/build_service_spec.rb
@@ -261,6 +261,16 @@ describe MergeRequests::BuildService, services: true do
end
end
+ context 'upstream project has disabled merge requests' do
+ let(:upstream_project) { create(:empty_project, :merge_requests_disabled) }
+ let(:project) { create(:empty_project, forked_from_project: upstream_project) }
+ let(:commits) { Commit.decorate([commit_1], project) }
+
+ it 'sets target project correctly' do
+ expect(merge_request.target_project).to eq(project)
+ end
+ end
+
context 'target_project is set and accessible by current_user' do
let(:target_project) { create(:project, :public, :repository)}
let(:commits) { Commit.decorate([commit_1], project) }
diff --git a/spec/services/merge_requests/get_urls_service_spec.rb b/spec/services/merge_requests/get_urls_service_spec.rb
index 290e00ea1ba..4a7d8ab4c6c 100644
--- a/spec/services/merge_requests/get_urls_service_spec.rb
+++ b/spec/services/merge_requests/get_urls_service_spec.rb
@@ -2,7 +2,7 @@ require "spec_helper"
describe MergeRequests::GetUrlsService do
let(:project) { create(:project, :public, :repository) }
- let(:service) { MergeRequests::GetUrlsService.new(project) }
+ let(:service) { described_class.new(project) }
let(:source_branch) { "my_branch" }
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}" }
@@ -89,7 +89,7 @@ describe MergeRequests::GetUrlsService do
let!(:merge_request) { create(:merge_request, source_project: forked_project, target_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
# Source project is now the forked one
- let(:service) { MergeRequests::GetUrlsService.new(forked_project) }
+ let(:service) { described_class.new(forked_project) }
before do
allow(forked_project).to receive(:empty_repo?).and_return(false)
diff --git a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
index 35804d41b46..935f4710851 100644
--- a/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
+++ b/spec/services/merge_requests/merge_request_diff_cache_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe MergeRequests::MergeRequestDiffCacheService do
- let(:subject) { MergeRequests::MergeRequestDiffCacheService.new }
+ let(:subject) { described_class.new }
describe '#execute' do
it 'retrieves the diff files to cache the highlighted result' do
diff --git a/spec/services/merge_requests/resolve_service_spec.rb b/spec/services/merge_requests/resolve_service_spec.rb
index eaf7785e549..3afd6b92900 100644
--- a/spec/services/merge_requests/resolve_service_spec.rb
+++ b/spec/services/merge_requests/resolve_service_spec.rb
@@ -50,7 +50,7 @@ describe MergeRequests::ResolveService do
context 'when the source and target project are the same' do
before do
- MergeRequests::ResolveService.new(project, user, params).execute(merge_request)
+ described_class.new(project, user, params).execute(merge_request)
end
it 'creates a commit with the message' do
@@ -75,7 +75,7 @@ describe MergeRequests::ResolveService do
end
before do
- MergeRequests::ResolveService.new(fork_project, user, params).execute(merge_request_from_fork)
+ described_class.new(fork_project, user, params).execute(merge_request_from_fork)
end
it 'creates a commit with the message' do
@@ -115,7 +115,7 @@ describe MergeRequests::ResolveService do
end
before do
- MergeRequests::ResolveService.new(project, user, params).execute(merge_request)
+ described_class.new(project, user, params).execute(merge_request)
end
it 'creates a commit with the message' do
@@ -154,7 +154,7 @@ describe MergeRequests::ResolveService do
}
end
- let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) }
+ let(:service) { described_class.new(project, user, invalid_params) }
it 'raises a MissingResolution error' do
expect { service.execute(merge_request) }.
@@ -180,7 +180,7 @@ describe MergeRequests::ResolveService do
}
end
- let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) }
+ let(:service) { described_class.new(project, user, invalid_params) }
it 'raises a MissingResolution error' do
expect { service.execute(merge_request) }.
@@ -202,7 +202,7 @@ describe MergeRequests::ResolveService do
}
end
- let(:service) { MergeRequests::ResolveService.new(project, user, invalid_params) }
+ let(:service) { described_class.new(project, user, invalid_params) }
it 'raises a MissingFiles error' do
expect { service.execute(merge_request) }.
diff --git a/spec/services/merge_requests/resolved_discussion_notification_service.rb b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
index 7ddd812e513..7ddd812e513 100644
--- a/spec/services/merge_requests/resolved_discussion_notification_service.rb
+++ b/spec/services/merge_requests/resolved_discussion_notification_service_spec.rb
diff --git a/spec/services/projects/enable_deploy_key_service_spec.rb b/spec/services/projects/enable_deploy_key_service_spec.rb
index a37510cf159..78626fbad4b 100644
--- a/spec/services/projects/enable_deploy_key_service_spec.rb
+++ b/spec/services/projects/enable_deploy_key_service_spec.rb
@@ -21,6 +21,16 @@ describe Projects::EnableDeployKeyService, services: true do
end
end
+ context 'add the same key twice' do
+ before do
+ project.deploy_keys << deploy_key
+ end
+
+ it 'returns existing key' do
+ expect(service.execute).to eq(deploy_key)
+ end
+ end
+
def service
Projects::EnableDeployKeyService.new(project, user, params)
end
diff --git a/spec/services/projects/housekeeping_service_spec.rb b/spec/services/projects/housekeeping_service_spec.rb
index eaf63457b32..fff12beed71 100644
--- a/spec/services/projects/housekeeping_service_spec.rb
+++ b/spec/services/projects/housekeeping_service_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe Projects::HousekeepingService do
- subject { Projects::HousekeepingService.new(project) }
+ subject { described_class.new(project) }
let(:project) { create(:project, :repository) }
before do
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index e67ad8f3455..e2d5928e5b2 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -13,8 +13,9 @@ rspec_profiling_is_configured =
ENV['RSPEC_PROFILING_POSTGRES_URL'] ||
ENV['RSPEC_PROFILING']
branch_can_be_profiled =
- ENV['CI_COMMIT_REF_NAME'] == 'master' ||
- ENV['CI_COMMIT_REF_NAME'] =~ /rspec-profile/
+ ENV['GITLAB_DATABASE'] == 'postgresql' &&
+ (ENV['CI_COMMIT_REF_NAME'] == 'master' ||
+ ENV['CI_COMMIT_REF_NAME'] =~ /rspec-profile/)
if rspec_profiling_is_configured && (!ENV.key?('CI') || branch_can_be_profiled)
require 'rspec_profiling/rspec'
diff --git a/spec/support/fake_migration_classes.rb b/spec/support/fake_migration_classes.rb
new file mode 100644
index 00000000000..3de0460c3ca
--- /dev/null
+++ b/spec/support/fake_migration_classes.rb
@@ -0,0 +1,3 @@
+class FakeRenameReservedPathMigrationV1 < ActiveRecord::Migration
+ include Gitlab::Database::RenameReservedPathsMigration::V1
+end
diff --git a/spec/support/import_export/import_export.yml b/spec/support/import_export/import_export.yml
index 17136dee000..734d6838f4d 100644
--- a/spec/support/import_export/import_export.yml
+++ b/spec/support/import_export/import_export.yml
@@ -11,9 +11,6 @@ project_tree:
- :user
included_attributes:
- project:
- - :name
- - :path
merge_requests:
- :id
user:
@@ -21,4 +18,7 @@ included_attributes:
excluded_attributes:
merge_requests:
- - :iid \ No newline at end of file
+ - :iid
+ project:
+ - :id
+ - :created_at \ No newline at end of file
diff --git a/spec/support/milestone_tabs_examples.rb b/spec/support/milestone_tabs_examples.rb
new file mode 100644
index 00000000000..c69f8e11008
--- /dev/null
+++ b/spec/support/milestone_tabs_examples.rb
@@ -0,0 +1,68 @@
+shared_examples 'milestone tabs' do
+ def go(path, extra_params = {})
+ params = if milestone.is_a?(GlobalMilestone)
+ { group_id: group.id, id: milestone.safe_title, title: milestone.title }
+ else
+ { namespace_id: project.namespace.to_param, project_id: project, id: milestone.iid }
+ end
+
+ get path, params.merge(extra_params)
+ end
+
+ describe '#merge_requests' do
+ context 'as html' do
+ before { go(:merge_requests, format: 'html') }
+
+ it 'redirects to milestone#show' do
+ expect(response).to redirect_to(milestone_path)
+ end
+ end
+
+ context 'as json' do
+ before { go(:merge_requests, format: 'json') }
+
+ it 'renders the merge requests tab template to a string' do
+ expect(response).to render_template('shared/milestones/_merge_requests_tab')
+ expect(json_response).to have_key('html')
+ end
+ end
+ end
+
+ describe '#participants' do
+ context 'as html' do
+ before { go(:participants, format: 'html') }
+
+ it 'redirects to milestone#show' do
+ expect(response).to redirect_to(milestone_path)
+ end
+ end
+
+ context 'as json' do
+ before { go(:participants, format: 'json') }
+
+ it 'renders the participants tab template to a string' do
+ expect(response).to render_template('shared/milestones/_participants_tab')
+ expect(json_response).to have_key('html')
+ end
+ end
+ end
+
+ describe '#labels' do
+ context 'as html' do
+ before { go(:labels, format: 'html') }
+
+ it 'redirects to milestone#show' do
+ expect(response).to redirect_to(milestone_path)
+ end
+ end
+
+ context 'as json' do
+ before { go(:labels, format: 'json') }
+
+ it 'renders the labels tab template to a string' do
+ expect(response).to render_template('shared/milestones/_labels_tab')
+ expect(json_response).to have_key('html')
+ end
+ end
+ end
+end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index 5c8ee8d62f5..0b3c6169c9b 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -39,7 +39,8 @@ module TestEnv
'wip' => 'b9238ee',
'csv' => '3dd0896',
'v1.1.0' => 'b83d6e3',
- 'add-ipython-files' => '6d85bb69'
+ 'add-ipython-files' => '6d85bb69',
+ 'add-pdf-file' => 'e774ebd3'
}.freeze
# gitlab-test-fork is a fork of gitlab-fork, but we don't necessarily
diff --git a/spec/support/wait_for_requests.rb b/spec/support/wait_for_requests.rb
index 0bfa7f72ff8..73da23391ee 100644
--- a/spec/support/wait_for_requests.rb
+++ b/spec/support/wait_for_requests.rb
@@ -1,11 +1,15 @@
+require_relative './wait_for_ajax'
+
module WaitForRequests
extend self
+ include WaitForAjax
# This is inspired by http://www.salsify.com/blog/engineering/tearing-capybara-ajax-tests
def wait_for_requests_complete
Gitlab::Testing::RequestBlockerMiddleware.block_requests!
wait_for('pending AJAX requests complete') do
- Gitlab::Testing::RequestBlockerMiddleware.num_active_requests.zero?
+ Gitlab::Testing::RequestBlockerMiddleware.num_active_requests.zero? &&
+ finished_all_ajax_requests?
end
ensure
Gitlab::Testing::RequestBlockerMiddleware.allow_requests!
diff --git a/spec/tasks/config_lint_spec.rb b/spec/tasks/config_lint_spec.rb
index c32f9a740b7..ed6c5b09663 100644
--- a/spec/tasks/config_lint_spec.rb
+++ b/spec/tasks/config_lint_spec.rb
@@ -5,11 +5,11 @@ describe ConfigLint do
let(:files){ ['lib/support/fake.sh'] }
it 'errors out if any bash scripts have errors' do
- expect { ConfigLint.run(files){ system('exit 1') } }.to raise_error(SystemExit)
+ expect { described_class.run(files){ system('exit 1') } }.to raise_error(SystemExit)
end
it 'passes if all scripts are fine' do
- expect { ConfigLint.run(files){ system('exit 0') } }.not_to raise_error
+ expect { described_class.run(files){ system('exit 0') } }.not_to raise_error
end
end
diff --git a/spec/tasks/gitlab/backup_rake_spec.rb b/spec/tasks/gitlab/backup_rake_spec.rb
index 0a4a6ed8145..df2f2ce95e6 100644
--- a/spec/tasks/gitlab/backup_rake_spec.rb
+++ b/spec/tasks/gitlab/backup_rake_spec.rb
@@ -230,11 +230,13 @@ describe 'gitlab:app namespace rake task' do
before do
FileUtils.mkdir('tmp/tests/default_storage')
FileUtils.mkdir('tmp/tests/custom_storage')
+ gitaly_address = Gitlab.config.repositories.storages.default.gitaly_address
storages = {
- 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage') },
- 'custom' => { 'path' => Settings.absolute('tmp/tests/custom_storage') }
+ 'default' => { 'path' => Settings.absolute('tmp/tests/default_storage'), 'gitaly_address' => gitaly_address },
+ 'custom' => { 'path' => Settings.absolute('tmp/tests/custom_storage'), 'gitaly_address' => gitaly_address }
}
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
+ Gitlab::GitalyClient.configure_channels
# Create the projects now, after mocking the settings but before doing the backup
project_a
diff --git a/spec/validators/dynamic_path_validator_spec.rb b/spec/validators/dynamic_path_validator_spec.rb
new file mode 100644
index 00000000000..b114bfc1bca
--- /dev/null
+++ b/spec/validators/dynamic_path_validator_spec.rb
@@ -0,0 +1,266 @@
+require 'spec_helper'
+
+describe DynamicPathValidator do
+ let(:validator) { described_class.new(attributes: [:path]) }
+
+ # Pass in a full path to remove the format segment:
+ # `/ci/lint(.:format)` -> `/ci/lint`
+ def without_format(path)
+ path.split('(', 2)[0]
+ end
+
+ # Pass in a full path and get the last segment before a wildcard
+ # That's not a parameter
+ # `/*namespace_id/:project_id/builds/artifacts/*ref_name_and_path`
+ # -> 'builds/artifacts'
+ def path_before_wildcard(path)
+ path = path.gsub(STARTING_WITH_NAMESPACE, "")
+ path_segments = path.split('/').reject(&:empty?)
+ wildcard_index = path_segments.index { |segment| parameter?(segment) }
+
+ segments_before_wildcard = path_segments[0..wildcard_index - 1]
+
+ segments_before_wildcard.join('/')
+ end
+
+ def parameter?(segment)
+ segment =~ /[*:]/
+ end
+
+ # If the path is reserved. Then no conflicting paths can# be created for any
+ # route using this reserved word.
+ #
+ # Both `builds/artifacts` & `build` are covered by reserving the word
+ # `build`
+ def wildcards_include?(path)
+ described_class::WILDCARD_ROUTES.include?(path) ||
+ described_class::WILDCARD_ROUTES.include?(path.split('/').first)
+ end
+
+ def failure_message(missing_words, constant_name, migration_helper)
+ missing_words = Array(missing_words)
+ <<-MSG
+ Found new routes that could cause conflicts with existing namespaced routes
+ for groups or projects.
+
+ Add <#{missing_words.join(', ')}> to `DynamicPathValidator::#{constant_name}
+ to make sure no projects or namespaces can be created with those paths.
+
+ To rename any existing records with those paths you can use the
+ `Gitlab::Database::RenameReservedpathsMigration::<VERSION>.#{migration_helper}`
+ migration helper.
+
+ Make sure to make a note of the renamed records in the release blog post.
+
+ MSG
+ end
+
+ let(:all_routes) do
+ Rails.application.routes.routes.routes.
+ map { |r| r.path.spec.to_s }
+ end
+
+ let(:routes_without_format) { all_routes.map { |path| without_format(path) } }
+
+ # Routes not starting with `/:` or `/*`
+ # all routes not starting with a param
+ let(:routes_not_starting_in_wildcard) { routes_without_format.select { |p| p !~ %r{^/[:*]} } }
+
+ let(:top_level_words) do
+ routes_not_starting_in_wildcard.map do |route|
+ route.split('/')[1]
+ end.compact.uniq
+ end
+
+ # All routes that start with a namespaced path, that have 1 or more
+ # path-segments before having another wildcard parameter.
+ # - Starting with paths:
+ # - `/*namespace_id/:project_id/`
+ # - `/*namespace_id/:id/`
+ # - Followed by one or more path-parts not starting with `:` or `*`
+ # - Followed by a path-part that includes a wildcard parameter `*`
+ # At the time of writing these routes match: http://rubular.com/r/Rv2pDE5Dvw
+ STARTING_WITH_NAMESPACE = %r{^/\*namespace_id/:(project_)?id}
+ NON_PARAM_PARTS = %r{[^:*][a-z\-_/]*}
+ ANY_OTHER_PATH_PART = %r{[a-z\-_/:]*}
+ WILDCARD_SEGMENT = %r{\*}
+ let(:namespaced_wildcard_routes) do
+ routes_without_format.select do |p|
+ p =~ %r{#{STARTING_WITH_NAMESPACE}/#{NON_PARAM_PARTS}/#{ANY_OTHER_PATH_PART}#{WILDCARD_SEGMENT}}
+ end
+ end
+
+ # This will return all paths that are used in a namespaced route
+ # before another wildcard path:
+ #
+ # /*namespace_id/:project_id/builds/artifacts/*ref_name_and_path
+ # /*namespace_id/:project_id/info/lfs/objects/*oid
+ # /*namespace_id/:project_id/commits/*id
+ # /*namespace_id/:project_id/builds/:build_id/artifacts/file/*path
+ # -> ['builds/artifacts', 'info/lfs/objects', 'commits', 'artifacts/file']
+ let(:all_wildcard_paths) do
+ namespaced_wildcard_routes.map do |route|
+ path_before_wildcard(route)
+ end.uniq
+ end
+
+ STARTING_WITH_GROUP = %r{^/groups/\*(group_)?id/}
+ let(:group_routes) do
+ routes_without_format.select do |path|
+ path =~ STARTING_WITH_GROUP
+ end
+ end
+
+ let(:paths_after_group_id) do
+ group_routes.map do |route|
+ route.gsub(STARTING_WITH_GROUP, '').split('/').first
+ end.uniq
+ end
+
+ describe 'TOP_LEVEL_ROUTES' do
+ it 'includes all the top level namespaces' do
+ failure_block = lambda do
+ missing_words = top_level_words - described_class::TOP_LEVEL_ROUTES
+ failure_message(missing_words, 'TOP_LEVEL_ROUTES', 'rename_root_paths')
+ end
+
+ expect(described_class::TOP_LEVEL_ROUTES)
+ .to include(*top_level_words), failure_block
+ end
+ end
+
+ describe 'GROUP_ROUTES' do
+ it "don't contain a second wildcard" do
+ failure_block = lambda do
+ missing_words = paths_after_group_id - described_class::GROUP_ROUTES
+ failure_message(missing_words, 'GROUP_ROUTES', 'rename_child_paths')
+ end
+
+ expect(described_class::GROUP_ROUTES)
+ .to include(*paths_after_group_id), failure_block
+ end
+ end
+
+ describe 'WILDCARD_ROUTES' do
+ it 'includes all paths that can be used after a namespace/project path' do
+ aggregate_failures do
+ all_wildcard_paths.each do |path|
+ expect(wildcards_include?(path))
+ .to be(true), failure_message(path, 'WILDCARD_ROUTES', 'rename_wildcard_paths')
+ end
+ end
+ end
+ end
+
+ describe '.without_reserved_wildcard_paths_regex' do
+ subject { described_class.without_reserved_wildcard_paths_regex }
+
+ it 'rejects paths starting with a reserved top level' do
+ expect(subject).not_to match('dashboard/hello/world')
+ expect(subject).not_to match('dashboard')
+ end
+
+ it 'matches valid paths with a toplevel word in a different place' do
+ expect(subject).to match('parent/dashboard/project-path')
+ end
+
+ it 'rejects paths containing a wildcard reserved word' do
+ expect(subject).not_to match('hello/edit')
+ expect(subject).not_to match('hello/edit/in-the-middle')
+ expect(subject).not_to match('foo/bar1/refs/master/logs_tree')
+ end
+
+ it 'matches valid paths' do
+ expect(subject).to match('parent/child/project-path')
+ end
+ end
+
+ describe '.regex_excluding_child_paths' do
+ let(:subject) { described_class.without_reserved_child_paths_regex }
+
+ it 'rejects paths containing a child reserved word' do
+ expect(subject).not_to match('hello/group_members')
+ expect(subject).not_to match('hello/activity/in-the-middle')
+ expect(subject).not_to match('foo/bar1/refs/master/logs_tree')
+ end
+
+ it 'allows a child path on the top level' do
+ expect(subject).to match('activity/foo')
+ expect(subject).to match('avatar')
+ end
+ end
+
+ describe ".valid?" do
+ it 'is not case sensitive' do
+ expect(described_class.valid?("Users")).to be_falsey
+ end
+
+ it "isn't valid when the top level is reserved" do
+ test_path = 'u/should-be-a/reserved-word'
+
+ expect(described_class.valid?(test_path)).to be_falsey
+ end
+
+ it "isn't valid if any of the path segments is reserved" do
+ test_path = 'the-wildcard/wikis/is-not-allowed'
+
+ expect(described_class.valid?(test_path)).to be_falsey
+ end
+
+ it "is valid if the path doesn't contain reserved words" do
+ test_path = 'there-are/no-wildcards/in-this-path'
+
+ expect(described_class.valid?(test_path)).to be_truthy
+ end
+
+ it 'allows allows a child path on the last spot' do
+ test_path = 'there/can-be-a/project-called/labels'
+
+ expect(described_class.valid?(test_path)).to be_truthy
+ end
+
+ it 'rejects a child path somewhere else' do
+ test_path = 'there/can-be-no/labels/group'
+
+ expect(described_class.valid?(test_path)).to be_falsey
+ end
+
+ it 'rejects paths that are in an incorrect format' do
+ test_path = 'incorrect/format.git'
+
+ expect(described_class.valid?(test_path)).to be_falsey
+ end
+ end
+
+ describe '#path_reserved_for_record?' do
+ it 'reserves a sub-group named activity' do
+ group = build(:group, :nested, path: 'activity')
+
+ expect(validator.path_reserved_for_record?(group, 'activity')).to be_truthy
+ end
+
+ it "doesn't reserve a project called activity" do
+ project = build(:project, path: 'activity')
+
+ expect(validator.path_reserved_for_record?(project, 'activity')).to be_falsey
+ end
+ end
+
+ describe '#validates_each' do
+ it 'adds a message when the path is not in the correct format' do
+ group = build(:group)
+
+ validator.validate_each(group, :path, "Path with spaces, and comma's!")
+
+ expect(group.errors[:path]).to include(Gitlab::Regex.namespace_regex_message)
+ end
+
+ it 'adds a message when the path is not in the correct format' do
+ group = build(:group, path: 'users')
+
+ validator.validate_each(group, :path, 'users')
+
+ expect(group.errors[:path]).to include('users is a reserved name')
+ end
+ end
+end
diff --git a/spec/views/projects/blob/_viewer.html.haml_spec.rb b/spec/views/projects/blob/_viewer.html.haml_spec.rb
index a4915264abe..501f90c5f9a 100644
--- a/spec/views/projects/blob/_viewer.html.haml_spec.rb
+++ b/spec/views/projects/blob/_viewer.html.haml_spec.rb
@@ -21,6 +21,7 @@ describe 'projects/blob/_viewer.html.haml', :view do
before do
assign(:project, project)
+ assign(:blob, blob)
assign(:id, File.join('master', blob.path))
controller.params[:controller] = 'projects/blob'
diff --git a/spec/views/projects/commit/show.html.haml_spec.rb b/spec/views/projects/commit/show.html.haml_spec.rb
new file mode 100644
index 00000000000..122075cc10e
--- /dev/null
+++ b/spec/views/projects/commit/show.html.haml_spec.rb
@@ -0,0 +1,44 @@
+require 'spec_helper'
+
+describe 'projects/commit/show.html.haml', :view do
+ let(:project) { create(:project, :repository) }
+
+ before do
+ assign(:project, project)
+ assign(:repository, project.repository)
+ assign(:commit, project.commit)
+ assign(:noteable, project.commit)
+ assign(:notes, [])
+ assign(:diffs, project.commit.diffs)
+
+ allow(view).to receive(:current_user).and_return(nil)
+ allow(view).to receive(:can?).and_return(false)
+ allow(view).to receive(:can_collaborate_with_project?).and_return(false)
+ allow(view).to receive(:current_ref).and_return(project.repository.root_ref)
+ allow(view).to receive(:diff_btn).and_return('')
+ end
+
+ context 'inline diff view' do
+ before do
+ allow(view).to receive(:diff_view).and_return(:inline)
+
+ render
+ end
+
+ it 'keeps container-limited' do
+ expect(rendered).not_to have_selector('.limit-container-width')
+ end
+ end
+
+ context 'parallel diff view' do
+ before do
+ allow(view).to receive(:diff_view).and_return(:parallel)
+
+ render
+ end
+
+ it 'spans full width' do
+ expect(rendered).to have_selector('.limit-container-width')
+ end
+ end
+end
diff --git a/spec/workers/delete_user_worker_spec.rb b/spec/workers/delete_user_worker_spec.rb
index 0765573408c..5912dd76262 100644
--- a/spec/workers/delete_user_worker_spec.rb
+++ b/spec/workers/delete_user_worker_spec.rb
@@ -8,13 +8,13 @@ describe DeleteUserWorker do
expect_any_instance_of(Users::DestroyService).to receive(:execute).
with(user, {})
- DeleteUserWorker.new.perform(current_user.id, user.id)
+ described_class.new.perform(current_user.id, user.id)
end
it "uses symbolized keys" do
expect_any_instance_of(Users::DestroyService).to receive(:execute).
with(user, test: "test")
- DeleteUserWorker.new.perform(current_user.id, user.id, "test" => "test")
+ described_class.new.perform(current_user.id, user.id, "test" => "test")
end
end
diff --git a/spec/workers/emails_on_push_worker_spec.rb b/spec/workers/emails_on_push_worker_spec.rb
index 8cf2b888f9a..a0ed85cc0b3 100644
--- a/spec/workers/emails_on_push_worker_spec.rb
+++ b/spec/workers/emails_on_push_worker_spec.rb
@@ -12,7 +12,7 @@ describe EmailsOnPushWorker do
let(:perform) { subject.perform(project.id, recipients, data.stringify_keys) }
let(:email) { ActionMailer::Base.deliveries.last }
- subject { EmailsOnPushWorker.new }
+ subject { described_class.new }
describe "#perform" do
context "when push is a new branch" do
diff --git a/spec/workers/expire_build_instance_artifacts_worker_spec.rb b/spec/workers/expire_build_instance_artifacts_worker_spec.rb
index d202b3de77e..1d8da68883b 100644
--- a/spec/workers/expire_build_instance_artifacts_worker_spec.rb
+++ b/spec/workers/expire_build_instance_artifacts_worker_spec.rb
@@ -34,12 +34,14 @@ describe ExpireBuildInstanceArtifactsWorker do
context 'when associated project was removed' do
let(:build) do
create(:ci_build, :artifacts, artifacts_expiry) do |build|
- build.project.delete
+ build.project.pending_delete = true
end
end
it 'does not remove artifacts' do
- expect(build.reload.artifacts_file.exists?).to be_truthy
+ expect do
+ build.reload.artifacts_file
+ end.not_to raise_error
end
end
end
diff --git a/spec/workers/git_garbage_collect_worker_spec.rb b/spec/workers/git_garbage_collect_worker_spec.rb
index 029f35512e0..7a590f64e3c 100644
--- a/spec/workers/git_garbage_collect_worker_spec.rb
+++ b/spec/workers/git_garbage_collect_worker_spec.rb
@@ -6,7 +6,7 @@ describe GitGarbageCollectWorker do
let(:project) { create(:project, :repository) }
let(:shell) { Gitlab::Shell.new }
- subject { GitGarbageCollectWorker.new }
+ subject { described_class.new }
describe "#perform" do
it "flushes ref caches when the task is 'gc'" do
diff --git a/spec/workers/gitlab_usage_ping_worker_spec.rb b/spec/workers/gitlab_usage_ping_worker_spec.rb
index b6c080f36f4..26241044533 100644
--- a/spec/workers/gitlab_usage_ping_worker_spec.rb
+++ b/spec/workers/gitlab_usage_ping_worker_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe GitlabUsagePingWorker do
- subject { GitlabUsagePingWorker.new }
+ subject { described_class.new }
it "sends POST request" do
stub_application_setting(usage_ping_enabled: true)
diff --git a/spec/workers/group_destroy_worker_spec.rb b/spec/workers/group_destroy_worker_spec.rb
index 1ff5a3b9034..c78efc67076 100644
--- a/spec/workers/group_destroy_worker_spec.rb
+++ b/spec/workers/group_destroy_worker_spec.rb
@@ -5,7 +5,7 @@ describe GroupDestroyWorker do
let(:user) { create(:admin) }
let!(:project) { create(:empty_project, namespace: group) }
- subject { GroupDestroyWorker.new }
+ subject { described_class.new }
describe "#perform" do
it "deletes the project" do
diff --git a/spec/workers/merge_worker_spec.rb b/spec/workers/merge_worker_spec.rb
index b5e1fdb8ded..303193bab9b 100644
--- a/spec/workers/merge_worker_spec.rb
+++ b/spec/workers/merge_worker_spec.rb
@@ -15,7 +15,7 @@ describe MergeWorker do
it 'clears cache of source repo after removing source branch' do
expect(source_project.repository.branch_names).to include('markdown')
- MergeWorker.new.perform(
+ described_class.new.perform(
merge_request.id, merge_request.author_id,
commit_message: 'wow such merge',
should_remove_source_branch: true)
diff --git a/spec/workers/pipeline_proccess_worker_spec.rb b/spec/workers/pipeline_process_worker_spec.rb
index 86e9d7f6684..86e9d7f6684 100644
--- a/spec/workers/pipeline_proccess_worker_spec.rb
+++ b/spec/workers/pipeline_process_worker_spec.rb
diff --git a/spec/workers/post_receive_spec.rb b/spec/workers/post_receive_spec.rb
index a2a559a2369..5ab3c4a0e34 100644
--- a/spec/workers/post_receive_spec.rb
+++ b/spec/workers/post_receive_spec.rb
@@ -10,7 +10,7 @@ describe PostReceive do
context "as a resque worker" do
it "reponds to #perform" do
- expect(PostReceive.new).to respond_to(:perform)
+ expect(described_class.new).to respond_to(:perform)
end
end
@@ -25,7 +25,7 @@ describe PostReceive do
it "calls GitTagPushService" do
expect_any_instance_of(GitPushService).to receive(:execute).and_return(true)
expect_any_instance_of(GitTagPushService).not_to receive(:execute)
- PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ described_class.new.perform(pwd(project), key_id, base64_changes)
end
end
@@ -35,7 +35,7 @@ describe PostReceive do
it "calls GitTagPushService" do
expect_any_instance_of(GitPushService).not_to receive(:execute)
expect_any_instance_of(GitTagPushService).to receive(:execute).and_return(true)
- PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ described_class.new.perform(pwd(project), key_id, base64_changes)
end
end
@@ -45,12 +45,12 @@ describe PostReceive do
it "does not call any of the services" do
expect_any_instance_of(GitPushService).not_to receive(:execute)
expect_any_instance_of(GitTagPushService).not_to receive(:execute)
- PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ described_class.new.perform(pwd(project), key_id, base64_changes)
end
end
context "gitlab-ci.yml" do
- subject { PostReceive.new.perform(pwd(project), key_id, base64_changes) }
+ subject { described_class.new.perform(pwd(project), key_id, base64_changes) }
context "creates a Ci::Pipeline for every change" do
before do
@@ -75,7 +75,7 @@ describe PostReceive do
context "webhook" do
it "fetches the correct project" do
expect(Project).to receive(:find_by_full_path).with(project.path_with_namespace).and_return(project)
- PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ described_class.new.perform(pwd(project), key_id, base64_changes)
end
it "does not run if the author is not in the project" do
@@ -85,7 +85,7 @@ describe PostReceive do
expect(project).not_to receive(:execute_hooks)
- expect(PostReceive.new.perform(pwd(project), key_id, base64_changes)).to be_falsey
+ expect(described_class.new.perform(pwd(project), key_id, base64_changes)).to be_falsey
end
it "asks the project to trigger all hooks" do
@@ -93,14 +93,14 @@ describe PostReceive do
expect(project).to receive(:execute_hooks).twice
expect(project).to receive(:execute_services).twice
- PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ described_class.new.perform(pwd(project), key_id, base64_changes)
end
it "enqueues a UpdateMergeRequestsWorker job" do
allow(Project).to receive(:find_by_full_path).and_return(project)
expect(UpdateMergeRequestsWorker).to receive(:perform_async).with(project.id, project.owner.id, any_args)
- PostReceive.new.perform(pwd(project), key_id, base64_changes)
+ described_class.new.perform(pwd(project), key_id, base64_changes)
end
end
diff --git a/spec/workers/project_destroy_worker_spec.rb b/spec/workers/project_destroy_worker_spec.rb
index 0ab42f99510..3d135f40c1f 100644
--- a/spec/workers/project_destroy_worker_spec.rb
+++ b/spec/workers/project_destroy_worker_spec.rb
@@ -4,7 +4,7 @@ describe ProjectDestroyWorker do
let(:project) { create(:project, :repository) }
let(:path) { project.repository.path_to_repo }
- subject { ProjectDestroyWorker.new }
+ subject { described_class.new }
describe "#perform" do
it "deletes the project" do
diff --git a/spec/workers/remove_expired_members_worker_spec.rb b/spec/workers/remove_expired_members_worker_spec.rb
index 402aa1e714e..058fdf4c009 100644
--- a/spec/workers/remove_expired_members_worker_spec.rb
+++ b/spec/workers/remove_expired_members_worker_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe RemoveExpiredMembersWorker do
- let(:worker) { RemoveExpiredMembersWorker.new }
+ let(:worker) { described_class.new }
describe '#perform' do
context 'project members' do
diff --git a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
index 6d42946de38..1c183ce54f4 100644
--- a/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
+++ b/spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb
@@ -1,7 +1,7 @@
require 'spec_helper'
describe RemoveUnreferencedLfsObjectsWorker do
- let(:worker) { RemoveUnreferencedLfsObjectsWorker.new }
+ let(:worker) { described_class.new }
describe '#perform' do
let!(:unreferenced_lfs_object1) { create(:lfs_object, oid: '1') }
diff --git a/spec/workers/repository_fork_worker_spec.rb b/spec/workers/repository_fork_worker_spec.rb
index 7d6a2db2972..5e1cb74c7fc 100644
--- a/spec/workers/repository_fork_worker_spec.rb
+++ b/spec/workers/repository_fork_worker_spec.rb
@@ -5,7 +5,7 @@ describe RepositoryForkWorker do
let(:fork_project) { create(:project, :repository, forked_from_project: project) }
let(:shell) { Gitlab::Shell.new }
- subject { RepositoryForkWorker.new }
+ subject { described_class.new }
before do
allow(subject).to receive(:gitlab_shell).and_return(shell)