Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix bug 1132961: Add cache to twitter feeds.
- Loading branch information
Showing
5 changed files
with
93 additions
and
15 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 |
---|---|---|
@@ -1,10 +1,33 @@ | ||
from django.core.cache import cache | ||
from django.db import models | ||
from django.db.utils import DatabaseError | ||
|
||
from picklefield import PickledObjectField | ||
from django_extensions.db.fields import ModificationDateTimeField | ||
|
||
|
||
class TwitterCacheManager(models.Manager): | ||
def get_tweets_for(self, account): | ||
cache_key = 'tweets-for-' + str(account) | ||
tweets = cache.get(cache_key) | ||
if tweets is None: | ||
try: | ||
tweets = TwitterCache.objects.get(account=account).tweets | ||
except (TwitterCache.DoesNotExist, DatabaseError): | ||
# TODO: see if we should catch other errors | ||
tweets = [] | ||
|
||
cache.set(cache_key, tweets, 60 * 60 * 6) # 6 hours, same as cron | ||
|
||
return tweets | ||
|
||
|
||
class TwitterCache(models.Model): | ||
account = models.CharField(max_length=100, db_index=True, unique=True) | ||
tweets = PickledObjectField(default=list) | ||
updated = ModificationDateTimeField() | ||
|
||
objects = TwitterCacheManager() | ||
|
||
def __unicode__(self): | ||
return u'Tweets from @' + self.account |
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,57 @@ | ||
# -*- coding: utf-8 -*- | ||
# This Source Code Form is subject to the terms of the Mozilla Public | ||
# License, v. 2.0. If a copy of the MPL was not distributed with this | ||
# file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
|
||
from django.core.cache import cache | ||
from django.db.utils import DatabaseError | ||
|
||
from mock import patch | ||
|
||
from bedrock.mozorg.models import TwitterCache | ||
from bedrock.mozorg.tests import TestCase | ||
|
||
|
||
@patch.object(TwitterCache.objects, 'get') | ||
class TestTwitterCacheManager(TestCase): | ||
def setUp(self): | ||
cache.clear() | ||
|
||
def test_results_cached(self, get_mock): | ||
"""Results from get_tweets_for() should be cached.""" | ||
get_mock.return_value.tweets = ['dude'] | ||
|
||
tweets = TwitterCache.objects.get_tweets_for('dude') | ||
self.assertEqual(['dude'], tweets) | ||
|
||
tweets = TwitterCache.objects.get_tweets_for('dude') | ||
self.assertEqual(['dude'], tweets) | ||
|
||
get_mock.assert_called_once_with(account='dude') | ||
|
||
get_mock.return_value.tweets = ['donny'] | ||
|
||
tweets = TwitterCache.objects.get_tweets_for('donny') | ||
self.assertEqual(['donny'], tweets) | ||
|
||
tweets = TwitterCache.objects.get_tweets_for('donny') | ||
self.assertEqual(['donny'], tweets) | ||
|
||
self.assertEqual(get_mock.call_count, 2) | ||
|
||
def test_errors_fail_silently(self, get_mock): | ||
"""Errors should return an empty list""" | ||
get_mock.side_effect = TwitterCache.DoesNotExist | ||
self.assertEqual(TwitterCache.objects.get_tweets_for('dude'), []) | ||
self.assertEqual(TwitterCache.objects.get_tweets_for('dude'), []) | ||
|
||
# and even errors should be cached | ||
get_mock.assert_called_once_with(account='dude') | ||
|
||
get_mock.reset_mock() | ||
get_mock.side_effect = DatabaseError | ||
self.assertEqual(TwitterCache.objects.get_tweets_for('walter'), []) | ||
self.assertEqual(TwitterCache.objects.get_tweets_for('walter'), []) | ||
|
||
# and even errors should be cached | ||
get_mock.assert_called_once_with(account='walter') |
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
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