@@ -53,6 +53,15 @@ def tearDown(self):
5353 return super ().tearDown ()
5454
5555
56+ class MockOauthlibCoreClass :
57+ """
58+ Mock oauthlib, used in test_token_view_status_equals_what_oauthlib_token_response_method_returns.
59+ """
60+
61+ def create_token_response (self , _ ):
62+ return "url" , {"headers_are_ignored" : True }, '{"Key": "Value"}' , 299
63+
64+
5665class TestDeviceFlow (DeviceFlowBaseTestCase ):
5766 """
5867 The first 2 tests test the device flow in order
@@ -439,6 +448,43 @@ def test_token_view_returns_404_error_if_device_not_found(self):
439448 # consumed by devices.
440449 self .assertEqual (response .__getitem__ ("content-type" ), "application/json" )
441450
451+ @mock .patch ("oauth2_provider.views.mixins.OAuthLibMixin.get_oauthlib_core" , MockOauthlibCoreClass )
452+ def test_token_view_status_equals_what_oauthlib_token_response_method_returns (self ):
453+ """
454+ Tests the use case where oauthlib create_token_response returns a status different
455+ than 200.
456+ """
457+ device = DeviceModel (
458+ client_id = "client_id" ,
459+ device_code = "device_code" ,
460+ user_code = "user_code" ,
461+ scope = "scope" ,
462+ expires = datetime .now () + timedelta (seconds = 60 ),
463+ status = "authorized" ,
464+ )
465+ device .save ()
466+
467+ token_payload = {
468+ "device_code" : "device_code" ,
469+ "client_id" : "client_id" ,
470+ "grant_type" : "urn:ietf:params:oauth:grant-type:device_code" ,
471+ }
472+
473+ response = self .client .post (
474+ "/o/token/" ,
475+ data = urlencode (token_payload ),
476+ content_type = "application/x-www-form-urlencoded" ,
477+ )
478+
479+ self .assertEqual (response ["content-type" ], "application/json" )
480+ self .assertContains (
481+ response = response ,
482+ status_code = 299 ,
483+ text = '{"Key": "Value"}' ,
484+ count = 1 ,
485+ )
486+ assert not response .has_header ("headers_are_ignored" )
487+
442488 @mock .patch (
443489 "oauthlib.oauth2.rfc8628.endpoints.device_authorization.generate_token" ,
444490 lambda : "abc" ,
@@ -644,3 +690,9 @@ def test_device_is_expired_method_sets_status_to_expired_if_deadline_passed(self
644690
645691 assert is_expired
646692 assert device .status == device .EXPIRED
693+
694+ # calling again is_expired() should return true and not change the state
695+ is_expired = device .is_expired ()
696+
697+ assert is_expired
698+ assert device .status == device .EXPIRED
0 commit comments