hobo/tests/test_matomo_views.py

266 lines
9.0 KiB
Python

import json
import re
from unittest import mock
import pytest
from django.contrib.auth.models import User
from django.test import override_settings
from requests import Response
from test_manager import login
from hobo.environment.models import Combo, Fargo, Wcs
pytestmark = pytest.mark.django_db
CONFIG = {'URL': 'https://matomo.test', 'TOKEN_AUTH': '1234', 'EMAIL_TEMPLATE': 'noreply+%s@entrouvert.test'}
GET_NO_SITE_FROM_URL = b"""<?xml version="1.0" encoding="utf-8" ?>
<result />
"""
ADD_SITE_SUCCESS = b"""<?xml version="1.0" encoding="utf-8" ?>
<result>42</result>
"""
ADD_SITE_ALIAS_URLS_SUCCESS = b"""<?xml version="1.0" encoding="utf-8" ?>
<result>1</result>
"""
DEL_UNKNOWN_USER = b"""<?xml version="1.0" encoding="utf-8" ?>
<result>
<error message="User 'hobo.dev.publik.love' doesn't exist." />
</result>
"""
MATOMO_SUCCESS = b"""<?xml version="1.0" encoding="utf-8" ?>
<result>
<success message="ok" />
</result>
"""
JAVASCRIPT_TAG_BAD_RESPONSE = b"""<?xml version="1.0" encoding="utf-8" ?>
<no_result_tag/>
"""
JAVASCRIPT_TAG = b"""<?xml version="1.0" encoding="utf-8" ?>
<result>&lt;!-- Matomo --&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
var _paq = window._paq || [];
/* tracker methods like &quot;setCustomDimension&quot; should be called before &quot;trackPageView&quot; */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u=&quot;//matomo-test.entrouvert.org/&quot;;
_paq.push(['setTrackerUrl', u+'piwik.php']);
_paq.push(['setSiteId', '7']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s);
})();
&lt;/script&gt;
&lt;!-- End Matomo Code --&gt;
</result>
"""
PING_SUCCESS = '{"status":"success","tracked":1,"invalid":0}'
PING_ERROR = '{"status":"not success"}'
def requests_post_mocked_replies(contents):
"""buid an iterator for mock's side_effect parameter"""
responses = []
for content in contents:
response = Response()
# response may be XML or JSON
if content[0] == '{':
response.json = mock.MagicMock(return_value=json.loads(content))
response._content = content
response.status_code = 200
responses.append(response)
return responses
def test_unlogged_access(app):
# connect while not being logged in
resp = app.get('/visits-tracking/', status=302)
assert resp.location.endswith('/login/?next=/visits-tracking/')
def test_access(app, admin_user):
login(app)
assert app.get('/visits-tracking/', status=200)
def test_disable(app, admin_user):
login(app)
resp1 = app.get('/visits-tracking/disable', status=200)
resp2 = resp1.form.submit()
assert resp2.location.endswith('/visits-tracking/')
def test_enable_manual(app, admin_user):
"""scenario where user manually paste a javascript code"""
login(app)
# get matomo's validation page
resp = app.get('/visits-tracking/enable-manual', status=200)
assert re.search('<textarea.* name="tracking_js"', resp.text)
# validate and get matomo's home page
resp.form['tracking_js'] = '...js_code_1...'
resp = resp.form.submit().follow()
assert resp.text.find('Manual configuration.')
assert re.search('<textarea.* name="tracking_js"', resp.text)
assert resp.text.find('...js_code_1...</textarea>') != -1
assert resp.text.find('<button class="submit-button">Save</button>') != -1
# update JS code on matomo's home page
resp.form['tracking_js'] = '...js_code_2...'
resp = resp.form.submit().follow()
assert resp.text.find('Manual configuration.') != -1
assert re.search('<textarea.* name="tracking_js"', resp.text)
assert resp.text.find('...js_code_2...</textarea>') != -1
assert resp.text.find('<button class="submit-button">Save</button>') != -1
assert resp.text.find('Good respect of user rights') != -1
# check erroneous html tag
resp.form['tracking_js'] = '<script >'
resp = resp.form.submit()
assert (
'<ul class="errorlist"><li>This field should only contain the Javascript code. '
'You should remove the surrounding &lt;script&gt; markup.</li></ul>'
) in resp.text
# check against a more realistic tracking js input. it should succeed.
resp.form[
'tracking_js'
] = '''<!-- Matomo -->
<script type="text/javascript">
var _paq = window._paq = window._paq || [];
/* tracker methods like "setCustomDimension" should be called before "trackPageView" */
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="https://.../";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '112']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->'''
resp = resp.form.submit().follow()
assert resp.text.find('Manual configuration.') != -1
assert re.search('<textarea.* name="tracking_js"', resp.text)
assert resp.text.find('enableLinkTracking') != -1
assert resp.text.find('<button class="submit-button">Save</button>') != -1
assert resp.text.find('Good respect of user rights') != -1
def test_available_options(app, admin_user):
"""check available buttons (manual/automatic configurations)"""
login(app)
with override_settings(MATOMO_SERVER=CONFIG):
resp = app.get('/visits-tracking/', status=200)
assert str(resp).find('href="/visits-tracking/enable-manual"') != -1
assert str(resp).find('href="/visits-tracking/enable-auto"') != -1
# without configuration: no automatic configuration available
resp = app.get('/visits-tracking/', status=200)
assert str(resp).find('href="/visits-tracking/enable-manual"') != -1
assert str(resp).find('href="/visits-tracking/enable-auto"') == -1
@mock.patch('requests.post')
def test_enable_auto(mocked_post, app, admin_user):
"""succesfull automatic scenario"""
Combo.objects.create(base_url='https://combo.dev.publik.love', template_name='portal-user')
Wcs.objects.create(base_url='https://wcs.dev.publik.love')
Fargo.objects.create(base_url='https://fargo.dev.publik.love')
login(app)
contents = [
GET_NO_SITE_FROM_URL,
ADD_SITE_SUCCESS,
ADD_SITE_ALIAS_URLS_SUCCESS,
DEL_UNKNOWN_USER,
MATOMO_SUCCESS,
JAVASCRIPT_TAG,
PING_SUCCESS,
]
mocked_post.side_effect = requests_post_mocked_replies(contents)
with override_settings(MATOMO_SERVER=CONFIG):
resp1 = app.get('/visits-tracking/enable-auto', status=200)
resp2 = resp1.form.submit()
# call utils.py::auto_configure_matomo()
resp3 = resp2.follow()
# expect the CNIL compliance message is displayed
assert resp3.text.find('Excellent respect of user rights') != -1
@mock.patch('requests.post')
def test_enable_auto_warning(mocked_post, app, admin_user):
"""succesfull automatic scenario having final ping failure"""
Combo.objects.create(base_url='https://combo.dev.publik.love', template_name='portal-user')
Wcs.objects.create(base_url='https://wcs.dev.publik.love')
Fargo.objects.create(base_url='https://fargo.dev.publik.love')
login(app)
contents = [
GET_NO_SITE_FROM_URL,
ADD_SITE_SUCCESS,
ADD_SITE_ALIAS_URLS_SUCCESS,
DEL_UNKNOWN_USER,
MATOMO_SUCCESS,
JAVASCRIPT_TAG,
PING_ERROR,
]
mocked_post.side_effect = requests_post_mocked_replies(contents)
with override_settings(MATOMO_SERVER=CONFIG):
resp1 = app.get('/visits-tracking/enable-auto', status=200)
resp2 = resp1.form.submit()
# call utils.py::auto_configure_matomo()
resp3 = resp2.follow()
# expect 'ping fails' warning
assert resp3.text.find('class="warning">ping: ping fails') != -1
# expect the CNIL compliance message is displayed
assert resp3.text.find('Excellent respect of user rights') != -1
@mock.patch('requests.post')
def test_enable_auto_error(mocked_post, app, admin_user):
"""error on automatic scenario"""
Combo.objects.create(base_url='https://combo.dev.publik.love', template_name='portal-user')
Wcs.objects.create(base_url='https://wcs.dev.publik.love')
Fargo.objects.create(base_url='https://fargo.dev.publik.love')
login(app)
contents = [
GET_NO_SITE_FROM_URL,
ADD_SITE_SUCCESS,
ADD_SITE_ALIAS_URLS_SUCCESS,
DEL_UNKNOWN_USER,
MATOMO_SUCCESS,
JAVASCRIPT_TAG_BAD_RESPONSE,
]
mocked_post.side_effect = requests_post_mocked_replies(contents)
with override_settings(MATOMO_SERVER=CONFIG):
resp1 = app.get('/visits-tracking/enable-auto', status=200)
resp2 = resp1.form.submit()
# call utils.py::auto_configure_matomo()
resp3 = resp2.follow()
# expect a Django error message is displayed
assert resp3.text.find('class="error">matomo: get_javascript_tag fails') != -1