projects_helper_spec.rb 13.8 KB
Newer Older
1 2 3
require 'spec_helper'

describe ProjectsHelper do
4 5
  include ProjectForksHelper

Valery Sizov's avatar
Valery Sizov committed
6 7
  describe "#project_status_css_class" do
    it "returns appropriate class" do
8 9 10
      expect(project_status_css_class("started")).to eq("active")
      expect(project_status_css_class("failed")).to eq("danger")
      expect(project_status_css_class("finished")).to eq("success")
Valery Sizov's avatar
Valery Sizov committed
11 12
    end
  end
Valery Sizov's avatar
Valery Sizov committed
13 14

  describe "can_change_visibility_level?" do
15
    let(:project) { create(:project) }
16
    let(:user) { create(:project_member, :reporter, user: create(:user), project: project).user }
17
    let(:forked_project) { fork_project(project, user) }
Valery Sizov's avatar
Valery Sizov committed
18

19
    it "returns false if there are no appropriate permissions" do
Valery Sizov's avatar
Valery Sizov committed
20 21 22 23 24 25 26 27 28 29 30
      allow(helper).to receive(:can?) { false }

      expect(helper.can_change_visibility_level?(project, user)).to be_falsey
    end

    it "returns true if there are permissions and it is not fork" do
      allow(helper).to receive(:can?) { true }

      expect(helper.can_change_visibility_level?(project, user)).to be_truthy
    end

31 32
    it 'allows visibility level to be changed if the project is forked' do
      allow(helper).to receive(:can?).with(user, :change_visibility_level, project) { true }
33
      project.update!(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
34 35 36 37 38
      fork_project(project)

      expect(helper.can_change_visibility_level?(project, user)).to be_truthy
    end

Valery Sizov's avatar
Valery Sizov committed
39 40 41 42
    context "forks" do
      it "returns false if there are permissions and origin project is PRIVATE" do
        allow(helper).to receive(:can?) { true }

43
        project.update(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
Valery Sizov's avatar
Valery Sizov committed
44

45
        expect(helper.can_change_visibility_level?(forked_project, user)).to be_falsey
Valery Sizov's avatar
Valery Sizov committed
46 47 48 49 50
      end

      it "returns true if there are permissions and origin project is INTERNAL" do
        allow(helper).to receive(:can?) { true }

51
        project.update(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
Valery Sizov's avatar
Valery Sizov committed
52

53
        expect(helper.can_change_visibility_level?(forked_project, user)).to be_truthy
Valery Sizov's avatar
Valery Sizov committed
54 55 56
      end
    end
  end
57 58

  describe "readme_cache_key" do
59
    let(:project) { create(:project, :repository) }
60 61 62 63 64 65

    before do
      helper.instance_variable_set(:@project, project)
    end

    it "returns a valid cach key" do
66
      expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-#{project.commit.id}-readme")
67 68 69 70 71
    end

    it "returns a valid cache key if HEAD does not exist" do
      allow(project).to receive(:commit) { nil }

72
      expect(helper.send(:readme_cache_key)).to eq("#{project.full_path}-nil-readme")
73 74
    end
  end
75

76
  describe "#project_list_cache_key", :clean_gitlab_redis_shared_state do
77
    let(:project) { create(:project, :repository) }
78 79 80 81 82 83
    let(:user) { create(:user) }

    before do
      allow(helper).to receive(:current_user).and_return(user)
      allow(helper).to receive(:can?).with(user, :read_cross_project) { true }
    end
84

85 86
    it "includes the route" do
      expect(helper.project_list_cache_key(project)).to include(project.route.cache_key)
87 88
    end

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
    it "includes the project" do
      expect(helper.project_list_cache_key(project)).to include(project.cache_key)
    end

    it "includes the controller name" do
      expect(helper.controller).to receive(:controller_name).and_return("testcontroller")

      expect(helper.project_list_cache_key(project)).to include("testcontroller")
    end

    it "includes the controller action" do
      expect(helper.controller).to receive(:action_name).and_return("testaction")

      expect(helper.project_list_cache_key(project)).to include("testaction")
    end

    it "includes the application settings" do
      settings = Gitlab::CurrentSettings.current_application_settings

      expect(helper.project_list_cache_key(project)).to include(settings.cache_key)
    end

    it "includes a version" do
112
      expect(helper.project_list_cache_key(project).last).to start_with('v')
113 114
    end

115 116 117 118
    it 'includes wether or not the user can read cross project' do
      expect(helper.project_list_cache_key(project)).to include('cross-project:true')
    end

119 120 121 122 123 124
    it "includes the pipeline status when there is a status" do
      create(:ci_pipeline, :success, project: project, sha: project.commit.sha)

      expect(helper.project_list_cache_key(project)).to include("pipeline-status/#{project.commit.sha}-success")
    end
  end
125

126 127
  describe '#load_pipeline_status' do
    it 'loads the pipeline status in batch' do
128
      project = build(:project)
129 130 131 132 133 134 135 136 137

      helper.load_pipeline_status([project])
      # Skip lazy loading of the `pipeline_status` attribute
      pipeline_status = project.instance_variable_get('@pipeline_status')

      expect(pipeline_status).to be_a(Gitlab::Cache::Ci::ProjectPipelineStatus)
    end
  end

138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  describe '#show_no_ssh_key_message?' do
    let(:user) { create(:user) }

    before do
      allow(helper).to receive(:current_user).and_return(user)
    end

    context 'user has no keys' do
      it 'returns true' do
        expect(helper.show_no_ssh_key_message?).to be_truthy
      end
    end

    context 'user has an ssh key' do
      it 'returns false' do
        create(:personal_key, user: user)

        expect(helper.show_no_ssh_key_message?).to be_falsey
      end
    end
  end

  describe '#show_no_password_message?' do
    let(:user) { create(:user) }

    before do
      allow(helper).to receive(:current_user).and_return(user)
    end

    context 'user has password set' do
      it 'returns false' do
        expect(helper.show_no_password_message?).to be_falsey
      end
    end

173 174 175 176 177 178 179
    context 'user has hidden the message' do
      it 'returns false' do
        allow(helper).to receive(:cookies).and_return(hide_no_password_message: true)

        expect(helper.show_no_password_message?).to be_falsey
      end
    end
180

181
    context 'user requires a password for Git' do
182
      it 'returns true' do
183 184
        allow(user).to receive(:require_password_creation_for_git?).and_return(true)

185 186 187 188
        expect(helper.show_no_password_message?).to be_truthy
      end
    end

189
    context 'user requires a personal access token for Git' do
190
      it 'returns true' do
191 192
        allow(user).to receive(:require_password_creation_for_git?).and_return(false)
        allow(user).to receive(:require_personal_access_token_creation_for_git_auth?).and_return(true)
193 194 195 196 197 198 199

        expect(helper.show_no_password_message?).to be_truthy
      end
    end
  end

  describe '#link_to_set_password' do
200 201
    let(:user) { create(:user, password_automatically_set: true) }

202 203 204 205
    before do
      allow(helper).to receive(:current_user).and_return(user)
    end

206
    context 'password authentication is enabled for Git' do
207
      it 'returns link to set a password' do
208 209
        stub_application_setting(password_authentication_enabled_for_git?: true)

210 211 212 213
        expect(helper.link_to_set_password).to match %r{<a href="#{edit_profile_password_path}">set a password</a>}
      end
    end

214
    context 'password authentication is disabled for Git' do
215
      it 'returns link to create a personal access token' do
216
        stub_application_setting(password_authentication_enabled_for_git?: false)
217 218 219 220 221 222

        expect(helper.link_to_set_password).to match %r{<a href="#{profile_personal_access_tokens_path}">create a personal access token</a>}
      end
    end
  end

223
  describe '#link_to_member_avatar' do
Maxim Rydkin's avatar
Maxim Rydkin committed
224
    let(:user) { build_stubbed(:user) }
225
    let(:expected) { double }
226

227
    before do
228
      expect(helper).to receive(:avatar_icon_for_user).with(user, 16).and_return(expected)
229 230 231
    end

    it 'returns image tag for member avatar' do
232
      expect(helper).to receive(:image_tag).with(expected, { width: 16, class: ["avatar", "avatar-inline", "s16"], alt: "", "data-src" => anything })
Maxim Rydkin's avatar
Maxim Rydkin committed
233 234

      helper.link_to_member_avatar(user)
235
    end
236 237

    it 'returns image tag with avatar class' do
238
      expect(helper).to receive(:image_tag).with(expected, { width: 16, class: ["avatar", "avatar-inline", "s16", "any-avatar-class"], alt: "", "data-src" => anything })
239 240 241

      helper.link_to_member_avatar(user, avatar_class: "any-avatar-class")
    end
242 243 244
  end

  describe '#link_to_member' do
Maxim Rydkin's avatar
Maxim Rydkin committed
245 246 247
    let(:group)   { build_stubbed(:group) }
    let(:project) { build_stubbed(:project, group: group) }
    let(:user)    { build_stubbed(:user) }
248 249 250 251 252

    describe 'using the default options' do
      it 'returns an HTML link to the user' do
        link = helper.link_to_member(project, user)

253
        expect(link).to match(%r{/#{user.username}})
254 255 256
      end
    end
  end
257 258

  describe 'default_clone_protocol' do
259
    context 'when user is not logged in and gitlab protocol is HTTP' do
260
      it 'returns HTTP' do
261
        allow(helper).to receive(:current_user).and_return(nil)
262 263 264 265 266

        expect(helper.send(:default_clone_protocol)).to eq('http')
      end
    end

267
    context 'when user is not logged in and gitlab protocol is HTTPS' do
268
      it 'returns HTTPS' do
269 270
        stub_config_setting(protocol: 'https')
        allow(helper).to receive(:current_user).and_return(nil)
271 272 273 274 275

        expect(helper.send(:default_clone_protocol)).to eq('https')
      end
    end
  end
276

277
  describe '#sanitizerepo_repo_path' do
278
    let(:project) { create(:project, :repository) }
279
    let(:storage_path) { Gitlab.config.repositories.storages.default.legacy_disk_path }
280 281

    before do
282
      allow(Settings.shared).to receive(:[]).with('path').and_return('/base/repo/export/path')
283 284
    end

285
    it 'removes the repo path' do
286
      repo = "#{storage_path}/namespace/test.git"
287 288
      import_error = "Could not clone #{repo}\n"

289
      expect(sanitize_repo_path(project, import_error)).to eq('Could not clone [REPOS PATH]/namespace/test.git')
290
    end
291 292 293 294 295 296 297

    it 'removes the temporary repo path used for uploads/exports' do
      repo = '/base/repo/export/path/tmp/project_exports/uploads/test.tar.gz'
      import_error = "Unable to decompress #{repo}\n"

      expect(sanitize_repo_path(project, import_error)).to eq('Unable to decompress [REPO EXPORT PATH]/uploads/test.tar.gz')
    end
298
  end
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

  describe '#last_push_event' do
    let(:user) { double(:user, fork_of: nil) }
    let(:project) { double(:project, id: 1) }

    before do
      allow(helper).to receive(:current_user).and_return(user)
      helper.instance_variable_set(:@project, project)
    end

    context 'when there is no current_user' do
      let(:user) { nil }

      it 'returns nil' do
        expect(helper.last_push_event).to eq(nil)
      end
    end

    it 'returns recent push on the current project' do
      event = double(:event)
319
      expect(user).to receive(:recent_push).with(project).and_return(event)
320 321 322 323

      expect(helper.last_push_event).to eq(event)
    end
  end
Felipe Artur's avatar
Felipe Artur committed
324

325
  describe '#get_project_nav_tabs' do
326
    let(:project) { create(:project) }
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
    let(:user)    { create(:user) }

    before do
      allow(helper).to receive(:can?) { true }
    end

    subject do
      helper.send(:get_project_nav_tabs, project, user)
    end

    context 'when builds feature is enabled' do
      before do
        allow(project).to receive(:builds_enabled?).and_return(true)
      end

      it "does include pipelines tab" do
        is_expected.to include(:pipelines)
      end
    end

    context 'when builds feature is disabled' do
      before do
        allow(project).to receive(:builds_enabled?).and_return(false)
      end

      it "do not include pipelines tab" do
        is_expected.not_to include(:pipelines)
      end
    end
  end
357

358
  describe '#show_projects' do
359 360 361 362 363 364
    let(:projects) do
      create(:project)
      Project.all
    end

    it 'returns true when there are projects' do
365
      expect(helper.show_projects?(projects, {})).to eq(true)
366 367 368
    end

    it 'returns true when there are no projects but a name is given' do
369 370 371 372 373
      expect(helper.show_projects?(Project.none, name: 'foo')).to eq(true)
    end

    it 'returns true when there are no projects but personal is present' do
      expect(helper.show_projects?(Project.none, personal: 'true')).to eq(true)
374 375 376
    end

    it 'returns false when there are no projects and there is no name' do
377
      expect(helper.show_projects?(Project.none, {})).to eq(false)
378 379 380
    end
  end

381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396
  describe('#push_to_create_project_command') do
    let(:user) { create(:user, username: 'john') }

    it 'returns the command to push to create project over HTTP' do
      allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'http' }

      expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream http://test.host/john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)')
    end

    it 'returns the command to push to create project over SSH' do
      allow(Gitlab::CurrentSettings.current_application_settings).to receive(:enabled_git_access_protocol) { 'ssh' }

      expect(helper.push_to_create_project_command(user)).to eq('git push --set-upstream git@localhost:john/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)')
    end
  end

397
  describe '#any_projects?' do
398
    let!(:project) { create(:project) }
399 400 401 402 403 404 405 406 407

    it 'returns true when projects will be returned' do
      expect(helper.any_projects?(Project.all)).to eq(true)
    end

    it 'returns false when no projects will be returned' do
      expect(helper.any_projects?(Project.none)).to eq(false)
    end

408 409 410 411 412 413 414 415
    it 'returns true when using a non-empty Array' do
      expect(helper.any_projects?([project])).to eq(true)
    end

    it 'returns false when using an empty Array' do
      expect(helper.any_projects?([])).to eq(false)
    end

416 417 418 419 420 421 422 423 424 425 426
    it 'only executes a single query when a LIMIT is applied' do
      relation = Project.limit(1)
      recorder = ActiveRecord::QueryRecorder.new do
        2.times do
          helper.any_projects?(relation)
        end
      end

      expect(recorder.count).to eq(1)
    end
  end
427 428 429 430 431 432 433 434 435 436 437

  describe '#git_user_name' do
    let(:user) { double(:user, name: 'John "A" Doe53') }
    before do
      allow(helper).to receive(:current_user).and_return(user)
    end

    it 'parses quotes in name' do
      expect(helper.send(:git_user_name)).to eq('John \"A\" Doe53')
    end
  end
438
end