[tests] Add REST API tests for creating a twitter bot and fix issues
This commit is contained in:
parent
a3f8679b34
commit
48db2de748
|
@ -42,12 +42,14 @@ class TwitterBot(Censor):
|
||||||
await gather(self.poll(), self.push())
|
await gather(self.poll(), self.push())
|
||||||
except CancelledError:
|
except CancelledError:
|
||||||
logger.debug(f'Bot {self.twitter_model.hood.name} received Cancellation.')
|
logger.debug(f'Bot {self.twitter_model.hood.name} received Cancellation.')
|
||||||
raise
|
|
||||||
except exceptions.Unauthorized:
|
except exceptions.Unauthorized:
|
||||||
logger.debug(f'Bot {self.twitter_model.hood.name} has invalid auth token.')
|
logger.debug(f'Bot {self.twitter_model.hood.name} has invalid auth token.')
|
||||||
await self.twitter_model.update(enabled=False)
|
await self.twitter_model.update(enabled=False)
|
||||||
self.enabled = self.twitter_model.enabled
|
self.enabled = self.twitter_model.enabled
|
||||||
raise
|
except (KeyError, ValueError, exceptions.NotAuthenticated):
|
||||||
|
logger.warning('Missing consumer_keys for Twitter in your configuration.')
|
||||||
|
await self.twitter_model.update(enabled=False)
|
||||||
|
self.enabled = self.twitter_model.enabled
|
||||||
finally:
|
finally:
|
||||||
logger.debug(f'Bot {self.twitter_model.hood.name} stopped.')
|
logger.debug(f'Bot {self.twitter_model.hood.name} stopped.')
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from logging import getLogger
|
||||||
from sqlite3 import IntegrityError
|
from sqlite3 import IntegrityError
|
||||||
from ormantic.exceptions import NoMatch
|
from ormantic.exceptions import NoMatch
|
||||||
from peony.oauth_dance import get_oauth_token, get_access_token
|
from peony.oauth_dance import get_oauth_token, get_access_token
|
||||||
|
from peony.exceptions import NotAuthenticated
|
||||||
|
|
||||||
|
|
||||||
logger = getLogger(__name__)
|
logger = getLogger(__name__)
|
||||||
|
@ -84,6 +85,8 @@ async def twitter_create(response: Response, hood=Depends(get_hood)):
|
||||||
return twitter
|
return twitter
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT)
|
raise HTTPException(status_code=status.HTTP_409_CONFLICT)
|
||||||
|
except (KeyError, ValueError, NotAuthenticated):
|
||||||
|
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
|
||||||
@twitter_callback_router.get('/callback')
|
@twitter_callback_router.get('/callback')
|
||||||
|
@ -104,8 +107,10 @@ async def twitter_read_callback(oauth_token: str, oauth_verifier: str):
|
||||||
enabled=True,
|
enabled=True,
|
||||||
)
|
)
|
||||||
spawner.start(twitter)
|
spawner.start(twitter)
|
||||||
return []
|
return {}
|
||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT)
|
raise HTTPException(status_code=status.HTTP_409_CONFLICT)
|
||||||
except NoMatch:
|
except NoMatch:
|
||||||
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)
|
||||||
|
except (KeyError, ValueError, NotAuthenticated):
|
||||||
|
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
143
tests/test_api_twitter_create_bot.py
Normal file
143
tests/test_api_twitter_create_bot.py
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
# Copyright (C) 2020 by Cathy Hu <cathy.hu@fau.de>
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: 0BSD
|
||||||
|
|
||||||
|
from fastapi import status
|
||||||
|
from kibicara import config
|
||||||
|
from kibicara.platforms import twitter
|
||||||
|
from kibicara.platforms.twitter.model import Twitter
|
||||||
|
from pytest import fixture
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
|
@fixture(scope='function')
|
||||||
|
def receive_oauth_request_token(monkeypatch, twitter_request_response):
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def mock_get_oauth_request_token(
|
||||||
|
consumer_key, consumer_secret, callback_uri=''
|
||||||
|
):
|
||||||
|
return twitter_request_response
|
||||||
|
|
||||||
|
monkeypatch.setattr(twitter.webapi, 'get_oauth_token', mock_get_oauth_request_token)
|
||||||
|
|
||||||
|
|
||||||
|
@fixture(scope='function')
|
||||||
|
def receive_oauth_access_token(monkeypatch, twitter_access_response):
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def mock_get_oauth_access_token(
|
||||||
|
consumer_key, consumer_secret, access_token, access_token_secret, oauth_verifier
|
||||||
|
):
|
||||||
|
return twitter_access_response
|
||||||
|
|
||||||
|
monkeypatch.setattr(twitter.webapi, 'get_access_token', mock_get_oauth_access_token)
|
||||||
|
|
||||||
|
|
||||||
|
@fixture(scope='function')
|
||||||
|
def disable_spawner(monkeypatch):
|
||||||
|
class DoNothing:
|
||||||
|
def start(self, bot):
|
||||||
|
assert bot is not None
|
||||||
|
|
||||||
|
monkeypatch.setattr(twitter.webapi, 'spawner', DoNothing())
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
'twitter_request_response, twitter_access_response',
|
||||||
|
[
|
||||||
|
(
|
||||||
|
{
|
||||||
|
'oauth_callback_confirmed': 'true',
|
||||||
|
'oauth_token': 'oauth_request_token123',
|
||||||
|
'oauth_token_secret': 'oauth_request_secret123',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'oauth_token': 'oauth_access_token123',
|
||||||
|
'oauth_token_secret': 'oauth_access_secret123',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_twitter_create_bot(
|
||||||
|
client,
|
||||||
|
event_loop,
|
||||||
|
monkeypatch,
|
||||||
|
auth_header,
|
||||||
|
hood_id,
|
||||||
|
receive_oauth_request_token,
|
||||||
|
receive_oauth_access_token,
|
||||||
|
disable_spawner,
|
||||||
|
twitter_request_response,
|
||||||
|
twitter_access_response,
|
||||||
|
):
|
||||||
|
monkeypatch.setitem(
|
||||||
|
config.config,
|
||||||
|
'twitter',
|
||||||
|
{'consumer_key': 'consumer_key123', 'consumer_secret': 'consumer_secret123'},
|
||||||
|
)
|
||||||
|
|
||||||
|
# Twitter create endpoint
|
||||||
|
response = client.post(f'/api/hoods/{hood_id}/twitter/', headers=auth_header)
|
||||||
|
assert response.status_code == status.HTTP_201_CREATED
|
||||||
|
bot_id = response.json()['id']
|
||||||
|
twitter = event_loop.run_until_complete(Twitter.objects.get(id=bot_id))
|
||||||
|
assert (
|
||||||
|
response.json()['access_token']
|
||||||
|
== twitter_request_response['oauth_token']
|
||||||
|
== twitter.access_token
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
response.json()['access_token_secret']
|
||||||
|
== twitter_request_response['oauth_token_secret']
|
||||||
|
== twitter.access_token_secret
|
||||||
|
)
|
||||||
|
assert not twitter.verified
|
||||||
|
assert response.json()['verified'] == twitter.verified
|
||||||
|
assert not twitter.enabled
|
||||||
|
assert response.json()['enabled'] == twitter.enabled
|
||||||
|
assert response.json()['hood']['id'] == hood_id
|
||||||
|
|
||||||
|
# Twitter callback endpoint should enable bot
|
||||||
|
response = client.get(
|
||||||
|
'/api/twitter/callback',
|
||||||
|
params={
|
||||||
|
'oauth_token': twitter_request_response['oauth_token'],
|
||||||
|
'oauth_verifier': 'oauth_verifier123',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_200_OK
|
||||||
|
assert response.json() == {}
|
||||||
|
twitter = event_loop.run_until_complete(Twitter.objects.get(id=bot_id))
|
||||||
|
assert twitter_access_response['oauth_token'] == twitter.access_token
|
||||||
|
assert twitter_access_response['oauth_token_secret'] == twitter.access_token_secret
|
||||||
|
assert twitter.verified
|
||||||
|
assert twitter.enabled
|
||||||
|
|
||||||
|
|
||||||
|
def test_twitter_callback_invalid_oauth_token(client):
|
||||||
|
response = client.get(
|
||||||
|
'/api/twitter/callback', params={'oauth_token': 'abc', 'oauth_verifier': 'def'}
|
||||||
|
)
|
||||||
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
|
||||||
|
|
||||||
|
def test_twitter_create_twitter_invalid_hood(client, auth_header):
|
||||||
|
response = client.post('/api/hoods/1337/twitter/', headers=auth_header)
|
||||||
|
assert response.status_code == status.HTTP_404_NOT_FOUND
|
||||||
|
response = client.post('/api/hoods/wrong/twitter/', headers=auth_header)
|
||||||
|
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
|
||||||
|
|
||||||
|
|
||||||
|
def test_twitter_create_wrong_consumer_keys(client, monkeypatch, auth_header, hood_id):
|
||||||
|
# No consumer keys
|
||||||
|
response = client.post(f'/api/hoods/{hood_id}/twitter/', headers=auth_header)
|
||||||
|
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
|
||||||
|
|
||||||
|
# Invalid consumer keys
|
||||||
|
monkeypatch.setitem(
|
||||||
|
config.config,
|
||||||
|
'twitter',
|
||||||
|
{'consumer_key': 'consumer_key123', 'consumer_secret': 'consumer_secret123'},
|
||||||
|
)
|
||||||
|
|
||||||
|
response = client.post(f'/api/hoods/{hood_id}/twitter/', headers=auth_header)
|
||||||
|
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
|
Loading…
Reference in a new issue