summaryrefslogtreecommitdiff
path: root/spec/services/packages
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services/packages')
-rw-r--r--spec/services/packages/create_dependency_service_spec.rb2
-rw-r--r--spec/services/packages/debian/extract_changes_metadata_service_spec.rb160
-rw-r--r--spec/services/packages/debian/extract_deb_metadata_service_spec.rb22
-rw-r--r--spec/services/packages/debian/extract_metadata_service_spec.rb10
-rw-r--r--spec/services/packages/debian/parse_debian822_service_spec.rb74
-rw-r--r--spec/services/packages/debian/process_changes_service_spec.rb58
-rw-r--r--spec/services/packages/go/create_package_service_spec.rb73
-rw-r--r--spec/services/packages/go/sync_packages_service_spec.rb40
-rw-r--r--spec/services/packages/maven/metadata/sync_service_spec.rb15
-rw-r--r--spec/services/packages/rubygems/create_dependencies_service_spec.rb33
-rw-r--r--spec/services/packages/rubygems/create_gemspec_service_spec.rb28
-rw-r--r--spec/services/packages/rubygems/metadata_extraction_service_spec.rb50
-rw-r--r--spec/services/packages/rubygems/process_gem_service_spec.rb134
13 files changed, 642 insertions, 57 deletions
diff --git a/spec/services/packages/create_dependency_service_spec.rb b/spec/services/packages/create_dependency_service_spec.rb
index 3ad59b31b2c..3eae9f099f7 100644
--- a/spec/services/packages/create_dependency_service_spec.rb
+++ b/spec/services/packages/create_dependency_service_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe Packages::CreateDependencyService do
describe '#execute' do
let_it_be(:namespace) {create(:namespace)}
let_it_be(:version) { '1.0.1' }
- let_it_be(:package_name) { "@#{namespace.path}/my-app".freeze }
+ let_it_be(:package_name) { "@#{namespace.path}/my-app" }
context 'when packages are published' do
let(:json_file) { 'packages/npm/payload.json' }
diff --git a/spec/services/packages/debian/extract_changes_metadata_service_spec.rb b/spec/services/packages/debian/extract_changes_metadata_service_spec.rb
new file mode 100644
index 00000000000..2a92b8ed26e
--- /dev/null
+++ b/spec/services/packages/debian/extract_changes_metadata_service_spec.rb
@@ -0,0 +1,160 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Debian::ExtractChangesMetadataService do
+ describe '#execute' do
+ let_it_be(:distribution) { create(:debian_project_distribution, codename: 'unstable') }
+ let_it_be(:incoming) { create(:debian_incoming, project: distribution.project) }
+
+ let(:package_file) { incoming.package_files.last }
+ let(:service) { described_class.new(package_file) }
+
+ subject { service.execute }
+
+ context 'with valid package file' do
+ it 'extract metadata', :aggregate_failures do
+ expected_fields = { 'Architecture' => 'source amd64', 'Binary' => 'libsample0 sample-dev sample-udeb' }
+
+ expect(subject[:file_type]).to eq(:changes)
+ expect(subject[:architecture]).to be_nil
+ expect(subject[:fields]).to include(expected_fields)
+ expect(subject[:files].count).to eq(6)
+ end
+ end
+
+ context 'with invalid package file' do
+ let(:package_file) { incoming.package_files.first }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "is not a changes file")
+ end
+ end
+
+ context 'with invalid metadata' do
+ let(:md5_dsc) { '3b0817804f669e16cdefac583ad88f0e 671 libs optional sample_1.2.3~alpha2.dsc' }
+ let(:md5_source) { 'd79b34f58f61ff4ad696d9bd0b8daa68 864 libs optional sample_1.2.3~alpha2.tar.xz' }
+ let(:md5s) { "#{md5_dsc}\n#{md5_source}" }
+ let(:sha1_dsc) { '32ecbd674f0bfd310df68484d87752490685a8d6 671 sample_1.2.3~alpha2.dsc' }
+ let(:sha1_source) { '5f8bba5574eb01ac3b1f5e2988e8c29307788236 864 sample_1.2.3~alpha2.tar.xz' }
+ let(:sha1s) { "#{sha1_dsc}\n#{sha1_source}" }
+ let(:sha256_dsc) { '844f79825b7e8aaa191e514b58a81f9ac1e58e2180134b0c9512fa66d896d7ba 671 sample_1.2.3~alpha2.dsc' }
+ let(:sha256_source) { 'b5a599e88e7cbdda3bde808160a21ba1dd1ec76b2ec8d4912aae769648d68362 864 sample_1.2.3~alpha2.tar.xz' }
+ let(:sha256s) { "#{sha256_dsc}\n#{sha256_source}" }
+ let(:fields) { { 'Files' => md5s, 'Checksums-Sha1' => sha1s, 'Checksums-Sha256' => sha256s } }
+ let(:metadata) { { file_type: :changes, architecture: 'amd64', fields: fields } }
+
+ before do
+ allow_next_instance_of(::Packages::Debian::ExtractMetadataService) do |extract_metadata_service|
+ allow(extract_metadata_service).to receive(:execute).and_return(metadata)
+ end
+ end
+
+ context 'without Files field' do
+ let(:md5s) { nil }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Files field is missing")
+ end
+ end
+
+ context 'without Checksums-Sha1 field' do
+ let(:sha1s) { nil }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Checksums-Sha1 field is missing")
+ end
+ end
+
+ context 'without Checksums-Sha256 field' do
+ let(:sha256s) { nil }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Checksums-Sha256 field is missing")
+ end
+ end
+
+ context 'with file in Checksums-Sha1 but not in Files' do
+ let(:md5_dsc) { '' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "sample_1.2.3~alpha2.dsc is listed in Checksums-Sha1 but not in Files")
+ end
+ end
+
+ context 'with different size in Checksums-Sha1' do
+ let(:sha1_dsc) { '32ecbd674f0bfd310df68484d87752490685a8d6 42 sample_1.2.3~alpha2.dsc' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Size for sample_1.2.3~alpha2.dsc in Files and Checksums-Sha1 differ")
+ end
+ end
+
+ context 'with file in Checksums-Sha256 but not in Files' do
+ let(:md5_dsc) { '' }
+ let(:sha1_dsc) { '' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "sample_1.2.3~alpha2.dsc is listed in Checksums-Sha256 but not in Files")
+ end
+ end
+
+ context 'with different size in Checksums-Sha256' do
+ let(:sha256_dsc) { '844f79825b7e8aaa191e514b58a81f9ac1e58e2180134b0c9512fa66d896d7ba 42 sample_1.2.3~alpha2.dsc' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Size for sample_1.2.3~alpha2.dsc in Files and Checksums-Sha256 differ")
+ end
+ end
+
+ context 'with file in Files but not in Checksums-Sha1' do
+ let(:sha1_dsc) { '' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Validation failed: Sha1sum can't be blank")
+ end
+ end
+
+ context 'with file in Files but not in Checksums-Sha256' do
+ let(:sha256_dsc) { '' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Validation failed: Sha256sum can't be blank")
+ end
+ end
+
+ context 'with invalid MD5' do
+ let(:md5_dsc) { '1234567890123456789012345678012 671 libs optional sample_1.2.3~alpha2.dsc' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Validation failed: Md5sum mismatch for sample_1.2.3~alpha2.dsc: 3b0817804f669e16cdefac583ad88f0e != 1234567890123456789012345678012")
+ end
+ end
+
+ context 'with invalid SHA1' do
+ let(:sha1_dsc) { '1234567890123456789012345678901234567890 671 sample_1.2.3~alpha2.dsc' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Validation failed: Sha1sum mismatch for sample_1.2.3~alpha2.dsc: 32ecbd674f0bfd310df68484d87752490685a8d6 != 1234567890123456789012345678901234567890")
+ end
+ end
+
+ context 'with invalid SHA256' do
+ let(:sha256_dsc) { '1234567890123456789012345678901234567890123456789012345678901234 671 sample_1.2.3~alpha2.dsc' }
+
+ it 'raise ArgumentError', :aggregate_failures do
+ expect { subject }.to raise_error(described_class::ExtractionError, "Validation failed: Sha256sum mismatch for sample_1.2.3~alpha2.dsc: 844f79825b7e8aaa191e514b58a81f9ac1e58e2180134b0c9512fa66d896d7ba != 1234567890123456789012345678901234567890123456789012345678901234")
+ end
+ end
+ end
+
+ context 'with missing package file' do
+ before do
+ incoming.package_files.first.destroy!
+ end
+
+ it 'raise ArgumentError' do
+ expect { subject }.to raise_error(described_class::ExtractionError, "sample_1.2.3~alpha2.tar.xz is listed in Files but was not uploaded")
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/debian/extract_deb_metadata_service_spec.rb b/spec/services/packages/debian/extract_deb_metadata_service_spec.rb
index 33059adf8a2..ee3f3d179dc 100644
--- a/spec/services/packages/debian/extract_deb_metadata_service_spec.rb
+++ b/spec/services/packages/debian/extract_deb_metadata_service_spec.rb
@@ -10,17 +10,17 @@ RSpec.describe Packages::Debian::ExtractDebMetadataService do
context 'with correct file' do
it 'return as expected' do
expected = {
- 'Package': 'libsample0',
- 'Source': 'sample',
- 'Version': '1.2.3~alpha2',
- 'Architecture': 'amd64',
- 'Maintainer': 'John Doe <john.doe@example.com>',
- 'Installed-Size': '7',
- 'Section': 'libs',
- 'Priority': 'optional',
- 'Multi-Arch': 'same',
- 'Homepage': 'https://gitlab.com/',
- 'Description': "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph."
+ 'Package' => 'libsample0',
+ 'Source' => 'sample',
+ 'Version' => '1.2.3~alpha2',
+ 'Architecture' => 'amd64',
+ 'Maintainer' => 'John Doe <john.doe@example.com>',
+ 'Installed-Size' => '7',
+ 'Section' => 'libs',
+ 'Priority' => 'optional',
+ 'Multi-Arch' => 'same',
+ 'Homepage' => 'https://gitlab.com/',
+ 'Description' => "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph."
}
expect(subject.execute).to eq expected
diff --git a/spec/services/packages/debian/extract_metadata_service_spec.rb b/spec/services/packages/debian/extract_metadata_service_spec.rb
index 0aa9a67b263..e3911dbbfe0 100644
--- a/spec/services/packages/debian/extract_metadata_service_spec.rb
+++ b/spec/services/packages/debian/extract_metadata_service_spec.rb
@@ -33,11 +33,11 @@ RSpec.describe Packages::Debian::ExtractMetadataService do
where(:case_name, :trait, :expected_file_type, :expected_architecture, :expected_fields) do
'with invalid' | :invalid | :unknown | nil | nil
'with source' | :source | :source | nil | nil
- 'with dsc' | :dsc | :dsc | nil | { 'Binary': 'sample-dev, libsample0, sample-udeb' }
- 'with deb' | :deb | :deb | 'amd64' | { 'Multi-Arch': 'same' }
- 'with udeb' | :udeb | :udeb | 'amd64' | { 'Package': 'sample-udeb' }
- 'with buildinfo' | :buildinfo | :buildinfo | nil | { 'Architecture': 'amd64 source', 'Build-Architecture': 'amd64' }
- 'with changes' | :changes | :changes | nil | { 'Architecture': 'source amd64', 'Binary': 'libsample0 sample-dev sample-udeb' }
+ 'with dsc' | :dsc | :dsc | nil | { 'Binary' => 'sample-dev, libsample0, sample-udeb' }
+ 'with deb' | :deb | :deb | 'amd64' | { 'Multi-Arch' => 'same' }
+ 'with udeb' | :udeb | :udeb | 'amd64' | { 'Package' => 'sample-udeb' }
+ 'with buildinfo' | :buildinfo | :buildinfo | nil | { 'Architecture' => 'amd64 source', 'Build-Architecture' => 'amd64' }
+ 'with changes' | :changes | :changes | nil | { 'Architecture' => 'source amd64', 'Binary' => 'libsample0 sample-dev sample-udeb' }
end
with_them do
diff --git a/spec/services/packages/debian/parse_debian822_service_spec.rb b/spec/services/packages/debian/parse_debian822_service_spec.rb
index b67daca89c4..f43e38991ce 100644
--- a/spec/services/packages/debian/parse_debian822_service_spec.rb
+++ b/spec/services/packages/debian/parse_debian822_service_spec.rb
@@ -27,17 +27,17 @@ RSpec.describe Packages::Debian::ParseDebian822Service do
it 'return as expected, preserving order' do
expected = {
'Package: libsample0' => {
- 'Package': 'libsample0',
- 'Source': 'sample',
- 'Version': '1.2.3~alpha2',
- 'Architecture': 'amd64',
- 'Maintainer': 'John Doe <john.doe@example.com>',
- 'Installed-Size': '9',
- 'Section': 'libs',
- 'Priority': 'optional',
- 'Multi-Arch': 'same',
- 'Homepage': 'https://gitlab.com/',
- 'Description': "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph."
+ 'Package' => 'libsample0',
+ 'Source' => 'sample',
+ 'Version' => '1.2.3~alpha2',
+ 'Architecture' => 'amd64',
+ 'Maintainer' => 'John Doe <john.doe@example.com>',
+ 'Installed-Size' => '9',
+ 'Section' => 'libs',
+ 'Priority' => 'optional',
+ 'Multi-Arch' => 'same',
+ 'Homepage' => 'https://gitlab.com/',
+ 'Description' => "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph."
}
}
@@ -51,38 +51,38 @@ RSpec.describe Packages::Debian::ParseDebian822Service do
it 'return as expected, preserving order' do
expected = {
'Source: sample' => {
- 'Source': 'sample',
- 'Priority': 'optional',
- 'Maintainer': 'John Doe <john.doe@example.com>',
- 'Build-Depends': 'debhelper-compat (= 13)',
- 'Standards-Version': '4.5.0',
- 'Section': 'libs',
- 'Homepage': 'https://gitlab.com/',
- # 'Vcs-Browser': 'https://salsa.debian.org/debian/sample-1.2.3',
- # '#Vcs-Git': 'https://salsa.debian.org/debian/sample-1.2.3.git',
- 'Rules-Requires-Root': 'no'
+ 'Source' => 'sample',
+ 'Priority' => 'optional',
+ 'Maintainer' => 'John Doe <john.doe@example.com>',
+ 'Build-Depends' => 'debhelper-compat (= 13)',
+ 'Standards-Version' => '4.5.0',
+ 'Section' => 'libs',
+ 'Homepage' => 'https://gitlab.com/',
+ # 'Vcs-Browser' => 'https://salsa.debian.org/debian/sample-1.2.3',
+ # '#Vcs-Git' => 'https://salsa.debian.org/debian/sample-1.2.3.git',
+ 'Rules-Requires-Root' => 'no'
},
'Package: sample-dev' => {
- 'Package': 'sample-dev',
- 'Section': 'libdevel',
- 'Architecture': 'any',
- 'Multi-Arch': 'same',
- 'Depends': 'libsample0 (= ${binary:Version}), ${misc:Depends}',
- 'Description': "Some mostly empty developpement files\nUsed in GitLab tests.\n\nTesting another paragraph."
+ 'Package' => 'sample-dev',
+ 'Section' => 'libdevel',
+ 'Architecture' => 'any',
+ 'Multi-Arch' => 'same',
+ 'Depends' => 'libsample0 (= ${binary:Version}), ${misc:Depends}',
+ 'Description' => "Some mostly empty developpement files\nUsed in GitLab tests.\n\nTesting another paragraph."
},
'Package: libsample0' => {
- 'Package': 'libsample0',
- 'Architecture': 'any',
- 'Multi-Arch': 'same',
- 'Depends': '${shlibs:Depends}, ${misc:Depends}',
- 'Description': "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph."
+ 'Package' => 'libsample0',
+ 'Architecture' => 'any',
+ 'Multi-Arch' => 'same',
+ 'Depends' => '${shlibs:Depends}, ${misc:Depends}',
+ 'Description' => "Some mostly empty lib\nUsed in GitLab tests.\n\nTesting another paragraph."
},
'Package: sample-udeb' => {
- 'Package': 'sample-udeb',
- 'Package-Type': 'udeb',
- 'Architecture': 'any',
- 'Depends': 'installed-base',
- 'Description': 'Some mostly empty udeb'
+ 'Package' => 'sample-udeb',
+ 'Package-Type' => 'udeb',
+ 'Architecture' => 'any',
+ 'Depends' => 'installed-base',
+ 'Description' => 'Some mostly empty udeb'
}
}
diff --git a/spec/services/packages/debian/process_changes_service_spec.rb b/spec/services/packages/debian/process_changes_service_spec.rb
new file mode 100644
index 00000000000..98b531bde10
--- /dev/null
+++ b/spec/services/packages/debian/process_changes_service_spec.rb
@@ -0,0 +1,58 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Debian::ProcessChangesService do
+ describe '#execute' do
+ let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:distribution) { create(:debian_project_distribution, :with_file, codename: 'unstable') }
+ let_it_be(:incoming) { create(:debian_incoming, project: distribution.project) }
+
+ let(:package_file) { incoming.package_files.last }
+
+ subject { described_class.new(package_file, user) }
+
+ context 'with valid package file' do
+ it 'updates package and package file', :aggregate_failures do
+ expect { subject.execute }
+ .to change { Packages::Package.count }.from(1).to(2)
+ .and not_change { Packages::PackageFile.count }
+ .and change { incoming.package_files.count }.from(7).to(0)
+
+ created_package = Packages::Package.last
+ expect(created_package.name).to eq 'sample'
+ expect(created_package.version).to eq '1.2.3~alpha2'
+ expect(created_package.creator).to eq user
+ end
+ end
+
+ context 'with invalid package file' do
+ let(:package_file) { incoming.package_files.first }
+
+ it 'raise ExtractionError', :aggregate_failures do
+ expect { subject.execute }
+ .to not_change { Packages::Package.count }
+ .and not_change { Packages::PackageFile.count }
+ .and not_change { incoming.package_files.count }
+ .and not_change { distribution.reload.needs_update? }
+ .and raise_error(Packages::Debian::ExtractChangesMetadataService::ExtractionError, 'is not a changes file')
+ end
+ end
+
+ context 'when creating package fails' do
+ before do
+ allow_next_instance_of(::Packages::Debian::FindOrCreatePackageService) do |find_or_create_package_service|
+ expect(find_or_create_package_service).to receive(:execute).and_raise(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
+ end
+ end
+
+ it 'remove the package file', :aggregate_failures do
+ expect { subject.execute }
+ .to not_change { Packages::Package.count }
+ .and not_change { Packages::PackageFile.count }
+ .and not_change { incoming.package_files.count }
+ .and not_change { distribution.reload.needs_update? }
+ .and raise_error(ActiveRecord::ConnectionTimeoutError, 'connect timeout')
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/go/create_package_service_spec.rb b/spec/services/packages/go/create_package_service_spec.rb
new file mode 100644
index 00000000000..5c5fec0aa3a
--- /dev/null
+++ b/spec/services/packages/go/create_package_service_spec.rb
@@ -0,0 +1,73 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Go::CreatePackageService do
+ let_it_be(:project) { create :project_empty_repo, path: 'my-go-lib' }
+ let_it_be(:mod) { create :go_module, project: project }
+
+ before :all do
+ create :go_module_commit, :module, project: project, tag: 'v1.0.0'
+ end
+
+ shared_examples 'creates a package' do |files:|
+ it "returns a valid package with #{files ? files.to_s : 'no'} file(s)" do
+ expect(subject).to be_valid
+ expect(subject.name).to eq(version.mod.name)
+ expect(subject.version).to eq(version.name)
+ expect(subject.package_type).to eq('golang')
+ expect(subject.created_at).to eq(version.commit.committed_date)
+ expect(subject.package_files.count).to eq(files)
+ end
+ end
+
+ shared_examples 'creates a package file' do |type|
+ it "returns a package with a #{type} file" do
+ file_name = "#{version.name}.#{type}"
+ expect(subject.package_files.map { |f| f.file_name }).to include(file_name)
+
+ file = subject.package_files.with_file_name(file_name).first
+ expect(file).not_to be_nil
+ expect(file.file).not_to be_nil
+ expect(file.size).to eq(file.file.size)
+ expect(file.file_name).to eq(file_name)
+ expect(file.file_md5).not_to be_nil
+ expect(file.file_sha1).not_to be_nil
+ expect(file.file_sha256).not_to be_nil
+ end
+ end
+
+ describe '#execute' do
+ subject { described_class.new(project, nil, version: version).execute }
+
+ let(:version) { create :go_module_version, :tagged, mod: mod, name: 'v1.0.0' }
+
+ context 'with no existing package' do
+ it_behaves_like 'creates a package', files: 2
+ it_behaves_like 'creates a package file', :mod
+ it_behaves_like 'creates a package file', :zip
+
+ it 'creates a new package' do
+ expect { subject }
+ .to change { project.packages.count }.by(1)
+ .and change { Packages::PackageFile.count }.by(2)
+ end
+ end
+
+ context 'with an existing package' do
+ before do
+ described_class.new(project, version: version).execute
+ end
+
+ it_behaves_like 'creates a package', files: 2
+ it_behaves_like 'creates a package file', :mod
+ it_behaves_like 'creates a package file', :zip
+
+ it 'does not create a package or files' do
+ expect { subject }
+ .to not_change { project.packages.count }
+ .and not_change { Packages::PackageFile.count }
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/go/sync_packages_service_spec.rb b/spec/services/packages/go/sync_packages_service_spec.rb
new file mode 100644
index 00000000000..565b0f252ce
--- /dev/null
+++ b/spec/services/packages/go/sync_packages_service_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Go::SyncPackagesService do
+ include_context 'basic Go module'
+
+ let(:params) { { info: true, mod: true, zip: true } }
+
+ describe '#execute_async' do
+ it 'schedules a package refresh' do
+ expect(::Packages::Go::SyncPackagesWorker).to receive(:perform_async).once
+
+ described_class.new(project, 'master').execute_async
+ end
+ end
+
+ describe '#initialize' do
+ context 'without a project' do
+ it 'raises an error' do
+ expect { described_class.new(nil, 'master') }
+ .to raise_error(ArgumentError, 'project is required')
+ end
+ end
+
+ context 'without a ref' do
+ it 'raises an error' do
+ expect { described_class.new(project, nil) }
+ .to raise_error(ArgumentError, 'ref is required')
+ end
+ end
+
+ context 'with an invalid ref' do
+ it 'raises an error' do
+ expect { described_class.new(project, 'not-a-ref') }
+ .to raise_error(ArgumentError)
+ end
+ end
+ end
+end
diff --git a/spec/services/packages/maven/metadata/sync_service_spec.rb b/spec/services/packages/maven/metadata/sync_service_spec.rb
index f5634159e6d..30ddb48207a 100644
--- a/spec/services/packages/maven/metadata/sync_service_spec.rb
+++ b/spec/services/packages/maven/metadata/sync_service_spec.rb
@@ -131,7 +131,7 @@ RSpec.describe ::Packages::Maven::Metadata::SyncService do
expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
end
- it_behaves_like 'returning an error service response', message: 'Non existing versionless package'
+ it_behaves_like 'returning a success service response', message: 'Non existing versionless package(s). Nothing to do.'
end
context 'without a metadata package file for versions' do
@@ -141,7 +141,7 @@ RSpec.describe ::Packages::Maven::Metadata::SyncService do
expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
end
- it_behaves_like 'returning an error service response', message: 'Non existing metadata file for versions'
+ it_behaves_like 'returning a success service response', message: 'Non existing versionless package(s). Nothing to do.'
end
context 'without a project' do
@@ -205,7 +205,7 @@ RSpec.describe ::Packages::Maven::Metadata::SyncService do
it_behaves_like 'returning a success service response', message: 'Versionless package for versions destroyed'
end
- context 'with a too big maven metadata file for versions' do
+ context 'with a too big maven metadata file for plugins' do
before do
metadata_file_for_plugins.update!(size: 100.megabytes)
end
@@ -244,6 +244,15 @@ RSpec.describe ::Packages::Maven::Metadata::SyncService do
it_behaves_like 'returning a success service response', message: 'New metadata package files created'
end
+ context 'without a versionless package for versions' do
+ before do
+ versionless_package_for_versions.package_files.update_all(file_name: 'test.txt')
+ expect(::Packages::Maven::Metadata::CreateVersionsXmlService).not_to receive(:new)
+ end
+
+ it_behaves_like 'returning a success service response', message: 'No changes for plugins xml'
+ end
+
context 'without a metadata package file for plugins' do
before do
versionless_package_for_plugins.package_files.update_all(file_name: 'test.txt')
diff --git a/spec/services/packages/rubygems/create_dependencies_service_spec.rb b/spec/services/packages/rubygems/create_dependencies_service_spec.rb
new file mode 100644
index 00000000000..b6e12b1cc61
--- /dev/null
+++ b/spec/services/packages/rubygems/create_dependencies_service_spec.rb
@@ -0,0 +1,33 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Rubygems::CreateDependenciesService do
+ include RubygemsHelpers
+
+ let_it_be(:package) { create(:rubygems_package) }
+ let_it_be(:package_file) { create(:package_file, :gem) }
+ let_it_be(:gem) { gem_from_file(package_file.file) }
+ let_it_be(:gemspec) { gem.spec }
+
+ let(:service) { described_class.new(package, gemspec) }
+
+ describe '#execute' do
+ subject { service.execute }
+
+ it 'creates dependencies', :aggregate_failures do
+ expect { subject }.to change { Packages::Dependency.count }.by(4)
+
+ gemspec.dependencies.each do |dependency|
+ persisted_dependency = Packages::Dependency.find_by(name: dependency.name)
+
+ expect(persisted_dependency.version_pattern).to eq dependency.requirement.to_s
+ end
+ end
+
+ it 'links dependencies to the package' do
+ expect { subject }.to change { package.dependency_links.count }.by(4)
+
+ expect(package.dependency_links.first).to be_dependencies
+ end
+ end
+end
diff --git a/spec/services/packages/rubygems/create_gemspec_service_spec.rb b/spec/services/packages/rubygems/create_gemspec_service_spec.rb
new file mode 100644
index 00000000000..198e978a47e
--- /dev/null
+++ b/spec/services/packages/rubygems/create_gemspec_service_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+require 'spec_helper'
+
+RSpec.describe Packages::Rubygems::CreateGemspecService do
+ include RubygemsHelpers
+
+ let_it_be(:package_file) { create(:package_file, :gem) }
+ let_it_be(:gem) { gem_from_file(package_file.file) }
+ let_it_be(:gemspec) { gem.spec }
+ let_it_be(:package) { package_file.package }
+
+ let(:service) { described_class.new(package, gemspec) }
+
+ describe '#execute' do
+ subject { service.execute }
+
+ it 'creates a new package file', :aggregate_failures do
+ expect { subject }.to change { package.package_files.count }.by(1)
+
+ gemspec_file = package.package_files.find_by(file_name: "#{gemspec.name}.gemspec")
+ expect(gemspec_file.file).not_to be_nil
+ expect(gemspec_file.size).not_to be_nil
+ expect(gemspec_file.file_md5).not_to be_nil
+ expect(gemspec_file.file_sha1).not_to be_nil
+ expect(gemspec_file.file_sha256).not_to be_nil
+ end
+ end
+end
diff --git a/spec/services/packages/rubygems/metadata_extraction_service_spec.rb b/spec/services/packages/rubygems/metadata_extraction_service_spec.rb
new file mode 100644
index 00000000000..b308daad8f5
--- /dev/null
+++ b/spec/services/packages/rubygems/metadata_extraction_service_spec.rb
@@ -0,0 +1,50 @@
+# frozen_string_literal: true
+require 'spec_helper'
+require 'rubygems/package'
+
+RSpec.describe Packages::Rubygems::MetadataExtractionService do
+ include RubygemsHelpers
+
+ let_it_be(:package) { create(:rubygems_package) }
+ let_it_be(:package_file) { create(:package_file, :gem) }
+ let_it_be(:gem) { gem_from_file(package_file.file) }
+ let_it_be(:gemspec) { gem.spec }
+
+ let(:service) { described_class.new(package, gemspec) }
+
+ describe '#execute' do
+ subject { service.execute }
+
+ it 'creates the metadata' do
+ expect { subject }.to change { Packages::Rubygems::Metadatum.count }.by(1)
+ end
+
+ it 'stores the metadata', :aggregate_failures do
+ subject
+
+ metadata = package.rubygems_metadatum
+
+ expect(metadata.authors).to eq(gemspec.authors.to_json)
+ expect(metadata.files).to eq(gemspec.files.to_json)
+ expect(metadata.summary).to eq(gemspec.summary)
+ expect(metadata.description).to eq(gemspec.description)
+ expect(metadata.email).to eq(gemspec.email)
+ expect(metadata.homepage).to eq(gemspec.homepage)
+ expect(metadata.licenses).to eq(gemspec.licenses.to_json)
+ expect(metadata.metadata).to eq(gemspec.metadata.to_json)
+ expect(metadata.author).to eq(gemspec.author)
+ expect(metadata.bindir).to eq(gemspec.bindir)
+ expect(metadata.executables).to eq(gemspec.executables.to_json)
+ expect(metadata.extensions).to eq(gemspec.extensions.to_json)
+ expect(metadata.extra_rdoc_files).to eq(gemspec.extra_rdoc_files.to_json)
+ expect(metadata.platform).to eq(gemspec.platform)
+ expect(metadata.post_install_message).to eq(gemspec.post_install_message)
+ expect(metadata.rdoc_options).to eq(gemspec.rdoc_options.to_json)
+ expect(metadata.require_paths).to eq(gemspec.require_paths.to_json)
+ expect(metadata.required_ruby_version).to eq(gemspec.required_ruby_version.to_s)
+ expect(metadata.required_rubygems_version).to eq(gemspec.required_rubygems_version.to_s)
+ expect(metadata.requirements).to eq(gemspec.requirements.to_json)
+ expect(metadata.rubygems_version).to eq(gemspec.rubygems_version)
+ end
+ end
+end
diff --git a/spec/services/packages/rubygems/process_gem_service_spec.rb b/spec/services/packages/rubygems/process_gem_service_spec.rb
new file mode 100644
index 00000000000..83e868d9579
--- /dev/null
+++ b/spec/services/packages/rubygems/process_gem_service_spec.rb
@@ -0,0 +1,134 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Packages::Rubygems::ProcessGemService do
+ include ExclusiveLeaseHelpers
+ include RubygemsHelpers
+
+ let_it_be_with_reload(:package) { create(:rubygems_package, :processing, name: 'temp_name', version: '0.0.0') }
+
+ let(:package_file) { create(:package_file, :unprocessed_gem, package: package) }
+ let(:gem) { gem_from_file(package_file.file) }
+ let(:gemspec) { gem.spec }
+ let(:service) { described_class.new(package_file) }
+
+ describe '#execute' do
+ subject { service.execute }
+
+ context 'no gem file', :aggregate_failures do
+ let(:package_file) { nil }
+
+ it 'returns an error' do
+ expect(subject.error?).to be(true)
+ expect(subject.message).to eq('Gem was not processed')
+ end
+ end
+
+ context 'success' do
+ let(:sub_service) { double }
+
+ before do
+ expect(Packages::Rubygems::MetadataExtractionService).to receive(:new).with(package, gemspec).and_return(sub_service)
+ expect(Packages::Rubygems::CreateGemspecService).to receive(:new).with(package, gemspec).and_return(sub_service)
+ expect(Packages::Rubygems::CreateDependenciesService).to receive(:new).with(package, gemspec).and_return(sub_service)
+
+ expect(sub_service).to receive(:execute).exactly(3).times.and_return(true)
+ end
+
+ it 'returns successfully', :aggregate_failures do
+ result = subject
+
+ expect(result.success?).to be true
+ expect(result.payload[:package]).to eq(package)
+ end
+
+ it 'updates the package name and version', :aggregate_failures do
+ expect(package.name).to eq('temp_name')
+ expect(package.version).to eq('0.0.0')
+ expect(package).to be_processing
+
+ subject
+
+ expect(package.reload.name).to eq('package')
+ expect(package.version).to eq('0.0.1')
+ expect(package).to be_default
+ end
+
+ it 'updates the package file name', :aggregate_failures do
+ expect(package_file.file_name).to eq('package.gem')
+
+ subject
+
+ expect(package_file.reload.file_name).to eq('package-0.0.1.gem')
+ end
+ end
+
+ context 'when the package already exists' do
+ let_it_be(:existing_package) { create(:rubygems_package, name: 'package', version: '0.0.1', project: package.project) }
+
+ let(:sub_service) { double }
+
+ before do
+ expect(Packages::Rubygems::MetadataExtractionService).to receive(:new).with(existing_package, gemspec).and_return(sub_service)
+ expect(Packages::Rubygems::CreateGemspecService).to receive(:new).with(existing_package, gemspec).and_return(sub_service)
+ expect(Packages::Rubygems::CreateDependenciesService).to receive(:new).with(existing_package, gemspec).and_return(sub_service)
+
+ expect(sub_service).to receive(:execute).exactly(3).times.and_return(true)
+ end
+
+ it 'assigns the package_file to the existing package and deletes the temporary package', :aggregate_failures do
+ expect(package).to receive(:destroy)
+
+ expect { subject }.to change { existing_package.package_files.count }.by(1)
+
+ expect(package_file.reload.package).to eq(existing_package)
+ end
+ end
+
+ context 'sub-service failure' do
+ before do
+ expect(Packages::Rubygems::MetadataExtractionService).to receive(:new).with(package, gemspec).and_raise(::Packages::Rubygems::ProcessGemService::ExtractionError.new('failure'))
+ end
+
+ it 'returns an error' do
+ expect { subject }.to raise_error(::Packages::Rubygems::ProcessGemService::ExtractionError, 'failure')
+ end
+ end
+
+ context 'bad gem file' do
+ before do
+ expect(Gem::Package).to receive(:new).and_raise(ArgumentError)
+ end
+
+ it 'returns an error' do
+ expect { subject }.to raise_error(::Packages::Rubygems::ProcessGemService::ExtractionError, 'Unable to read gem file')
+ end
+ end
+
+ context 'without obtaining an exclusive lease' do
+ let(:lease_key) { "packages:rubygems:process_gem_service:package:#{package.id}" }
+
+ before do
+ stub_exclusive_lease_taken(lease_key, timeout: 1.hour)
+ end
+
+ it 'does not perform the services', :aggregate_failures do
+ # The #use_file call triggers a separate lease on the package file being opened
+ # for use with the gem. We don't want to test that here, so we allow the call to proceed
+ expect(Gitlab::ExclusiveLease).to receive(:new).with("object_storage_migrate:Packages::PackageFile:#{package_file.id}", anything).and_call_original
+
+ expect(Packages::Rubygems::MetadataExtractionService).not_to receive(:new)
+ expect(Packages::Rubygems::CreateGemspecService).not_to receive(:new)
+ expect(Packages::Rubygems::CreateDependenciesService).not_to receive(:new)
+
+ subject
+
+ expect(package.reload.name).to eq('temp_name')
+ expect(package.version).to eq('0.0.0')
+ expect(package).to be_processing
+ expect(package_file.reload.file_name).to eq('package.gem')
+ end
+ end
+ end
+end