-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
max_number_of_devices should be used in a new session as well #1109
max_number_of_devices should be used in a new session as well #1109
Conversation
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.
Wait a minute, I removed the code and the test is still working... |
7800929
to
8a4688f
Compare
The code was correct but the test doesn't, this happens when |
@@ -257,4 +255,10 @@ def remove_tokens_after_password_reset | |||
end | |||
end | |||
|
|||
def clean_old_tokens |
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.
Isn't this code technically O(n2)
? (The Enumberable#min_by
call is inside a while
loop).
Even though Enumberable#min_by
returns a single key/value pair, it still iterates over the entire collection every time it's called.
I would think that it is more efficient to iterate over the collection once, sorting the key/value pairs by :expiry
of the value, and then shift the oldest key/values from tokens in a while loop.
...
protected
...
def max_client_tokens_exceeded?
tokens.length > DeviseTokenAuth.max_number_of_devices
end
def clean_old_tokens
if tokens.present? && max_client_tokens_exceeded?
# Using Enumerable#sort_by on a Hash will typecast it into an associative
# Array (i.e. an Array of key-value Array pairs). However, since Hashes
# have an internal order in Ruby 1.9+, the resulting sorted associative
# Array can be converted back into a Hash, while maintaining the sorted
# order.
self.tokens = tokens.sort_by { |_cid, v| v[:expiry] || v['expiry'] }.to_h
# Since the tokens are sorted by expiry, shift the oldest client token
# off the Hash until it no longer exceeds the maximum number of clients
tokens.shift while max_client_tokens_exceeded?
end
end
...
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.
This change breaks randomically the test that you mentioned: test/controllers/demo_user_controller_test.rb#L506
. I tried for a day fixing it but it's quite weird (and hard to debug with minitest). If we merge the PR without this change, can you create a new one and try to fix it with your comment?
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.
Yeah, no problem. I can submit a second PR. Although, I think I saw random test failures on travis-ci before I even made my comment?
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.
Yes, but they weren't random, they were my errors, I haven't updated the PR yet
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.
Is the debugging a challenge because the Minitest::Reporters::ProgressReporter
leaves out line numbers? I've definitely been challenged with debugging failing tests while using that reporter. While I prefer the ProgressReporter
, I find that the default minitest reporter provides much more useful debugging info.
I usually just temporarily comment out line 27 of the test_helper.rb
while running these tests. YMMV.
I've been meaning to look into the the issue and submit a PR to kern/minitest-reporters
with a fix.
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.
Thanks for the tip! It doesn't throw a backtrace either 😞
@@ -72,6 +72,23 @@ class DeviseTokenAuth::SessionsControllerTest < ActionController::TestCase | |||
assert_equal '0.0.0.0', @new_last_sign_in_ip | |||
end | |||
end | |||
|
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.
Shouldn't you assert that the correct tokens (i.e. the oldest tokens) are deleted here?
E.g.:
Given that the max_number_of_devices = 5
, and there are 5 existing tokens,
When an additional token is added, the oldest token is dropped and the new one is present.
@MaicolBen: not sure if it will help here, but in my fork to get multi-auth working (#990), I refactored some of the test code in From diff of describe 'maximum concurrent devices per user' do
before do
@max_devices = DeviseTokenAuth.max_number_of_devices
end
it 'should limit the maximum number of concurrent devices' do
# increment the number of devices until the maximum is exceeded
1.upto(@max_devices + 1).each do |n|
assert_equal [n, @max_devices].min, @resource.reload.tokens.keys.length
@resource.create_new_auth_token
end
end
it 'should drop the oldest token when the maximum number of devices is exceeded' do
# create the maximum number of tokens
1.upto(@max_devices).each { @resource.create_new_auth_token }
# get the oldest token
oldest_token, _ = @resource.reload.tokens \
.min_by { |cid, v| v[:expiry] || v["expiry"] }
# create another token, thereby dropping the oldest token
@resource.create_new_auth_token
assert_not_includes @resource.reload.tokens.keys, oldest_token
end
end I refactored the code, in part, because it seemed like testing expired token deletion should not be in the Refer to PR One thing of note regarding commit ...
@resource.create_new_auth_token
... Additionally, I further refactored this code in commit |
8a4688f
to
76fca0e
Compare
Fixed test, @Evan-M will be making another PR improving |
@MaicolBen: I checked out the You could either: |
@MaicolBen I've only got |
I didn't know, sorry, can you approve? |
Resolves #1107
Resolves #637