0

I'm unittesting token creation (think PyJWT) and I need to test if expired token raises exception:

from jwt.exceptions import ExpiredSignatureError

def test_invalid_logout_expired_token(self):
    add_user('testuser', 'testemail@mail.com', 'hakunamatata')
    current_app.config['TOKEN_EXPIRATION_SECONDS'] = -1
    with self.client:
        resp_login = self.client.post(
            '/auth/login',
            data=json.dumps({
                'email': 'testemail@mail.com',
                'password': 'hakunamatata'
            }),
            content_type='application/json'
            )

        token = json.loads(resp_login.data.decode())['auth_token']
        response = self.client.get('/auth/logout', headers={'Authorization': f'Bearer {token}'})
        data = json.loads(response.data.decode())
        self.assertRaises(ExpiredSignatureError, data)  # <-- isn't working

exception is raised correctly:

  File "/usr/src/app/project/api/auth.py", line 90, in logout
    resp = User.decode_auth_token(auth_token)
  File "/usr/src/app/project/api/models.py", line 45, in decode_auth_token
    return jwt.decode(token, current_app.config.get('SECRET_KEY'), algorithms=["HS256"])
  File "/usr/local/lib/python3.8/site-packages/jwt/api_jwt.py", line 119, in decode
    decoded = self.decode_complete(jwt, key, algorithms, options, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/jwt/api_jwt.py", line 106, in decode_complete
    self._validate_claims(payload, merged_options, **kwargs)
  File "/usr/local/lib/python3.8/site-packages/jwt/api_jwt.py", line 142, in _validate_claims
    self._validate_exp(payload, now, leeway)
  File "/usr/local/lib/python3.8/site-packages/jwt/api_jwt.py", line 177, in _validate_exp
    raise ExpiredSignatureError("Signature has expired")
jwt.exceptions.ExpiredSignatureError: Signature has expired

but test runner gives error: test_invalid_logout_expired_token (test_auth.TestAuthBlueprint) ... ERROR

What is the right way to go about it ?

Update:

def test_invalid_logout_expired_token(self):
    add_user('testuser', 'testemail@mail.com', 'hakunamatata')
    current_app.config['TOKEN_EXPIRATION_SECONDS'] = -1
    with self.client:
        resp_login = self.client.post(
                '/auth/login',
                data=json.dumps({
                    'email': 'testemail@mail.com',
                    'password': 'hakunamatata'
                }),
                content_type='application/json'
            )

        token = json.loads(resp_login.data.decode())['auth_token']
        self.assertRaises(ExpiredSignatureError, User.decode_auth_token(token))

User class:

class User:
    ...

    @staticmethod
    def decode_auth_token(token):
        return jwt.decode(token, current_app.config.get('SECRET_KEY'), algorithms=["HS256"])

Replaced data with User.decode_auth_token().

Mark
  • 1,385
  • 3
  • 16
  • 29
  • `assertRaises` takes the _callable_ as a parameter where the exception occurs. The more readable way is to use the context manager form: `with assertRaises(ExpiredSignatureError): code_that_throws_exception()`. – MrBean Bremen Jul 09 '21 at 17:54
  • I'm passing in callable but get the error anyway. – Mark Jul 09 '21 at 19:00
  • Well, I don't know where the exception should happen, and if you are passing the callable where it happens. Better to show the code you actually use. – MrBean Bremen Jul 09 '21 at 19:14
  • 1
    In your updated version, you are still not passing a callable, but the _result_ of the call, meaning the exception is raised while evaluating the arguments for `assertRaises`. Use `self.assertRaises(ExpiredSignatureError, User.decode_auth_token, token)`, or better the context manager version I have mentioned above. – MrBean Bremen Jul 10 '21 at 05:25

0 Answers0