Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix HTTPTransport downgrade causing callback error #369

Merged
merged 9 commits into from
Mar 27, 2018

Conversation

delner
Copy link
Contributor

@delner delner commented Mar 15, 2018

If priority sampling is enabled, and HTTPTransport triggered an API downgrade, for example after receiving a 404 from an outdated agent, it would pass the downgraded response to the callback expecting the new response format. This would consequently result in a parse error.

This pull request passes the API as a parameter to the callback, so it can use that information to change how it handles responses. This PR also adds tests for this scenario, after converting Minitests to RSpec to perform better mocking.

Side note; this should probably be considered a stop-gap measure. There's a lot of coupling between Writer, Transport, and the concept of "API" which makes this design fairly brittle. Would recommend a refactor in the future.

@delner delner added bug Involves a bug core Involves Datadog core libraries labels Mar 15, 2018
@delner delner self-assigned this Mar 15, 2018
@palazzem palazzem added this to the 0.12.0 milestone Mar 22, 2018
Copy link
Contributor

@palazzem palazzem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One question, since we're changing the default in case the outer component doesn't pass the API version.

@@ -42,7 +46,7 @@ class HTTPTransport
private_constant :API

def initialize(hostname, port, options = {})
api_version = options.fetch(:api_version, V3)
api_version = options.fetch(:api_version, V4)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the default is V4 now? V4 endpoint is for distributed sampling that is disabled by default. Endpoint V3 is the right one to use unless an explicit configuration is used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I misread the code here. It had looked like in writer.rb that the api_version was always being set to V4 anyways. That's only true of priority sampling though, not the default case.

I'll change this back.

@delner delner force-pushed the bugfix/transport_downgrade_callbacks branch from 902078d to b778d23 Compare March 22, 2018 18:42
Copy link
Member

@p-lambert p-lambert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great job. Left a couple of comments but none blocking.

service_rates = JSON.parse(response.body)
@priority_sampler.update(service_rates)

if api[:version] == HTTPTransport::V4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that should do the trick, but I agree with you that this coupling between Writer and Transport makes the code brittle and should be addressed in a future PR.

Datadog::Tracer.log.level = @original_level
end

describe '#handle_response' do
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably worth checking here if the callback is processed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable. Although, for what it's worth, the callback is removed from this function in the next PR (becomes a part of post instead in the next PR.)

subject(:result) { transport.handle_response(response) }

context 'given an OK response' do
let(:response) { Net::HTTPResponse.new(1.0, 200, 'OK') }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a a thought: sometimes adding some randomness to the test might make it more robust without requiring a exhaustive list of test cases. in case of this method you could do something like:

let(:status_code) { (200...500).to_a.sample }
let(:response) { Net::HTTPResponse.new(1.0, status_code, 'whatever') }

and test if the return value of the method is equal to status_code

Copy link
Contributor Author

@delner delner Mar 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that works if the expected behavior is totally abstracted away from the input itself (e.g. it always replies with whatever input it was given.)

end

describe '#send' do
before(:each) { skip "TEST_DATADOG_INTEGRATION not set." unless ENV['TEST_DATADOG_INTEGRATION'] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps we should use rspec tags for that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't follow?

before(:each) do
original_post = transport.method(:post)
call_count = 0
allow(transport).to receive(:post) do |url, *rest|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

let(:body) { service_rates.to_json }

it do
expect(sampler).to receive(:update).with(service_rates)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@delner delner merged commit 7fc6061 into master Mar 27, 2018
@delner delner modified the milestones: 0.12.0, 0.11.4 Mar 28, 2018
@palazzem palazzem deleted the bugfix/transport_downgrade_callbacks branch March 29, 2018 15:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Involves a bug core Involves Datadog core libraries
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants