-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from MarekSuchanek/task04
Task04
- Loading branch information
Showing
21 changed files
with
3,094 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
language: python | ||
python: | ||
- '3.5' | ||
install: | ||
- python setup.py install | ||
script: | ||
- python setup.py test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
include LICENSE | ||
exclude README.md | ||
include pytest.ini | ||
include config/auth.example.cfg | ||
include tests/*.py | ||
graft tests/fixtures |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,8 @@ | ||
# Twitter Wall | ||
|
||
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) | ||
![Version](https://img.shields.io/badge/release-v0.3-orange.svg) | ||
![Version](https://img.shields.io/badge/release-v0.4-orange.svg) | ||
[![Build Status](https://travis-ci.com/MarekSuchanek/PYT-TwitterWall.svg?token=XD73y3snHDycemSiHx3H&branch=task04)](https://travis-ci.com/MarekSuchanek/PYT-TwitterWall) | ||
|
||
|
||
Twitter Wall is simple [Python](https://www.python.org) powered app for | ||
|
@@ -244,6 +245,52 @@ Enlarged photo of cat :smiley_cat: via [Lightbox](http://lokeshdhakar.com/projec | |
|
||
![Enlarged photo of cat via Lightbox](http://marsu.9e.cz/github/twitterwall-lightbox.png) | ||
|
||
|
||
## Testing | ||
|
||
This project uses the most fabulous testing tools for Python: | ||
|
||
* [pytest](http://doc.pytest.org/) | ||
* [pytest-cov](https://pypi.python.org/pypi/pytest-cov) | ||
* [pytest-pep8](https://pypi.python.org/pypi/pytest-pep8) | ||
* [pytest-sugar](https://pypi.python.org/pypi/pytest-sugar) | ||
* [flexmock](http://flexmock.readthedocs.io/en/latest/) | ||
* [betamax](betamax.readthedocs.io) | ||
|
||
Run tests: | ||
|
||
``` | ||
python setup.py test | ||
``` | ||
|
||
or (if you have installed dependencies): | ||
|
||
``` | ||
python -m pytest [options] | ||
pytest [options] | ||
``` | ||
|
||
### Betamax cassettes | ||
|
||
Betamax cassettes are stored in `tests/fixtures/cassettes` directory. If | ||
you are not connected to the internet, Twitter API is not working and/or | ||
you don't have own API credentials you will use (replay) them in order to | ||
test API client. | ||
|
||
If you want to run your own cassettes, you need to setup system variables | ||
|
||
* `API_KEY` | ||
* `API_SECRET` | ||
|
||
Your test command then might look like: | ||
|
||
``` | ||
API_KEY=<YOUR_API_KEY> API_SECRET=<YOUR_API_SECRET> \ | ||
python setup.py test | ||
``` | ||
|
||
For more information, enjoy reading [Betamax documentation](http://betamax.readthedocs.io/en/latest/introduction.html). | ||
|
||
## Authors | ||
|
||
* Marek Suchánek [[[email protected]](mailto:[email protected])] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[pytest] | ||
addopts = tests/ twitterwall/ --pep8 --cov=twitterwall |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
[aliases] | ||
test=pytest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import pytest | ||
import betamax | ||
import flexmock | ||
from betamax.cassette import cassette | ||
import os | ||
import json | ||
import flask_injector | ||
import injector | ||
from twitterwall.common import TwitterConnection | ||
|
||
|
||
def sanitize_requests(interaction, current_cassette): | ||
headers = interaction.data['request']['headers'] | ||
auth = headers.get('Authorization')[0] | ||
if auth is None: | ||
return | ||
current_cassette.placeholders.append( | ||
cassette.Placeholder( | ||
placeholder='<AUTH>', | ||
replace=auth | ||
) | ||
) | ||
|
||
|
||
def sanitize_responses(interaction, current_cassette): | ||
if interaction.data['response']['status']['code'] != 200: | ||
return | ||
data = interaction.as_response().json() | ||
if 'access_token' not in data: | ||
return | ||
current_cassette.placeholders.append( | ||
cassette.Placeholder( | ||
placeholder='<TOKEN>', | ||
replace=data['access_token']) | ||
) | ||
|
||
|
||
def sanitize_token(interaction, current_cassette): | ||
sanitize_requests(interaction, current_cassette) | ||
sanitize_responses(interaction, current_cassette) | ||
|
||
|
||
with betamax.Betamax.configure() as config: | ||
config.cassette_library_dir = 'tests/fixtures/cassettes' | ||
if 'API_KEY' in os.environ and 'API_SECRET' in os.environ: | ||
config.default_cassette_options['record_mode'] = 'all' | ||
else: | ||
config.default_cassette_options['record_mode'] = 'none' | ||
config.before_record(callback=sanitize_token) | ||
|
||
|
||
@pytest.fixture | ||
def twitter(betamax_session): | ||
"""TwitterConnection with betamax session""" | ||
betamax_session.headers.update({'accept-encoding': 'identity'}) | ||
api_key = os.environ.get('API_KEY', 'fake_key') | ||
api_secret = os.environ.get('API_SECRET', 'fake_secret') | ||
return TwitterConnection(api_key, api_secret, session=betamax_session) | ||
|
||
|
||
@pytest.fixture | ||
def twitter_mock(): | ||
"""TwitterConnection Mock returning tweets from example JSON file""" | ||
from twitterwall.common import Tweet | ||
|
||
def get_tweets(params): | ||
with open('tests/fixtures/tweets.json') as f: | ||
return [Tweet(data) for data in json.load(f)['statuses']] | ||
return flexmock.flexmock(get_tweets=get_tweets) | ||
|
||
|
||
@pytest.fixture | ||
def webapp(twitter_mock): | ||
"""Flask web application test client""" | ||
from twitterwall.web import app | ||
|
||
def configure(binder): | ||
binder.bind( | ||
TwitterConnection, | ||
to=twitter_mock, | ||
scope=injector.singleton | ||
) | ||
|
||
flask_injector.FlaskInjector(app=app, modules=[configure]) | ||
|
||
app.config['TESTING'] = True | ||
app.config['AJAX_INTERVAL'] = 7 | ||
app.config['INIT_COUNT'] = 10 | ||
return app.test_client() |
169 changes: 169 additions & 0 deletions
169
tests/fixtures/cassettes/test_twitterconnection.test_client_max_id.json
Large diffs are not rendered by default.
Oops, something went wrong.
1,039 changes: 1,039 additions & 0 deletions
1,039
tests/fixtures/cassettes/test_twitterconnection.test_client_query.json
Large diffs are not rendered by default.
Oops, something went wrong.
385 changes: 385 additions & 0 deletions
385
tests/fixtures/cassettes/test_twitterconnection.test_client_simple.json
Large diffs are not rendered by default.
Oops, something went wrong.
277 changes: 277 additions & 0 deletions
277
tests/fixtures/cassettes/test_twitterconnection.test_client_since_id.json
Large diffs are not rendered by default.
Oops, something went wrong.
169 changes: 169 additions & 0 deletions
169
tests/fixtures/cassettes/test_twitterconnection.test_client_until.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
{ | ||
"http_interactions": [ | ||
{ | ||
"response": { | ||
"body": { | ||
"encoding": "utf-8", | ||
"string": "{\"statuses\":[],\"search_metadata\":{\"completed_in\":0.004,\"max_id\":793485822497128448,\"max_id_str\":\"793485822497128448\",\"query\":\"%23python+until%3A2016-01-01\",\"refresh_url\":\"?since_id=793485822497128448&q=%23python%20until%3A2016-01-01&include_entities=1\",\"count\":10,\"since_id\":0,\"since_id_str\":\"0\"}}" | ||
}, | ||
"headers": { | ||
"x-content-type-options": "nosniff", | ||
"x-access-level": "read", | ||
"server": "tsa_b", | ||
"status": "200 OK", | ||
"x-response-time": "18", | ||
"content-length": "297", | ||
"x-frame-options": "SAMEORIGIN", | ||
"cache-control": "no-cache, no-store, must-revalidate, pre-check=0, post-check=0", | ||
"x-rate-limit-remaining": "418", | ||
"x-connection-hash": "3c4f965e9d6d4dbe12f4acaf111abe28", | ||
"x-twitter-response-tags": "BouncerCompliant", | ||
"x-rate-limit-limit": "450", | ||
"last-modified": "Tue, 01 Nov 2016 16:12:16 GMT", | ||
"strict-transport-security": "max-age=631138519", | ||
"pragma": "no-cache", | ||
"expires": "Tue, 31 Mar 1981 05:00:00 GMT", | ||
"x-xss-protection": "1; mode=block", | ||
"content-type": "application/json;charset=utf-8", | ||
"x-rate-limit-reset": "1478017059", | ||
"x-transaction": "00fcd53a009082b9", | ||
"content-disposition": "attachment; filename=json.json", | ||
"date": "Tue, 01 Nov 2016 16:12:16 GMT" | ||
}, | ||
"status": { | ||
"code": 200, | ||
"message": "OK" | ||
}, | ||
"url": "https://api.twitter.com/1.1/search/tweets.json?count=10&q=%23python&until=2016-01-01" | ||
}, | ||
"recorded_at": "2016-11-01T16:12:17", | ||
"request": { | ||
"body": { | ||
"encoding": "utf-8", | ||
"string": "" | ||
}, | ||
"headers": { | ||
"Cookie": "guest_id=v1%3A147801673635265550", | ||
"Connection": "keep-alive", | ||
"User-Agent": "python-requests/2.11.1", | ||
"Accept": "*/*", | ||
"accept-encoding": "identity", | ||
"Authorization": "Bearer <TOKEN>" | ||
}, | ||
"method": "GET", | ||
"uri": "https://api.twitter.com/1.1/search/tweets.json?count=10&q=%23python&until=2016-01-01" | ||
} | ||
}, | ||
{ | ||
"response": { | ||
"body": { | ||
"encoding": "utf-8", | ||
"string": "{\"token_type\":\"bearer\",\"access_token\":\"<TOKEN>\"}" | ||
}, | ||
"headers": { | ||
"x-content-type-options": "nosniff", | ||
"content-length": "153", | ||
"server": "tsa_b", | ||
"status": "200 OK", | ||
"set-cookie": "guest_id=v1%3A147801673889803128; Domain=.twitter.com; Path=/; Expires=Thu, 01-Nov-2018 16:12:18 UTC", | ||
"x-response-time": "20", | ||
"x-twitter-response-tags": "BouncerCompliant", | ||
"x-frame-options": "DENY", | ||
"ml": "A", | ||
"cache-control": "no-cache, no-store, must-revalidate, pre-check=0, post-check=0", | ||
"x-connection-hash": "a7a26fb2b110f8399b56de3a07baed1b", | ||
"last-modified": "Tue, 01 Nov 2016 16:12:18 GMT", | ||
"strict-transport-security": "max-age=631138519", | ||
"pragma": "no-cache", | ||
"expires": "Tue, 31 Mar 1981 05:00:00 GMT", | ||
"x-xss-protection": "1; mode=block", | ||
"content-type": "application/json;charset=utf-8", | ||
"x-transaction": "0073101400f5db58", | ||
"content-disposition": "attachment; filename=json.json", | ||
"x-tsa-request-body-time": "76", | ||
"x-ua-compatible": "IE=edge,chrome=1", | ||
"date": "Tue, 01 Nov 2016 16:12:18 GMT" | ||
}, | ||
"url": "https://api.twitter.com/oauth2/token", | ||
"status": { | ||
"code": 200, | ||
"message": "OK" | ||
} | ||
}, | ||
"recorded_at": "2016-11-01T16:12:18", | ||
"request": { | ||
"body": { | ||
"encoding": "utf-8", | ||
"string": "grant_type=client_credentials" | ||
}, | ||
"headers": { | ||
"Content-Type": "application/x-www-form-urlencoded", | ||
"Authorization": "<AUTH>", | ||
"Connection": "keep-alive", | ||
"Content-Length": "29", | ||
"User-Agent": "python-requests/2.11.1", | ||
"Accept": "*/*", | ||
"accept-encoding": "identity", | ||
"Host": "api.twitter.com" | ||
}, | ||
"method": "POST", | ||
"uri": "https://api.twitter.com/oauth2/token" | ||
} | ||
}, | ||
{ | ||
"response": { | ||
"body": { | ||
"encoding": "utf-8", | ||
"string": "{\"statuses\":[],\"search_metadata\":{\"completed_in\":0.004,\"max_id\":793485831338721280,\"max_id_str\":\"793485831338721280\",\"query\":\"%23python+until%3A2015-05-15\",\"refresh_url\":\"?since_id=793485831338721280&q=%23python%20until%3A2015-05-15&include_entities=1\",\"count\":10,\"since_id\":0,\"since_id_str\":\"0\"}}" | ||
}, | ||
"headers": { | ||
"x-content-type-options": "nosniff", | ||
"content-length": "297", | ||
"server": "tsa_b", | ||
"status": "200 OK", | ||
"x-access-level": "read", | ||
"x-response-time": "18", | ||
"x-twitter-response-tags": "BouncerCompliant", | ||
"x-frame-options": "SAMEORIGIN", | ||
"cache-control": "no-cache, no-store, must-revalidate, pre-check=0, post-check=0", | ||
"x-rate-limit-remaining": "417", | ||
"x-connection-hash": "a7a26fb2b110f8399b56de3a07baed1b", | ||
"x-rate-limit-limit": "450", | ||
"last-modified": "Tue, 01 Nov 2016 16:12:19 GMT", | ||
"strict-transport-security": "max-age=631138519", | ||
"pragma": "no-cache", | ||
"expires": "Tue, 31 Mar 1981 05:00:00 GMT", | ||
"x-xss-protection": "1; mode=block", | ||
"content-type": "application/json;charset=utf-8", | ||
"x-rate-limit-reset": "1478017059", | ||
"x-transaction": "009295110002f388", | ||
"content-disposition": "attachment; filename=json.json", | ||
"date": "Tue, 01 Nov 2016 16:12:19 GMT" | ||
}, | ||
"url": "https://api.twitter.com/1.1/search/tweets.json?count=10&q=%23python&until=2015-05-15", | ||
"status": { | ||
"code": 200, | ||
"message": "OK" | ||
} | ||
}, | ||
"recorded_at": "2016-11-01T16:12:19", | ||
"request": { | ||
"body": { | ||
"encoding": "utf-8", | ||
"string": "" | ||
}, | ||
"headers": { | ||
"Cookie": "guest_id=v1%3A147801673889803128", | ||
"Connection": "keep-alive", | ||
"Authorization": "Bearer <TOKEN>", | ||
"Accept": "*/*", | ||
"accept-encoding": "identity", | ||
"User-Agent": "python-requests/2.11.1" | ||
}, | ||
"method": "GET", | ||
"uri": "https://api.twitter.com/1.1/search/tweets.json?count=10&q=%23python&until=2015-05-15" | ||
} | ||
} | ||
], | ||
"recorded_with": "betamax/0.8.0" | ||
} |
Oops, something went wrong.