Skip to content

Commit

Permalink
add disassociation of obsolete repos from product after sync
Browse files Browse the repository at this point in the history
  • Loading branch information
paragjain0910 committed Jan 9, 2025
1 parent b6d73c7 commit a916bc9
Show file tree
Hide file tree
Showing 5 changed files with 174 additions and 6 deletions.
1 change: 1 addition & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ RSpec/MultipleExpectations:
Metrics/ClassLength:
Exclude:
- lib/rmt/downloader.rb
Max: 250

Naming/FileName:
Exclude:
Expand Down
2 changes: 0 additions & 2 deletions engines/scc_proxy/lib/scc_proxy/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,6 @@ def scc_upgrade(auth, product, system_login, mode, logger)
end
end

# rubocop:disable Metrics/ClassLength
class Engine < ::Rails::Engine
isolate_namespace SccProxy
config.generators.api_only = true
Expand Down Expand Up @@ -534,6 +533,5 @@ def get_system(systems)
end
end
end
# rubocop:enable Metrics/ClassLength
end
# rubocop:enable Metrics/ModuleLength
20 changes: 18 additions & 2 deletions lib/rmt/scc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ def sync

def remove_obsolete_repositories(repos_data)
@logger.info _('Removing obsolete repositories')
return if repos_data.empty?

scc_repo_ids = repos_data.pluck(:id)


# Find repositories in RMT that no longer exist in SCC
# Only consider repositories that have a non-null scc_id
repos_to_remove = Repository.where.not(scc_id: nil)
.where.not(scc_id: scc_repo_ids)
repos_to_remove = Repository.only_scc.where.not(scc_id: scc_repo_ids)
if repos_to_remove.any?
repos_to_remove.delete_all
@logger.info("Successfully removed #{repos_to_remove.count} obsolete repositories")
Expand Down Expand Up @@ -203,8 +204,23 @@ def create_product(item, root_product_id = nil, base_product = nil, recommended

def create_service(item, product)
product.find_or_create_service!
existing_repo_ids = product.repositories.only_scc.pluck(:scc_id)

item[:repositories].each do |repo_item|
repository_service.update_or_create_repository!(product, repo_item[:url], repo_item)
existing_repo_ids.delete(repo_item[:id])
end
disassociate_obsolete_repositories(product, existing_repo_ids)
end

def disassociate_obsolete_repositories(product, existing_repo_ids)
existing_repo_ids.each do |repo_id|
repository = product.repositories.only_scc.find_by(scc_id: repo_id)
if repository
product.service.repositories_services_associations
.where(repository_id: repository.id)
.destroy_all
end
end
end

Expand Down
7 changes: 7 additions & 0 deletions spec/factories/services.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,10 @@
end
end
end

FactoryBot.define do
factory :repositories_services_association do
association :repository
association :service
end
end
150 changes: 148 additions & 2 deletions spec/lib/rmt/scc_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@

describe '#remove_suse_repos_without_tokens' do
let(:api_double) { double }
let!(:suse_repo_with_token) { FactoryBot.create(:repository, :with_products, auth_token: 'auth_token') }
let!(:suse_repo_with_token) { FactoryBot.create(:repository, :with_products, auth_token: 'auth_token', scc_id: 200000) }
let!(:suse_repo_without_token) do
FactoryBot.create(
:repository,
Expand All @@ -262,7 +262,8 @@
:with_products,
auth_token: nil,
external_url: 'https://installer-updates.suse.com/repos/not/updates',
installer_updates: true
installer_updates: true,
scc_id: 200001
)
end
let!(:custom_repo) do
Expand Down Expand Up @@ -314,6 +315,151 @@ def scc
end
end

describe '#remove_obsolete_repositories' do
let(:api_double) { instance_double 'SUSE::Connect::Api' }
let(:logger) { instance_double('RMT::Logger').as_null_object }
let!(:suse_repo_one) { create(:repository, :with_products, scc_id: 1) }
let!(:suse_repo_two) { create(:repository, :with_products, scc_id: 2) }
let!(:custom_repo) { create(:repository, :with_products, scc_id: nil) }

before do
allow(Settings).to receive(:scc).and_return OpenStruct.new(username: 'foo', password: 'bar')
allow(RMT::Logger).to receive(:new).and_return(logger)
end

context 'when repos_data is empty' do
it 'returns early and does not remove any repositories' do
expect(Repository).not_to receive(:only_scc)
described_class.new.remove_obsolete_repositories([])
expect(Repository.count).to eq(3)
end
end

context 'when repos_data contains all existing SCC repositories' do
let(:repos_data) do
[
{ id: suse_repo_one.scc_id },
{ id: suse_repo_two.scc_id }
]
end

it 'does not remove any repositories' do
expect { described_class.new.remove_obsolete_repositories(repos_data) }.not_to change(Repository, :count)
end
end

context 'when repos_data is missing some existing SCC repositories' do
let(:repos_data) do
[
{ id: suse_repo_one.scc_id }
]
end

it 'removes only the obsolete SCC repositories' do
expect { described_class.new.remove_obsolete_repositories(repos_data) }.to change(Repository, :count).by(-1)

expect(Repository.find_by(id: suse_repo_one.id)).to be_present
expect(Repository.find_by(id: suse_repo_two.id)).to be_nil
expect(Repository.find_by(id: custom_repo.id)).to be_present
end
end

context 'when repos_data does not contain any existing SCC repository IDs' do
let(:repos_data) do
[
{ id: 999 }
]
end

it 'removes all SCC repositories' do
expect { described_class.new.remove_obsolete_repositories(repos_data) }.to change(Repository, :count).by(-2)

expect(Repository.find_by(id: suse_repo_one.id)).to be_nil
expect(Repository.find_by(id: suse_repo_two.id)).to be_nil
expect(Repository.find_by(id: custom_repo.id)).to be_present
end
end
end


describe '#disassociate_obsolete_repositories' do
let(:logger) { instance_double('RMT::Logger').as_null_object }
let(:product) { create(:product) }
let(:service) { create(:service, product: product) }

before do
allow(RMT::Logger).to receive(:new).and_return(logger)
end

context 'when existing_repo_ids is empty' do
it 'does not remove any associations' do
expect { described_class.new.send(:disassociate_obsolete_repositories, product, []) }.not_to change(RepositoriesServicesAssociation, :count)
end
end

context 'when existing_repo_ids contains repository IDs' do
let!(:repo_one) { create(:repository, :with_products, scc_id: 101) }
let!(:repo_two) { create(:repository, :with_products, scc_id: 102) }
let!(:repo_three) { create(:repository, :with_products, scc_id: 103) }
let(:existing_repo_ids) { [repo_one.scc_id, repo_two.scc_id] }

before do
# Associate repositories with the product through services
[repo_one, repo_two, repo_three].each do |repo|
create(:repositories_services_association,
repository: repo,
service: service)
end
end

it 'removes repository associations for the specified repo IDs' do
expect do
described_class.new.send(:disassociate_obsolete_repositories, product, existing_repo_ids)
end.to change(RepositoriesServicesAssociation, :count).by(-2)
end

it 'only removes associations for specified repositories' do
described_class.new.send(:disassociate_obsolete_repositories, product, existing_repo_ids)

expect(product.repositories).not_to include(repo_one)
expect(product.repositories).not_to include(repo_two)
expect(product.repositories).to include(repo_three)
end
end

context 'when repository no longer exists' do
let(:nonexistent_repo_id) { 999 }

it 'handles missing repositories gracefully' do
expect { described_class.new.send(:disassociate_obsolete_repositories, product, [nonexistent_repo_id]) }.not_to raise_error
end
end

context 'when product has no service' do
let(:product_without_service) { create(:product) }

it 'handles missing service gracefully' do
expect { described_class.new.send(:disassociate_obsolete_repositories, product_without_service, [123]) }.not_to raise_error
end
end

context 'with non-SCC repositories' do
let!(:custom_repo) { create(:repository, scc_id: nil) }

before do
create(:repositories_services_association,
repository: custom_repo,
service: service)
end

it 'only considers SCC repositories' do
expect do
described_class.new.send(:disassociate_obsolete_repositories, product, [custom_repo.id])
end.not_to change(RepositoriesServicesAssociation, :count)
end
end
end

describe '#export' do
let(:path) { '/tmp/usb' }

Expand Down

0 comments on commit a916bc9

Please sign in to comment.