1require 'rubygems/test_case' 2require 'rubygems/spec_fetcher' 3 4class TestGemSpecFetcher < Gem::TestCase 5 6 def tuple(*args) 7 Gem::NameTuple.new(*args) 8 end 9 10 def setup 11 super 12 13 @uri = URI.parse @gem_repo 14 @source = Gem::Source.new(@uri) 15 16 util_setup_fake_fetcher 17 18 @a_pre = new_spec 'a', '1.a' 19 20 install_specs @a_pre 21 22 Gem::Specification.remove_spec @b2 23 24 all = Gem::Specification.map { |spec| 25 Gem::NameTuple.new(spec.name, spec.version, spec.original_platform) 26 }.sort 27 28 @prerelease_specs, @specs = all.partition { |g| g.prerelease? } 29 30 # TODO: couldn't all of this come from the fake spec fetcher? 31 @latest_specs = Gem::Specification.latest_specs.sort.map { |spec| 32 Gem::NameTuple.new(spec.name, spec.version, spec.original_platform) 33 } 34 35 v = Gem.marshal_version 36 s_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@specs))) 37 l_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@latest_specs))) 38 p_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@prerelease_specs))) 39 @fetcher.data["#{@gem_repo}specs.#{v}.gz"] = s_zip 40 @fetcher.data["#{@gem_repo}latest_specs.#{v}.gz"] = l_zip 41 @fetcher.data["#{@gem_repo}prerelease_specs.#{v}.gz"] = p_zip 42 43 @sf = Gem::SpecFetcher.new 44 45 @released = Gem::NameTuple.from_list \ 46 [["a", Gem::Version.new("1"), "ruby"], 47 ["a", Gem::Version.new("2"), "ruby"], 48 ["a_evil", Gem::Version.new("9"), "ruby"], 49 ["c", Gem::Version.new("1.2"), "ruby"], 50 ['dep_x', Gem::Version.new(1), 'ruby'], 51 ["pl", Gem::Version.new("1"), "i386-linux"], 52 ['x', Gem::Version.new(1), 'ruby']] 53 end 54 55 def test_initialize_unwritable_home_dir 56 skip 'chmod not supported' if Gem.win_platform? 57 58 FileUtils.chmod 0000, Gem.user_home 59 60 begin 61 assert Gem::SpecFetcher.new 62 ensure 63 FileUtils.chmod 0755, Gem.user_home 64 end 65 end 66 67 def test_spec_for_dependency_all 68 d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" 69 @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) 70 @fetcher.data["#{d}#{@a2.spec_name}.rz"] = util_zip(Marshal.dump(@a2)) 71 @fetcher.data["#{d}#{@a_pre.spec_name}.rz"] = util_zip(Marshal.dump(@a_pre)) 72 @fetcher.data["#{d}#{@a3a.spec_name}.rz"] = util_zip(Marshal.dump(@a3a)) 73 74 dep = Gem::Dependency.new 'a', ">= 1" 75 76 specs_and_sources, _ = @sf.spec_for_dependency dep 77 78 spec_names = specs_and_sources.map do |spec, source_uri| 79 [spec.full_name, source_uri] 80 end 81 82 expected = [[@a1.full_name, @source], [@a2.full_name, @source]] 83 84 assert_equal expected, spec_names 85 86 assert_same specs_and_sources.first.last, specs_and_sources.last.last 87 end 88 89 def test_spec_for_dependency_latest 90 d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" 91 @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) 92 @fetcher.data["#{d}#{@a2.spec_name}.rz"] = util_zip(Marshal.dump(@a2)) 93 @fetcher.data["#{d}#{@a_pre.spec_name}.rz"] = util_zip(Marshal.dump(@a_pre)) 94 95 dep = Gem::Dependency.new 'a' 96 specs_and_sources, _ = @sf.spec_for_dependency dep 97 98 spec_names = specs_and_sources.map do |spec, source_uri| 99 [spec.full_name, source_uri] 100 end 101 102 assert_equal [[@a2.full_name, Gem::Source.new(@gem_repo)]], spec_names 103 end 104 105 def test_spec_for_dependency_prerelease 106 d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" 107 @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) 108 @fetcher.data["#{d}#{@a2.spec_name}.rz"] = util_zip(Marshal.dump(@a2)) 109 @fetcher.data["#{d}#{@a_pre.spec_name}.rz"] = util_zip(Marshal.dump(@a_pre)) 110 111 specs_and_sources, _ = @sf.spec_for_dependency dep('a', '1.a') 112 113 spec_names = specs_and_sources.map do |spec, source_uri| 114 [spec.full_name, source_uri] 115 end 116 117 assert_equal [[@a_pre.full_name, Gem::Source.new(@gem_repo)]], spec_names 118 end 119 120 def test_spec_for_dependency_platform 121 util_set_arch 'i386-linux' 122 123 @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@pl1.original_name}.gemspec.rz"] = 124 util_zip(Marshal.dump(@pl1)) 125 126 dep = Gem::Dependency.new 'pl', 1 127 specs_and_sources, _ = @sf.spec_for_dependency dep 128 129 spec_names = specs_and_sources.map do |spec, source_uri| 130 [spec.full_name, source_uri] 131 end 132 133 assert_equal [[@pl1.full_name, Gem::Source.new(@gem_repo)]], spec_names 134 end 135 136 def test_spec_for_dependency_mismatched_platform 137 util_set_arch 'hrpa-989' 138 139 @fetcher.data["#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}#{@pl1.original_name}.gemspec.rz"] = 140 util_zip(Marshal.dump(@pl1)) 141 142 dep = Gem::Dependency.new 'pl', 1 143 specs_and_sources, errors = @sf.spec_for_dependency dep 144 145 assert_equal 0, specs_and_sources.size 146 assert_equal 1, errors.size 147 pmm = errors.first 148 149 assert_equal "i386-linux", pmm.platforms.first 150 assert_equal "Found pl (1), but was for platform i386-linux", pmm.wordy 151 end 152 153 def test_spec_for_dependency_bad_fetch_spec 154 src = Gem::Source.new(@gem_repo) 155 def src.fetch_spec(name) 156 raise Gem::RemoteFetcher::FetchError.new("bad news from the internet", @uri) 157 end 158 159 Gem.sources.replace [src] 160 161 d = "#{@gem_repo}#{Gem::MARSHAL_SPEC_DIR}" 162 @fetcher.data["#{d}#{@a1.spec_name}.rz"] = util_zip(Marshal.dump(@a1)) 163 @fetcher.data["#{d}#{@a2.spec_name}.rz"] = util_zip(Marshal.dump(@a2)) 164 @fetcher.data["#{d}#{@a_pre.spec_name}.rz"] = util_zip(Marshal.dump(@a_pre)) 165 @fetcher.data["#{d}#{@a3a.spec_name}.rz"] = util_zip(Marshal.dump(@a3a)) 166 167 dep = Gem::Dependency.new 'a', ">= 1" 168 169 specs_and_sources, errors = @sf.spec_for_dependency dep 170 171 assert_equal [], specs_and_sources 172 sfp = errors.first 173 174 assert_kind_of Gem::SourceFetchProblem, sfp 175 assert_equal src, sfp.source 176 assert_equal "bad news from the internet (#{@gem_repo})", sfp.error.message 177 end 178 179 def test_available_specs_latest 180 specs, _ = @sf.available_specs(:latest) 181 182 assert_equal [@source], specs.keys 183 assert_equal @latest_specs, specs[@source].sort 184 end 185 186 def test_available_specs_released 187 specs, _ = @sf.available_specs(:released) 188 189 assert_equal [@source], specs.keys 190 191 assert_equal @released, specs[@source].sort 192 end 193 194 def test_available_specs_complete 195 specs, _ = @sf.available_specs(:complete) 196 197 assert_equal [@source], specs.keys 198 199 comp = @prerelease_specs + @released 200 201 assert_equal comp.sort, specs[@source].sort 202 end 203 204 def test_available_specs_complete_handles_no_prerelease 205 v = Gem.marshal_version 206 @fetcher.data.delete "#{@gem_repo}prerelease_specs.#{v}.gz" 207 208 specs, _ = @sf.available_specs(:complete) 209 210 assert_equal [@source], specs.keys 211 212 comp = @released 213 214 assert_equal comp.sort, specs[@source].sort 215 end 216 217 218 def test_available_specs_cache 219 specs, _ = @sf.available_specs(:latest) 220 221 refute specs[@source].empty? 222 223 @fetcher.data["#{@gem_repo}/latest_specs.#{Gem.marshal_version}.gz"] = nil 224 225 cached_specs, _ = @sf.available_specs(:latest) 226 227 assert_equal specs, cached_specs 228 end 229 230 def test_available_specs_cache_released 231 specs, _ = @sf.available_specs(:released) 232 233 refute specs[@source].empty? 234 235 @fetcher.data["#{@gem_repo}/specs.#{Gem.marshal_version}.gz"] = nil 236 237 cached_specs, _ = @sf.available_specs(:released) 238 239 assert_equal specs, cached_specs 240 end 241 242 def test_available_specs_prerelease 243 specs, _ = @sf.available_specs(:prerelease) 244 245 assert_equal @prerelease_specs, specs[@source].sort 246 end 247 248 def test_available_specs_with_bad_source 249 Gem.sources.replace ["http://not-there.nothing"] 250 251 specs, errors = @sf.available_specs(:latest) 252 253 assert_equal({}, specs) 254 assert_kind_of Gem::SourceFetchProblem, errors.first 255 end 256 257end 258 259