@@ -7,8 +7,8 @@ def remote(cooldown:)
77 instance_double ( Bundler ::Source ::Rubygems ::Remote , effective_cooldown : cooldown )
88 end
99
10- def spec ( created_at :, remote :)
11- Struct . new ( :created_at , :remote ) . new ( created_at , remote )
10+ def spec ( created_at :, remote :, name : "myrack" , version : "1.0.0" )
11+ Struct . new ( :name , :version , : created_at, :remote ) . new ( name , Gem :: Version . new ( version ) , created_at , remote )
1212 end
1313
1414 describe "#filter_cooldown" do
@@ -18,8 +18,8 @@ def spec(created_at:, remote:)
1818 let ( :r ) { remote ( cooldown : 7 ) }
1919
2020 it "rejects versions published within the window" do
21- recent = spec ( created_at : now - ( 2 * 86_400 ) , remote : r )
22- old = spec ( created_at : now - ( 30 * 86_400 ) , remote : r )
21+ recent = spec ( version : "1.1.0" , created_at : now - ( 2 * 86_400 ) , remote : r )
22+ old = spec ( version : "1.0.0" , created_at : now - ( 30 * 86_400 ) , remote : r )
2323
2424 expect ( resolver . send ( :filter_cooldown , [ recent , old ] ) ) . to eq ( [ old ] )
2525 end
@@ -32,14 +32,37 @@ def spec(created_at:, remote:)
3232
3333 it "leaves rolling-delay history intact" do
3434 # 7-day cooldown with frequent releases must still expose an older candidate.
35- in_cooldown = spec ( created_at : now - 86_400 , remote : r )
36- also_in_cooldown = spec ( created_at : now - ( 3 * 86_400 ) , remote : r )
37- eligible = spec ( created_at : now - ( 10 * 86_400 ) , remote : r )
35+ in_cooldown = spec ( version : "1.2.0" , created_at : now - 86_400 , remote : r )
36+ also_in_cooldown = spec ( version : "1.1.0" , created_at : now - ( 3 * 86_400 ) , remote : r )
37+ eligible = spec ( version : "1.0.0" , created_at : now - ( 10 * 86_400 ) , remote : r )
3838
3939 result = resolver . send ( :filter_cooldown , [ in_cooldown , also_in_cooldown , eligible ] )
4040
4141 expect ( result ) . to eq ( [ eligible ] )
4242 end
43+
44+ it "drops every spec sharing an excluded [name, version] tuple" do
45+ # The cooldown check is by version, not per-spec: a StubSpecification for an
46+ # in-cooldown release would otherwise slip through on local install paths.
47+ endpoint = spec ( version : "2.0.0" , created_at : now - 86_400 , remote : r )
48+ local_stub = Struct . new ( :name , :version ) . new ( "myrack" , Gem ::Version . new ( "2.0.0" ) )
49+ eligible = spec ( version : "1.0.0" , created_at : now - ( 30 * 86_400 ) , remote : r )
50+
51+ result = resolver . send ( :filter_cooldown , [ endpoint , local_stub , eligible ] )
52+
53+ expect ( result ) . to eq ( [ eligible ] )
54+ end
55+
56+ it "keeps stub-only versions that no endpoint marks as in cooldown" do
57+ # If no remote spec carries created_at for a version, cooldown cannot judge it;
58+ # the stub stays in.
59+ local_only = Struct . new ( :name , :version ) . new ( "myrack" , Gem ::Version . new ( "2.0.0" ) )
60+ eligible = spec ( version : "1.0.0" , created_at : now - ( 30 * 86_400 ) , remote : r )
61+
62+ result = resolver . send ( :filter_cooldown , [ local_only , eligible ] )
63+
64+ expect ( result ) . to eq ( [ local_only , eligible ] )
65+ end
4366 end
4467
4568 context "when created_at is missing (blank metadata)" do
@@ -111,9 +134,15 @@ def spec(created_at:, remote:)
111134 end
112135
113136 it "uses plural wording when multiple versions are excluded" do
114- excluded = Array . new ( 3 ) { spec ( created_at : now - 86_400 , remote : r ) }
137+ excluded = %w[ 1.0.0 1.1.0 1.2.0 ] . map { | v | spec ( version : v , created_at : now - 86_400 , remote : r ) }
115138
116139 expect ( resolver . send ( :cooldown_hint , excluded ) ) . to match ( /3 versions excluded/ )
117140 end
141+
142+ it "counts each unique version once even when multiple spec instances share it" do
143+ duplicates = Array . new ( 3 ) { spec ( created_at : now - 86_400 , remote : r ) }
144+
145+ expect ( resolver . send ( :cooldown_hint , duplicates ) ) . to match ( /1 version excluded/ )
146+ end
118147 end
119148end
0 commit comments