bblimke / webmock

Library for stubbing and setting expectations on HTTP requests in Ruby.
MIT License
3.97k stars 555 forks source link

When using matcher with block, the block is executed less than expected #548

Open rockuw opened 9 years ago

rockuw commented 9 years ago

Hi, with the following code:

it "test matcher with block", :focus => true do
  stub_request(:get, "xxx.com")

  10.times do
    RestClient.get("xxx.com", :headers => {'Range' => '1-100'})
  end

  expect(WebMock).to have_requested(:get, "xxx.com")
                      .with{ |req|
    puts "req"
    true
  }.times(10)
end

I expect the block to be executed 10 times. But only one "req" was printed.

However, if I send different requests each time, the behavior is as expected.

it "test matcher with block", :focus => true do
  stub_request(:get, "xxx.com")

  10.times do |i|
    RestClient.get("xxx.com", :headers => {'Range' => "#{i}-100"})
  end

  expect(WebMock).to have_requested(:get, "xxx.com")
                      .with{ |req|
    puts "req"
    true
  }.times(10)
end

What's the problem here?

rockuw commented 9 years ago

After digging into the code, I find out the cause: RequestRegistry uses a Util::HashCounter to store all the request signatures. When there are two request signatures that equal in the HashCounter, it will only be matched with the request pattern once.

def times_executed(request_pattern)
  self.requested_signatures.hash.select { |request_signature, times_executed|
    request_pattern.matches?(request_signature)
  }.inject(0) {|sum, (_, times_executed)| sum + times_executed }
end

Please fix it.