Skip to content

Commit

Permalink
Use a private reference to JSON.parse to prevent it being mocked
Browse files Browse the repository at this point in the history
PIE-979

It is possible for test suites to mock the parse method of JSON.
For example:

allow(JSON).to receive(:parse).and_raise(JSON::ParserError)

This will cause the test collector library to misbehave.

We can resolve this problem by updating the test collector code to
use a private reference to the JSON method which is immune to mocking.

This solution is similar to
#132
and https://github.com/ruby/timeout/pull/18/files

Resolves #144
  • Loading branch information
gchan committed Aug 9, 2022
1 parent f861373 commit b45007b
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 1 deletion.
6 changes: 5 additions & 1 deletion lib/buildkite/test_collector/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ class Session
MAX_RECONNECTION_ATTEMPTS = ENV.fetch("BUILDKITE_ANALYTICS_RECONNECTION_ATTEMPTS") { 3 }.to_i
WAIT_BETWEEN_RECONNECTIONS = ENV.fetch("BUILDKITE_ANALYTICS_RECONNECTION_WAIT") { 5 }.to_i

# We keep a private reference so that mocking libraries won't break JSON
JSON_PARSE = JSON.method(:parse)
private_constant :JSON_PARSE

class RejectedSubscription < StandardError; end
class InitialConnectionFailure < StandardError; end

Expand Down Expand Up @@ -120,7 +124,7 @@ def close(examples_count)
end

def handle(_connection, data)
data = JSON.parse(data)
data = JSON_PARSE.call(data)
case data["type"]
when "ping"
# In absence of other message, the server sends us a ping every 3 seconds
Expand Down
6 changes: 6 additions & 0 deletions spec/test_collector/session_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
session.handle(socket_double, {"type"=> "message", "identifier"=> "fake_channel", "message" => {"confirm"=> ["./spec/analytics/session_spec.rb[1:1]"]}}.to_json)
expect(session.unconfirmed_idents_count).to be 0
end

it "is immune to JSON.parse being mocked" do
allow(JSON).to receive(:parse).and_raise(JSON::ParserError)

session.handle(socket_double, {"type"=> "message", "identifier"=> "fake_channel", "message" => {"confirm"=> ["./spec/analytics/session_spec.rb[1:1]"]}}.to_json)
end
end

describe "#close" do
Expand Down

0 comments on commit b45007b

Please sign in to comment.