Squashed commit of the following:

Updated the supported python versions list.
    Fixed regression in displaying xposts. #173.
    Fixing a few style things.
    Added a more robust test for the tornado handler.
    Trying without pytest-cov
    Updated travis for coverage.
    Remove python 3.2 support because no unicode literals, following what praw supports.
    "Side effect is not iterable."
    Added requirements for travis.
    Renamed travis file correctly.
    Adding test configurations, got tox working.
    Adding vcr cassettes to the repo.
    Renamed requirements files.
    Split up tests and cleaned up test names.
    Tests done, still one failure.
    Treat cassettes as binary to prevent bad merging.
    Fixed a few broken tests.
    Added a timeout to notifications.
    Prepping subreddit page.
    Finished submission page tests.
    Working on submission tests.
    Fixed vcr matching on urls with params, started submission tests.
    Log cleanup.
    Still trying to fix a broken test.
    -Fixed a few pytest bugs and tweaked logging.
    Still working on subscription tests.
    Finished page tests, on to subscription page.
    Finished content tests and starting page tests.
    Added the test refresh-token file to gitignore.
    Moved functional test file out of the repository.
    Continuing work on subreddit content tests.
    Tests now match module names, cassettes are split into individual tests for faster loading.
    Linter fixes.
    Cleanup.
    Added support for nested loaders.
    Added pytest options, starting subreddit content tests.
    Back on track with loader, continuing content tests.
    Finishing submission content tests and discovered snag with loader exception handling.
    VCR up and running, continuing to implement content tests.
    Playing around with vcr.py
    Moved helper functions into terminal and new objects.py
    Fixed a few broken tests.
    Working on navigator tests.
    Reorganizing some things.
    Mocked webbrowser._tryorder for terminal test.
    Completed oauth tests.
    Progress on the oauth tests.
    Working on adding fake tornado request.
    Starting on OAuth tool tests.
    Finished curses helpers tests.
    Still working on curses helpers tests.
    Almost finished with tests on curses helpers.
    Adding tests and working on mocking stdscr.
    Starting to add tests for curses functions.
    Merge branch 'future_work' of https://github.com/michael-lazar/rtv into future_work
    Refactoring controller, still in progress.
    Renamed auth handler.
    Rename CursesHelper to CursesBase.
    Added temporary file with a possible template for func testing.
    Mixup between basename and dirname.
    Merge branch 'future_work' of https://github.com/michael-lazar/rtv into future_work
    py3 compatability for mock.
    Beginning to refactor the curses session.
    Started adding tests, improved unicode handling in the config.
    Cleanup, fixed a few typos.
    Major refactor, almost done!.
    Started a config class.
    Merge branch 'master' into future_work
    The editor now handles unicode characters in all situations.
    Fixed a few typos from previous commits.
    __main__.py formatting.
    Cleaned up history logic and moved to the config file.
This commit is contained in:
Michael Lazar
2015-12-02 22:37:50 -08:00
parent b91bb86e36
commit a7b789bfd9
70 changed files with 42141 additions and 1560 deletions

164
tests/test_oauth.py Normal file
View File

@@ -0,0 +1,164 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import os
from tornado.web import Application
from tornado.testing import AsyncHTTPTestCase
from praw.errors import OAuthException
from rtv.oauth import OAuthHelper, OAuthHandler
from rtv.config import TEMPLATE
try:
from unittest import mock
except ImportError:
import mock
class TestAuthHandler(AsyncHTTPTestCase):
def get_app(self):
self.params = {}
handler = [('/', OAuthHandler, {'params': self.params})]
return Application(handler, template_path=TEMPLATE)
def test_no_callback(self):
resp = self.fetch('/')
assert resp.code == 200
assert self.params['error'] is None
assert 'Wait...' in resp.body.decode()
def test_access_denied(self):
resp = self.fetch('/?error=access_denied')
assert resp.code == 200
assert self.params['error'] == 'access_denied'
assert 'was denied access' in resp.body.decode()
def test_error(self):
resp = self.fetch('/?error=fake')
assert resp.code == 200
assert self.params['error'] == 'fake'
assert 'fake' in resp.body.decode()
def test_success(self):
resp = self.fetch('/?state=fake_state&code=fake_code')
assert resp.code == 200
assert self.params['error'] is None
assert self.params['state'] == 'fake_state'
assert self.params['code'] == 'fake_code'
assert 'Access Granted' in resp.body.decode()
def test_oauth_terminal_non_mobile_authorize(reddit, terminal, config):
# Should direct to the desktop version if using a graphical browser
reddit.config.API_PATHS['authorize'] = 'api/v1/authorize/'
terminal._display = True
oauth = OAuthHelper(reddit, terminal, config)
assert '.compact' not in oauth.reddit.config.API_PATHS['authorize']
def test_oauth_terminal_mobile_authorize(reddit, terminal, config):
# Should direct to the mobile version if using a terminal browser
reddit.config.API_PATHS['authorize'] = 'api/v1/authorize/'
terminal._display = False
oauth = OAuthHelper(reddit, terminal, config)
assert '.compact' in oauth.reddit.config.API_PATHS['authorize']
def test_oauth_authorize_with_refresh_token(oauth, stdscr, refresh_token):
oauth.config.refresh_token = refresh_token
oauth.authorize()
assert oauth.http_server is None
# We should be able to handle an oauth failure
with mock.patch.object(oauth.reddit, 'refresh_access_information'):
exception = OAuthException('', '')
oauth.reddit.refresh_access_information.side_effect = exception
oauth.authorize()
message = 'Invalid OAuth data'.encode('utf-8')
stdscr.derwin().addstr.assert_called_with(1, 1, message)
assert oauth.http_server is None
def test_oauth_authorize(oauth, reddit, stdscr, refresh_token):
# Because we use `from .helpers import open_browser` we have to patch the
# function in the destination oauth module and not the helpers module
with mock.patch('uuid.UUID.hex', new_callable=mock.PropertyMock) as uuid, \
mock.patch('rtv.terminal.Terminal.open_browser') as open_browser, \
mock.patch('rtv.oauth.ioloop') as ioloop, \
mock.patch('rtv.oauth.httpserver'), \
mock.patch.object(oauth.reddit, 'user'), \
mock.patch('time.sleep'):
io = ioloop.IOLoop.current.return_value
# Valid authorization
oauth.term._display = False
params = {'state': 'uniqueid', 'code': 'secretcode', 'error': None}
uuid.return_value = params['state']
io.start.side_effect = lambda *_: oauth.params.update(**params)
oauth.authorize()
assert not open_browser.called
oauth.reddit.get_access_information.assert_called_with(
reddit, params['code'])
assert oauth.config.refresh_token is not None
assert oauth.config.save_refresh_token.called
stdscr.reset_mock()
oauth.reddit.get_access_information.reset_mock()
oauth.config.save_refresh_token.reset_mock()
oauth.http_server = None
# The next authorization should skip the oauth process
oauth.config.refresh_token = refresh_token
oauth.authorize()
assert oauth.reddit.user is not None
assert oauth.http_server is None
stdscr.reset_mock()
# Invalid state returned
params = {'state': 'uniqueid', 'code': 'secretcode', 'error': None}
oauth.config.refresh_token = None
uuid.return_value = 'invalidcode'
oauth.authorize()
error_message = 'UUID mismatch'.encode('utf-8')
stdscr.subwin.addstr.assert_any_call(1, 1, error_message)
# Valid authorization, terminal browser
oauth.term._display = True
params = {'state': 'uniqueid', 'code': 'secretcode', 'error': None}
uuid.return_value = params['state']
io.start.side_effect = lambda *_: oauth.params.update(**params)
oauth.authorize()
assert open_browser.called
oauth.reddit.get_access_information.assert_called_with(
reddit, params['code'])
assert oauth.config.refresh_token is not None
assert oauth.config.save_refresh_token.called
stdscr.reset_mock()
oauth.reddit.get_access_information.reset_mock()
oauth.config.refresh_token = None
oauth.config.save_refresh_token.reset_mock()
oauth.http_server = None
# Exceptions when logging in are handled correctly
with mock.patch.object(oauth.reddit, 'get_access_information'):
exception = OAuthException('', '')
oauth.reddit.get_access_information.side_effect = exception
oauth.authorize()
message = 'Invalid OAuth data'.encode('utf-8')
stdscr.derwin().addstr.assert_called_with(1, 1, message)
assert not oauth.config.save_refresh_token.called
def test_oauth_clear_data(oauth):
oauth.config.refresh_token = 'secrettoken'
oauth.reddit.refresh_token = 'secrettoken'
oauth.clear_oauth_data()
assert oauth.config.refresh_token is None
assert oauth.reddit.refresh_token is None