routable_spec.rb 7.0 KB
Newer Older
1 2
# frozen_string_literal: true

3 4 5
require 'spec_helper'

describe Group, 'Routable' do
6
  let!(:group) { create(:group, name: 'foo') }
7

8 9 10 11
  describe 'Validations' do
    it { is_expected.to validate_presence_of(:route) }
  end

12 13
  describe 'Associations' do
    it { is_expected.to have_one(:route).dependent(:destroy) }
14
    it { is_expected.to have_many(:redirect_routes).dependent(:destroy) }
15
  end
T
Toon Claes 已提交
16

17
  describe 'Callbacks' do
18 19 20 21 22 23 24 25 26 27 28 29
    context 'for a group' do
      it 'creates route record on create' do
        expect(group.route.path).to eq(group.path)
        expect(group.route.name).to eq(group.name)
      end

      it 'updates route record on path change' do
        group.update(path: 'wow', name: 'much')

        expect(group.route.path).to eq('wow')
        expect(group.route.name).to eq('much')
      end
30

31 32 33
      it 'ensure route path uniqueness across different objects' do
        create(:group, parent: group, path: 'xyz')
        duplicate = build(:project, namespace: group, path: 'xyz')
34

35 36
        expect { duplicate.save! }.to raise_error(ActiveRecord::RecordInvalid, 'Validation failed: Path has already been taken')
      end
37 38
    end

39 40 41 42 43 44 45 46 47 48 49 50 51
    context 'for a user' do
      let(:user) { create(:user, username: 'jane', name: "Jane Doe") }

      it 'creates the route for a record on create' do
        expect(user.namespace.name).to eq('Jane Doe')
        expect(user.namespace.path).to eq('jane')
      end

      it 'updates routes and nested routes on name change' do
        project = create(:project, path: 'work-stuff', name: 'Work stuff', namespace: user.namespace)

        user.update!(username: 'jaen', name: 'Jaen Did')
        project.reload
52

53 54 55 56 57
        expect(user.namespace.name).to eq('Jaen Did')
        expect(user.namespace.path).to eq('jaen')
        expect(project.full_name).to eq('Jaen Did / Work stuff')
        expect(project.full_path).to eq('jaen/work-stuff')
      end
58 59 60
    end
  end

61
  shared_examples_for '.find_by_full_path' do
62 63
    let!(:nested_group) { create(:group, parent: group) }

64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
    context 'without any redirect routes' do
      it { expect(described_class.find_by_full_path(group.to_param)).to eq(group) }
      it { expect(described_class.find_by_full_path(group.to_param.upcase)).to eq(group) }
      it { expect(described_class.find_by_full_path(nested_group.to_param)).to eq(nested_group) }
      it { expect(described_class.find_by_full_path('unknown')).to eq(nil) }
    end

    context 'with redirect routes' do
      let!(:group_redirect_route) { group.redirect_routes.create!(path: 'bar') }
      let!(:nested_group_redirect_route) { nested_group.redirect_routes.create!(path: nested_group.path.sub('foo', 'bar')) }

      context 'without follow_redirects option' do
        context 'with the given path not matching any route' do
          it { expect(described_class.find_by_full_path('unknown')).to eq(nil) }
        end

        context 'with the given path matching the canonical route' do
          it { expect(described_class.find_by_full_path(group.to_param)).to eq(group) }
          it { expect(described_class.find_by_full_path(group.to_param.upcase)).to eq(group) }
          it { expect(described_class.find_by_full_path(nested_group.to_param)).to eq(nested_group) }
        end

        context 'with the given path matching a redirect route' do
          it { expect(described_class.find_by_full_path(group_redirect_route.path)).to eq(nil) }
          it { expect(described_class.find_by_full_path(group_redirect_route.path.upcase)).to eq(nil) }
          it { expect(described_class.find_by_full_path(nested_group_redirect_route.path)).to eq(nil) }
        end
      end

      context 'with follow_redirects option set to true' do
        context 'with the given path not matching any route' do
          it { expect(described_class.find_by_full_path('unknown', follow_redirects: true)).to eq(nil) }
        end

        context 'with the given path matching the canonical route' do
          it { expect(described_class.find_by_full_path(group.to_param, follow_redirects: true)).to eq(group) }
          it { expect(described_class.find_by_full_path(group.to_param.upcase, follow_redirects: true)).to eq(group) }
          it { expect(described_class.find_by_full_path(nested_group.to_param, follow_redirects: true)).to eq(nested_group) }
        end

        context 'with the given path matching a redirect route' do
          it { expect(described_class.find_by_full_path(group_redirect_route.path, follow_redirects: true)).to eq(group) }
          it { expect(described_class.find_by_full_path(group_redirect_route.path.upcase, follow_redirects: true)).to eq(group) }
          it { expect(described_class.find_by_full_path(nested_group_redirect_route.path, follow_redirects: true)).to eq(nested_group) }
        end
      end
    end
111 112
  end

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  describe '.find_by_full_path' do
    context 'with routable_two_step_lookup feature' do
      before do
        stub_feature_flags(routable_two_step_lookup: true)
      end

      it_behaves_like '.find_by_full_path'
    end

    context 'without routable_two_step_lookup feature' do
      before do
        stub_feature_flags(routable_two_step_lookup: false)
      end

      it_behaves_like '.find_by_full_path'
    end
  end

131
  describe '.where_full_path_in' do
132 133
    context 'without any paths' do
      it 'returns an empty relation' do
134
        expect(described_class.where_full_path_in([])).to eq([])
135 136 137 138 139
      end
    end

    context 'without any valid paths' do
      it 'returns an empty relation' do
140
        expect(described_class.where_full_path_in(%w[unknown])).to eq([])
141 142 143 144 145 146 147
      end
    end

    context 'with valid paths' do
      let!(:nested_group) { create(:group, parent: group) }

      it 'returns the projects matching the paths' do
148
        result = described_class.where_full_path_in([group.to_param, nested_group.to_param])
149 150 151 152 153

        expect(result).to contain_exactly(group, nested_group)
      end

      it 'returns projects regardless of the casing of paths' do
154
        result = described_class.where_full_path_in([group.to_param.upcase, nested_group.to_param.upcase])
155 156 157 158 159

        expect(result).to contain_exactly(group, nested_group)
      end
    end
  end
160

161 162 163 164 165
  describe '#full_path' do
    let(:group) { create(:group) }
    let(:nested_group) { create(:group, parent: group) }

    it { expect(group.full_path).to eq(group.path) }
166
    it { expect(nested_group.full_path).to eq("#{group.full_path}/#{nested_group.path}") }
167 168
  end

169 170 171 172 173 174 175 176 177 178 179
  describe '#full_name' do
    let(:group) { create(:group) }
    let(:nested_group) { create(:group, parent: group) }

    it { expect(group.full_name).to eq(group.name) }
    it { expect(nested_group.full_name).to eq("#{group.name} / #{nested_group.name}") }
  end
end

describe Project, 'Routable' do
  describe '#full_path' do
180
    let(:project) { build_stubbed(:project) }
181

182
    it { expect(project.full_path).to eq "#{project.namespace.full_path}/#{project.path}" }
183 184 185
  end

  describe '#full_name' do
186
    let(:project) { build_stubbed(:project) }
187 188 189

    it { expect(project.full_name).to eq "#{project.namespace.human_name} / #{project.name}" }
  end
190
end