Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Bug 654355 Multiple Client Match Rules #3

Merged
merged 3 commits into from

2 participants

@Osmose
Owner

Changes client match rules such that any inclusion rule that doesn't match a client causes the associated snippet to not be sent to the client.

This lets us scale by using a small set of rules and composing them together on snippets to limit which clients get which snippets.

@erikrose
# There's an include rule that doesn't match. Add it as an exclude rule so that...

(something like that)

@erikrose

And what should happen if they don't?

@erikrose

I really hate these tests (not your fault, of course). They're terribly brittle, as you can see from how much you had to change. Wouldn't it be better to just loop over the cache log and assert there are no sets?

@Osmose Osmose merged commit ee8a598 into mozilla:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 28, 2011
  1. @Osmose

    Change so inclusion rules on a snippet that don't

    Osmose authored
    match stop the snippet from being sent to the user
  2. @Osmose

    Pyflakes + PEP8 fix

    Osmose authored
Commits on Jul 9, 2011
  1. @Osmose

    Add better documentation

    Osmose authored
This page is out of date. Refresh to see the latest.
View
131 apps/homesnippets/models.py
@@ -1,19 +1,15 @@
"""
homesnippets models
"""
-import logging
import hashlib
from datetime import datetime
from time import mktime, gmtime
+
from django.conf import settings
-from django.db import models
-from django import forms
from django.core import urlresolvers
-from django.contrib.contenttypes.models import ContentType
-from django.db.models.signals import pre_save, post_save, pre_delete, post_delete
from django.core.cache import cache
-from django.contrib.sites.models import Site
-from django.contrib.auth.models import User
+from django.db import models
+from django.db.models.signals import post_save, post_delete
from django.utils.translation import ugettext_lazy as _
@@ -36,7 +32,13 @@ def _key_from_client(args):
class ClientMatchRuleManager(models.Manager):
"""Manager for client match rules, allows filtering against match logic"""
- def find_ids_for_matches(self, args):
+ def find_match_ids_for_request(self, args):
+ """
+ Finds all match rules that affect the given request. Returns two lists
+ containing the rules that will exclude or include snippets in the
+ response.
+ """
+
cache_key = '%s%s' % (CACHE_RULE_MATCH_PREFIX, _key_from_client(args))
cache_hit = cache.get(cache_key)
@@ -55,12 +57,22 @@ def find_ids_for_matches(self, args):
if not cache_hit:
# Cache miss, so recalculate the results and cache them.
- matches = [ rule for rule in self._cached_all()
- if rule.is_match(args) ]
- (include_ids, exclude_ids) = (
- [str(rule.id) for rule in matches if not rule.exclude],
- [str(rule.id) for rule in matches if rule.exclude],
- )
+ rules = self._cached_all()
+ include_ids, exclude_ids = [], []
+
+ # Check every rule
+ for rule in rules:
+ if rule.is_match(args):
+ if rule.exclude:
+ exclude_ids.append(str(rule.id))
+ else:
+ include_ids.append(str(rule.id))
+ elif not rule.exclude:
+ # Include rule that doesn't match? Add as an exclude rule
+ # so that snippets can split required matches into multiple
+ # rules and combine them together.
+ exclude_ids.append(str(rule.id))
+
cache_hit = (mktime(gmtime()), (include_ids, exclude_ids))
cache.set(cache_key, cache_hit, CACHE_TIMEOUT)
@@ -68,7 +80,7 @@ def find_ids_for_matches(self, args):
def _cached_all(self):
"""Cached version of self.all(), invalidated by change to any rule."""
- c_data = cache.get_many([CACHE_RULE_ALL_PREFIX,
+ c_data = cache.get_many([CACHE_RULE_ALL_PREFIX,
CACHE_RULE_ALL_LASTMOD_PREFIX])
lastmod = c_data.get(CACHE_RULE_ALL_LASTMOD_PREFIX, None)
@@ -97,34 +109,34 @@ class Meta():
exclude = models.BooleanField( _('exclusion rule?'),
default=False)
- # browser/components/nsBrowserContentHandler.js:911:
- # const SNIPPETS_URL = "http://snippets.mozilla.com/" + STARTPAGE_VERSION +
+ # browser/components/nsBrowserContentHandler.js:911:
+ # const SNIPPETS_URL = "http://snippets.mozilla.com/" + STARTPAGE_VERSION +
# "/%NAME%/%VERSION%/%APPBUILDID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%
# /%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/";
- startpage_version = models.CharField( _('start page version'),
+ startpage_version = models.CharField( _('start page version'),
null=True, blank=True, max_length=64)
- name = models.CharField( _('product name'),
+ name = models.CharField( _('product name'),
null=True, blank=True, max_length=64)
- version = models.CharField( _('product version'),
+ version = models.CharField( _('product version'),
null=True, blank=True, max_length=64)
- appbuildid = models.CharField( _('app build id'),
+ appbuildid = models.CharField( _('app build id'),
null=True, blank=True, max_length=64)
- build_target = models.CharField( _('build target'),
+ build_target = models.CharField( _('build target'),
null=True, blank=True, max_length=64)
- locale = models.CharField( _('locale'),
+ locale = models.CharField( _('locale'),
null=True, blank=True, max_length=64)
- channel = models.CharField( _('channel'),
+ channel = models.CharField( _('channel'),
null=True, blank=True, max_length=64)
- os_version = models.CharField( _('os version'),
+ os_version = models.CharField( _('os version'),
null=True, blank=True, max_length=64)
- distribution = models.CharField( _('distribution'),
+ distribution = models.CharField( _('distribution'),
null=True, blank=True, max_length=64)
- distribution_version = models.CharField( _('distribution version'),
+ distribution_version = models.CharField( _('distribution version'),
null=True, blank=True, max_length=64)
- created = models.DateTimeField( _('date created'),
+ created = models.DateTimeField( _('date created'),
auto_now_add=True, blank=False)
- modified = models.DateTimeField( _('date last modified'),
+ modified = models.DateTimeField( _('date last modified'),
auto_now=True, blank=False)
def __unicode__(self):
@@ -136,17 +148,17 @@ def __unicode__(self):
return self.description
else:
return '%s /%s' % (
- self.exclude and 'EXCLUDE' or 'INCLUDE',
- '/'.join(vals)
+ self.exclude and 'EXCLUDE' or 'INCLUDE',
+ '/'.join(vals)
)
def is_match(self, args):
is_match = True
for ak,av in args.items():
mv = getattr(self, ak, None)
- if not mv:
+ if not mv:
continue
-
+
if mv.startswith('/'):
# Regex match
import re
@@ -173,15 +185,15 @@ def related_snippets(self):
count = self.snippet_set.count()
# TODO: Needs l10n? Maybe not a priority for an admin page.
- return (
- ( (count != 1) and
+ return (
+ ( (count != 1) and
'<a href="%(link)s" title="Click to list snippets matched by this rule"><strong>%(count)d snippets</strong></a>' or
'<a href="%(link)s" title="Click to list snippets matched by this rule"><strong>%(count)d snippet</strong></a>' )
- % dict(count=count, link=link)
+ % dict(count=count, link=link)
)
related_snippets.allow_tags = True
-
+
def rule_update_lastmods(sender, instance, created=False, **kwargs):
"""On a change to a rule, bump lastmod timestamps for that rule and the set
@@ -205,10 +217,10 @@ def rule_update_lastmods(sender, instance, created=False, **kwargs):
class SnippetManager(models.Manager):
def find_snippets_with_match_rules(self, args, time_now=None):
- """Find snippets data using match rules.
+ """Find snippets data using match rules.
Returned is a list of dicts with id and body of snippets found, rather
- than full Snippet model objects. This makes things easier to cache -
+ than full Snippet model objects. This makes things easier to cache -
if full snippets are required, try using the id's to look them up.
"""
if time_now is None:
@@ -216,17 +228,17 @@ def find_snippets_with_match_rules(self, args, time_now=None):
preview = ( 'preview' in args ) and args['preview']
include_ids, exclude_ids = \
- ClientMatchRule.objects.find_ids_for_matches(args)
+ ClientMatchRule.objects.find_match_ids_for_request(args)
snippets = self.find_snippets_for_rule_ids(preview, include_ids, exclude_ids)
- # Filter for date ranges here, rather than in SQL.
+ # Filter for date ranges here, rather than in SQL.
#
# This is a compromise to make snippet match results more cacheable -
# ie. cached data should only be recalculated in response to content
# changes, not the passage of time.
- snippets_data = [ s for s in snippets if (
+ snippets_data = [ s for s in snippets if (
( not s['pub_start'] or time_now >= s['pub_start'] ) and
- ( not s['pub_end'] or time_now < s['pub_end'] )
+ ( not s['pub_end'] or time_now < s['pub_end'] )
) ]
return snippets_data
@@ -235,7 +247,7 @@ def find_snippets_for_rule_ids(self, preview, include_ids, exclude_ids):
"""Given a set of matching inclusion & exclusion rule IDs, look up the
corresponding snippets."""
- if not include_ids and not exclude_ids:
+ if not include_ids and not exclude_ids:
return []
# Could base the cache key on the entire text of the SQL query
@@ -263,7 +275,7 @@ def find_snippets_for_rule_ids(self, preview, include_ids, exclude_ids):
if not cache_hit:
# No cache hit, look up the snippets associated with rules.
sql_base = """
- SELECT homesnippets_snippet.*
+ SELECT homesnippets_snippet.*
FROM homesnippets_snippet
WHERE ( %s )
ORDER BY priority, pub_start, modified
@@ -274,28 +286,28 @@ def find_snippets_for_rule_ids(self, preview, include_ids, exclude_ids):
if not preview:
where.append('( homesnippets_snippet.preview <> 1 )')
if include_ids:
- where.append("""
+ where.append("""
homesnippets_snippet.id IN (
SELECT snippet_id
FROM homesnippets_snippet_client_match_rules
WHERE clientmatchrule_id IN (%s)
- )
+ )
""" % ",".join(include_ids))
if exclude_ids:
- where.append("""
+ where.append("""
homesnippets_snippet.id NOT IN (
SELECT snippet_id
FROM homesnippets_snippet_client_match_rules
WHERE clientmatchrule_id IN (%s)
- )
+ )
""" % ",".join(exclude_ids))
sql = sql_base % (' AND '.join(where))
# Reduce snippet model objects to more cacheable dicts
snippet_objs = self.raw(sql)
- snippets = [
+ snippets = [
dict(
- id=snippet.id,
+ id=snippet.id,
name=snippet.name,
body=snippet.body,
pub_start=snippet.pub_start,
@@ -318,10 +330,10 @@ class Meta():
client_match_rules = models.ManyToManyField(
ClientMatchRule, blank=False)
-
- name = models.CharField( _("short name (only shown to admins)"),
+
+ name = models.CharField( _("short name (only shown to admins)"),
blank=False, max_length=255)
- body = models.TextField( _("content body"),
+ body = models.TextField( _("content body"),
blank=False)
priority = models.IntegerField( _('sort order priority'),
@@ -331,16 +343,16 @@ class Meta():
preview = models.BooleanField( _('preview only?'),
default=False)
pub_start = models.DateTimeField( _('start time'),
- blank=True, null=True)
+ blank=True, null=True)
pub_end = models.DateTimeField( _('end time'),
- blank=True, null=True)
+ blank=True, null=True)
- created = models.DateTimeField( _('date created'),
+ created = models.DateTimeField( _('date created'),
auto_now_add=True, blank=False)
- modified = models.DateTimeField( _('date last modified'),
+ modified = models.DateTimeField( _('date last modified'),
auto_now=True, blank=False)
-
+
def snippet_update_lastmod(sender, instance, **kwargs):
"""On a change to a snippet, bump its cached lastmod timestamp"""
now = mktime(gmtime())
@@ -353,4 +365,3 @@ def snippet_update_lastmod(sender, instance, **kwargs):
post_save.connect(snippet_update_lastmod, sender=Snippet)
post_delete.connect(snippet_update_lastmod, sender=Snippet)
-
View
297 apps/homesnippets/tests/caching.py
@@ -1,55 +1,45 @@
"""
homesnippets caching tests
"""
-import logging
import time
import random
-import datetime
from django.conf import settings
-
-from django.db import connection
-
-from django.http import HttpRequest
-from django.test import TestCase
-from django.test.client import Client
-
-from django.core.cache import cache
+from django.core import cache
from django.core.cache.backends import locmem
-from nose.tools import assert_equal, with_setup, assert_false, eq_, ok_
-from nose.plugins.attrib import attr
+from nose.tools import eq_, ok_
-from homesnippets.models import Snippet, ClientMatchRule
-from homesnippets.models import CACHE_RULE_MATCH_PREFIX, CACHE_RULE_LASTMOD_PREFIX
-from homesnippets.models import CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX
-from homesnippets.models import CACHE_RULE_NEW_LASTMOD_PREFIX
-from homesnippets.models import CACHE_SNIPPET_LASTMOD_PREFIX
-from homesnippets.models import CACHE_SNIPPET_LOOKUP_PREFIX
-
-import django.core.cache
import homesnippets.models
-
+from homesnippets.models import (Snippet, ClientMatchRule,
+ CACHE_RULE_MATCH_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LOOKUP_PREFIX)
from homesnippets.tests.utils import HomesnippetsTestCase
+
class CacheClass(locmem.CacheClass):
"""Cache subclass that comes with a hacky event log for test assertions"""
def __init__(self, server, params):
locmem.CacheClass.__init__(self, server, params)
- self.id = random.randint(0,1000)
+ self.id = random.randint(0, 1000)
self.log = []
self.during_many = False
def get(self, key, default=None):
if not self.during_many:
self.log.append(('get', key))
- return locmem.CacheClass.get(self,key,default)
+ return locmem.CacheClass.get(self, key, default)
def set(self, key, value, timeout=None):
if not self.during_many:
self.log.append(('set', key, value))
- return locmem.CacheClass.set(self,key,value,timeout)
+ return locmem.CacheClass.set(self, key, value, timeout)
def clear(self):
self.log = []
@@ -58,14 +48,14 @@ def clear(self):
def get_many(self, keys):
self.log.append(('get_many', keys))
self.during_many = True
- rv = locmem.CacheClass.get_many(self,keys)
+ rv = locmem.CacheClass.get_many(self, keys)
self.during_many = False
return rv
def set_many(self, keys, timeout):
self.log.append(('set_many', keys, timeout))
self.during_many = True
- rv = locmem.CacheClass.set_many(self,keys,timeout)
+ rv = locmem.CacheClass.set_many(self, keys, timeout)
self.during_many = False
return rv
@@ -76,58 +66,59 @@ def setUp(self):
HomesnippetsTestCase.setUp(self)
settings.CACHE_BACKEND = 'homesnippets.tests://'
- self.cache = django.core.cache.get_cache(settings.CACHE_BACKEND)
- django.core.cache.cache = self.cache
+ self.cache = cache.get_cache(settings.CACHE_BACKEND)
+ cache.cache = self.cache
homesnippets.models.cache = self.cache
self.cache.clear()
self.rules = self.setup_rules({
- 'fields': ( 'startpage_version', 'name', 'version', 'locale', ),
+ 'fields': ('startpage_version', 'name', 'version', 'locale'),
'items': {
# Specific rule, expected to be matched
- 'specific': ( '1', 'Firefox', '4.0', 'en-US', ),
+ 'specific': ('1', 'Firefox', '4.0', 'en-US'),
# Less-specific rule, should match but not result in duplicate
- 'vague': ( '1', 'Firefox', '4.0', None, ),
+ 'vague': ('1', 'Firefox', '4.0', None),
# Rule that won't be attached to any snippet.
- 'unused': ( '1', 'Mudfish', '7.0', 'en-GB', ),
+ 'unused': ('1', 'Mudfish', '7.0', 'en-GB'),
# Rule that will be attached to snippet, but not matched.
- 'unmatched': ( '2', 'Airdog', '3.0', 'de' ),
+ 'unmatched': ('2', 'Airdog', '3.0', 'de'),
# Rule matching anything
- 'all': ( None, None, None, None ),
+ 'all': (None, None, None, None),
}
})
self.snippets = self.setup_snippets(self.rules, {
- 'fields': ( 'name', 'body', 'rules' ),
+ 'fields': ('name', 'body', 'rules'),
'items': {
# Using specific and less-specific rule
- 'expected': ( 'test 1', 'Expected body data',
- ( self.rules['specific'], self.rules['vague'] ) ),
+ 'expected': ('test 1', 'Expected body data',
+ (self.rules['specific'], self.rules['vague'])),
# No rules, so always included in results
- 'ever': ( 'test 2', 'Ever-present body data',
- ( self.rules['all'], ) ),
- # Rule attached that will never be matched, so should never appear
- 'never': (' test 3', 'Never-present body data',
- ( self.rules['unmatched'], ) ),
+ 'ever': ('test 2', 'Ever-present body data',
+ (self.rules['all'], )),
+ # Rule attached that will never be matched,
+ # so should never appear
+ 'never': ('test 3', 'Never-present body data',
+ (self.rules['unmatched'], )),
}
})
# Warm up the cache with some initial requests...
self.assert_snippets({
'/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['expected'], True ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], True),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
'/9/Waterduck/9.2/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['expected'], False ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], False),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
'/1/Mudfish/7.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( self.snippets['expected'], False ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], False),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
})
@@ -136,15 +127,15 @@ def setUp(self):
self.assert_cache_events((
# First, the lastmod times for rules are cached
- ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
+ ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
CACHE_RULE_ALL_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
- ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
+ ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
CACHE_RULE_ALL_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
- ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
+ ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
CACHE_RULE_ALL_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
- ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
+ ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
CACHE_RULE_ALL_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
- ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
+ ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
CACHE_RULE_ALL_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
# Then, lastmod times for snippets are cached.
@@ -154,7 +145,8 @@ def setUp(self):
# Request 1
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_ALL_PREFIX),
('set', CACHE_RULE_MATCH_PREFIX),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
@@ -162,18 +154,20 @@ def setUp(self):
# Request 2
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_MATCH_PREFIX),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
('set', CACHE_SNIPPET_LOOKUP_PREFIX),
# Request 3
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_MATCH_PREFIX),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
('set', CACHE_SNIPPET_LOOKUP_PREFIX),
-
+
))
# Ensure clock ticks before further cache activity
@@ -184,19 +178,19 @@ def test_cache_hits(self):
self.assert_snippets({
'/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['expected'], True ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], True),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
'/9/Waterduck/9.2/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['expected'], False ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], False),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
'/1/Mudfish/7.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( self.snippets['expected'], False ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], False),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
})
@@ -205,27 +199,37 @@ def test_cache_hits(self):
# Request 1
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
- CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX]),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
- CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX,
- CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX]),
# Request 2
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
- CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX]),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
- CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
# Request 3
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX,
- CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX]),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
))
@@ -238,25 +242,28 @@ def test_invalidation_on_rule_change(self):
self.assert_snippets({
'/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['expected'], True ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], True),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
})
self.assert_cache_events((
# Rule content changed.
- ('set_many', [ CACHE_RULE_LASTMOD_PREFIX,
+ ('set_many', [CACHE_RULE_LASTMOD_PREFIX,
CACHE_RULE_ALL_LASTMOD_PREFIX]),
-
+
# Rule cache miss
('get', CACHE_RULE_MATCH_PREFIX),
('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
- CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX]),
# All rules cache miss
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_ALL_PREFIX),
('set', CACHE_RULE_MATCH_PREFIX),
@@ -264,8 +271,10 @@ def test_invalidation_on_rule_change(self):
# Snippet cache miss
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
- CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX,
- CACHE_SNIPPET_LASTMOD_PREFIX]),
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
('set', CACHE_SNIPPET_LOOKUP_PREFIX),
@@ -280,99 +289,138 @@ def test_invalidation_on_snippet_change(self):
self.assert_snippets({
'/9/Waterduck/9.2/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['expected'], False ),
- ( self.snippets['ever'], True ),
- ( self.snippets['never'], False ),
+ (self.snippets['expected'], False),
+ (self.snippets['ever'], True),
+ (self.snippets['never'], False),
),
})
self.assert_cache_events((
# Snippet content changed, bumps rules as well.
- ('set_many', [CACHE_SNIPPET_LASTMOD_PREFIX,
+ ('set_many', [CACHE_SNIPPET_LASTMOD_PREFIX,
CACHE_RULE_LASTMOD_PREFIX]),
# Rule cache miss
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_MATCH_PREFIX),
-
+
# Snippet cache miss
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
('set', CACHE_SNIPPET_LOOKUP_PREFIX),
))
def test_invalidation_with_url_variety(self):
- """Exercise cache with a variety of URLs resulting in the same snippets"""
+ """
+ Exercise cache with a variety of URLs resulting in the same snippets
+ """
# Change a snippet, which should invalidate cached results for snippets
self.snippets['ever'].body = 'changed_again'
self.snippets['ever'].save()
- # Try multiple URLs that result in the same set of matching rules,
+ # Try multiple URLs that result in the same set of matching rules,
# should cause cache misses in rules, but not in snippet lookup
- for idx in (0,1):
+ for idx in (0, 1):
self.assert_snippets({
'/1/Alpha/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['ever'], True ),
+ (self.snippets['ever'], True),
),
'/1/Beta/9.2/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( self.snippets['ever'], True ),
+ (self.snippets['ever'], True),
),
'/1/Gamma/7.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( self.snippets['ever'], True ),
+ (self.snippets['ever'], True),
),
})
self.assert_cache_events((
# Content changed
- ('set_many', [CACHE_SNIPPET_LASTMOD_PREFIX,
+ ('set_many', [CACHE_SNIPPET_LASTMOD_PREFIX,
CACHE_RULE_LASTMOD_PREFIX]),
# Request #1 - cache miss on rules and snippets
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_MATCH_PREFIX),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
# Snippets looked up & cached for this request only
('set', CACHE_SNIPPET_LOOKUP_PREFIX),
# Request #2 - cache miss on rules, but hit on snippets
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_MATCH_PREFIX),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
# Request #3 - cache miss on rules, but hit on snippets
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_ALL_PREFIX, CACHE_RULE_ALL_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_ALL_PREFIX,
+ CACHE_RULE_ALL_LASTMOD_PREFIX]),
('set', CACHE_RULE_MATCH_PREFIX),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
# Request #4 - cache hits, all around
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX]),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
# Request #5 - cache hits, all around
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX]),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
# Request #6 - cache hits, all around
('get', CACHE_RULE_MATCH_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_NEW_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_NEW_LASTMOD_PREFIX]),
('get', CACHE_SNIPPET_LOOKUP_PREFIX),
- ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_SNIPPET_LASTMOD_PREFIX]),
+ ('get_many', [CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX, CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_RULE_LASTMOD_PREFIX,
+ CACHE_SNIPPET_LASTMOD_PREFIX]),
))
@@ -388,7 +436,7 @@ def test_new_rule_creation(self):
self.assert_snippets({
'/1/Gamma/7.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( new_snippet, True ),
+ (new_snippet, True),
),
})
@@ -396,19 +444,17 @@ def assert_cache_events(self, expected_events):
"""Match up a set of expected cache events and prefixes with the cache
log. Clears the log after a successful assertion set."""
- expected_len = len(expected_events)
-
expected_events = list(expected_events)
while expected_events:
expected = expected_events.pop(0)
- result = self.cache.log.pop(0)
+ result = self.cache.log.pop(0)
eq_(expected[0], result[0])
-
+
if type(expected[1]) is str:
ok_(result[1].startswith(expected[1]),
- '%s should start with %s' % (result[1], expected[1] ))
-
+ '%s should start with %s' % (result[1], expected[1]))
+
else:
prefixes = expected[1]
prefixes.sort()
@@ -421,11 +467,10 @@ def assert_cache_events(self, expected_events):
for idx2 in range(0, len(prefixes)):
ok_(result_keys[idx2].startswith(prefixes[idx2]),
'%s should start with %s' % (
- result_keys[idx2], prefixes[idx2] ))
+ result_keys[idx2], prefixes[idx2]))
result_len = len(self.cache.log)
eq_(0, result_len,
'Cache events should be exhausted, but %s left' % (result_len,))
self.cache.log = []
-
View
259 apps/homesnippets/tests/rules.py
@@ -1,31 +1,14 @@
"""
homesnippets client match rule tests
"""
-import logging
-import time
-import random
import datetime
-from django.conf import settings
-
-from django.db import connection
-
-from django.http import HttpRequest
-from django.test import TestCase
-from django.test.client import Client
-
-from django.core.cache import cache
-from django.core.cache.backends import locmem
-
-from nose.tools import assert_equal, with_setup, assert_false, eq_, ok_
-from nose.plugins.attrib import attr
-
-from homesnippets.models import Snippet, ClientMatchRule
-
-import homesnippets.models
+from nose.tools import eq_
+from homesnippets.models import Snippet
from homesnippets.tests.utils import HomesnippetsTestCase
+
class TestSnippetsMatch(HomesnippetsTestCase):
"""Exercise selection of snippets via client match rules"""
@@ -33,51 +16,52 @@ def test_simple_rules(self):
"""Exercise simple exact match rules"""
rules = self.setup_rules({
- 'fields': ( 'startpage_version', 'name', 'version', 'locale', ),
+ 'fields': ('startpage_version', 'name', 'version', 'locale'),
'items': {
# Specific rule, expected to be matched
- 'specific': ( '1', 'Firefox', '4.0', 'en-US', ),
+ 'specific': ('1', 'Firefox', '4.0', 'en-US'),
# Less-specific rule, should match but not result in duplicate
- 'vague': ( '1', 'Firefox', '4.0', None, ),
+ 'vague': ('1', 'Firefox', '4.0', None),
# Rule that won't be attached to any snippet.
- 'unused': ( '1', 'Mudfish', '7.0', 'en-GB', ),
+ 'unused': ('1', 'Mudfish', '7.0', 'en-GB'),
# Rule that will be attached to snippet, but not matched.
- 'unmatched': ( '2', 'Airdog', '3.0', 'de' ),
+ 'unmatched': ('2', 'Airdog', '3.0', 'de'),
# Rule matching anything
- 'all': ( None, None, None, None ),
+ 'all': (None, None, None, None),
}
})
snippets = self.setup_snippets(rules, {
- 'fields': ( 'name', 'body', 'rules' ),
+ 'fields': ('name', 'body', 'rules'),
'items': {
# Using specific and less-specific rule
- 'expected': ( 'test 1', 'Expected body data',
- ( rules['specific'], rules['vague'] ) ),
+ 'expected': ('test 1', 'Expected body data',
+ (rules['specific'], rules['vague'])),
# No rules, so always included in results
- 'ever': ( 'test 2', 'Ever-present body data',
- ( rules['all'], ) ),
- # Rule attached that will never be matched, so should never appear
- 'never': (' test 3', 'Never-present body data',
- ( rules['unmatched'], ) ),
+ 'ever': ('test 2', 'Ever-present body data',
+ (rules['all'],)),
+ # Rule attached that will never be matched,
+ # so should never appear
+ 'never': ('test 3', 'Never-present body data',
+ (rules['unmatched'],)),
}
})
self.assert_snippets({
'/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( snippets['expected'], True ),
- ( snippets['ever'], True ),
- ( snippets['never'], False ),
+ (snippets['expected'], True),
+ (snippets['ever'], True),
+ (snippets['never'], False),
),
'/9/Waterduck/9.2/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( snippets['expected'], False ),
- ( snippets['ever'], True ),
- ( snippets['never'], False ),
+ (snippets['expected'], False),
+ (snippets['ever'], True),
+ (snippets['never'], False),
),
'/1/Mudfish/7.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( snippets['expected'], False ),
- ( snippets['ever'], True ),
- ( snippets['never'], False ),
+ (snippets['expected'], False),
+ (snippets['ever'], True),
+ (snippets['never'], False),
),
})
@@ -85,49 +69,50 @@ def test_exclusion_rules(self):
"""Exercise match rules that exclude snippets"""
rules = self.setup_rules({
- 'fields': ( 'startpage_version', 'name', 'version', 'locale', 'exclude' ),
+ 'fields': ('startpage_version', 'name', 'version', 'locale',
+ 'exclude'),
'items': {
- 'specific': ( '1', 'Firefox', '4.0', 'en-US', True, ),
- 'vague': ( '1', 'Firefox', '4.0', None, False, ),
- 'mudfish': ( '1', 'Mudfish', '7.0', 'en-GB', True, ),
- 'airdog': ( '2', 'Airdog', '3.0', 'de', False, ),
- 'nowindcat': ( '1', 'Windcat', '9.3', 'fr', True ),
- 'all': ( None, None, None, None, False ),
+ 'specific': ('1', 'Firefox', '4.0', 'en-US', True),
+ 'vague': ('1', 'Firefox', '4.0', None, False),
+ 'mudfish': ('1', 'Mudfish', '7.0', 'en-GB', True),
+ 'airdog': ('2', 'Airdog', '3.0', 'de', False),
+ 'nowindcat': ('1', 'Windcat', '9.3', 'fr', True),
+ 'all': (None, None, None, None, False),
}
})
snippets = self.setup_snippets(rules, {
- 'fields': ( 'name', 'body', 'rules' ),
+ 'fields': ('name', 'body', 'rules'),
'items': {
- 'en-GB': ( 'test 1', 'Expected in en-GB but not en-US',
- ( rules['specific'], rules['vague'] ) ),
- 'ever': ( 'test 2', 'Ever-present body data',
- ( rules['all'], ) ),
- 'never': (' test 3', 'Never-present body data',
- ( rules['airdog'], ) ),
- 'usually': ( 'test 4', 'Usually-present body data',
- ( rules['all'], rules['nowindcat'], ) ),
+ 'en-GB': ('test 1', 'Expected in en-GB but not en-US',
+ (rules['specific'], rules['vague'])),
+ 'ever': ('test 2', 'Ever-present body data',
+ (rules['all'],)),
+ 'never': (' test 3', 'Never-present body data',
+ (rules['airdog'],)),
+ 'usually': ('test 4', 'Usually-present body data',
+ (rules['all'], rules['nowindcat'])),
}
})
self.assert_snippets({
'/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( snippets['en-GB'], False ),
- ( snippets['ever'], True ),
- ( snippets['never'], False ),
- ( snippets['usually'], True ),
+ (snippets['en-GB'], False),
+ (snippets['ever'], True),
+ (snippets['never'], False),
+ (snippets['usually'], True),
),
'/1/Firefox/4.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( snippets['en-GB'], True ),
- ( snippets['ever'], True ),
- ( snippets['never'], False ),
- ( snippets['usually'], True ),
+ (snippets['en-GB'], True),
+ (snippets['ever'], True),
+ (snippets['never'], False),
+ (snippets['usually'], True),
),
'/1/Windcat/9.3/xxx/xxx/fr/xxx/xxx/default/default/': (
- ( snippets['en-GB'], False ),
- ( snippets['ever'], True ),
- ( snippets['never'], False ),
- ( snippets['usually'], False ),
+ (snippets['en-GB'], False),
+ (snippets['ever'], True),
+ (snippets['never'], False),
+ (snippets['usually'], False),
),
})
@@ -135,26 +120,26 @@ def test_disabled_snippets(self):
"""Exercise omission of disabled snippets"""
rules = self.setup_rules({
- 'fields': ( 'exclude', ),
+ 'fields': ('exclude',),
'items': {
- 'all': ( False, ),
+ 'all': (False,),
}
})
snippets = self.setup_snippets(rules, {
- 'fields': ( 'name', 'body', 'disabled', 'rules' ),
+ 'fields': ('name', 'body', 'disabled', 'rules'),
'items': {
- 'shown_1': ( 'one', 'Shown 1', False, ( rules['all'], ) ),
- 'disabled': ( 'two', 'Disabled', True, ( rules['all'], ) ),
- 'shown_2': ( 'three', 'Shown 2', False, ( rules['all'], ) ),
+ 'shown_1': ('one', 'Shown 1', False, (rules['all'],)),
+ 'disabled': ('two', 'Disabled', True, (rules['all'],)),
+ 'shown_2': ('three', 'Shown 2', False, (rules['all'],)),
}
})
self.assert_snippets({
'/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( snippets['shown_1'], True ),
- ( snippets['shown_2'], True ),
- ( snippets['disabled'], False ),
+ (snippets['shown_1'], True),
+ (snippets['shown_2'], True),
+ (snippets['disabled'], False),
),
})
@@ -162,82 +147,120 @@ def test_pub_start_end_dates(self):
"""Exercise start/end publication dates"""
rules = self.setup_rules({
- 'fields': ( 'exclude', ),
+ 'fields': ('exclude',),
'items': {
- 'all': ( False, ),
+ 'all': (False,),
}
})
- snippets = self.setup_snippets(rules, {
- 'fields': ( 'body', 'rules', 'pub_start', 'pub_end', ),
+ self.setup_snippets(rules, {
+ 'fields': ('body', 'rules', 'pub_start', 'pub_end'),
'items': {
- 'shown_1': ( 'Shown 1', ( rules['all'],),
- None,
- None, ),
- 'shown_2': ( 'Shown 2', ( rules['all'],),
- datetime.datetime(2010, 10, 25),
- None, ),
- 'shown_3': ( 'Shown 3', ( rules['all'],),
- None,
- datetime.datetime(2010, 12, 24), ),
- 'shown_4': ( 'Shown 4', ( rules['all'],),
- datetime.datetime(2010, 10, 24),
- datetime.datetime(2010, 10, 31), ),
+ 'shown_1': ('Shown 1', (rules['all'],), None, None),
+ 'shown_2': ('Shown 2', (rules['all'],),
+ datetime.datetime(2010, 10, 25), None),
+ 'shown_3': ('Shown 3', (rules['all'],), None,
+ datetime.datetime(2010, 12, 24)),
+ 'shown_4': ('Shown 4', (rules['all'],),
+ datetime.datetime(2010, 10, 24),
+ datetime.datetime(2010, 10, 31)),
}
})
expected = [
- ( datetime.datetime(2010, 10, 01),
- ( 'shown_1', 'shown_3', ) ),
- ( datetime.datetime(2010, 10, 25),
- ( 'shown_1', 'shown_2', 'shown_3', 'shown_4', ) ),
- ( datetime.datetime(2010, 12, 24),
- ( 'shown_1', 'shown_2', 'shown_2', ) ),
- ( datetime.datetime(2011, 01, 01),
- ( 'shown_1', 'shown_2', ) ),
+ (datetime.datetime(2010, 10, 01), ('shown_1', 'shown_3')),
+ (datetime.datetime(2010, 10, 25), ('shown_1', 'shown_2',
+ 'shown_3', 'shown_4')),
+ (datetime.datetime(2010, 12, 24), ('shown_1', 'shown_2',
+ 'shown_2')),
+ (datetime.datetime(2011, 01, 01), ('shown_1', 'shown_2')),
]
for tm, snippet_names in expected:
expected_names = set(snippet_names)
- result_names = set(s['name']
- for s in Snippet.objects.find_snippets_with_match_rules({}, tm))
+ result_names = set(s['name'] for s in
+ Snippet.objects.find_snippets_with_match_rules({}, tm))
eq_(expected_names, result_names)
def test_regex_rules(self):
"""Exercise match rules that use regexes"""
rules = self.setup_rules({
- 'fields': ( 'startpage_version', 'name', 'version', 'locale', 'exclude' ),
+ 'fields': ('startpage_version', 'name', 'version', 'locale',
+ 'exclude'),
'items': {
- 'fire_or_mud': ( '1', '/(Firefox|Mudfish)/', '4.0', None, False, ),
- 'no_fr_or_de': ( '1', None, '4.0', '/(de|fr)/', True, ),
- 'all': ( None, None, None, None, False ),
+ 'fire_or_mud': ('1', '/(Firefox|Mudfish)/', '4.0', None,
+ False),
+ 'no_fr_or_de': ('1', None, '4.0', '/(de|fr)/', True),
+ 'all': (None, None, None, None, False),
}
})
snippets = self.setup_snippets(rules, {
- 'fields': ( 'name', 'body', 'rules' ),
+ 'fields': ('name', 'body', 'rules'),
'items': {
- 'fire_or_mud': ( 'Fire or Mud', 'Firefox or Mudfish but not Airdog',
- ( rules['fire_or_mud'], rules['no_fr_or_de'], ) ),
+ 'fire_or_mud': ('Fire or Mud',
+ 'Firefox or Mudfish but not Airdog',
+ (rules['fire_or_mud'], rules['no_fr_or_de']))
}
})
self.assert_snippets({
'/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
- ( snippets['fire_or_mud'], True ),
+ (snippets['fire_or_mud'], True),
),
'/1/Mudfish/4.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( snippets['fire_or_mud'], True ),
+ (snippets['fire_or_mud'], True),
),
'/1/Firefox/4.0/xxx/xxx/de/xxx/xxx/default/default/': (
- ( snippets['fire_or_mud'], False ),
+ (snippets['fire_or_mud'], False),
),
'/1/Mudfish/4.0/xxx/xxx/fr/xxx/xxx/default/default/': (
- ( snippets['fire_or_mud'], False ),
+ (snippets['fire_or_mud'], False),
),
'/1/Airdog/4.0/xxx/xxx/en-GB/xxx/xxx/default/default/': (
- ( snippets['fire_or_mud'], False ),
+ (snippets['fire_or_mud'], False),
),
})
+ def test_unmatched_inclusion_rules(self):
+ """
+ Test to ensure that if an inclusion rule does not match, the associated
+ snippet is not sent.
+ """
+
+ rules = self.setup_rules({
+ 'fields': ('name', 'version', 'exclude'),
+ 'items': {
+ 'firefox': ('Firefox', None, False),
+ '4.0': (None, '4.0', False),
+ }
+ })
+
+ snippets = self.setup_snippets(rules, {
+ 'fields': ('name', 'body', 'rules'),
+ 'items': {
+ 'fire_4.0': ('Firefox 4.0', 'Firefox and 4.0',
+ (rules['firefox'], rules['4.0'])),
+ 'fire': ('Firefox', 'Firefox but not 4.0', (rules['firefox'],)),
+ '4.0': ('4.0', '4.0 but not Firefox', (rules['4.0'],)),
+ }
+ })
+
+ self.assert_snippets({
+ '/1/Firefox/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
+ (snippets['fire_4.0'], True),
+ (snippets['fire'], True),
+ (snippets['4.0'], True),
+ ),
+ '/1/Firefox/3.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
+ (snippets['fire_4.0'], False),
+ (snippets['fire'], True),
+ (snippets['4.0'], False),
+ ),
+ '/1/Mudfish/4.0/xxx/xxx/en-US/xxx/xxx/default/default/': (
+ (snippets['fire_4.0'], False),
+ (snippets['fire'], False),
+ (snippets['4.0'], True),
+ ),
+ })
View
24 apps/homesnippets/tests/utils.py
@@ -1,23 +1,15 @@
"""homesnippets common test utils"""
import logging
-import time
-import random
-import datetime
from django.conf import settings
-
-from django.http import HttpRequest
from django.test import TestCase
from django.test.client import Client
-from django.core.cache import cache
-from django.core.cache.backends import locmem
+from nose.tools import eq_
import homesnippets
from homesnippets.models import Snippet, ClientMatchRule
-from nose.tools import assert_equal, with_setup, assert_false, eq_, ok_
-from nose.plugins.attrib import attr
class HomesnippetsTestCase(TestCase):
@@ -29,19 +21,16 @@ def setUp(self):
ClientMatchRule.objects.all().delete()
Snippet.objects.all().delete()
-
- homesnippets.models.cache.clear()
- def tearDown(self):
- from django.db import connection
- #logging.debug(connection.queries)
+ homesnippets.models.cache.clear()
def setup_rules(self, rules_data):
- """Given a data structure defining client match rules, create the
+ """Given a data structure defining client match rules, create the
model items"""
rules = {}
for name, item in rules_data['items'].items():
- rules[name] = ClientMatchRule(**dict(zip(rules_data['fields'], item)))
+ rules[name] = ClientMatchRule(**dict(zip(rules_data['fields'],
+ item)))
rules[name].save()
return rules
@@ -49,7 +38,7 @@ def setup_snippets(self, rules, snippets_data):
"""Given a data structure defining snippets, create the model items"""
snippets = {}
for name, item_data in snippets_data['items'].items():
-
+
item = dict(zip(snippets_data['fields'], item_data))
if not 'name' in item:
item['name'] = name
@@ -75,4 +64,3 @@ def assert_snippets(self, tests):
eq_(resp.content.count(e_content), e_present and 1 or 0,
'Snippet "%s" should%sappear in content for %s' % (
e_content, e_present and ' ' or ' not ', path))
-
Something went wrong with that request. Please try again.