Welcome to mirror list, hosted at ThFree Co, Russian Federation.

snippet_repo_restorer_spec.rb « import_export « gitlab « lib « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 97e3caba9b3f18a8f0f463220d3cd8f7683ca3e2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Gitlab::ImportExport::SnippetRepoRestorer do
  let_it_be(:user) { create(:user) }

  let(:project) { create(:project, namespace: user.namespace) }
  let(:snippet) { create(:project_snippet, project: project, author: user) }
  let(:shared) { project.import_export_shared }
  let(:exporter) { Gitlab::ImportExport::SnippetsRepoSaver.new(project: project, shared: shared, current_user: user) }
  let(:restorer) do
    described_class.new(
      user: user,
      shared: shared,
      snippet: snippet,
      path_to_bundle: snippet_bundle_path
    )
  end

  after do
    FileUtils.rm_rf(shared.export_path)
  end

  shared_examples 'no bundle file present' do
    it 'creates the repository from the database content' do
      expect(snippet.repository_exists?).to be_falsey

      aggregate_failures do
        expect do
          expect(restorer.restore).to be_truthy
        end.to change { SnippetRepository.count }.by(1)

        snippet.repository.expire_method_caches(%i[exists?])
        expect(snippet.repository_exists?).to be_truthy

        blob = snippet.repository.blob_at(snippet.default_branch, snippet.file_name)
        expect(blob).not_to be_nil
        expect(blob.data).to eq(snippet.content)
      end
    end

    it 'does not call snippet update statistics service' do
      expect(Snippets::UpdateStatisticsService).not_to receive(:new).with(snippet)

      restorer.restore
    end

    context 'when the repository creation fails' do
      it 'returns false' do
        allow_any_instance_of(Gitlab::BackgroundMigration::BackfillSnippetRepositories).to receive(:perform_by_ids).and_return(nil)

        expect(restorer.restore).to be false
        expect(shared.errors.first).to match(/Error creating repository for snippet/)
      end
    end
  end

  context 'when the snippet does not have a bundle file path' do
    let(:snippet_bundle_path) { nil }

    it_behaves_like 'no bundle file present'
  end

  context 'when the snippet bundle path is not present' do
    let(:snippet_bundle_path) { 'foo' }

    it_behaves_like 'no bundle file present'
  end

  context 'when the snippet repository bundle exists' do
    let!(:snippet_with_repo) { create(:project_snippet, :repository, project: project, author: user) }
    let(:bundle_path) { ::Gitlab::ImportExport.snippets_repo_bundle_path(shared.export_path) }
    let(:snippet_bundle_path) { File.join(bundle_path, "#{snippet_with_repo.hexdigest}.bundle") }
    let(:result) { exporter.save } # rubocop:disable Rails/SaveBang
    let(:repository) { snippet.repository }

    before do
      expect(exporter.save).to be_truthy

      allow_next_instance_of(Snippets::RepositoryValidationService) do |instance|
        allow(instance).to receive(:execute).and_return(ServiceResponse.success)
      end
    end

    context 'when it is valid' do
      before do
        allow(repository).to receive(:branch_count).and_return(1)
        allow(repository).to receive(:tag_count).and_return(0)
        allow(repository).to receive(:branch_names).and_return(['master'])
        allow(repository).to receive(:ls_files).and_return(['foo'])
      end

      it 'creates the repository from the bundle' do
        expect(snippet.repository_exists?).to be_falsey
        expect(snippet.snippet_repository).to be_nil
        expect(repository).to receive(:create_from_bundle).and_call_original

        expect(restorer.restore).to be_truthy
        expect(snippet.repository_exists?).to be_truthy
        expect(snippet.snippet_repository).not_to be_nil
      end

      it 'sets same shard in snippet repository as in the repository storage' do
        expect(repository).to receive(:storage).and_return('picked')
        expect(repository).to receive(:create_from_bundle)

        expect(restorer.restore).to be_truthy
        expect(snippet.snippet_repository.shard_name).to eq 'picked'
      end
    end

    context 'when it is invalid' do
      it 'returns false and deletes the repository from disk and the database' do
        gitlab_shell = Gitlab::Shell.new
        shard_name = snippet.repository.shard
        path = snippet.disk_path + '.git'
        error_response = ServiceResponse.error(message: 'Foo', http_status: 400)

        allow_next_instance_of(Snippets::RepositoryValidationService) do |instance|
          allow(instance).to receive(:execute).and_return(error_response)
        end

        aggregate_failures do
          expect(restorer.restore).to be false
          expect(shared.errors.first).to match(/Invalid repository bundle/)
          expect(snippet.repository_exists?).to eq false
          expect(snippet.reload.snippet_repository).to be_nil
          expect(gitlab_shell.repository_exists?(shard_name, path)).to eq false
        end
      end
    end

    it 'refreshes snippet statistics' do
      expect(snippet.statistics.commit_count).to be_zero
      expect(snippet.statistics.file_count).to be_zero
      expect(snippet.statistics.repository_size).to be_zero

      expect(Snippets::UpdateStatisticsService).to receive(:new).with(snippet).and_call_original

      restorer.restore

      expect(snippet.statistics.commit_count).not_to be_zero
      expect(snippet.statistics.file_count).not_to be_zero
      expect(snippet.statistics.repository_size).not_to be_zero
    end
  end
end