BigW Consortium Gitlab

group_spec.rb 14.9 KB
Newer Older
1 2
require 'spec_helper'

3
describe Group do
4
  let!(:group) { create(:group, :access_requestable) }
5

6
  describe 'associations' do
7
    it { is_expected.to have_many :projects }
8 9
    it { is_expected.to have_many(:group_members).dependent(:destroy) }
    it { is_expected.to have_many(:users).through(:group_members) }
10 11
    it { is_expected.to have_many(:owners).through(:group_members) }
    it { is_expected.to have_many(:requesters).dependent(:destroy) }
12 13 14
    it { is_expected.to have_many(:project_group_links).dependent(:destroy) }
    it { is_expected.to have_many(:shared_projects).through(:project_group_links) }
    it { is_expected.to have_many(:notification_settings).dependent(:destroy) }
15
    it { is_expected.to have_many(:labels).class_name('GroupLabel') }
Shinya Maeda committed
16
    it { is_expected.to have_many(:variables).class_name('Ci::GroupVariable') }
17
    it { is_expected.to have_many(:uploads).dependent(:destroy) }
18
    it { is_expected.to have_one(:chat_team) }
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45

    describe '#members & #requesters' do
      let(:requester) { create(:user) }
      let(:developer) { create(:user) }
      before do
        group.request_access(requester)
        group.add_developer(developer)
      end

      describe '#members' do
        it 'includes members and exclude requesters' do
          member_user_ids = group.members.pluck(:user_id)

          expect(member_user_ids).to include(developer.id)
          expect(member_user_ids).not_to include(requester.id)
        end
      end

      describe '#requesters' do
        it 'does not include requesters' do
          requester_user_ids = group.requesters.pluck(:user_id)

          expect(requester_user_ids).to include(requester.id)
          expect(requester_user_ids).not_to include(developer.id)
        end
      end
    end
46 47
  end

48 49 50 51 52 53 54 55
  describe 'modules' do
    subject { described_class }

    it { is_expected.to include_module(Referable) }
  end

  describe 'validations' do
    it { is_expected.to validate_presence_of :name }
56
    it { is_expected.to validate_uniqueness_of(:name).scoped_to(:parent_id) }
57 58
    it { is_expected.to validate_presence_of :path }
    it { is_expected.not_to validate_presence_of :owner }
59 60
    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) }
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79

    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
80 81 82 83 84 85

      it 'rejects reserved group paths' do
        group = build(:group, path: 'activity', parent: create(:group))

        expect(group).not_to be_valid
      end
86
    end
87 88
  end

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
  describe '.visible_to_user' do
    let!(:group) { create(:group) }
    let!(:user)  { create(:user) }

    subject { described_class.visible_to_user(user) }

    describe 'when the user has access to a group' do
      before do
        group.add_user(user, Gitlab::Access::MASTER)
      end

      it { is_expected.to eq([group]) }
    end

    describe 'when the user does not have access to any groups' do
      it { is_expected.to eq([]) }
    end
  end

108
  describe 'scopes' do
109 110
    let!(:private_group)  { create(:group, :private)  }
    let!(:internal_group) { create(:group, :internal) }
111 112

    describe 'public_only' do
113
      subject { described_class.public_only.to_a }
114

115
      it { is_expected.to eq([group]) }
116 117 118
    end

    describe 'public_and_internal_only' do
Douwe Maan committed
119
      subject { described_class.public_and_internal_only.to_a }
120

121 122 123 124 125 126 127
      it { is_expected.to match_array([group, internal_group]) }
    end

    describe 'non_public_only' do
      subject { described_class.non_public_only.to_a }

      it { is_expected.to match_array([private_group, internal_group]) }
128 129 130
    end
  end

131 132 133 134 135
  describe '#to_reference' do
    it 'returns a String reference to the object' do
      expect(group.to_reference).to eq "@#{group.name}"
    end
  end
136

137
  describe '#users' do
138
    it { expect(group.users).to eq(group.owners) }
139 140
  end

141
  describe '#human_name' do
142
    it { expect(group.human_name).to eq(group.name) }
143
  end
144

145
  describe '#add_user' do
146
    let(:user) { create(:user) }
147 148 149 150

    before do
      group.add_user(user, GroupMember::MASTER)
    end
151

152
    it { expect(group.group_members.masters.map(&:user)).to include(user) }
153
  end
154

155
  describe '#add_users' do
156
    let(:user) { create(:user) }
157 158 159 160

    before do
      group.add_users([user.id], GroupMember::GUEST)
    end
161

162
    it "updates the group permission" do
163
      expect(group.group_members.guests.map(&:user)).to include(user)
164
      group.add_users([user.id], GroupMember::DEVELOPER)
165 166
      expect(group.group_members.developers.map(&:user)).to include(user)
      expect(group.group_members.guests.map(&:user)).not_to include(user)
167 168
    end
  end
Steven Thonus committed
169

170
  describe '#avatar_type' do
Steven Thonus committed
171
    let(:user) { create(:user) }
172 173 174 175

    before do
      group.add_user(user, GroupMember::MASTER)
    end
Steven Thonus committed
176

177
    it "is true if avatar is image" do
Steven Thonus committed
178
      group.update_attribute(:avatar, 'uploads/avatar.png')
179
      expect(group.avatar_type).to be_truthy
Steven Thonus committed
180 181
    end

182
    it "is false if avatar is html page" do
Steven Thonus committed
183
      group.update_attribute(:avatar, 'uploads/avatar.html')
184
      expect(group.avatar_type).to eq(["only images allowed"])
Steven Thonus committed
185 186
    end
  end
187

188 189 190
  describe '#avatar_url' do
    let!(:group) { create(:group, :access_requestable, :with_avatar) }
    let(:user) { create(:user) }
191
    let(:gitlab_host) { "http://#{Gitlab.config.gitlab.host}" }
192
    let(:avatar_path) { "/uploads/-/system/group/avatar/#{group.id}/dk.png" }
193 194

    context 'when avatar file is uploaded' do
195 196 197
      before do
        group.add_master(user)
      end
198

199 200 201
      it 'shows correct avatar url' do
        expect(group.avatar_url).to eq(avatar_path)
        expect(group.avatar_url(only_path: false)).to eq([gitlab_host, avatar_path].join)
202

203 204 205 206
        allow(ActionController::Base).to receive(:asset_host).and_return(gitlab_host)

        expect(group.avatar_url).to eq([gitlab_host, avatar_path].join)
      end
207 208 209
    end
  end

210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
  describe '.search' do
    it 'returns groups with a matching name' do
      expect(described_class.search(group.name)).to eq([group])
    end

    it 'returns groups with a partially matching name' do
      expect(described_class.search(group.name[0..2])).to eq([group])
    end

    it 'returns groups with a matching name regardless of the casing' do
      expect(described_class.search(group.name.upcase)).to eq([group])
    end

    it 'returns groups with a matching path' do
      expect(described_class.search(group.path)).to eq([group])
    end

    it 'returns groups with a partially matching path' do
      expect(described_class.search(group.path[0..2])).to eq([group])
    end

    it 'returns groups with a matching path regardless of the casing' do
      expect(described_class.search(group.path.upcase)).to eq([group])
    end
  end
235 236

  describe '#has_owner?' do
237 238
    before do
      @members = setup_group_members(group)
239
      create(:group_member, :invited, :owner, group: group)
240
    end
241 242 243 244 245 246 247

    it { expect(group.has_owner?(@members[:owner])).to be_truthy }
    it { expect(group.has_owner?(@members[:master])).to be_falsey }
    it { expect(group.has_owner?(@members[:developer])).to be_falsey }
    it { expect(group.has_owner?(@members[:reporter])).to be_falsey }
    it { expect(group.has_owner?(@members[:guest])).to be_falsey }
    it { expect(group.has_owner?(@members[:requester])).to be_falsey }
248
    it { expect(group.has_owner?(nil)).to be_falsey }
249 250 251
  end

  describe '#has_master?' do
252 253
    before do
      @members = setup_group_members(group)
254
      create(:group_member, :invited, :master, group: group)
255
    end
256 257 258 259 260 261 262

    it { expect(group.has_master?(@members[:owner])).to be_falsey }
    it { expect(group.has_master?(@members[:master])).to be_truthy }
    it { expect(group.has_master?(@members[:developer])).to be_falsey }
    it { expect(group.has_master?(@members[:reporter])).to be_falsey }
    it { expect(group.has_master?(@members[:guest])).to be_falsey }
    it { expect(group.has_master?(@members[:requester])).to be_falsey }
263
    it { expect(group.has_master?(nil)).to be_falsey }
264 265
  end

266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
  describe '#lfs_enabled?' do
    context 'LFS enabled globally' do
      before do
        allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
      end

      it 'returns true when nothing is set' do
        expect(group.lfs_enabled?).to be_truthy
      end

      it 'returns false when set to false' do
        group.update_attribute(:lfs_enabled, false)

        expect(group.lfs_enabled?).to be_falsey
      end

      it 'returns true when set to true' do
        group.update_attribute(:lfs_enabled, true)

        expect(group.lfs_enabled?).to be_truthy
      end
    end

    context 'LFS disabled globally' do
      before do
        allow(Gitlab.config.lfs).to receive(:enabled).and_return(false)
      end

      it 'returns false when nothing is set' do
        expect(group.lfs_enabled?).to be_falsey
      end

      it 'returns false when set to false' do
        group.update_attribute(:lfs_enabled, false)

        expect(group.lfs_enabled?).to be_falsey
      end

      it 'returns false when set to true' do
        group.update_attribute(:lfs_enabled, true)

        expect(group.lfs_enabled?).to be_falsey
      end
    end
  end

312 313 314 315 316 317 318 319 320 321 322 323
  describe '#owners' do
    let(:owner) { create(:user) }
    let(:developer) { create(:user) }

    it 'returns the owners of a Group' do
      group.add_owner(owner)
      group.add_developer(developer)

      expect(group.owners).to eq([owner])
    end
  end

324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
  def setup_group_members(group)
    members = {
      owner: create(:user),
      master: create(:user),
      developer: create(:user),
      reporter: create(:user),
      guest: create(:user),
      requester: create(:user)
    }

    group.add_user(members[:owner], GroupMember::OWNER)
    group.add_user(members[:master], GroupMember::MASTER)
    group.add_user(members[:developer], GroupMember::DEVELOPER)
    group.add_user(members[:reporter], GroupMember::REPORTER)
    group.add_user(members[:guest], GroupMember::GUEST)
    group.request_access(members[:requester])

    members
  end
343 344 345 346 347

  describe '#web_url' do
    it 'returns the canonical URL' do
      expect(group.web_url).to include("groups/#{group.name}")
    end
348 349 350 351 352 353

    context 'nested group' do
      let(:nested_group) { create(:group, :nested) }

      it { expect(nested_group.web_url).to include("groups/#{nested_group.full_path}") }
    end
354
  end
355 356

  describe 'nested group' do
357
    subject { build(:group, :nested) }
358 359

    it { is_expected.to be_valid }
360
    it { expect(subject.parent).to be_kind_of(described_class) }
361
  end
362

363
  describe '#members_with_parents', :nested_groups do
364 365 366 367 368 369 370 371 372
    let!(:group) { create(:group, :nested) }
    let!(:master) { group.parent.add_user(create(:user), GroupMember::MASTER) }
    let!(:developer) { group.add_user(create(:user), GroupMember::DEVELOPER) }

    it 'returns parents members' do
      expect(group.members_with_parents).to include(developer)
      expect(group.members_with_parents).to include(master)
    end
  end
373 374 375 376 377 378 379 380 381

  describe '#user_ids_for_project_authorizations' do
    it 'returns the user IDs for which to refresh authorizations' do
      master = create(:user)
      developer = create(:user)

      group.add_user(master, GroupMember::MASTER)
      group.add_user(developer, GroupMember::DEVELOPER)

382 383
      expect(group.user_ids_for_project_authorizations)
        .to include(master.id, developer.id)
384 385
    end
  end
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425

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

    before do
      group.add_user(user, GroupMember::OWNER)
    end

    it 'is called when require_two_factor_authentication is changed' do
      expect_any_instance_of(User).to receive(:update_two_factor_requirement)

      group.update!(require_two_factor_authentication: true)
    end

    it 'is called when two_factor_grace_period is changed' do
      expect_any_instance_of(User).to receive(:update_two_factor_requirement)

      group.update!(two_factor_grace_period: 23)
    end

    it 'is not called when other attributes are changed' do
      expect_any_instance_of(User).not_to receive(:update_two_factor_requirement)

      group.update!(description: 'foobar')
    end

    it 'calls #update_two_factor_requirement on each group member' do
      other_user = create(:user)
      group.add_user(other_user, GroupMember::OWNER)

      calls = 0
      allow_any_instance_of(User).to receive(:update_two_factor_requirement) do
        calls += 1
      end

      group.update!(require_two_factor_authentication: true, two_factor_grace_period: 23)

      expect(calls).to eq 2
    end
  end
Shinya Maeda committed
426 427

  describe '#secret_variables_for' do
428
    let(:project) { create(:project, group: group) }
Shinya Maeda committed
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472

    let!(:secret_variable) do
      create(:ci_group_variable, value: 'secret', group: group)
    end

    let!(:protected_variable) do
      create(:ci_group_variable, :protected, value: 'protected', group: group)
    end

    subject { group.secret_variables_for('ref', project) }

    shared_examples 'ref is protected' do
      it 'contains all the variables' do
        is_expected.to contain_exactly(secret_variable, protected_variable)
      end
    end

    context 'when the ref is not protected' do
      before do
        stub_application_setting(
          default_branch_protection: Gitlab::Access::PROTECTION_NONE)
      end

      it 'contains only the secret variables' do
        is_expected.to contain_exactly(secret_variable)
      end
    end

    context 'when the ref is a protected branch' do
      before do
        create(:protected_branch, name: 'ref', project: project)
      end

      it_behaves_like 'ref is protected'
    end

    context 'when the ref is a protected tag' do
      before do
        create(:protected_tag, name: 'ref', project: project)
      end

      it_behaves_like 'ref is protected'
    end

473 474 475 476 477 478 479
    context 'when group has children', :postgresql do
      let(:group_child)      { create(:group, parent: group) }
      let(:group_child_2)    { create(:group, parent: group_child) }
      let(:group_child_3)    { create(:group, parent: group_child_2) }
      let(:variable_child)   { create(:ci_group_variable, group: group_child) }
      let(:variable_child_2) { create(:ci_group_variable, group: group_child_2) }
      let(:variable_child_3) { create(:ci_group_variable, group: group_child_3) }
Shinya Maeda committed
480 481

      it 'returns all variables belong to the group and parent groups' do
482 483 484 485 486 487
        expected_array1 = [protected_variable, secret_variable]
        expected_array2 = [variable_child, variable_child_2, variable_child_3]
        got_array = group_child_3.secret_variables_for('ref', project).to_a

        expect(got_array.shift(2)).to contain_exactly(*expected_array1)
        expect(got_array).to eq(expected_array2)
Shinya Maeda committed
488 489 490
      end
    end
  end
491
end