Skip to content

Commit 46b1187

Browse files
committed
Introduce better Compact Index API stub for testing.
1 parent b70f364 commit 46b1187

3 files changed

Lines changed: 126 additions & 21 deletions

File tree

test/rubygems/helper.rb

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1143,6 +1143,25 @@ def write_marshalled_gemspecs(*all_specs)
11431143
end
11441144
end
11451145

1146+
##
1147+
# Sets up Compact Index API endpoints for testing. Does NOT set up old marshal API.
1148+
# This causes Source#new_dependency_resolver_set to use APISet.
1149+
#
1150+
# Usage:
1151+
# compact_index do |ci|
1152+
# ci.gem "a", 1 do |s|
1153+
# s.add_dependency "b", ">= 2.0"
1154+
# end
1155+
# ci.gem "b", 2
1156+
# end
1157+
1158+
def compact_index(&block)
1159+
fake_compact_index = Gem::TestCase::CompactIndexSetup.new(self, @gem_repo)
1160+
yield fake_compact_index
1161+
fake_compact_index.stub
1162+
fake_compact_index.specs
1163+
end
1164+
11461165
##
11471166
# Deflates +data+
11481167

test/rubygems/test_gem_commands_install_command.rb

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1644,38 +1644,22 @@ def test_execute_bindir_with_nonexistent_parent_dirs
16441644
end
16451645

16461646
def test_install_from_compact_index_only_source
1647-
specs = spec_fetcher do |fetcher|
1648-
fetcher.gem "main-gem", "2" do |s|
1647+
compact_index do |ci|
1648+
ci.gem "main-gem", "2" do |s|
16491649
s.add_dependency "dep-gem", ">= 1.0"
16501650
end
1651-
fetcher.gem "dep-gem", "1"
1651+
ci.gem "dep-gem", "1"
16521652
end
16531653

1654-
compact_index_response = Gem::Net::HTTPResponse.new "1.1", 200, "OK"
1655-
compact_index_response.uri = Gem::URI(@gem_repo) + "versions"
1656-
@fetcher.data["#{@gem_repo}versions"] = compact_index_response
1657-
1658-
info_main_gem_response = <<~INFO
1659-
---
1660-
2 dep-gem:>= 1.0|ruby:>= 2.5.0,rubygems:>= 3.0.0
1661-
INFO
1662-
@fetcher.data["#{@gem_repo}info/main-gem"] = info_main_gem_response
1663-
1664-
info_dep_gem_response = <<~INFO
1665-
---
1666-
1 |ruby:>= 2.0.0
1667-
INFO
1668-
@fetcher.data["#{@gem_repo}info/dep-gem"] = info_dep_gem_response
1669-
1670-
@cmd.options[:args] = %w[main-gem] # gem install main-gem
1654+
@cmd.options[:args] = %w[main-gem]
16711655

16721656
use_ui @ui do
16731657
assert_raise Gem::MockGemUi::SystemExitException, @ui.error do
16741658
@cmd.execute
16751659
end
16761660
end
16771661

1678-
assert_equal %w[main-gem-2], @cmd.installed_specs.map(&:full_name)
1662+
assert_equal %w[dep-gem-1 main-gem-2], @cmd.installed_specs.map(&:full_name).sort
16791663

16801664
installed_gem = @cmd.installed_specs.find {|s| s.name == "main-gem" }
16811665
assert_equal "main-gem", installed_gem.name

test/rubygems/utilities.rb

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,108 @@ def write_spec(spec) # :nodoc:
420420
end
421421
end
422422

423+
##
424+
# Minimal CompactIndex implementation for tests.
425+
# This is a simplified version that only implements what's needed for test fixtures.
426+
module CompactIndexBuilder
427+
# Generates the /info/{gem_name} response body
428+
# Format: ---\nVERSION DEPS|METADATA\n
429+
# Where DEPS is: dep_name:requirement,dep_name:requirement
430+
# And METADATA is: checksum:SHA256,ruby:requirement,rubygems:requirement
431+
def self.info(versions)
432+
lines = ["---"]
433+
versions.each do |version|
434+
parts = [version.version]
435+
436+
# Add dependencies (if any)
437+
deps = version.dependencies.map {|d| "#{d.name}:#{d.requirement}" }
438+
deps_string = deps.join(",")
439+
440+
# Build metadata
441+
metadata = []
442+
metadata << "checksum:#{version.checksum}" if version.checksum
443+
metadata << "ruby:#{version.ruby_version}" if version.ruby_version && version.ruby_version != ">= 0"
444+
metadata << "rubygems:#{version.rubygems_version}" if version.rubygems_version && version.rubygems_version != ">= 0"
445+
446+
# Format: "VERSION DEPS|METADATA" or "VERSION |METADATA" (space before | only when no deps)
447+
line = "#{version.version} #{deps_string}|" + metadata.join(",")
448+
lines << line
449+
end
450+
lines.join("\n") << "\n"
451+
end
452+
453+
GemVersion = Data.define(:version, :platform, :checksum, :info_checksum, :dependencies, :ruby_version, :rubygems_version) do
454+
def initialize(version:, platform:, checksum:, info_checksum: nil, dependencies: [], ruby_version: nil, rubygems_version: nil)
455+
super(version:, platform:, checksum:, info_checksum:, dependencies:, ruby_version:, rubygems_version:)
456+
end
457+
end
458+
459+
Dependency = Data.define(:name, :requirement)
460+
end
461+
462+
##
463+
# The CompactIndexSetup allows easy setup of compact index endpoints in tests.
464+
# Unlike SpecFetcherSetup, this only sets up compact index (no marshal API).
465+
#
466+
# compact_index do |ci|
467+
# ci.gem "a", 1 do |s|
468+
# s.add_dependency "b", "~> 2.0"
469+
# end
470+
# ci.gem "b", 2
471+
# end
472+
473+
class Gem::TestCase::CompactIndexSetup
474+
attr_reader :specs
475+
476+
def initialize(test, repository)
477+
@test = test
478+
@repository = repository
479+
@test.fetcher = Gem::FakeFetcher.new
480+
Gem::RemoteFetcher.fetcher = @test.fetcher
481+
@specs = {}
482+
end
483+
484+
def gem(name, version, dependencies = nil, &block)
485+
spec = @test.util_spec(name, version, dependencies, &block)
486+
@specs[spec.full_name] = spec
487+
end
488+
489+
def stub
490+
@specs.values.group_by(&:name).each do |name, gem_specs|
491+
versions = gem_specs.map do |spec|
492+
gem_file = Gem::Package.build(spec)
493+
gem_contents = Gem.read_binary(gem_file)
494+
FileUtils.cp gem_file, spec.cache_file
495+
496+
@test.fetcher.data["#{@repository}gems/#{spec.file_name}"] = gem_contents
497+
498+
dependencies = spec.dependencies.select(&:runtime?).map do |dep|
499+
CompactIndexBuilder::Dependency.new(dep.name, dep.requirement.to_s)
500+
end
501+
502+
checksum = Digest::SHA256.hexdigest(gem_contents)
503+
504+
CompactIndexBuilder::GemVersion.new(
505+
spec.version.to_s,
506+
spec.platform.to_s,
507+
checksum,
508+
nil,
509+
dependencies,
510+
spec.required_ruby_version.to_s,
511+
spec.required_rubygems_version.to_s
512+
)
513+
end
514+
515+
@test.fetcher.data["#{@repository}info/#{name}"] = CompactIndexBuilder.info(versions)
516+
end
517+
518+
# stub only to pass Compact Index API presence check currently
519+
versions_response = Gem::Net::HTTPResponse.new "1.1", 200, "OK"
520+
versions_response.uri = Gem::URI("#{@repository}versions")
521+
@test.fetcher.data["#{@repository}versions"] = versions_response
522+
end
523+
end
524+
423525
##
424526
# A StringIO duck-typed class that uses Tempfile instead of String as the
425527
# backing store.

0 commit comments

Comments
 (0)