Add SnippetRepositoryStorageMove class

This new class will store the repository storage
changes for snippets.
parent eaa75548
......@@ -44,6 +44,7 @@ class Snippet < ApplicationRecord
has_many :notes, as: :noteable, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_many :user_mentions, class_name: "SnippetUserMention", dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_one :snippet_repository, inverse_of: :snippet
has_many :repository_storage_moves, class_name: 'SnippetRepositoryStorageMove', inverse_of: :container
# We need to add the `dependent` in order to call the after_destroy callback
has_one :statistics, class_name: 'SnippetStatistics', dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
......
# frozen_string_literal: true
# SnippetRepositoryStorageMove are details of repository storage moves for a
# snippet. For example, moving a snippet to another gitaly node to help
# balance storage capacity.
class SnippetRepositoryStorageMove < ApplicationRecord
extend ::Gitlab::Utils::Override
include RepositoryStorageMovable
belongs_to :container, class_name: 'Snippet', inverse_of: :repository_storage_moves, foreign_key: :snippet_id
alias_attribute :snippet, :container
override :schedule_repository_storage_update_worker
def schedule_repository_storage_update_worker
# TODO https://gitlab.com/gitlab-org/gitlab/-/issues/218991
end
private
override :error_key
def error_key
:snippet
end
end
# frozen_string_literal: true
FactoryBot.define do
factory :snippet_repository_storage_move, class: 'SnippetRepositoryStorageMove' do
container { association(:snippet) }
source_storage_name { 'default' }
trait :scheduled do
state { SnippetRepositoryStorageMove.state_machines[:state].states[:scheduled].value }
end
trait :started do
state { SnippetRepositoryStorageMove.state_machines[:state].states[:started].value }
end
trait :replicated do
state { SnippetRepositoryStorageMove.state_machines[:state].states[:replicated].value }
end
trait :finished do
state { SnippetRepositoryStorageMove.state_machines[:state].states[:finished].value }
end
trait :failed do
state { SnippetRepositoryStorageMove.state_machines[:state].states[:failed].value }
end
end
end
......@@ -107,6 +107,7 @@ snippets:
- user_mentions
- snippet_repository
- statistics
- repository_storage_moves
releases:
- author
- project
......
......@@ -3,11 +3,33 @@
require 'spec_helper'
RSpec.describe ProjectRepositoryStorageMove, type: :model do
it_behaves_like 'handles repository moves' do
let_it_be_with_refind(:container) { create(:project) }
let_it_be_with_refind(:project) { create(:project) }
it_behaves_like 'handles repository moves' do
let(:container) { project }
let(:repository_storage_factory_key) { :project_repository_storage_move }
let(:error_key) { :project }
let(:repository_storage_worker) { ProjectUpdateRepositoryStorageWorker }
end
describe 'state transitions' do
let(:storage) { 'test_second_storage' }
before do
stub_storage_settings(storage => { 'path' => 'tmp/tests/extra_storage' })
end
context 'when started' do
subject(:storage_move) { create(:project_repository_storage_move, :started, container: project, destination_storage_name: storage) }
context 'and transits to replicated' do
it 'sets the repository storage and marks the container as writable' do
storage_move.finish_replication!
expect(project.repository_storage).to eq(storage)
expect(project).not_to be_repository_read_only
end
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe SnippetRepositoryStorageMove, type: :model do
it_behaves_like 'handles repository moves' do
let_it_be_with_refind(:container) { create(:snippet) }
let(:repository_storage_factory_key) { :snippet_repository_storage_move }
let(:error_key) { :snippet }
let(:repository_storage_worker) { nil } # TODO set to SnippetUpdateRepositoryStorageWorker after https://gitlab.com/gitlab-org/gitlab/-/issues/218991 is implemented
end
end
......@@ -21,6 +21,7 @@ RSpec.describe Snippet do
it { is_expected.to have_many(:user_mentions).class_name("SnippetUserMention") }
it { is_expected.to have_one(:snippet_repository) }
it { is_expected.to have_one(:statistics).class_name('SnippetStatistics').dependent(:destroy) }
it { is_expected.to have_many(:repository_storage_moves).class_name('SnippetRepositoryStorageMove').inverse_of(:container) }
end
describe 'validation' do
......
......@@ -63,6 +63,7 @@ RSpec.shared_examples 'handles repository moves' do
context 'and transits to scheduled' do
it 'triggers the corresponding repository storage worker' do
skip unless repository_storage_worker # TODO remove after https://gitlab.com/gitlab-org/gitlab/-/issues/218991 is implemented
expect(repository_storage_worker).to receive(:perform_async).with(container.id, 'test_second_storage', storage_move.id)
storage_move.schedule!
......@@ -72,6 +73,7 @@ RSpec.shared_examples 'handles repository moves' do
context 'when the transition fails' do
it 'does not trigger ProjectUpdateRepositoryStorageWorker and adds an error' do
skip unless repository_storage_worker # TODO remove after https://gitlab.com/gitlab-org/gitlab/-/issues/218991 is implemented
allow(storage_move.container).to receive(:set_repository_read_only!).and_raise(StandardError, 'foobar')
expect(repository_storage_worker).not_to receive(:perform_async)
......@@ -94,10 +96,9 @@ RSpec.shared_examples 'handles repository moves' do
subject(:storage_move) { create(repository_storage_factory_key, :started, container: container, destination_storage_name: 'test_second_storage') }
context 'and transits to replicated' do
it 'sets the repository storage and marks the container as writable' do
it 'marks the container as writable' do
storage_move.finish_replication!
expect(container.repository_storage).to eq('test_second_storage')
expect(container).not_to be_repository_read_only
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment