This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
mandayejs/tests/test_mandayejs.py

309 lines
11 KiB
Python

# -*- coding: utf-8 -*-
import json
import time
import mock
import os
import pytest
from django.conf import settings
from django.core.management import call_command
from django.http.request import HttpRequest, QueryDict
from django.forms.fields import DateField
from django.test.client import RequestFactory, Client
from django.core.urlresolvers import reverse
from mandayejs.mandaye.models import UserCredentials
from mandayejs.mandaye.utils import exec_phantom, get_login_info
from mandayejs.mandaye.forms import FormFactory
from mandayejs.mandaye.views import post_login_do
pytestmark = pytest.mark.django_db
LOGIN_INFO = {
"address": "https://whatever.com",
"auth_checker": "tenants/static/js/auth.checker.js",
"cookies": [],
"form_submit_element": "input[type=submit], button",
"locators": [
{
"#username": "myusername",
"#password": "mypassoword"
}
]
}
MOCKED_SITE_LOCATORS = [
{'id': '#login',
'label': 'Login',
'name': 'login',
'kind': 'string', },
{'id': '#password',
'label': 'Password',
'name': 'password',
'kind': 'password'},
{'id': '#birth_date',
'label': 'Birthdata',
'name': 'birth_date',
'kind': 'date'}]
class MockedPopen(mock.Mock):
stall_for = False
def communicate(self, data):
if self.stall_for:
time.sleep(13)
return self.expected_output
# ENCRYPTION/DECRYPTION
def test_encryption(credentials):
decrypted = credentials.decrypt()
assert decrypted.get('password') == u'jôhn password'
@pytest.fixture(params=['command_ldap', 'command_csv'])
def command(request, command_ldap, command_csv):
return locals().get(request.param)
@mock.patch('mandayejs.mandaye.management.commands.migrate-users.get_idps')
def test_command_migrate_users(mocked_idps, command):
mocked_idps.return_value = iter(settings.MELLON_IDENTITY_PROVIDERS)
call_command(command.name, *command.args, **command.opts)
if command.opts.get('ldap'):
credentials = UserCredentials.objects.filter(user__last_name__in=[
'ldap_user1',
'ldap_user2',
'ldap_user3'])
assert len(credentials) == 3
for cred in credentials:
assert cred.to_login_info(decrypt=True)['#password'] == 'password_{}'.format(cred.user.last_name)
else:
credentials = UserCredentials.objects.all().exclude(user__last_name__in=[
'ldap_user1',
'ldap_user2',
'ldap_user3'
])
assert len(credentials) == 4
for cred in credentials:
assert cred.to_login_info(decrypt=True)['#password'] == cred.to_login_info()['#username']
@mock.patch('mandayejs.mandaye.utils.subprocess.Popen')
@mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS)
def test_phantom_invalid_json(mocked_popen, caplog, user_john):
expected_output = ('This is not a valid JSON', 'msg on stderr')
mocked_popen.return_value = MockedPopen(expected_output=expected_output)
UserCredentials.objects.create(user=user_john,
locators={
'login': 'johnny', 'password': 'jumper',
'birth_date': '1995-06-11'})
client = Client()
client.login(username='john', password='john')
response = client.get(reverse('post-login-do'))
assert 'window.top.location = "/_mandaye/associate/"' in response.content
for message in response.context['messages']:
assert message.level_tag == 'error'
assert message.message == 'invalid response from server'
for record in caplog.records:
if record.levelname == 'ERROR':
assert record.message == 'invalid json: This is not a valid JSON (stderr: msg on stderr)'
@mock.patch('mandayejs.mandaye.utils.subprocess.Popen')
def test_phantom_js_errors(mocked_popen, caplog):
stdout = {
"stderr": "ERROR: TypeError: undefined is not a function (evaluating \'$( \"#datepicker\" )",
"url": "https://whatever.com/someurl",
"result": "ok"
}
expected_output = ('<mandayejs>%s</mandayejs>' % json.dumps(stdout), None)
mocked_popen.return_value = MockedPopen(expected_output=expected_output)
result = exec_phantom(LOGIN_INFO)
for record in caplog.records:
assert record.levelname == 'WARNING'
assert record.message == "ERROR: TypeError: undefined is not a function (evaluating \'$( \"#datepicker\" )"
assert result['result'] == 'ok'
assert result['url'] == 'https://whatever.com/someurl'
@mock.patch('mandayejs.mandaye.utils.subprocess.Popen')
def test_phantom_js_timeout(mocked_popen, caplog):
mocked_popen.return_value = MockedPopen(expected_output=json.dumps({'whatever': 'whatever'}), stall_for=True)
result = exec_phantom(LOGIN_INFO)
for record in caplog.records:
assert record.levelname == 'ERROR'
assert 'https://whatever.com' in record.message
assert 'tenants/static/js/auth.checker.js' in record.message
assert 'input[type=submit], button' in record.message
assert result['result'] == 'timeout'
@mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS)
def test_credentials_json_encoding(user_john):
request = HttpRequest()
request.POST = QueryDict('', mutable=True)
formdata = {
'login': 'johnny',
'password': 'jumper',
'birth_date': '1995-06-11'
}
request.POST.update(formdata)
form = FormFactory(request.POST)
form.is_valid()
assert isinstance(form.fields['birth_date'], DateField) is True
UserCredentials.objects.create(user=user_john, locators=form.cleaned_data)
cred = UserCredentials.objects.get(user=user_john)
assert cred.locators['login'] == 'johnny'
assert cred.locators['birth_date'] == '1995-06-11'
@pytest.fixture(params=[
{'url1': 'http://mydomain.com/update_password.aspx'},
{'url2': 'http://mydomain.com/index?path=change_pass'}])
def redirect_url(request):
return request.param
@mock.patch('mandayejs.mandaye.utils.subprocess.Popen')
@mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS)
def test_password_redirection(mocked_popen, user_john, redirect_url):
expected_output = {
"result": "redirect",
"reason": "password change required",
"url": redirect_url.get('url1') or redirect_url.get('url2')
}
expected_output = '<mandayejs>%s</mandayejs>' % json.dumps(expected_output)
mocked_popen.return_value = MockedPopen(expected_output=(expected_output, None))
UserCredentials.objects.create(user=user_john,
locators={
'login': 'johnny', 'password': 'jumper',
'birth_date': '1995-06-11'})
request = RequestFactory()
request = request.get(reverse('post-login-do'))
request.user = user_john
response = post_login_do(request)
if 'url1' in redirect_url:
assert 'window.top.location = "/update_password.aspx"' in response.content
else:
assert 'window.top.location = "/index?path=change_pass"' in response.content
@mock.patch('mandayejs.mandaye.utils.subprocess.Popen')
@mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS)
def test_enclosed_response(mocked_popen):
output = """<mandayejs>{"result": "ok",
"authentication": "success"} </mandayejs>
this is just a random error"""
mocked_popen.return_value = MockedPopen(expected_output=(output, None))
result = exec_phantom(LOGIN_INFO)
assert result['result'] == 'ok'
# with no match
mocked_popen.return_value = MockedPopen(expected_output=('<mandayejs></mandayejs>', None))
result = exec_phantom(LOGIN_INFO)
assert result['result'] == 'json_error'
@mock.patch('mandayejs.mandaye.utils.subprocess.Popen')
@mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS)
def test_post_login_do_with_next_url(mocked_popen, user_john):
# when sso fails
expected_output = {
"result": "redirect",
"reason": "password change required",
"url": "http://mydomain.com/update_password.aspx"
}
expected_output = '<mandayejs>%s</mandayejs>' % json.dumps(expected_output)
mocked_popen.return_value = MockedPopen(expected_output=(expected_output, None))
UserCredentials.objects.create(user=user_john,
locators={
'login': 'johnny', 'password': 'jumper',
'birth_date': '1995-06-11'})
request = RequestFactory()
url = '%s?next=http://example.net/' % reverse('post-login-do')
request = request.get(url)
request.user = user_john
response = post_login_do(request)
assert 'window.top.location = "http://example.net/"' not in response.content
# when SSO succeeds
expected_output = {
"result": "ok",
"url": "http://mydomain.com/account.aspx"
}
expected_output = '<mandayejs>%s</mandayejs>' % json.dumps(expected_output)
mocked_popen.return_value = MockedPopen(expected_output=(expected_output, None))
request = RequestFactory()
url = '%s?next_url=http://example.net/' % reverse('post-login-do')
request = request.get(url)
request.user = user_john
response = post_login_do(request)
assert 'window.top.location = "http://example.net/"' in response.content
@mock.patch('mandayejs.applications.Test.SITE_LOCATORS', MOCKED_SITE_LOCATORS)
def test_app_settings_overriding(settings, cred_john):
request = RequestFactory().get('/')
data = get_login_info(request, cred_john)
assert data['address'] == 'http://testserver/'
assert data['auth_checker'] == os.path.join(settings.STATIC_ROOT, 'js/test/auth.checker.js')
assert data['form_submit_element'] == 'input[type=submit], button'
# when overriding settings
settings.SITE_LOGIN_PATH = 'account/login'
settings.SITE_AUTH_CHECKER = 'js/global.auth.checker.js'
settings.SITE_FORM_SUBMIT_ELEMENT = 'button'
data = get_login_info(request, cred_john)
assert data['address'] == 'http://testserver/account/login'
assert data['auth_checker'] == os.path.join(settings.STATIC_ROOT, 'js/global.auth.checker.js')
assert data['form_submit_element'] == 'button'
settings.SITE_LOGIN_PATH = ''
settings.SITE_FORM_SUBMIT_ELEMENT = ''
data = get_login_info(request, cred_john)
assert data['address'] == 'http://testserver/'
assert data['form_submit_element'] == ''
def test_app_name_slug_in_association_context(settings, user_john):
client = Client()
client.login(username='john', password='john')
response = client.get(reverse('associate'))
assert response.context['app']['name'] == 'Test'
assert response.context['app']['slug'] == 'test'
# when overidding the appname in settings
settings.SITE_APP_NAME = 'Test A'
response = client.get(reverse('associate'))
assert response.context['app']['name'] == 'Test A'
assert response.context['app']['slug'] == 'test'