@@ -127,4 +127,98 @@ class UserTest < ActiveSupport::TestCase
127127 end
128128 end
129129 end
130+
131+ describe 'clean_old_tokens' do
132+ before do
133+ @resource = create ( :user , :confirmed )
134+ @token_lifespan = DeviseTokenAuth . token_lifespan
135+ @max_client_count = DeviseTokenAuth . max_number_of_devices
136+ DeviseTokenAuth . max_number_of_devices = 2
137+ DeviseTokenAuth . token_lifespan = 1 . week
138+ end
139+
140+ after do
141+ DeviseTokenAuth . token_lifespan = @token_lifespan
142+ DeviseTokenAuth . max_number_of_devices = @max_client_count
143+ end
144+
145+ test 'removes tokens with expiry beyond the maximum lifespan' do
146+ # Create tokens with different expiry times
147+ current_time = Time . now . to_i
148+
149+ max_lifespan = current_time + DeviseTokenAuth . token_lifespan . to_i
150+
151+ # Valid token within lifespan
152+ @resource . tokens [ 'valid_client' ] = {
153+ 'token' => 'valid_token' ,
154+ 'expiry' => current_time + 1 . day . to_i
155+ }
156+
157+ # Token exactly at max lifespan (should be kept)
158+ @resource . tokens [ 'edge_client' ] = {
159+ 'token' => 'edge_token' ,
160+ 'expiry' => max_lifespan
161+ }
162+
163+ # Token beyond max lifespan (should be removed)
164+ @resource . tokens [ 'expired_client' ] = {
165+ 'token' => 'expired_token' ,
166+ 'expiry' => max_lifespan + 1 . day . to_i
167+ }
168+
169+ # Call the method under test
170+ @resource . send ( :clean_old_tokens )
171+
172+ # Assert that tokens beyond lifespan were removed
173+ assert @resource . tokens . key? ( 'valid_client' ) , 'Valid token should be kept'
174+ assert @resource . tokens . key? ( 'edge_client' ) , 'Edge case token at max lifespan should be kept'
175+ refute @resource . tokens . key? ( 'expired_client' ) , 'Token beyond max lifespan should be removed'
176+ end
177+
178+ test 'handles token lifespan reduction when creating token' do
179+ # Setup: Create the maximum allowed number of tokens with a longer lifespan
180+ DeviseTokenAuth . token_lifespan = 2 . weeks
181+ DeviseTokenAuth . max_number_of_devices = 3
182+
183+ # Create tokens at different times but all within the initial long lifespan
184+ @resource . tokens = { }
185+ @resource . tokens [ 'client_1' ] = {
186+ 'token' => 'token_1' ,
187+ 'expiry' => Time . now . to_i + 12 . days . to_i
188+ }
189+
190+ @resource . tokens [ 'client_2' ] = {
191+ 'token' => 'token_2' ,
192+ 'expiry' => Time . now . to_i + 10 . days . to_i
193+ }
194+
195+ @resource . tokens [ 'client_3' ] = {
196+ 'token' => 'token_3' ,
197+ 'expiry' => Time . now . to_i + 5 . days . to_i
198+ }
199+
200+ # We've reached the maximum number of devices/tokens
201+ assert_equal 3 , @resource . tokens . length
202+
203+ # Now reduce token lifespan - simulating a config change
204+ DeviseTokenAuth . token_lifespan = 1 . week
205+
206+ # Create a new token which should trigger clean_old_tokens
207+ new_auth_headers = @resource . create_new_auth_token
208+ new_client = new_auth_headers [ 'client' ]
209+
210+ # The new token should exist
211+ assert @resource . tokens . key? ( new_client ) , 'New token should exist'
212+
213+ # Tokens exceeding the new reduced lifespan should be removed
214+ refute @resource . tokens . key? ( 'client_1' ) , 'Token with expiry > new lifespan should be removed'
215+ refute @resource . tokens . key? ( 'client_2' ) , 'Token with expiry > new lifespan should be removed'
216+
217+ # Token within new lifespan should be kept
218+ assert @resource . tokens . key? ( 'client_3' ) , 'Token within new reduced lifespan should be kept'
219+
220+ # We should have exactly 2 tokens: the new one and client_3
221+ assert_equal 2 , @resource . tokens . length
222+ end
223+ end
130224end
0 commit comments