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

Rewrite specs using rspec #135

Merged
merged 12 commits into from
Mar 23, 2020
Merged

Rewrite specs using rspec #135

merged 12 commits into from
Mar 23, 2020

Conversation

kbogtob
Copy link
Contributor

@kbogtob kbogtob commented Feb 25, 2020

What does this PR?

It rewrites the tests using RSpec and mocking in the idea of refactoring the project to have more SOLID code. Some tests are still breaking encapsulation and fixing them implies to modify the code to make it more testable and uncoupled.

Motivation

Clarify the project, use more recent testing techniques and allowing people to contribute easily + making grounds to refactor the project.

Notes

Found a bug, notified it in comment.

@kbogtob kbogtob added the WIP label Feb 25, 2020
@kbogtob kbogtob changed the title (WIP) Rewrite specs using rspec Rewrite specs using rspec Feb 26, 2020
@kbogtob kbogtob removed the WIP label Feb 26, 2020
@kbogtob kbogtob force-pushed the kbogtob/rewrite-specs branch 2 times, most recently from e3eb299 to 7c1e15d Compare February 26, 2020 14:26
@@ -28,6 +28,9 @@ def send_message(message)
socket.sendmsg_nonblock(message)
rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ENOENT => e
@socket = nil
# TODO: FIXME: This error should be considered as a retryable error in the
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 found this bug, it was not caught by the previous tests: If we catch a connection refused or reset, we don't try to reconnect to the UDS socket. For the missing socket, it seems relevant, it means that the socket was never found, but for other cases, I think we should retry.

@kbogtob kbogtob force-pushed the kbogtob/rewrite-specs branch 2 times, most recently from 30907e1 to 9603e9f Compare February 26, 2020 15:26
Copy link
Contributor

@albertvaka albertvaka left a comment

Choose a reason for hiding this comment

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

Do you think it could be worth keeping some of the old tests that were more like integration/high level? Aren't we reducing the coverage?

RSpec::Matchers.define :eq_with_telemetry do |expected, telemetry_options|
telemetry_options ||= {}

def text_with_telemetry(text, metrics: 1, events: 0, service_checks: 0, bytes_sent: 0, bytes_dropped:0, packets_sent: 0, packets_dropped: 0, transport: 'udp')
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
def text_with_telemetry(text, metrics: 1, events: 0, service_checks: 0, bytes_sent: 0, bytes_dropped:0, packets_sent: 0, packets_dropped: 0, transport: 'udp')
# Appends the telemetry metrics to the metrics string passed as 'text'
def add_telemetry(text, metrics: 1, events: 0, service_checks: 0, bytes_sent: 0, bytes_dropped:0, packets_sent: 0, packets_dropped: 0, transport: 'udp')

Better function name (I think).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is!

end

match do |actual|
actual == text_with_telemetry(expected, **telemetry_options)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
actual == text_with_telemetry(expected, **telemetry_options)
actual == add_telemetry(expected, **telemetry_options)

describe Datadog::Statsd do
describe 'VERSION' do
it 'has a version' do
expect(Datadog::Statsd::VERSION).to eq '4.6.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

We will need to update this for every version. Isn't it better to use a regex like before?

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 like this part to be explicit everytime we release but I can change it to a regexp

Copy link
Contributor

Choose a reason for hiding this comment

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

Let's properly update the release documentation then, let me know if you need the link to the document I'm mentioning

end

let(:expected_allocations) do
if RUBY_VERSION >= '2.3.0' && RUBY_VERSION < '2.4.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if RUBY_VERSION >= '2.3.0' && RUBY_VERSION < '2.4.0'
if RUBY_VERSION < '2.4.0'

Otherwise, older rubies would fall in the else case, which isn't what this code wants to express.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is what I wanted :). Older rubies make 8 allocations in this case.

end

let(:expected_allocations) do
if RUBY_VERSION >= '2.3.0' && RUBY_VERSION < '2.4.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if RUBY_VERSION >= '2.3.0' && RUBY_VERSION < '2.4.0'
if RUBY_VERSION < '2.4.0'

idem.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is what I wanted :). Older rubies make 8 allocations in this case.

Copy link
Contributor

@remeh remeh left a comment

Choose a reason for hiding this comment

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

Did my best to review this carefully but I won't lie, I may have been a bit fast on some of the tests.
In all cases, great update and it'll definitely be helpful to have solid unit testing on this lib. Thanks 🙇


module Datadog
class Statsd
VERSION = '4.6.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: it's most likely 4.7.0 now.

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'll fix it :)

describe Datadog::Statsd do
describe 'VERSION' do
it 'has a version' do
expect(Datadog::Statsd::VERSION).to eq '4.6.0'
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's properly update the release documentation then, let me know if you need the link to the document I'm mentioning

Comment on lines +98 to +135
context 'because of an unknown error' do
before do
allow(fake_socket_retry)
.to receive(:send)
.and_raise(RuntimeError, 'yolo')
end

it 'ignores the connection failure' do
expect do
subject.write('foobar')
end.not_to raise_error
end

it 'logs the error message' do
subject.write('foobar')
expect(log.string).to match 'Statsd: RuntimeError yolo'
end
end

context 'because of a SocketError' do
before do
allow(fake_socket_retry)
.to receive(:send)
.and_raise(SocketError, 'yolo')
end

it 'ignores the connection failure' do
expect do
subject.write('foobar')
end.not_to raise_error
end

it 'logs the error message' do
subject.write('foobar')
expect(log.string).to match 'Statsd: SocketError yolo'
end
end
end
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't they testing the same thing? I'm may miss a subtlety here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is, just to be sure that we don't handle socketerrors differently.

statsd = Datadog::Statsd.new(host, port)
statsd.increment('foobar')
message = socket.recvfrom(64).first
expect(message).to eq 'foobar:1|c'
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we test more than just a counter? Probably not has you improved the test coverage on everything but if that's like 2, 4 more lines, could be helpful someday.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We could make a big test for that. I'll add it.

let(:sample_rate) { nil }
let(:socket) { FakeUDPSocket.new }
let(:tags) { %w[abc def] }
Copy link
Contributor

Choose a reason for hiding this comment

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

Because it doesn't harm, let's use tags just slightly more realistic: for instance abc:def host:myhost12-11, WDYT?

Copy link
Contributor

Choose a reason for hiding this comment

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

Actually you did it right after, nvm.

We discovered that there is a bug with which strategy each error has to have. Connection refused or connection reset are not retried on UDS Connections.
@kbogtob kbogtob merged commit 040407d into master Mar 23, 2020
@kbogtob kbogtob deleted the kbogtob/rewrite-specs branch April 7, 2020 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants