-
Notifications
You must be signed in to change notification settings - Fork 44
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
Refactor StatsTracker
#103
Conversation
81145d8
to
012b3ab
Compare
As I explained here: #103 (comment) The mock for the trait TrackerStatisticsEventSender did not work completely weel becuase it only checked for the rigth type of the triggered event but It did not check if the event was sent. I finally used a mockinf library becuase I do not know how to mock trait that uses a mutable reference to 'self'. I need to store wether the event was sent or not and I do not know how to do that without changing the function signature making it mutable.
Parallel change. We are still using the old TrackerStatsService to send events.
instead of StatsTracker.
- The StatsTracker does not need anymore the channel sender. - A setup function for statistics was extracted.
I only change test to use the new mock. I realized test were wrong becuase they do not fail when no event is sent. THey only fail when the event sent is not the rigth type.
It will be used to mock a trait in tests.
As I explained here: #103 (comment) The mock for the trait TrackerStatisticsEventSender did not work completely weel becuase it only checked for the rigth type of the triggered event but It did not check if the event was sent. I finally used a mockinf library becuase I do not know how to mock trait that uses a mutable reference to 'self'. I need to store wether the event was sent or not and I do not know how to do that without changing the function signature making it mutable.
af6b730
to
8874032
Compare
hi @da2ce7 @WarmBeer, I've fixed the tests that were using my incomplete custom mock. In this commit. I did not find a way to mock a trait function which is not mutable. This was my mock: struct StatsEventSenderMock {
expected_event: Option<TrackerStatisticsEvent>,
}
impl StatsEventSenderMock {
fn new() -> Self {
Self { expected_event: None }
}
fn should_throw_event(&mut self, expected_event: TrackerStatisticsEvent) {
self.expected_event = Some(expected_event);
}
}
#[async_trait]
impl TrackerStatisticsEventSender for StatsEventSenderMock {
async fn send_event(&self, event: TrackerStatisticsEvent) -> Option<Result<(), SendError<TrackerStatisticsEvent>>> {
if self.expected_event.is_some() {
assert_eq!(event, *self.expected_event.as_ref().unwrap());
}
None
}
} I needed to know if the method was called. If the method The only way to do it (or the only way I found) is by adding a new field to the struct to store the state. But I could not do that without changing the function signature to: async fn send_event(&mut self, event: TrackerStatisticsEvent) -> Option<Result<(), SendError<TrackerStatisticsEvent>>>; I tried with a mocking library, and it works: let mut stats_event_sender_mock = MockTrackerStatisticsEventSender::new();
stats_event_sender_mock
.expect_send_event()
.with(eq(TrackerStatisticsEvent::Udp4Connect))
.times(1)
.returning(|_| Box::pin(future::ready(Some(Ok(())))));
let stats_event_sender = Box::new(stats_event_sender_mock); I think sooner or later, we will need it for more complex mocks. I wonder how they can check that the method is called without changing its signature. I'm curious. The other tricky thing was the returning value: Since the function is an async function, you need to return a "future". But I do not know why they need the "pin". We can apply this commit in the |
hi @da2ce7 @WarmBeer, I've finished the experimental refactor. I think it is worth merging it for two reasons:
There are a couple of things I do not like:
|
I forgot to mention that this refactor makes it easier to decouple events from statistics in the future. Statistics would be only one of the consumers of those events. But it's not a reason to merge this PR since we have not decided how to handle events and their relationship with logging. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks Good to me. Nice work! :)
ACK 6f77dfe |
This is an experimental refactor of the StatsTracker.
It's still a WIP.
Tracker statistics are optional, and we had problems testing that behaviour.
I decided to try to make that code more testable. My idea is:
The high-level service (StatsService) only creates the StatisticsRepository used by the EventListener and the TorrusTracker. And the communication channel (with the sender and listener).
TODO:
Once we have the EventListener, we can add tests to check if it updates the stats correctly, which is something we did not test on PR-112.
While working on the refactor, I realized the
StatsEventSenderMock
does not work correctly. It only works when the event is sent, but it does not fail if no event is sent. The obvious solution would be to store the event sent in the Mock, but the method is not mutable.I did not want to add a mocking library only for this case. That's why I did it manually. And I do not want to make that function mutable only for the test.