Misunderstood, an example from the documentation Pytest authorization - pytest

I decided to look at Pytest and immediately misunderstood, an example from the documentation, but there is no authorization, the test crashes with a code of 301, can anyone know what is the reason?
def test_with_authenticated_client(client, django_user_model):
username = "TestUser"
password = "1234567"
user = django_user_model.objects.create_user(username=username,
password=password)
# Use this:
client.force_login(user)
response = client.get('/new')
assert response.status_code == 200
def test_with_authenticated_client2(client):
username = "user2"
password = "bar"
# Or this:
client.login(username=username, password=password)
response = client.get('/new')
assert response.status_code == 200
with an unauthorized client, expected code 301
def test_make_not_authorized_user(client):
response = client.get('/new')
assert response.status_code in (302, 301)

Related

How mock requests exception using Pytest fixture for mock_requests?

So I was using the requests-mock library to mock the HTTP requests that I do with the requests library and everything went fine until I had to do a test to catch the exception.
Example of my function to be tested
def get_wordpress_installed_plugins(url: str, user: str, password: str) -> bytes:
try:
credentials = user + ':' + password
token = base64.b64encode(credentials.encode())
header = {'Authorization': 'Basic ' + token.decode('utf-8')}
response = requests.get(url, headers=header, verify=False)
response.raise_for_status()
except requests.exceptions.HTTPError as err:
logger.exception(f"Got response from {url} correctly with error {err}.")
raise CouldNotConnectWithApi(f"Problem retrieving information.")
logger.info(f"Got response from {url} correctly.")
return response.content
And the test to assert function did ok
#mock.patch("checkpluginsversion.logging.Logger.info")
def test_api_wordpress_list_plugins(logger_mock, requests_mock):
user = "user"
password = "password"
url = "https://www.example.com"
expected_result = b'[{"plugin": "akismet\\/akismet", "status": "active", "name": "Akismet Anti-Spam","version": "4.2.2"}]'
requests_mock.get(url,
content=b'[{"plugin": "akismet\\/akismet", "status": "active", "name": "Akismet Anti-Spam","version": "4.2.2"}]')
result = get_wordpress_installed_plugins(url, user, password)
assert result == expected_result
logger_mock.assert_called_with(f"Got response from {url} correctly.")
To be honest, I don't know if using pytest fixture mode of this library is the best way, but ok it is working for me. So the problem I have is when I have to test the function and raise the exception. Eventually, I did a workaround with #mock.patch, and worked for me.
#mock.patch("checkpluginsversion.requests.get")
#mock.patch("checkpluginsversion.logging.Logger.exception")
def test_api_should_return_an_exception(logger_mock,my_request_mock):
user = "user"
password = "password"
url = "https://www.example.com"
expected_result = b'[{"plugin": "akismet\\/akismet", "status": "active", "name": "Akismet Anti-Spam","version": "4.2.2"}]'
my_request_mock.side_effect = requests.exceptions.HTTPError
with pytest.raises(CouldNotConnectWithApi):
result = get_wordpress_installed_plugins(url, user, password)
#assert result == expected_result
logger_mock.assert_called_with(f"Got response from {url} correctly with error .")
But I would know and I will really appreciate it if someone could explain to me how to do a test to raise an exception using the pytest fixture of requests_mock library, thanks!

FastAPI pytest with arguments

I try to test fastAPI get route with pytest and the problem is how i can pass params to client.get
main.py
#app.get('/purpose'):
async def read_purpose(name, date):
"""some logic"""
return {'ok':'ok'}
test.py
client = TestClient(app)
def test_purpose():
response = client.get("/purpose", json={"name":"test_name", "date":"01.01.2020"})
assert response.status_code = 200
My test is failed. it can not find name, and date arguments.
How i can pass this arguments to my test.
Thank you
I have same problem when writing pytest for my first FastAPI demo.
#router.post('/item', tags=['items'], response_model=ShowItem)
async def create_item(item: ItemCreate,
user_id: int,
db: Session = Depends(get_db)):
date_posted = datetime.now().date()
# owner_id = 1
item = Items(**item.dict(),
date_posted=date_posted,
owner_id=user_id)
db.add(item)
db.commit()
db.refresh(item)
return item
You can try "params" instead of "json", because you are passing isolated query parameters
def test_create_item():
# wrong
data = {'title': 'Hot Boat', 'description': 'This is a boat', 'user_id': 1}
resp = client.post('/item', json.dumps(data))
# correct
data = {'title': 'Hot Boat', 'description': 'This is a boat'}
resp = client.post('/item', json.dumps(data), params={"user_id": 2})
assert resp.status_code == 200
Then i can by pass above error.
Try this fix:
client = TestClient(app)
def test_purpose():
response = client.get("/purpose", params={"name":"test_name", "date":"01.01.2020"})
assert response.status_code = 200
More detail refer Question 61383179

How to check for proper format in my API response

Currently running tests for my REST API which:
takes an endpoint from the user
using that endpoint, grabs info from a server
sends it to another server to be translated
then proceeds to jsonify the data.
I've written a series of automated tests running and I cannot get one to pass - the test that actually identifies the content of the response. I've tried including several variations of what the test is expecting but I feel it's the actual implementation that's the issue. Here's the expected API response from the client request:
{ "name": "random_character", "description": "Translated description of requested character is output here" }
Here is the testing class inside my test_main.py:
class Test_functions(unittest.TestCase):
# checking if response of 200 is returned
def test_healthcheck_PokeAPI(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/")
status_code = response.status_code
self.assertEqual(status_code, 200)
# the status code should be a redirect i.e. 308; so I made a separate test for this
def test_healthcheck_ShakesprAPI(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/charizard")
self.assertEqual(response.status_code, 308)
def test_response_content(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/charizard")
self.assertEqual(response.content_type,
'application/json') <<<< this test is failing
def test_trans_shakespeare_response(self):
manualtest = app.test_client(self)
response = manualtest.get("/pokemon/charizard")
self.assertFalse(b"doth" in response.data)
Traceback:
AssertionError: 'text/html; charset=utf-8' != 'application/json' - text/html; charset=utf-8 + application/json
Any help would be greatly appreciated

Flask REST - UPDATE user model

i am building a REST api with JWT authorization abstracting the user model. So these are some of the functions I define in my user model definition:
def save_to_db(self):
db.session.add(self)
db.session.commit()
def update_db(self):
db.session.commit()
def delete_from_db(self):
db.session.delete(self)
db.session.commit()
and these are the methods:
#jwt_required()
def get(self):
user = UserModel.find_by_email(current_identity.email)
if user:
return user.json(), 200
return {'message': 'User not found'}, 400
def post(self):
data = UserRegister.parser.parse_args()
if UserModel.find_by_email(data['email']):
return {"message": "User already exists"}, 400
user = UserModel(**data)
user.save_to_db()
return user.json(), 200
#jwt_required()
def put(self):
user = UserModel.find_by_email(current_identity.email)
if user:
data = UserRegister.parser.parse_args()
try:
user = UserModel(**data)
user.update_db()
return user.json(), 200
except:
return {'message': 'An error ocurred while inserting user data.'}, 400
Everything is working except the PUT method. It does not store the actual value in the database, I am wondering why.

How to generate the IAM access tokens for analytics engine requests using python?

The documentation for Analytics Engine provides a link to generate a IAM access tokens using the CLI, but I need to generate the token with an API call. This is the CLI approach:
bx api https://api.ng.bluemix.net
bx login
<enter your credentials>
<If you are part of multiple IBM Cloud accounts, you'll be asked to choose an account for the current session. Also, you'll need to choose an organization and space in IBM Cloud.>
bx iam oauth-tokens
The documentation also states that the Cloud Foundry API is deprecated? How can I generate the IAM access tokens?
Here is the code I created in the end ...
Some utility classes for logging and exceptions:
import requests
import json
from datetime import datetime, timedelta
import logging
import os
class Logger:
def __init__(self):
format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
logging.basicConfig(format=format)
self.ch = logging.StreamHandler()
def get_logger(self, clazz):
logger = logging.getLogger(clazz)
logger.setLevel(os.getenv("LOG_LEVEL", logging.INFO))
return logger
class CloudFoundryException(Exception):
def __init__(self, message, *args):
self.message = message
super(CloudFoundryException, self).__init__(message, *args)
Then a class to do the main work:
class CloudFoundryAPI(object):
def __init__(self, api_key=None, api_key_filename=None, api_endpoint='https://api.ng.bluemix.net', provision_poll_timeout_mins=30):
self.log = Logger().get_logger(self.__class__.__name__)
self.provision_poll_timeout_mins = provision_poll_timeout_mins
assert api_key is not None or api_key_filename is not None, "You must provide a value for api_key or for api_key_filename"
# allow tests to override the api_key_filename parameter
if hasattr(CloudFoundryAPI, 'api_key_filename') and CloudFoundryAPI is not None:
api_key_filename = CloudFoundryAPI.api_key_filename
if api_key_filename is not None:
try:
with open(api_key_filename, 'r') as api_file:
d = json.load(api_file)
try:
self.api_key = d['apikey']
except KeyError:
# The attibute name used to be
self.api_key = d['apiKey']
except:
self.log.error('Error retrieving "apiKey" from file {}'.format(api_key_filename))
raise
else:
self.api_key = api_key
self.api_endpoint = api_endpoint
self.info = self._get_info()
def auth(self):
self.log.debug('Authenticating to CloudFoundry')
url = self.info['authorization_endpoint'] + '/oauth/token'
headers = {
'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8',
'Accept': 'application/x-www-form-urlencoded;charset=utf-8',
'Authorization': 'Basic Y2Y6'
}
data = 'grant_type=password&username=apikey&password={}'.format(self.api_key)
try:
response = requests.post(url, headers=headers, data=data)
response.raise_for_status()
except requests.exceptions.RequestException as e:
self.log.error('Cloud Foundry Auth Response: ' + response.text)
# TODO we should define a custom application exception for this
raise
self.auth_token = response.json()
self.expires_at = datetime.now() + timedelta(seconds=self.auth_token['expires_in']/60)
self.log.debug('Authenticated to CloudFoundry')
def oidc_token(self):
self.log.debug('Retrieving IAM token')
url='https://iam.bluemix.net/identity/token'
data="grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey={}".format(self.api_key)
try:
response = requests.post(url, data=data)
response.raise_for_status()
except requests.exceptions.RequestException as e:
self.log.debug('IAM token response: ' + response.text)
raise
self.oidc_token = response.json()
self.oidc_expires_at = datetime.now() + timedelta(seconds=self.oidc_token['expires_in']/60)
self.log.debug('Retrieved IAM token')
return self.oidc_token
def get_auth_token(self):
if not hasattr(self, 'auth_token') or not hasattr(self, 'expires_at') or datetime.now() > self.expires_at:
self.auth()
return self.auth_token
def get_oidc_token(self):
if not hasattr(self, 'oidc_token') or not hasattr(self, 'oidc_expires_at') or datetime.now() > self.oidc_expires_at:
self.oidc_token()
return self.oidc_token
def _request_headers(self):
auth_token = self.get_auth_token()
access_token = auth_token['access_token']
token_type = auth_token['token_type']
headers = {
'accept': 'application/json',
'authorization': '{} {}'.format(token_type, access_token),
'cache-control': 'no-cache',
'content-type': 'application/json'
}
return headers
def _request(self, url, http_method='get', data=None, description='', create_auth_headers=True):
if create_auth_headers:
headers = self._request_headers()
else:
headers = {}
try:
if http_method == 'get':
response = requests.get(url, headers=headers)
elif http_method == 'post':
response = requests.post(url, headers=headers, data=json.dumps(data))
elif http_method == 'delete':
response = requests.delete(url, headers=headers)
response.raise_for_status()
except requests.exceptions.RequestException as e:
self.log.error('{} : {} {} : {} {}'.format(description, http_method, url, response.status_code, response.text))
raise CloudFoundryException(message=response.text)
try:
self.log.debug('{} : {} {} : {} {}'.format(description, http_method, url, response.status_code, json.dumps(response.json())))
except ValueError:
self.log.debug('{} : {} {} : {} {}'.format(description, http_method, url, response.status_code, response.text))
return response
def _get_info(self):
url = '{}/v2/info'.format(self.api_endpoint)
response = self._request(url=url, http_method='get', description='_get_info', create_auth_headers=False)
return response.json()
You can then use it like so:
cf = CloudFoundryAPI(api_key="xxxx") # or pass api_key_filename
cf.get_auth_token() # get UAA token
cf.get_oidc_token() # get IAM token