mirror of
https://github.com/jazzband/django-analytical.git
synced 2026-03-16 22:20:25 +00:00
Fix tests
Some parts of the code are not yet tested: * internal IP addresses feature * utils module
This commit is contained in:
parent
4bf0fcfcc5
commit
cf7589bc20
41 changed files with 746 additions and 886 deletions
|
|
@ -13,10 +13,3 @@ __email__ = "joost@cassee.net"
|
|||
__version__ = "0.2.0alpha"
|
||||
__copyright__ = "Copyright (C) 2011 Joost Cassee"
|
||||
__license__ = "MIT License"
|
||||
|
||||
try:
|
||||
from collections import namedtuple
|
||||
except ImportError:
|
||||
namedtuple = lambda name, fields: lambda *values: values
|
||||
|
||||
Property = namedtuple('Property', ['num', 'name', 'value'])
|
||||
|
|
|
|||
|
|
@ -1,33 +0,0 @@
|
|||
"""
|
||||
Context processors for django-analytical.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
IMPORT_SETTINGS = [
|
||||
'ANALYTICAL_INTERNAL_IPS',
|
||||
'ANALYTICAL_SERVICES',
|
||||
'CHARTBEAT_USER_ID',
|
||||
'CLICKY_SITE_ID',
|
||||
'CRAZY_EGG_ACCOUNT_NUMBER',
|
||||
'GOOGLE_ANALYTICS_PROPERTY_ID',
|
||||
'KISS_INSIGHTS_ACCOUNT_NUMBER',
|
||||
'KISS_INSIGHTS_SITE_CODE',
|
||||
'KISS_METRICS_API_KEY',
|
||||
'MIXPANEL_TOKEN',
|
||||
'OPTIMIZELY_ACCOUNT_NUMBER',
|
||||
]
|
||||
|
||||
|
||||
def settings(request):
|
||||
"""
|
||||
Import all django-analytical settings into the template context.
|
||||
"""
|
||||
vars = {}
|
||||
for setting in IMPORT_SETTINGS:
|
||||
try:
|
||||
vars[setting] = getattr(settings, setting)
|
||||
except AttributeError:
|
||||
pass
|
||||
return vars
|
||||
|
|
@ -5,36 +5,24 @@ Analytical template tags and filters.
|
|||
import logging
|
||||
|
||||
from django import template
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.template import Node, TemplateSyntaxError
|
||||
from django.utils.importlib import import_module
|
||||
|
||||
from analytical.templatetags import chartbeat, clicky, crazy_egg, \
|
||||
google_analytics, hubspot, kiss_insights, kiss_metrics, mixpanel, \
|
||||
optimizely
|
||||
|
||||
|
||||
TAG_NODES = {
|
||||
'head_top': [
|
||||
chartbeat.ChartbeatTopNode, # Chartbeat should come first
|
||||
kiss_metrics.KissMetricsNode,
|
||||
optimizely.OptimizelyNode,
|
||||
],
|
||||
'head_bottom': [
|
||||
google_analytics.GoogleAnalyticsNode,
|
||||
mixpanel.MixpanelNode,
|
||||
],
|
||||
'body_top': [
|
||||
kiss_insights.KissInsightsNode,
|
||||
],
|
||||
'body_bottom': [
|
||||
clicky.ClickyNode,
|
||||
crazy_egg.CrazyEggNode,
|
||||
hubspot.HubSpotNode,
|
||||
chartbeat.ChartbeatBottomNode, # Chartbeat should come last
|
||||
],
|
||||
}
|
||||
TAG_LOCATIONS = ['head_top', 'head_bottom', 'body_top', 'body_bottom']
|
||||
TAG_POSITIONS = ['first', None, 'last']
|
||||
TAG_MODULES = [
|
||||
'analytical.chartbeat',
|
||||
'analytical.clicky',
|
||||
'analytical.crazy_egg',
|
||||
'analytical.google_analytics',
|
||||
'analytical.hubspot',
|
||||
'analytical.kiss_insights',
|
||||
'analytical.kiss_metrics',
|
||||
'analytical.mixpanel',
|
||||
'analytical.optimizely'
|
||||
]
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -49,29 +37,36 @@ def _location_tag(location):
|
|||
return AnalyticalNode(location)
|
||||
return analytical_tag
|
||||
|
||||
for loc in TAG_NODES.keys():
|
||||
for loc in TAG_LOCATIONS:
|
||||
register.tag('analytical_%s' % loc, _location_tag(loc))
|
||||
|
||||
|
||||
class AnalyticalNode(Node):
|
||||
def __init__(self, location):
|
||||
self.nodes = template_nodes[location]
|
||||
self.nodes = [node_cls() for node_cls in template_nodes[location]]
|
||||
|
||||
def render(self, context):
|
||||
return "".join([node.render(context) for node in self.nodes])
|
||||
|
||||
|
||||
def _load_template_nodes():
|
||||
location_nodes = {}
|
||||
for location, node_classes in TAG_NODES.items():
|
||||
location_nodes[location] = []
|
||||
for node_class in node_classes:
|
||||
try:
|
||||
node = node_class()
|
||||
except ImproperlyConfigured, e:
|
||||
logger.debug("not loading analytical service '%s': %s",
|
||||
node_class.name, e)
|
||||
location_nodes.append(node)
|
||||
return location_nodes
|
||||
template_nodes = dict((l, dict((p, []) for p in TAG_POSITIONS))
|
||||
for l in TAG_LOCATIONS)
|
||||
def add_node_cls(location, node, position=None):
|
||||
template_nodes[location][position].append(node)
|
||||
for path in TAG_MODULES:
|
||||
module = _import_tag_module(path)
|
||||
try:
|
||||
module.contribute_to_analytical(add_node_cls)
|
||||
except ImproperlyConfigured, e:
|
||||
logger.debug("not loading tags from '%s': %s", path, e)
|
||||
for location in TAG_LOCATIONS:
|
||||
template_nodes[location] = sum((template_nodes[location][p]
|
||||
for p in TAG_POSITIONS), [])
|
||||
return template_nodes
|
||||
|
||||
def _import_tag_module(path):
|
||||
app_name, lib_name = path.rsplit('.', 1)
|
||||
return import_module("%s.templatetags.%s" % (app_name, lib_name))
|
||||
|
||||
template_nodes = _load_template_nodes()
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ from django.core.exceptions import ImproperlyConfigured
|
|||
from django.template import Library, Node, TemplateSyntaxError
|
||||
from django.utils import simplejson
|
||||
|
||||
from analytical.utils import is_internal_ip, disable_html
|
||||
from analytical.utils import is_internal_ip, disable_html, validate_setting, \
|
||||
get_required_setting
|
||||
|
||||
|
||||
USER_ID_RE = re.compile(r'^\d{5}$')
|
||||
|
|
@ -56,8 +57,6 @@ def chartbeat_top(parser, token):
|
|||
return ChartbeatTopNode()
|
||||
|
||||
class ChartbeatTopNode(Node):
|
||||
name = 'Chartbeat top code'
|
||||
|
||||
def render(self, context):
|
||||
if is_internal_ip(context):
|
||||
return disable_html(INIT_CODE, self.name)
|
||||
|
|
@ -79,10 +78,8 @@ def chartbeat_bottom(parser, token):
|
|||
return ChartbeatBottomNode()
|
||||
|
||||
class ChartbeatBottomNode(Node):
|
||||
name = 'Chartbeat bottom code'
|
||||
|
||||
def __init__(self):
|
||||
self.user_id = self.get_required_setting(
|
||||
self.user_id = get_required_setting(
|
||||
'CHARTBEAT_USER_ID', USER_ID_RE,
|
||||
"must be a string containing an five-digit number")
|
||||
|
||||
|
|
@ -97,6 +94,13 @@ class ChartbeatBottomNode(Node):
|
|||
if domain is not None:
|
||||
config['domain'] = domain
|
||||
html = SETUP_CODE % {'config': simplejson.dumps(config)}
|
||||
if is_internal_ip(context):
|
||||
html = disable_html(html, self.name)
|
||||
if is_internal_ip(context, 'CHARTBEAT'):
|
||||
html = disable_html(html, 'Chartbeat')
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('CHARTBEAT_USER_ID', USER_ID_RE,
|
||||
"must be a string containing an five-digit number")
|
||||
add_node('head_top', ChartbeatTopNode, 'first')
|
||||
add_node('body_bottom', ChartbeatBottomNode, 'last')
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@ import re
|
|||
from django.template import Library, Node, TemplateSyntaxError
|
||||
from django.utils import simplejson
|
||||
|
||||
from analytical.utils import get_required_setting, get_identity, \
|
||||
is_internal_ip, disable_html
|
||||
from analytical.utils import get_identity, is_internal_ip, disable_html, \
|
||||
validate_setting, get_required_setting
|
||||
|
||||
|
||||
SITE_ID_RE = re.compile(r'^\d{8}$')
|
||||
|
|
@ -49,24 +49,29 @@ def clicky(parser, token):
|
|||
return ClickyNode()
|
||||
|
||||
class ClickyNode(Node):
|
||||
name = 'Clicky'
|
||||
|
||||
def __init__(self):
|
||||
self.site_id = get_required_setting('CLICKY_SITE_ID', SITE_ID_RE,
|
||||
"must be a string containing an eight-digit number")
|
||||
|
||||
def render(self, context):
|
||||
custom = {}
|
||||
for var, value in context.items():
|
||||
if var.startswith('clicky_'):
|
||||
custom[var[7:]] = value
|
||||
for dict_ in context:
|
||||
for var, val in dict_.items():
|
||||
if var.startswith('clicky_'):
|
||||
custom[var[7:]] = val
|
||||
if 'username' not in custom.get('session', {}):
|
||||
identity = get_identity(context)
|
||||
identity = get_identity(context, 'clicky')
|
||||
if identity is not None:
|
||||
custom.setdefault('session', {})['username'] = identity
|
||||
|
||||
html = TRACKING_CODE % {'site_id': self.site_id,
|
||||
'custom': simplejson.dumps(custom)}
|
||||
if is_internal_ip(context):
|
||||
html = disable_html(html, self.name)
|
||||
if is_internal_ip(context, 'CLICKY'):
|
||||
html = disable_html(html, 'Clicky')
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('CLICKY_SITE_ID', SITE_ID_RE,
|
||||
"must be a string containing an eight-digit number")
|
||||
add_node('body_bottom', ClickyNode)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import re
|
|||
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.utils import is_internal_ip, disable_html
|
||||
from analytical.utils import is_internal_ip, disable_html, validate_setting, \
|
||||
get_required_setting
|
||||
|
||||
|
||||
ACCOUNT_NUMBER_RE = re.compile(r'^\d{8}$')
|
||||
|
|
@ -34,10 +35,8 @@ def crazy_egg(parser, token):
|
|||
return CrazyEggNode()
|
||||
|
||||
class CrazyEggNode(Node):
|
||||
name = 'Crazy Egg'
|
||||
|
||||
def __init__(self):
|
||||
self.account_nr = self.get_required_setting('CRAZY_EGG_ACCOUNT_NUMBER',
|
||||
self.account_nr = get_required_setting('CRAZY_EGG_ACCOUNT_NUMBER',
|
||||
ACCOUNT_NUMBER_RE,
|
||||
"must be a string containing an eight-digit number")
|
||||
|
||||
|
|
@ -51,6 +50,12 @@ class CrazyEggNode(Node):
|
|||
for (varnr, value) in vars)
|
||||
html = '%s\n<script type="text/javascript">%s</script>' \
|
||||
% (html, js)
|
||||
if is_internal_ip(context):
|
||||
html = disable_html(html, self.name)
|
||||
if is_internal_ip(context, 'CRAZY_EGG'):
|
||||
html = disable_html(html, 'Crazy Egg')
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('CRAZY_EGG_ACCOUNT_NUMBER', ACCOUNT_NUMBER_RE,
|
||||
"must be a string containing an eight-digit number")
|
||||
add_node('body_bottom', CrazyEggNode)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import re
|
|||
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.utils import is_internal_ip, disable_html
|
||||
from analytical.utils import is_internal_ip, disable_html, validate_setting, \
|
||||
get_required_setting
|
||||
|
||||
SCOPE_VISITOR = 1
|
||||
SCOPE_SESSION = 2
|
||||
|
|
@ -30,8 +31,8 @@ SETUP_CODE = """
|
|||
|
||||
</script>
|
||||
"""
|
||||
CUSTOM_VAR_CODE = "_gaq.push(['_setCustomVar', %(index)d, '%(name)s', " \
|
||||
"'%(value)s', %(scope)d]);"
|
||||
CUSTOM_VAR_CODE = "_gaq.push(['_setCustomVar', %(index)s, '%(name)s', " \
|
||||
"'%(value)s', %(scope)s]);"
|
||||
|
||||
|
||||
register = Library()
|
||||
|
|
@ -52,10 +53,8 @@ def google_analytics(parser, token):
|
|||
return GoogleAnalyticsNode()
|
||||
|
||||
class GoogleAnalyticsNode(Node):
|
||||
name = 'Google Analytics'
|
||||
|
||||
def __init__(self):
|
||||
self.property_id = self.get_required_setting(
|
||||
self.property_id = get_required_setting(
|
||||
'GOOGLE_ANALYTICS_PROPERTY_ID', PROPERTY_ID_RE,
|
||||
"must be a string looking like 'UA-XXXXXX-Y'")
|
||||
|
||||
|
|
@ -63,21 +62,27 @@ class GoogleAnalyticsNode(Node):
|
|||
commands = self._get_custom_var_commands(context)
|
||||
html = SETUP_CODE % {'property_id': self.property_id,
|
||||
'commands': " ".join(commands)}
|
||||
if is_internal_ip(context):
|
||||
html = disable_html(html, self.name)
|
||||
if is_internal_ip(context, 'GOOGLE_ANALYTICS'):
|
||||
html = disable_html(html, 'Google Analytics')
|
||||
return html
|
||||
|
||||
def _get_custom_var_commands(self, context):
|
||||
values = (context.get('google_analytics_var%d' % i)
|
||||
values = (context.get('google_analytics_var%s' % i)
|
||||
for i in range(1, 6))
|
||||
vars = [(i, v) for i, v in enumerate(values, 1) if v is not None]
|
||||
commands = []
|
||||
for index, value in vars:
|
||||
name = value[0]
|
||||
value = value[1]
|
||||
for index, var in vars:
|
||||
name = var[0]
|
||||
value = var[1]
|
||||
try:
|
||||
scope = value[2]
|
||||
scope = var[2]
|
||||
except IndexError:
|
||||
scope = SCOPE_PAGE
|
||||
commands.append(CUSTOM_VAR_CODE % locals())
|
||||
return commands
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('GOOGLE_ANALYTICS_PROPERTY_ID', PROPERTY_ID_RE,
|
||||
"must be a string looking like 'UA-XXXXXX-Y'")
|
||||
add_node('head_bottom', GoogleAnalyticsNode)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import re
|
|||
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.utils import get_required_setting, is_internal_ip, disable_html
|
||||
from analytical.utils import is_internal_ip, disable_html, validate_setting, \
|
||||
get_required_setting
|
||||
|
||||
|
||||
PORTAL_ID_RE = re.compile(r'^\d+$')
|
||||
|
|
@ -18,7 +19,7 @@ TRACKING_CODE = """
|
|||
var hs_portalid = %(portal_id)s;
|
||||
var hs_salog_version = "2.00";
|
||||
var hs_ppa = "%(domain)s";
|
||||
document.write(unescape("%3Cscript src='" + document.location.protocol + "//" + hs_ppa + "/salog.js.aspx' type='text/javascript'%3E%3C/script%3E"));
|
||||
document.write(unescape("%%3Cscript src='" + document.location.protocol + "//" + hs_ppa + "/salog.js.aspx' type='text/javascript'%%3E%%3C/script%%3E"));
|
||||
</script>
|
||||
"""
|
||||
|
||||
|
|
@ -41,17 +42,23 @@ def hubspot(parser, token):
|
|||
return HubSpotNode()
|
||||
|
||||
class HubSpotNode(Node):
|
||||
name = 'HubSpot'
|
||||
|
||||
def __init__(self):
|
||||
self.site_id = get_required_setting('HUPSPOT_PORTAL_ID',
|
||||
self.portal_id = get_required_setting('HUBSPOT_PORTAL_ID',
|
||||
PORTAL_ID_RE, "must be a (string containing a) number")
|
||||
self.domain = get_required_setting('HUPSPOT_DOMAIN',
|
||||
self.domain = get_required_setting('HUBSPOT_DOMAIN',
|
||||
DOMAIN_RE, "must be an internet domain name")
|
||||
|
||||
def render(self, context):
|
||||
html = TRACKING_CODE % {'portal_id': self.portal_id,
|
||||
'domain': self.domain}
|
||||
if is_internal_ip(context):
|
||||
if is_internal_ip(context, 'HUBSPOT'):
|
||||
html = disable_html(html, self.name)
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('HUBSPOT_PORTAL_ID', PORTAL_ID_RE,
|
||||
"must be a (string containing a) number")
|
||||
validate_setting('HUBSPOT_DOMAIN', DOMAIN_RE,
|
||||
"must be an internet domain name")
|
||||
add_node('body_bottom', HubSpotNode)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,9 @@ import re
|
|||
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.utils import validate_setting, get_identity, \
|
||||
get_required_setting
|
||||
|
||||
|
||||
ACCOUNT_NUMBER_RE = re.compile(r'^\d+$')
|
||||
SITE_CODE_RE = re.compile(r'^[\w]{3}$')
|
||||
|
|
@ -39,18 +42,16 @@ def kiss_insights(parser, token):
|
|||
return KissInsightsNode()
|
||||
|
||||
class KissInsightsNode(Node):
|
||||
name = 'KISSinsights'
|
||||
|
||||
def __init__(self):
|
||||
self.account_number = self.get_required_setting(
|
||||
self.account_number = get_required_setting(
|
||||
'KISS_INSIGHTS_ACCOUNT_NUMBER', ACCOUNT_NUMBER_RE,
|
||||
"must be (a string containing) a number")
|
||||
self.site_code = self.get_required_setting('KISS_INSIGHTS_SITE_CODE',
|
||||
self.site_code = get_required_setting('KISS_INSIGHTS_SITE_CODE',
|
||||
SITE_CODE_RE, "must be a string containing three characters")
|
||||
|
||||
def render(self, context):
|
||||
commands = []
|
||||
identity = self.get_identity(context)
|
||||
identity = get_identity(context, 'kiss_insights')
|
||||
if identity is not None:
|
||||
commands.append(IDENTIFY_CODE % identity)
|
||||
try:
|
||||
|
|
@ -61,3 +62,9 @@ class KissInsightsNode(Node):
|
|||
html = SETUP_CODE % {'account_number': self.account_number,
|
||||
'site_code': self.site_code, 'commands': " ".join(commands)}
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('KISS_INSIGHTS_ACCOUNT_NUMBER', ACCOUNT_NUMBER_RE,
|
||||
"must be (a string containing) a number")
|
||||
add_node('body_top', KissInsightsNode)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import re
|
|||
from django.template import Library, Node, TemplateSyntaxError
|
||||
from django.utils import simplejson
|
||||
|
||||
from analytical.utils import is_internal_ip, disable_html
|
||||
from analytical.utils import is_internal_ip, disable_html, get_identity, \
|
||||
validate_setting, get_required_setting
|
||||
|
||||
|
||||
API_KEY_RE = re.compile(r'^[0-9a-f]{40}$')
|
||||
|
|
@ -53,16 +54,14 @@ def kiss_metrics(parser, token):
|
|||
return KissMetricsNode()
|
||||
|
||||
class KissMetricsNode(Node):
|
||||
name = 'KISSmetrics'
|
||||
|
||||
def __init__(self):
|
||||
self.api_key = self.get_required_setting('KISS_METRICS_API_KEY',
|
||||
self.api_key = get_required_setting('KISS_METRICS_API_KEY',
|
||||
API_KEY_RE,
|
||||
"must be a string containing a 40-digit hexadecimal number")
|
||||
|
||||
def render(self, context):
|
||||
commands = []
|
||||
identity = self.get_identity(context)
|
||||
identity = get_identity(context, 'kiss_metrics')
|
||||
if identity is not None:
|
||||
commands.append(IDENTIFY_CODE % identity)
|
||||
try:
|
||||
|
|
@ -73,6 +72,12 @@ class KissMetricsNode(Node):
|
|||
pass
|
||||
html = TRACKING_CODE % {'api_key': self.api_key,
|
||||
'commands': " ".join(commands)}
|
||||
if is_internal_ip(context):
|
||||
html = disable_html(html, self.name)
|
||||
if is_internal_ip(context, 'KISS_METRICS'):
|
||||
html = disable_html(html, 'KISSmetrics')
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('KISS_METRICS_API_KEY', API_KEY_RE,
|
||||
"must be a string containing a 40-digit hexadecimal number")
|
||||
add_node('head_top', KissMetricsNode)
|
||||
|
|
|
|||
|
|
@ -9,7 +9,8 @@ import re
|
|||
from django.template import Library, Node, TemplateSyntaxError
|
||||
from django.utils import simplejson
|
||||
|
||||
from analytical.utils import is_internal_ip, disable_html
|
||||
from analytical.utils import is_internal_ip, disable_html, get_identity, \
|
||||
validate_setting, get_required_setting
|
||||
|
||||
|
||||
MIXPANEL_TOKEN_RE = re.compile(r'^[0-9a-f]{32}$')
|
||||
|
|
@ -27,7 +28,7 @@ TRACKING_CODE = """
|
|||
"""
|
||||
IDENTIFY_CODE = "mpq.push(['identify', '%s']);"
|
||||
EVENT_CODE = "mpq.push(['track', '%(name)s', %(properties)s]);"
|
||||
EVENT_CONTEXT_KEY = 'mixpanel_metrics_event'
|
||||
EVENT_CONTEXT_KEY = 'mixpanel_event'
|
||||
|
||||
register = Library()
|
||||
|
||||
|
|
@ -46,16 +47,14 @@ def mixpanel(parser, token):
|
|||
return MixpanelNode()
|
||||
|
||||
class MixpanelNode(Node):
|
||||
name = 'Mixpanel'
|
||||
|
||||
def __init__(self):
|
||||
self.token = self.get_required_setting('MIXPANEL_TOKEN',
|
||||
self.token = get_required_setting('MIXPANEL_TOKEN',
|
||||
MIXPANEL_TOKEN_RE,
|
||||
"must be a string containing a 32-digit hexadecimal number")
|
||||
|
||||
def render(self, context):
|
||||
commands = []
|
||||
identity = self.get_identity(context)
|
||||
identity = get_identity(context, 'mixpanel')
|
||||
if identity is not None:
|
||||
commands.append(IDENTIFY_CODE % identity)
|
||||
try:
|
||||
|
|
@ -66,6 +65,12 @@ class MixpanelNode(Node):
|
|||
pass
|
||||
html = TRACKING_CODE % {'token': self.token,
|
||||
'commands': " ".join(commands)}
|
||||
if is_internal_ip(context):
|
||||
html = disable_html(html, self.name)
|
||||
if is_internal_ip(context, 'MIXPANEL'):
|
||||
html = disable_html(html, 'Mixpanel')
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('MIXPANEL_TOKEN', MIXPANEL_TOKEN_RE,
|
||||
"must be a string containing a 32-digit hexadecimal number")
|
||||
add_node('head_bottom', MixpanelNode)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ import re
|
|||
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.utils import is_internal_ip, disable_html
|
||||
from analytical.utils import is_internal_ip, disable_html, validate_setting, \
|
||||
get_required_setting
|
||||
|
||||
|
||||
ACCOUNT_NUMBER_RE = re.compile(r'^\d{7}$')
|
||||
|
|
@ -33,15 +34,19 @@ def optimizely(parser, token):
|
|||
return OptimizelyNode()
|
||||
|
||||
class OptimizelyNode(Node):
|
||||
name = 'Optimizely'
|
||||
|
||||
def __init__(self):
|
||||
self.account_number = self.get_required_setting(
|
||||
self.account_number = get_required_setting(
|
||||
'OPTIMIZELY_ACCOUNT_NUMBER', ACCOUNT_NUMBER_RE,
|
||||
"must be a string containing an seven-digit number")
|
||||
|
||||
def render(self, context):
|
||||
html = SETUP_CODE % {'account_number': self.account_number}
|
||||
if is_internal_ip(context):
|
||||
if is_internal_ip(context, 'OPTIMIZELY'):
|
||||
html = disable_html(html, self.name)
|
||||
return html
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node):
|
||||
validate_setting('OPTIMIZELY_ACCOUNT_NUMBER', ACCOUNT_NUMBER_RE,
|
||||
"must be a string containing an seven-digit number")
|
||||
add_node('head_top', OptimizelyNode)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,14 @@
|
|||
Tests for django-analytical.
|
||||
"""
|
||||
|
||||
from analytical.tests.test_services import *
|
||||
from analytical.tests.test_template_tags import *
|
||||
|
||||
from analytical.tests.services import *
|
||||
from analytical.tests.test_tag_analytical import *
|
||||
from analytical.tests.test_tag_chartbeat import *
|
||||
from analytical.tests.test_tag_clicky import *
|
||||
from analytical.tests.test_tag_crazy_egg import *
|
||||
from analytical.tests.test_tag_google_analytics import *
|
||||
from analytical.tests.test_tag_hubspot import *
|
||||
from analytical.tests.test_tag_kiss_insights import *
|
||||
from analytical.tests.test_tag_kiss_metrics import *
|
||||
from analytical.tests.test_tag_mixpanel import *
|
||||
from analytical.tests.test_tag_optimizely import *
|
||||
from analytical.tests.test_utils import *
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
"""
|
||||
Tests for the Analytical analytics services.
|
||||
"""
|
||||
|
||||
from analytical.tests.services.test_base import *
|
||||
from analytical.tests.services.test_chartbeat import *
|
||||
from analytical.tests.services.test_clicky import *
|
||||
from analytical.tests.services.test_console import *
|
||||
from analytical.tests.services.test_crazy_egg import *
|
||||
from analytical.tests.services.test_google_analytics import *
|
||||
from analytical.tests.services.test_kiss_insights import *
|
||||
from analytical.tests.services.test_kiss_metrics import *
|
||||
from analytical.tests.services.test_mixpanel import *
|
||||
from analytical.tests.services.test_optimizely import *
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
"""
|
||||
Tests for the base service.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from django.contrib.auth.models import User, AnonymousUser
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.http import HttpRequest
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.base import AnalyticalService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class DummyService(AnalyticalService):
|
||||
def render_test(self, context):
|
||||
return context
|
||||
|
||||
|
||||
class BaseServiceTestCase(TestCase):
|
||||
"""
|
||||
Tests for the base service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.service = DummyService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_render(self):
|
||||
r = self.service.render('test', 'foo')
|
||||
self.assertEqual('foo', r)
|
||||
|
||||
def test_get_required_setting(self):
|
||||
self.settings_manager.set(TEST='test')
|
||||
r = self.service.get_required_setting('TEST', re.compile('es'), 'fail')
|
||||
self.assertEqual('test', r)
|
||||
|
||||
def test_get_required_setting_missing(self):
|
||||
self.settings_manager.delete('TEST')
|
||||
self.assertRaises(ImproperlyConfigured,
|
||||
self.service.get_required_setting, 'TEST', re.compile('es'),
|
||||
'fail')
|
||||
|
||||
def test_get_required_setting_wrong(self):
|
||||
self.settings_manager.set(TEST='test')
|
||||
self.assertRaises(ImproperlyConfigured,
|
||||
self.service.get_required_setting, 'TEST', re.compile('foo'),
|
||||
'fail')
|
||||
|
||||
def test_get_identity_none(self):
|
||||
context = {}
|
||||
self.assertEqual(None, self.service.get_identity(context))
|
||||
|
||||
def test_get_identity_authenticated(self):
|
||||
context = {'user': User(username='test')}
|
||||
self.assertEqual('test', self.service.get_identity(context))
|
||||
|
||||
def test_get_identity_authenticated_request(self):
|
||||
req = HttpRequest()
|
||||
req.user = User(username='test')
|
||||
context = {'request': req}
|
||||
self.assertEqual('test', self.service.get_identity(context))
|
||||
|
||||
def test_get_identity_anonymous(self):
|
||||
context = {'user': AnonymousUser()}
|
||||
self.assertEqual(None, self.service.get_identity(context))
|
||||
|
||||
def test_get_identity_non_user(self):
|
||||
context = {'user': object()}
|
||||
self.assertEqual(None, self.service.get_identity(context))
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
"""
|
||||
Tests for the Clicky service.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.clicky import ClickyService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class ClickyTestCase(TestCase):
|
||||
"""
|
||||
Tests for the Clicky service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(CLICKY_SITE_ID='12345678')
|
||||
self.service = ClickyService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_top({}), "")
|
||||
self.assertEqual(self.service.render_head_bottom({}), "")
|
||||
self.assertEqual(self.service.render_body_top({}), "")
|
||||
|
||||
def test_no_site_id(self):
|
||||
self.settings_manager.delete('CLICKY_SITE_ID')
|
||||
self.assertRaises(ImproperlyConfigured, ClickyService)
|
||||
|
||||
def test_wrong_site_id(self):
|
||||
self.settings_manager.set(CLICKY_SITE_ID='1234567')
|
||||
self.assertRaises(ImproperlyConfigured, ClickyService)
|
||||
self.settings_manager.set(CLICKY_SITE_ID='123456789')
|
||||
self.assertRaises(ImproperlyConfigured, ClickyService)
|
||||
|
||||
def test_rendering(self):
|
||||
r = self.service.render_body_bottom({})
|
||||
self.assertTrue('var clicky_site_id = 12345678;' in r, r)
|
||||
self.assertTrue('src="http://in.getclicky.com/12345678ns.gif"' in r,
|
||||
r)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = self.service.render_body_bottom({'user': User(username='test')})
|
||||
self.assertTrue(
|
||||
'var clicky_custom = {"session": {"username": "test"}};' in r,
|
||||
r)
|
||||
|
||||
def test_custom(self):
|
||||
custom = {'var1': 'val1', 'var2': 'val2'}
|
||||
r = self.service.render_body_bottom({'clicky_custom': custom})
|
||||
self.assertTrue(re.search('var clicky_custom = {.*'
|
||||
'"var1": "val1", "var2": "val2".*};', r), r)
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
"""
|
||||
Tests for the console debugging service.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.console import ConsoleService
|
||||
|
||||
|
||||
class ConsoleTestCase(TestCase):
|
||||
"""
|
||||
Tests for the console debugging service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.service = ConsoleService()
|
||||
|
||||
def test_render_head_top(self):
|
||||
r = self.service.render_head_top({})
|
||||
self.assertTrue('rendering analytical_head_top tag' in r, r)
|
||||
r = self.service.render_head_top({'user': User(username='test')})
|
||||
self.assertTrue('rendering analytical_head_top tag for user test'
|
||||
in r, r)
|
||||
|
||||
def test_render_head_bottom(self):
|
||||
r = self.service.render_head_bottom({})
|
||||
self.assertTrue('rendering analytical_head_bottom tag' in r, r)
|
||||
r = self.service.render_head_bottom({'user': User(username='test')})
|
||||
self.assertTrue('rendering analytical_head_bottom tag for user test'
|
||||
in r, r)
|
||||
|
||||
def test_render_body_top(self):
|
||||
r = self.service.render_body_top({})
|
||||
self.assertTrue('rendering analytical_body_top tag' in r, r)
|
||||
r = self.service.render_body_top({'user': User(username='test')})
|
||||
self.assertTrue('rendering analytical_body_top tag for user test'
|
||||
in r, r)
|
||||
|
||||
def test_render_body_bottom(self):
|
||||
r = self.service.render_body_bottom({})
|
||||
self.assertTrue('rendering analytical_body_bottom tag' in r, r)
|
||||
r = self.service.render_body_bottom({'user': User(username='test')})
|
||||
self.assertTrue('rendering analytical_body_bottom tag for user test'
|
||||
in r, r)
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
"""
|
||||
Tests for the Crazy Egg service.
|
||||
"""
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.crazy_egg import CrazyEggService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class CrazyEggTestCase(TestCase):
|
||||
"""
|
||||
Tests for the Crazy Egg service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(CRAZY_EGG_ACCOUNT_NUMBER='12345678')
|
||||
self.service = CrazyEggService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_top({}), "")
|
||||
self.assertEqual(self.service.render_head_bottom({}), "")
|
||||
self.assertEqual(self.service.render_body_top({}), "")
|
||||
|
||||
def test_no_account_number(self):
|
||||
self.settings_manager.delete('CRAZY_EGG_ACCOUNT_NUMBER')
|
||||
self.assertRaises(ImproperlyConfigured, CrazyEggService)
|
||||
|
||||
def test_wrong_account_number(self):
|
||||
self.settings_manager.set(CRAZY_EGG_ACCOUNT_NUMBER='1234567')
|
||||
self.assertRaises(ImproperlyConfigured, CrazyEggService)
|
||||
self.settings_manager.set(CRAZY_EGG_ACCOUNT_NUMBER='123456789')
|
||||
self.assertRaises(ImproperlyConfigured, CrazyEggService)
|
||||
|
||||
def test_rendering(self):
|
||||
r = self.service.render_body_bottom({})
|
||||
self.assertTrue('/1234/5678.js' in r, r)
|
||||
|
||||
def test_uservars(self):
|
||||
context = {'crazy_egg_uservars': {1: 'foo', 2: 'bar'}}
|
||||
r = self.service.render_body_bottom(context)
|
||||
self.assertTrue("CE2.set(1, 'foo');" in r, r)
|
||||
self.assertTrue("CE2.set(2, 'bar');" in r, r)
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
"""
|
||||
Tests for the Google Analytics service.
|
||||
"""
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.google_analytics import GoogleAnalyticsService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class GoogleAnalyticsTestCase(TestCase):
|
||||
"""
|
||||
Tests for the Google Analytics service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(GOOGLE_ANALYTICS_PROPERTY_ID='UA-123456-7')
|
||||
self.service = GoogleAnalyticsService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_top({}), "")
|
||||
self.assertEqual(self.service.render_body_top({}), "")
|
||||
self.assertEqual(self.service.render_body_bottom({}), "")
|
||||
|
||||
def test_no_property_id(self):
|
||||
self.settings_manager.delete('GOOGLE_ANALYTICS_PROPERTY_ID')
|
||||
self.assertRaises(ImproperlyConfigured, GoogleAnalyticsService)
|
||||
|
||||
def test_wrong_property_id(self):
|
||||
self.settings_manager.set(GOOGLE_ANALYTICS_PROPERTY_ID='wrong')
|
||||
self.assertRaises(ImproperlyConfigured, GoogleAnalyticsService)
|
||||
|
||||
def test_rendering(self):
|
||||
r = self.service.render_head_bottom({})
|
||||
self.assertTrue("_gaq.push(['_setAccount', 'UA-123456-7']);" in r, r)
|
||||
self.assertTrue("_gaq.push(['_trackPageview']);" in r, r)
|
||||
|
||||
def test_custom_vars(self):
|
||||
context = {'google_analytics_custom_vars': [
|
||||
(1, 'test1', 'foo'),
|
||||
(5, 'test2', 'bar', 1),
|
||||
]}
|
||||
r = self.service.render_head_bottom(context)
|
||||
self.assertTrue("_gaq.push(['_setCustomVar', 1, 'test1', 'foo', 2]);"
|
||||
in r, r)
|
||||
self.assertTrue("_gaq.push(['_setCustomVar', 5, 'test2', 'bar', 1]);"
|
||||
in r, r)
|
||||
self.assertRaises(ValueError, self.service.render_head_bottom,
|
||||
{'google_analytics_custom_vars': [(0, 'test', 'test')]})
|
||||
self.assertRaises(ValueError, self.service.render_head_bottom,
|
||||
{'google_analytics_custom_vars': [(6, 'test', 'test')]})
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
"""
|
||||
Tests for the KISSinsights service.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.kiss_insights import KissInsightsService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class KissInsightsTestCase(TestCase):
|
||||
"""
|
||||
Tests for the KISSinsights service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(KISS_INSIGHTS_ACCOUNT_NUMBER='12345')
|
||||
self.settings_manager.set(KISS_INSIGHTS_SITE_CODE='abc')
|
||||
self.service = KissInsightsService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_top({}), "")
|
||||
self.assertEqual(self.service.render_head_bottom({}), "")
|
||||
self.assertEqual(self.service.render_body_bottom({}), "")
|
||||
|
||||
def test_no_account_number(self):
|
||||
self.settings_manager.delete('KISS_INSIGHTS_ACCOUNT_NUMBER')
|
||||
self.assertRaises(ImproperlyConfigured, KissInsightsService)
|
||||
|
||||
def test_no_site_code(self):
|
||||
self.settings_manager.delete('KISS_INSIGHTS_SITE_CODE')
|
||||
self.assertRaises(ImproperlyConfigured, KissInsightsService)
|
||||
|
||||
def test_wrong_account_number(self):
|
||||
self.settings_manager.set(KISS_INSIGHTS_ACCOUNT_NUMBER='1234')
|
||||
self.assertRaises(ImproperlyConfigured, KissInsightsService)
|
||||
self.settings_manager.set(KISS_INSIGHTS_ACCOUNT_NUMBER='123456')
|
||||
self.assertRaises(ImproperlyConfigured, KissInsightsService)
|
||||
|
||||
def test_wrong_site_id(self):
|
||||
self.settings_manager.set(KISS_INSIGHTS_SITE_CODE='ab')
|
||||
self.assertRaises(ImproperlyConfigured, KissInsightsService)
|
||||
self.settings_manager.set(KISS_INSIGHTS_SITE_CODE='abcd')
|
||||
self.assertRaises(ImproperlyConfigured, KissInsightsService)
|
||||
|
||||
def test_rendering(self):
|
||||
r = self.service.render_body_top({})
|
||||
self.assertTrue("//s3.amazonaws.com/ki.js/12345/abc.js" in r, r)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = self.service.render_body_top({'user': User(username='test')})
|
||||
self.assertTrue("_kiq.push(['identify', 'test']);" in r, r)
|
||||
|
||||
def test_show_survey(self):
|
||||
r = self.service.render_body_top({'kiss_insights_show_survey': 1234})
|
||||
self.assertTrue("_kiq.push(['showSurvey', 1234]);" in r, r)
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
"""
|
||||
Tests for the KISSmetrics service.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.kiss_metrics import KissMetricsService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class KissMetricsTestCase(TestCase):
|
||||
"""
|
||||
Tests for the KISSmetrics service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(KISS_METRICS_API_KEY='0123456789abcdef012345'
|
||||
'6789abcdef01234567')
|
||||
self.service = KissMetricsService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_bottom({}), "")
|
||||
self.assertEqual(self.service.render_body_top({}), "")
|
||||
self.assertEqual(self.service.render_body_bottom({}), "")
|
||||
|
||||
def test_no_api_key(self):
|
||||
self.settings_manager.delete('KISS_METRICS_API_KEY')
|
||||
self.assertRaises(ImproperlyConfigured, KissMetricsService)
|
||||
|
||||
def test_wrong_api_key(self):
|
||||
self.settings_manager.set(KISS_METRICS_API_KEY='0123456789abcdef012345'
|
||||
'6789abcdef0123456')
|
||||
self.assertRaises(ImproperlyConfigured, KissMetricsService)
|
||||
self.settings_manager.set(KISS_METRICS_API_KEY='0123456789abcdef012345'
|
||||
'6789abcdef012345678')
|
||||
self.assertRaises(ImproperlyConfigured, KissMetricsService)
|
||||
|
||||
def test_rendering(self):
|
||||
r = self.service.render_head_top({})
|
||||
self.assertTrue("//doug1izaerwt3.cloudfront.net/0123456789abcdef012345"
|
||||
"6789abcdef01234567.1.js" in r, r)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = self.service.render_head_top({'user': User(username='test')})
|
||||
self.assertTrue("_kmq.push(['identify', 'test']);" in r, r)
|
||||
|
||||
def test_event(self):
|
||||
r = self.service.render_event('test_event', {'prop1': 'val1',
|
||||
'prop2': 'val2'})
|
||||
self.assertEqual(r, "_kmq.push(['record', 'test_event', "
|
||||
'{"prop1": "val1", "prop2": "val2"}]);')
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
"""
|
||||
Tests for the Mixpanel service.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.mixpanel import MixpanelService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class MixpanelTestCase(TestCase):
|
||||
"""
|
||||
Tests for the Mixpanel service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(
|
||||
MIXPANEL_TOKEN='0123456789abcdef0123456789abcdef')
|
||||
self.service = MixpanelService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_top({}), "")
|
||||
self.assertEqual(self.service.render_body_top({}), "")
|
||||
self.assertEqual(self.service.render_body_bottom({}), "")
|
||||
|
||||
def test_no_token(self):
|
||||
self.settings_manager.delete('MIXPANEL_TOKEN')
|
||||
self.assertRaises(ImproperlyConfigured, MixpanelService)
|
||||
|
||||
def test_wrong_token(self):
|
||||
self.settings_manager.set(
|
||||
MIXPANEL_TOKEN='0123456789abcdef0123456789abcde')
|
||||
self.assertRaises(ImproperlyConfigured, MixpanelService)
|
||||
self.settings_manager.set(
|
||||
MIXPANEL_TOKEN='0123456789abcdef0123456789abcdef0')
|
||||
self.assertRaises(ImproperlyConfigured, MixpanelService)
|
||||
|
||||
def test_rendering(self):
|
||||
r = self.service.render_head_bottom({})
|
||||
self.assertTrue(
|
||||
"mpq.push(['init', '0123456789abcdef0123456789abcdef']);" in r,
|
||||
r)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = self.service.render_head_bottom({'user': User(username='test')})
|
||||
self.assertTrue("mpq.push(['identify', 'test']);" in r, r)
|
||||
|
||||
def test_event(self):
|
||||
r = self.service.render_event('test_event', {'prop1': 'val1',
|
||||
'prop2': 'val2'})
|
||||
self.assertEqual(r, "mpq.push(['track', 'test_event', "
|
||||
'{"prop1": "val1", "prop2": "val2"}]);')
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
"""
|
||||
Tests for the Optimizely service.
|
||||
"""
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical.services.optimizely import OptimizelyService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class OptimizelyTestCase(TestCase):
|
||||
"""
|
||||
Tests for the Optimizely service.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(OPTIMIZELY_ACCOUNT_NUMBER='1234567')
|
||||
self.service = OptimizelyService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_bottom({}), "")
|
||||
self.assertEqual(self.service.render_body_top({}), "")
|
||||
self.assertEqual(self.service.render_body_bottom({}), "")
|
||||
|
||||
def test_no_account_number(self):
|
||||
self.settings_manager.delete('OPTIMIZELY_ACCOUNT_NUMBER')
|
||||
self.assertRaises(ImproperlyConfigured, OptimizelyService)
|
||||
|
||||
def test_wrong_account_number(self):
|
||||
self.settings_manager.set(OPTIMIZELY_ACCOUNT_NUMBER='123456')
|
||||
self.assertRaises(ImproperlyConfigured, OptimizelyService)
|
||||
self.settings_manager.set(OPTIMIZELY_ACCOUNT_NUMBER='12345678')
|
||||
self.assertRaises(ImproperlyConfigured, OptimizelyService)
|
||||
|
||||
def test_rendering(self):
|
||||
self.assertEqual(self.service.render_head_top({}),
|
||||
'<script src="//cdn.optimizely.com/js/1234567.js"></script>')
|
||||
0
analytical/tests/templatetags/__init__.py
Normal file
0
analytical/tests/templatetags/__init__.py
Normal file
38
analytical/tests/templatetags/dummy.py
Normal file
38
analytical/tests/templatetags/dummy.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
"""
|
||||
Dummy testing template tags and filters.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.templatetags.analytical import TAG_LOCATIONS
|
||||
|
||||
|
||||
register = Library()
|
||||
|
||||
|
||||
def _location_node(location):
|
||||
class DummyNode(Node):
|
||||
def render(self, context):
|
||||
return "<!-- dummy_%s -->" % location
|
||||
return DummyNode
|
||||
|
||||
_location_nodes = dict((l, _location_node(l)) for l in TAG_LOCATIONS)
|
||||
|
||||
|
||||
def _location_tag(location):
|
||||
def dummy_tag(parser, token):
|
||||
bits = token.split_contents()
|
||||
if len(bits) > 1:
|
||||
raise TemplateSyntaxError("'%s' tag takes no arguments" % bits[0])
|
||||
return _location_nodes[location]
|
||||
return dummy_tag
|
||||
|
||||
for loc in TAG_LOCATIONS:
|
||||
register.tag('dummy_%s' % loc, _location_tag(loc))
|
||||
|
||||
|
||||
def contribute_to_analytical(add_node_cls):
|
||||
for location in TAG_LOCATIONS:
|
||||
add_node_cls(location, _location_nodes[location])
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
"""
|
||||
Tests for the services package.
|
||||
"""
|
||||
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical import services
|
||||
from analytical.services import load_services
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
from analytical.services.google_analytics import GoogleAnalyticsService
|
||||
|
||||
|
||||
class GetEnabledServicesTestCase(TestCase):
|
||||
"""
|
||||
Tests for get_enabled_services.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
services.enabled_services = None
|
||||
services.load_services = lambda: 'test'
|
||||
|
||||
def tearDown(self):
|
||||
services.enabled_services = None
|
||||
services.load_services = load_services
|
||||
|
||||
def test_get_enabled_services(self):
|
||||
result = services.get_enabled_services()
|
||||
self.assertEqual(result, 'test')
|
||||
services.load_services = lambda: 'test2'
|
||||
result = services.get_enabled_services()
|
||||
self.assertEqual(result, 'test')
|
||||
|
||||
|
||||
class LoadServicesTestCase(TestCase):
|
||||
"""
|
||||
Tests for load_services.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.delete('ANALYTICAL_SERVICES')
|
||||
self.settings_manager.delete('CLICKY_SITE_ID')
|
||||
self.settings_manager.delete('CHARTBEAT_USER_ID')
|
||||
self.settings_manager.delete('CRAZY_EGG_ACCOUNT_NUMBER')
|
||||
self.settings_manager.delete('GOOGLE_ANALYTICS_PROPERTY_ID')
|
||||
self.settings_manager.delete('KISSINSIGHTS_ACCOUNT_NUMBER')
|
||||
self.settings_manager.delete('KISSINSIGHTS_SITE_CODE')
|
||||
self.settings_manager.delete('KISSMETRICS_API_KEY')
|
||||
self.settings_manager.delete('MIXPANEL_TOKEN')
|
||||
self.settings_manager.delete('OPTIMIZELY_ACCOUNT_NUMBER')
|
||||
services.enabled_services = None
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
services.enabled_services = None
|
||||
|
||||
def test_no_services(self):
|
||||
self.assertEqual(load_services(), [])
|
||||
|
||||
def test_enabled_service(self):
|
||||
self.settings_manager.set(GOOGLE_ANALYTICS_PROPERTY_ID='UA-1234567-8')
|
||||
results = load_services()
|
||||
self.assertEqual(len(results), 1, results)
|
||||
self.assertTrue(isinstance(results[0], GoogleAnalyticsService),
|
||||
results)
|
||||
|
||||
def test_explicit_service(self):
|
||||
self.settings_manager.set(ANALYTICAL_SERVICES=[
|
||||
'analytical.services.google_analytics.GoogleAnalyticsService'])
|
||||
self.settings_manager.set(GOOGLE_ANALYTICS_PROPERTY_ID='UA-1234567-8')
|
||||
results = load_services()
|
||||
self.assertEqual(len(results), 1, results)
|
||||
self.assertTrue(isinstance(results[0], GoogleAnalyticsService),
|
||||
results)
|
||||
|
||||
def test_explicit_service_misconfigured(self):
|
||||
self.settings_manager.set(ANALYTICAL_SERVICES=[
|
||||
'analytical.services.google_analytics.GoogleAnalyticsService'])
|
||||
self.assertRaises(ImproperlyConfigured, load_services)
|
||||
37
analytical/tests/test_tag_analytical.py
Normal file
37
analytical/tests/test_tag_analytical.py
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
"""
|
||||
Tests for the generic template tags and filters.
|
||||
"""
|
||||
|
||||
from django.template import Context, Template
|
||||
|
||||
from analytical.templatetags import analytical
|
||||
from analytical.tests.utils import TagTestCase
|
||||
|
||||
|
||||
class AnalyticsTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``analytical`` template tags.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(AnalyticsTagTestCase, self).setUp()
|
||||
self._tag_modules = analytical.TAG_MODULES
|
||||
analytical.TAG_MODULES = ['analytical.tests.dummy']
|
||||
analytical.template_nodes = analytical._load_template_nodes()
|
||||
|
||||
def tearDown(self):
|
||||
analytical.TAG_MODULES = self._tag_modules
|
||||
analytical.template_nodes = analytical._load_template_nodes()
|
||||
super(AnalyticsTagTestCase, self).tearDown()
|
||||
|
||||
def render_location_tag(self, location, vars=None):
|
||||
if vars is None:
|
||||
vars = {}
|
||||
t = Template("{%% load analytical %%}{%% analytical_%s %%}"
|
||||
% location)
|
||||
return t.render(Context(vars))
|
||||
|
||||
def test_location_tags(self):
|
||||
for l in ['head_top', 'head_bottom', 'body_top', 'body_bottom']:
|
||||
r = self.render_location_tag(l)
|
||||
self.assertTrue('dummy_%s' % l in r, r)
|
||||
|
|
@ -1,62 +1,69 @@
|
|||
"""
|
||||
Tests for the Chartbeat service.
|
||||
Tests for the Chartbeat template tags and filters.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.http import HttpRequest
|
||||
from django.test import TestCase
|
||||
from django.template import Context
|
||||
|
||||
from analytical.services.chartbeat import ChartbeatService
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
from analytical.templatetags.chartbeat import ChartbeatTopNode, \
|
||||
ChartbeatBottomNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class ChartbeatTestCase(TestCase):
|
||||
class ChartbeatTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the Chartbeat service.
|
||||
Tests for the ``chartbeat`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
super(ChartbeatTagTestCase, self).setUp()
|
||||
self.settings_manager.set(CHARTBEAT_USER_ID='12345')
|
||||
self.service = ChartbeatService()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def test_empty_locations(self):
|
||||
self.assertEqual(self.service.render_head_bottom({}), "")
|
||||
self.assertEqual(self.service.render_body_top({}), "")
|
||||
|
||||
def test_no_user_id(self):
|
||||
self.settings_manager.delete('CHARTBEAT_USER_ID')
|
||||
self.assertRaises(ImproperlyConfigured, ChartbeatService)
|
||||
|
||||
def test_wrong_user_id(self):
|
||||
self.settings_manager.set(CHARTBEAT_USER_ID='1234')
|
||||
self.assertRaises(ImproperlyConfigured, ChartbeatService)
|
||||
self.settings_manager.set(CHARTBEAT_USER_ID='123456')
|
||||
self.assertRaises(ImproperlyConfigured, ChartbeatService)
|
||||
|
||||
def test_rendering_init(self):
|
||||
r = self.service.render_head_top({})
|
||||
def test_top_tag(self):
|
||||
r = self.render_tag('chartbeat', 'chartbeat_top',
|
||||
{'chartbeat_domain': "test.com"})
|
||||
self.assertTrue('var _sf_startpt=(new Date()).getTime()' in r, r)
|
||||
|
||||
def test_rendering_setup(self):
|
||||
r = self.service.render_body_bottom({'chartbeat_domain': "test.com"})
|
||||
def test_bottom_tag(self):
|
||||
r = self.render_tag('chartbeat', 'chartbeat_bottom',
|
||||
{'chartbeat_domain': "test.com"})
|
||||
self.assertTrue(re.search(
|
||||
'var _sf_async_config={.*"uid": "12345".*};', r), r)
|
||||
self.assertTrue(re.search(
|
||||
'var _sf_async_config={.*"domain": "test.com".*};', r), r)
|
||||
|
||||
def test_top_node(self):
|
||||
r = ChartbeatTopNode().render(
|
||||
Context({'chartbeat_domain': "test.com"}))
|
||||
self.assertTrue('var _sf_startpt=(new Date()).getTime()' in r, r)
|
||||
|
||||
def test_bottom_node(self):
|
||||
r = ChartbeatBottomNode().render(
|
||||
Context({'chartbeat_domain': "test.com"}))
|
||||
self.assertTrue(re.search(
|
||||
'var _sf_async_config={.*"uid": "12345".*};', r), r)
|
||||
self.assertTrue(re.search(
|
||||
'var _sf_async_config={.*"domain": "test.com".*};', r), r)
|
||||
|
||||
def test_no_user_id(self):
|
||||
self.settings_manager.delete('CHARTBEAT_USER_ID')
|
||||
self.assertRaises(AnalyticalException, ChartbeatBottomNode)
|
||||
|
||||
def test_wrong_user_id(self):
|
||||
self.settings_manager.set(CHARTBEAT_USER_ID='1234')
|
||||
self.assertRaises(AnalyticalException, ChartbeatBottomNode)
|
||||
self.settings_manager.set(CHARTBEAT_USER_ID='123456')
|
||||
self.assertRaises(AnalyticalException, ChartbeatBottomNode)
|
||||
|
||||
def test_rendering_setup_no_site(self):
|
||||
installed_apps = [a for a in settings.INSTALLED_APPS
|
||||
if a != 'django.contrib.sites']
|
||||
self.settings_manager.set(INSTALLED_APPS=installed_apps)
|
||||
r = self.service.render_body_bottom({})
|
||||
r = ChartbeatBottomNode().render(Context())
|
||||
self.assertTrue('var _sf_async_config={"uid": "12345"};' in r, r)
|
||||
|
||||
def test_rendering_setup_site(self):
|
||||
|
|
@ -65,7 +72,7 @@ class ChartbeatTestCase(TestCase):
|
|||
self.settings_manager.set(INSTALLED_APPS=installed_apps)
|
||||
site = Site.objects.create(domain="test.com", name="test")
|
||||
self.settings_manager.set(SITE_ID=site.id)
|
||||
r = self.service.render_body_bottom({})
|
||||
r = ChartbeatBottomNode().render(Context())
|
||||
self.assertTrue(re.search(
|
||||
'var _sf_async_config={.*"uid": "12345".*};', r), r)
|
||||
self.assertTrue(re.search(
|
||||
57
analytical/tests/test_tag_clicky.py
Normal file
57
analytical/tests/test_tag_clicky.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
"""
|
||||
Tests for the Clicky template tags and filters.
|
||||
"""
|
||||
|
||||
import re
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.clicky import ClickyNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class ClickyTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``clicky`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(ClickyTagTestCase, self).setUp()
|
||||
self.settings_manager.set(CLICKY_SITE_ID='12345678')
|
||||
|
||||
def test_tag(self):
|
||||
r = self.render_tag('clicky', 'clicky')
|
||||
self.assertTrue('var clicky_site_id = 12345678;' in r, r)
|
||||
self.assertTrue('src="http://in.getclicky.com/12345678ns.gif"' in r,
|
||||
r)
|
||||
|
||||
def test_node(self):
|
||||
r = ClickyNode().render(Context({}))
|
||||
self.assertTrue('var clicky_site_id = 12345678;' in r, r)
|
||||
self.assertTrue('src="http://in.getclicky.com/12345678ns.gif"' in r,
|
||||
r)
|
||||
|
||||
def test_no_site_id(self):
|
||||
self.settings_manager.delete('CLICKY_SITE_ID')
|
||||
self.assertRaises(AnalyticalException, ClickyNode)
|
||||
|
||||
def test_wrong_site_id(self):
|
||||
self.settings_manager.set(CLICKY_SITE_ID='1234567')
|
||||
self.assertRaises(AnalyticalException, ClickyNode)
|
||||
self.settings_manager.set(CLICKY_SITE_ID='123456789')
|
||||
self.assertRaises(AnalyticalException, ClickyNode)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = ClickyNode().render(Context({'user': User(username='test')}))
|
||||
self.assertTrue(
|
||||
'var clicky_custom = {"session": {"username": "test"}};' in r,
|
||||
r)
|
||||
|
||||
def test_custom(self):
|
||||
r = ClickyNode().render(Context({'clicky_var1': 'val1',
|
||||
'clicky_var2': 'val2'}))
|
||||
self.assertTrue(re.search('var clicky_custom = {.*'
|
||||
'"var1": "val1", "var2": "val2".*};', r), r)
|
||||
43
analytical/tests/test_tag_crazy_egg.py
Normal file
43
analytical/tests/test_tag_crazy_egg.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
"""
|
||||
Tests for the Crazy Egg template tags and filters.
|
||||
"""
|
||||
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.crazy_egg import CrazyEggNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class CrazyEggTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``crazy_egg`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(CrazyEggTagTestCase, self).setUp()
|
||||
self.settings_manager.set(CRAZY_EGG_ACCOUNT_NUMBER='12345678')
|
||||
|
||||
def test_tag(self):
|
||||
r = self.render_tag('crazy_egg', 'crazy_egg')
|
||||
self.assertTrue('/1234/5678.js' in r, r)
|
||||
|
||||
def test_node(self):
|
||||
r = CrazyEggNode().render(Context())
|
||||
self.assertTrue('/1234/5678.js' in r, r)
|
||||
|
||||
def test_no_account_number(self):
|
||||
self.settings_manager.delete('CRAZY_EGG_ACCOUNT_NUMBER')
|
||||
self.assertRaises(AnalyticalException, CrazyEggNode)
|
||||
|
||||
def test_wrong_account_number(self):
|
||||
self.settings_manager.set(CRAZY_EGG_ACCOUNT_NUMBER='1234567')
|
||||
self.assertRaises(AnalyticalException, CrazyEggNode)
|
||||
self.settings_manager.set(CRAZY_EGG_ACCOUNT_NUMBER='123456789')
|
||||
self.assertRaises(AnalyticalException, CrazyEggNode)
|
||||
|
||||
def test_uservars(self):
|
||||
context = Context({'crazy_egg_var1': 'foo', 'crazy_egg_var2': 'bar'})
|
||||
r = CrazyEggNode().render(context)
|
||||
self.assertTrue("CE2.set(1, 'foo');" in r, r)
|
||||
self.assertTrue("CE2.set(2, 'bar');" in r, r)
|
||||
46
analytical/tests/test_tag_google_analytics.py
Normal file
46
analytical/tests/test_tag_google_analytics.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
"""
|
||||
Tests for the Google Analytics template tags and filters.
|
||||
"""
|
||||
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.google_analytics import GoogleAnalyticsNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class GoogleAnalyticsTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``google_analytics`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(GoogleAnalyticsTagTestCase, self).setUp()
|
||||
self.settings_manager.set(GOOGLE_ANALYTICS_PROPERTY_ID='UA-123456-7')
|
||||
|
||||
def test_tag(self):
|
||||
r = self.render_tag('google_analytics', 'google_analytics')
|
||||
self.assertTrue("_gaq.push(['_setAccount', 'UA-123456-7']);" in r, r)
|
||||
self.assertTrue("_gaq.push(['_trackPageview']);" in r, r)
|
||||
|
||||
def test_node(self):
|
||||
r = GoogleAnalyticsNode().render(Context())
|
||||
self.assertTrue("_gaq.push(['_setAccount', 'UA-123456-7']);" in r, r)
|
||||
self.assertTrue("_gaq.push(['_trackPageview']);" in r, r)
|
||||
|
||||
def test_no_property_id(self):
|
||||
self.settings_manager.delete('GOOGLE_ANALYTICS_PROPERTY_ID')
|
||||
self.assertRaises(AnalyticalException, GoogleAnalyticsNode)
|
||||
|
||||
def test_wrong_property_id(self):
|
||||
self.settings_manager.set(GOOGLE_ANALYTICS_PROPERTY_ID='wrong')
|
||||
self.assertRaises(AnalyticalException, GoogleAnalyticsNode)
|
||||
|
||||
def test_custom_vars(self):
|
||||
context = Context({'google_analytics_var1': ('test1', 'foo'),
|
||||
'google_analytics_var5': ('test2', 'bar', 1)})
|
||||
r = GoogleAnalyticsNode().render(context)
|
||||
self.assertTrue("_gaq.push(['_setCustomVar', 1, 'test1', 'foo', 3]);"
|
||||
in r, r)
|
||||
self.assertTrue("_gaq.push(['_setCustomVar', 5, 'test2', 'bar', 1]);"
|
||||
in r, r)
|
||||
46
analytical/tests/test_tag_hubspot.py
Normal file
46
analytical/tests/test_tag_hubspot.py
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
"""
|
||||
Tests for the HubSpot template tags and filters.
|
||||
"""
|
||||
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.hubspot import HubSpotNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class HubSpotTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``hubspot`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(HubSpotTagTestCase, self).setUp()
|
||||
self.settings_manager.set(HUBSPOT_PORTAL_ID='1234')
|
||||
self.settings_manager.set(HUBSPOT_DOMAIN='example.com')
|
||||
|
||||
def test_tag(self):
|
||||
r = self.render_tag('hubspot', 'hubspot')
|
||||
self.assertTrue('var hs_portalid = 1234;' in r, r)
|
||||
self.assertTrue('var hs_ppa = "example.com";' in r, r)
|
||||
|
||||
def test_node(self):
|
||||
r = HubSpotNode().render(Context())
|
||||
self.assertTrue('var hs_portalid = 1234;' in r, r)
|
||||
self.assertTrue('var hs_ppa = "example.com";' in r, r)
|
||||
|
||||
def test_no_portal_id(self):
|
||||
self.settings_manager.delete('HUBSPOT_PORTAL_ID')
|
||||
self.assertRaises(AnalyticalException, HubSpotNode)
|
||||
|
||||
def test_wrong_portal_id(self):
|
||||
self.settings_manager.set(HUBSPOT_PORTAL_ID='wrong')
|
||||
self.assertRaises(AnalyticalException, HubSpotNode)
|
||||
|
||||
def test_no_domain(self):
|
||||
self.settings_manager.delete('HUBSPOT_DOMAIN')
|
||||
self.assertRaises(AnalyticalException, HubSpotNode)
|
||||
|
||||
def test_wrong_domain(self):
|
||||
self.settings_manager.set(HUBSPOT_DOMAIN='wrong domain')
|
||||
self.assertRaises(AnalyticalException, HubSpotNode)
|
||||
57
analytical/tests/test_tag_kiss_insights.py
Normal file
57
analytical/tests/test_tag_kiss_insights.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
"""
|
||||
Tests for the KISSinsights template tags and filters.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.kiss_insights import KissInsightsNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class KissInsightsTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``kiss_insights`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(KissInsightsTagTestCase, self).setUp()
|
||||
self.settings_manager.set(KISS_INSIGHTS_ACCOUNT_NUMBER='12345')
|
||||
self.settings_manager.set(KISS_INSIGHTS_SITE_CODE='abc')
|
||||
|
||||
def test_tag(self):
|
||||
r = self.render_tag('kiss_insights', 'kiss_insights')
|
||||
self.assertTrue("//s3.amazonaws.com/ki.js/12345/abc.js" in r, r)
|
||||
|
||||
def test_node(self):
|
||||
r = KissInsightsNode().render(Context())
|
||||
self.assertTrue("//s3.amazonaws.com/ki.js/12345/abc.js" in r, r)
|
||||
|
||||
def test_no_account_number(self):
|
||||
self.settings_manager.delete('KISS_INSIGHTS_ACCOUNT_NUMBER')
|
||||
self.assertRaises(AnalyticalException, KissInsightsNode)
|
||||
|
||||
def test_no_site_code(self):
|
||||
self.settings_manager.delete('KISS_INSIGHTS_SITE_CODE')
|
||||
self.assertRaises(AnalyticalException, KissInsightsNode)
|
||||
|
||||
def test_wrong_account_number(self):
|
||||
self.settings_manager.set(KISS_INSIGHTS_ACCOUNT_NUMBER='abcde')
|
||||
self.assertRaises(AnalyticalException, KissInsightsNode)
|
||||
|
||||
def test_wrong_site_id(self):
|
||||
self.settings_manager.set(KISS_INSIGHTS_SITE_CODE='ab')
|
||||
self.assertRaises(AnalyticalException, KissInsightsNode)
|
||||
self.settings_manager.set(KISS_INSIGHTS_SITE_CODE='abcd')
|
||||
self.assertRaises(AnalyticalException, KissInsightsNode)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = KissInsightsNode().render(Context({'user': User(username='test')}))
|
||||
self.assertTrue("_kiq.push(['identify', 'test']);" in r, r)
|
||||
|
||||
def test_show_survey(self):
|
||||
r = KissInsightsNode().render(
|
||||
Context({'kiss_insights_show_survey': 1234}))
|
||||
self.assertTrue("_kiq.push(['showSurvey', 1234]);" in r, r)
|
||||
54
analytical/tests/test_tag_kiss_metrics.py
Normal file
54
analytical/tests/test_tag_kiss_metrics.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
"""
|
||||
Tests for the KISSmetrics tags and filters.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.kiss_metrics import KissMetricsNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class KissMetricsTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``kiss_metrics`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(KissMetricsTagTestCase, self).setUp()
|
||||
self.settings_manager.set(KISS_METRICS_API_KEY='0123456789abcdef012345'
|
||||
'6789abcdef01234567')
|
||||
|
||||
def test_tag(self):
|
||||
r = self.render_tag('kiss_metrics', 'kiss_metrics')
|
||||
self.assertTrue("//doug1izaerwt3.cloudfront.net/0123456789abcdef012345"
|
||||
"6789abcdef01234567.1.js" in r, r)
|
||||
|
||||
def test_node(self):
|
||||
r = KissMetricsNode().render(Context())
|
||||
self.assertTrue("//doug1izaerwt3.cloudfront.net/0123456789abcdef012345"
|
||||
"6789abcdef01234567.1.js" in r, r)
|
||||
|
||||
def test_no_api_key(self):
|
||||
self.settings_manager.delete('KISS_METRICS_API_KEY')
|
||||
self.assertRaises(AnalyticalException, KissMetricsNode)
|
||||
|
||||
def test_wrong_api_key(self):
|
||||
self.settings_manager.set(KISS_METRICS_API_KEY='0123456789abcdef012345'
|
||||
'6789abcdef0123456')
|
||||
self.assertRaises(AnalyticalException, KissMetricsNode)
|
||||
self.settings_manager.set(KISS_METRICS_API_KEY='0123456789abcdef012345'
|
||||
'6789abcdef012345678')
|
||||
self.assertRaises(AnalyticalException, KissMetricsNode)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = KissMetricsNode().render(Context({'user': User(username='test')}))
|
||||
self.assertTrue("_kmq.push(['identify', 'test']);" in r, r)
|
||||
|
||||
def test_event(self):
|
||||
r = KissMetricsNode().render(Context({'kiss_metrics_event':
|
||||
('test_event', {'prop1': 'val1', 'prop2': 'val2'})}))
|
||||
self.assertTrue("_kmq.push(['record', 'test_event', "
|
||||
'{"prop1": "val1", "prop2": "val2"}]);' in r, r)
|
||||
57
analytical/tests/test_tag_mixpanel.py
Normal file
57
analytical/tests/test_tag_mixpanel.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
"""
|
||||
Tests for the Mixpanel tags and filters.
|
||||
"""
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.mixpanel import MixpanelNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class MixpanelTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``mixpanel`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(MixpanelTagTestCase, self).setUp()
|
||||
self.settings_manager.set(OPTIMIZELY_ACCOUNT_NUMBER='1234567')
|
||||
self.settings_manager.set(
|
||||
MIXPANEL_TOKEN='0123456789abcdef0123456789abcdef')
|
||||
|
||||
def test_tag(self):
|
||||
r = self.render_tag('mixpanel', 'mixpanel')
|
||||
self.assertTrue(
|
||||
"mpq.push(['init', '0123456789abcdef0123456789abcdef']);" in r,
|
||||
r)
|
||||
|
||||
def test_node(self):
|
||||
r = MixpanelNode().render(Context())
|
||||
self.assertTrue(
|
||||
"mpq.push(['init', '0123456789abcdef0123456789abcdef']);" in r,
|
||||
r)
|
||||
|
||||
def test_no_token(self):
|
||||
self.settings_manager.delete('MIXPANEL_TOKEN')
|
||||
self.assertRaises(AnalyticalException, MixpanelNode)
|
||||
|
||||
def test_wrong_token(self):
|
||||
self.settings_manager.set(
|
||||
MIXPANEL_TOKEN='0123456789abcdef0123456789abcde')
|
||||
self.assertRaises(AnalyticalException, MixpanelNode)
|
||||
self.settings_manager.set(
|
||||
MIXPANEL_TOKEN='0123456789abcdef0123456789abcdef0')
|
||||
self.assertRaises(AnalyticalException, MixpanelNode)
|
||||
|
||||
def test_identify(self):
|
||||
self.settings_manager.set(ANALYTICAL_AUTO_IDENTIFY=True)
|
||||
r = MixpanelNode().render(Context({'user': User(username='test')}))
|
||||
self.assertTrue("mpq.push(['identify', 'test']);" in r, r)
|
||||
|
||||
def test_event(self):
|
||||
r = MixpanelNode().render(Context({'mixpanel_event':
|
||||
('test_event', {'prop1': 'val1', 'prop2': 'val2'})}))
|
||||
self.assertTrue("mpq.push(['track', 'test_event', "
|
||||
'{"prop1": "val1", "prop2": "val2"}]);' in r, r)
|
||||
39
analytical/tests/test_tag_optimizely.py
Normal file
39
analytical/tests/test_tag_optimizely.py
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
"""
|
||||
Tests for the Optimizely template tags and filters.
|
||||
"""
|
||||
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.optimizely import OptimizelyNode
|
||||
from analytical.tests.utils import TagTestCase
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
class OptimizelyTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``optimizely`` template tag.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(OptimizelyTagTestCase, self).setUp()
|
||||
self.settings_manager.set(OPTIMIZELY_ACCOUNT_NUMBER='1234567')
|
||||
|
||||
def test_tag(self):
|
||||
self.assertEqual(
|
||||
'<script src="//cdn.optimizely.com/js/1234567.js"></script>',
|
||||
self.render_tag('optimizely', 'optimizely'))
|
||||
|
||||
def test_node(self):
|
||||
self.assertEqual(
|
||||
'<script src="//cdn.optimizely.com/js/1234567.js"></script>',
|
||||
OptimizelyNode().render(Context()))
|
||||
|
||||
def test_no_account_number(self):
|
||||
self.settings_manager.delete('OPTIMIZELY_ACCOUNT_NUMBER')
|
||||
self.assertRaises(AnalyticalException, OptimizelyNode)
|
||||
|
||||
def test_wrong_account_number(self):
|
||||
self.settings_manager.set(OPTIMIZELY_ACCOUNT_NUMBER='123456')
|
||||
self.assertRaises(AnalyticalException, OptimizelyNode)
|
||||
self.settings_manager.set(OPTIMIZELY_ACCOUNT_NUMBER='12345678')
|
||||
self.assertRaises(AnalyticalException, OptimizelyNode)
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
"""
|
||||
Tests for the template tags.
|
||||
"""
|
||||
|
||||
from django.http import HttpRequest
|
||||
from django import template
|
||||
from django.test import TestCase
|
||||
|
||||
from analytical import services
|
||||
from analytical.tests.utils import TestSettingsManager
|
||||
|
||||
|
||||
class TemplateTagsTestCase(TestCase):
|
||||
"""
|
||||
Tests for the template tags.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
self.settings_manager.set(ANALYTICAL_SERVICES=[
|
||||
'analytical.services.console.ConsoleService'])
|
||||
services.enabled_services = None
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
services.enabled_services = None
|
||||
|
||||
def render_location_tag(self, location, context=None):
|
||||
if context is None: context = {}
|
||||
t = template.Template(
|
||||
"{%% load analytical %%}{%% analytical_setup_%s %%}"
|
||||
% location)
|
||||
return t.render(template.Context(context))
|
||||
|
||||
def test_location_tags(self):
|
||||
for l in ['head_top', 'head_bottom', 'body_top', 'body_bottom']:
|
||||
r = self.render_location_tag(l)
|
||||
self.assertTrue('rendering analytical_%s tag' % l in r, r)
|
||||
|
||||
def test_render_internal_ip(self):
|
||||
self.settings_manager.set(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
|
||||
req = HttpRequest()
|
||||
req.META['REMOTE_ADDR'] = '1.1.1.1'
|
||||
for l in ['head_top', 'head_bottom', 'body_top', 'body_bottom']:
|
||||
r = self.render_location_tag(l, {'request': req})
|
||||
self.assertTrue('<!-- Analytical disabled on internal IP address'
|
||||
in r, r)
|
||||
|
||||
def test_render_internal_ip_fallback(self):
|
||||
self.settings_manager.set(INTERNAL_IPS=['1.1.1.1'])
|
||||
req = HttpRequest()
|
||||
req.META['REMOTE_ADDR'] = '1.1.1.1'
|
||||
for l in ['head_top', 'head_bottom', 'body_top', 'body_bottom']:
|
||||
r = self.render_location_tag(l, {'request': req})
|
||||
self.assertTrue('<!-- Analytical disabled on internal IP address'
|
||||
in r, r)
|
||||
|
||||
def test_render_internal_ip_forwarded_for(self):
|
||||
self.settings_manager.set(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
|
||||
req = HttpRequest()
|
||||
req.META['HTTP_X_FORWARDED_FOR'] = '1.1.1.1'
|
||||
for l in ['head_top', 'head_bottom', 'body_top', 'body_bottom']:
|
||||
r = self.render_location_tag(l, {'request': req})
|
||||
self.assertTrue('<!-- Analytical disabled on internal IP address'
|
||||
in r, r)
|
||||
|
||||
def test_render_different_internal_ip(self):
|
||||
self.settings_manager.set(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
|
||||
req = HttpRequest()
|
||||
req.META['REMOTE_ADDR'] = '2.2.2.2'
|
||||
for l in ['head_top', 'head_bottom', 'body_top', 'body_bottom']:
|
||||
r = self.render_location_tag(l, {'request': req})
|
||||
self.assertFalse('<!-- Analytical disabled on internal IP address'
|
||||
in r, r)
|
||||
|
||||
def test_render_internal_ip_empty(self):
|
||||
self.settings_manager.set(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
|
||||
self.settings_manager.delete('ANALYTICAL_SERVICES')
|
||||
self.settings_manager.delete('CLICKY_SITE_ID')
|
||||
self.settings_manager.delete('CRAZY_EGG_ACCOUNT_NUMBER')
|
||||
self.settings_manager.delete('GOOGLE_ANALYTICS_PROPERTY_ID')
|
||||
self.settings_manager.delete('KISSINSIGHTS_ACCOUNT_NUMBER')
|
||||
self.settings_manager.delete('KISSINSIGHTS_SITE_CODE')
|
||||
self.settings_manager.delete('KISSMETRICS_API_KEY')
|
||||
self.settings_manager.delete('MIXPANEL_TOKEN')
|
||||
self.settings_manager.delete('OPTIMIZELY_ACCOUNT_NUMBER')
|
||||
req = HttpRequest()
|
||||
req.META['REMOTE_ADDR'] = '1.1.1.1'
|
||||
for l in ['head_top', 'head_bottom', 'body_top', 'body_bottom']:
|
||||
self.assertEqual(self.render_location_tag(l, {'request': req}), "")
|
||||
3
analytical/tests/test_utils.py
Normal file
3
analytical/tests/test_utils.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
"""
|
||||
Tests for the analytical.utils module.
|
||||
"""
|
||||
|
|
@ -5,14 +5,40 @@ Testing utilities.
|
|||
from django.conf import settings
|
||||
from django.core.management import call_command
|
||||
from django.db.models import loading
|
||||
from django.template import Template, Context, RequestContext
|
||||
from django.test.simple import run_tests as django_run_tests
|
||||
from django.test.testcases import TestCase
|
||||
|
||||
|
||||
def run_tests():
|
||||
def run_tests(labels=()):
|
||||
"""
|
||||
Use the Django test runner to run the tests.
|
||||
"""
|
||||
django_run_tests([], verbosity=1, interactive=True)
|
||||
django_run_tests(labels, verbosity=1, interactive=True)
|
||||
|
||||
|
||||
class TagTestCase(TestCase):
|
||||
"""
|
||||
Tests for a template tag.
|
||||
|
||||
Includes the settings manager.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.settings_manager = TestSettingsManager()
|
||||
|
||||
def tearDown(self):
|
||||
self.settings_manager.revert()
|
||||
|
||||
def render_tag(self, library, tag, vars=None, request=None):
|
||||
if vars is None:
|
||||
vars = {}
|
||||
t = Template("{%% load %s %%}{%% %s %%}" % (library, tag))
|
||||
if request is not None:
|
||||
context = RequestContext(request, vars)
|
||||
else:
|
||||
context = Context(vars)
|
||||
return t.render(context)
|
||||
|
||||
|
||||
class TestSettingsManager(object):
|
||||
|
|
|
|||
|
|
@ -6,25 +6,36 @@ from django.conf import settings
|
|||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
|
||||
IDENTITY_CONTEXT_KEY = 'analytical_identity'
|
||||
HTML_COMMENT = "<!-- %(service)s disabled on internal IP address\n%(html)\n-->"
|
||||
|
||||
|
||||
def get_required_setting(self, setting, value_re, invalid_msg):
|
||||
def validate_setting(setting, value_re, invalid_msg):
|
||||
try:
|
||||
get_required_setting(setting, value_re, invalid_msg)
|
||||
except AnalyticalException, e:
|
||||
raise ImproperlyConfigured(e)
|
||||
|
||||
|
||||
def get_required_setting(setting, value_re, invalid_msg):
|
||||
try:
|
||||
value = getattr(settings, setting)
|
||||
except AttributeError:
|
||||
raise ImproperlyConfigured("%s setting: not found" % setting)
|
||||
raise AnalyticalException("%s setting: not found" % setting)
|
||||
value = str(value)
|
||||
if not value_re.search(value):
|
||||
raise ImproperlyConfigured("%s setting: %s: '%s'"
|
||||
raise AnalyticalException("%s setting: %s: '%s'"
|
||||
% (setting, invalid_msg, value))
|
||||
return value
|
||||
|
||||
|
||||
def get_identity(context):
|
||||
def get_identity(context, prefix=None):
|
||||
if prefix is not None:
|
||||
try:
|
||||
return context['%s_identity' % prefix]
|
||||
except KeyError:
|
||||
pass
|
||||
try:
|
||||
return context[IDENTITY_CONTEXT_KEY]
|
||||
return context['analytical_identity']
|
||||
except KeyError:
|
||||
pass
|
||||
if getattr(settings, 'ANALYTICAL_AUTO_IDENTIFY', True):
|
||||
|
|
@ -41,16 +52,33 @@ def get_identity(context):
|
|||
return None
|
||||
|
||||
|
||||
def is_internal_ip(context):
|
||||
def is_internal_ip(context, prefix=None):
|
||||
try:
|
||||
request = context['request']
|
||||
remote_ip = request.META.get('HTTP_X_FORWARDED_FOR',
|
||||
request.META.get('REMOTE_ADDR', ''))
|
||||
return remote_ip in getattr(settings, 'ANALYTICAL_INTERNAL_IPS',
|
||||
getattr(settings, 'INTERNAL_IPS', []))
|
||||
remote_ip = request.META.get('HTTP_X_FORWARDED_FOR', '')
|
||||
if not remote_ip:
|
||||
remote_ip = request.META.get('HTTP_X_FORWARDED_FOR', '')
|
||||
|
||||
internal_ips = ''
|
||||
if prefix is not None:
|
||||
internal_ips = getattr(settings, '%s_INTERNAL_IPS' % prefix, '')
|
||||
if not internal_ips:
|
||||
internal_ips = getattr(settings, 'ANALYTICAL_INTERNAL_IPS', '')
|
||||
if not internal_ips:
|
||||
internal_ips = getattr(settings, 'INTERNAL_IPS', '')
|
||||
|
||||
return remote_ip in internal_ips
|
||||
except KeyError, AttributeError:
|
||||
return False
|
||||
|
||||
|
||||
def disable_html(self, html, service):
|
||||
return HTML_COMMENT % locals()
|
||||
|
||||
|
||||
class AnalyticalException(Exception):
|
||||
"""
|
||||
Raised when an exception occurs in any django-analytical code that should
|
||||
be silenced in templates.
|
||||
"""
|
||||
silent_variable_failure = True
|
||||
|
|
|
|||
1
setup.py
1
setup.py
|
|
@ -17,6 +17,7 @@ except ImportError:
|
|||
|
||||
|
||||
class TestCommand(Command):
|
||||
description = "run package tests"
|
||||
user_options = []
|
||||
|
||||
def initialize_options(self):
|
||||
|
|
|
|||
Loading…
Reference in a new issue