mirror of https://github.com/interlegis/sapl.git
LeandroRoberto
8 years ago
2 changed files with 365 additions and 256 deletions
@ -0,0 +1,365 @@ |
|||
from django.apps import apps |
|||
from django.contrib.auth import get_user_model |
|||
from django.contrib.auth.management import _get_all_permissions |
|||
from django.contrib.auth.models import Permission, User |
|||
from django.contrib.contenttypes.models import ContentType |
|||
from django.core.exceptions import ObjectDoesNotExist |
|||
from django.core.urlresolvers import reverse |
|||
from django.db.models import CharField, TextField |
|||
from django.http.response import HttpResponseNotFound |
|||
from django.utils.translation import string_concat |
|||
from django.utils.translation import ugettext_lazy as _ |
|||
from model_mommy import mommy |
|||
import pytest |
|||
|
|||
from sapl.crud.base import PermissionRequiredForAppCrudMixin, CrudAux |
|||
from scripts.inicializa_grupos_autorizacoes import cria_grupos_permissoes |
|||
from scripts.lista_urls import lista_urls |
|||
|
|||
from .settings import SAPL_APPS |
|||
|
|||
|
|||
pytestmark = pytest.mark.django_db |
|||
|
|||
sapl_appconfs = [apps.get_app_config(n[5:]) for n in SAPL_APPS] |
|||
_lista_urls = lista_urls() |
|||
|
|||
|
|||
def create_perms_post_migrate(app): |
|||
|
|||
searched_perms = list() |
|||
# The codenames and ctypes that should exist. |
|||
ctypes = set() |
|||
|
|||
for klass in list(app.get_models()): |
|||
opts = klass._meta |
|||
permissions = ( |
|||
("list_" + opts.model_name, |
|||
string_concat( |
|||
_('Visualizaçao da lista de'), ' ', |
|||
opts.verbose_name_plural)), |
|||
("detail_" + opts.model_name, |
|||
string_concat( |
|||
_('Visualização dos detalhes de'), ' ', |
|||
opts.verbose_name_plural)), |
|||
) |
|||
opts.permissions = tuple( |
|||
set(list(permissions) + list(opts.permissions))) |
|||
|
|||
if opts.proxy: |
|||
# Force looking up the content types in the current database |
|||
# before creating foreign keys to them. |
|||
app_label, model = opts.app_label, opts.model_name |
|||
|
|||
try: |
|||
ctype = ContentType.objects.get_by_natural_key( |
|||
app_label, model) |
|||
except: |
|||
ctype = ContentType.objects.create( |
|||
app_label=app_label, model=model) |
|||
else: |
|||
ctype = ContentType.objects.get_for_model(klass) |
|||
|
|||
ctypes.add(ctype) |
|||
for perm in _get_all_permissions(klass._meta, ctype): |
|||
searched_perms.append((ctype, perm)) |
|||
|
|||
all_perms = set(Permission.objects.filter( |
|||
content_type__in=ctypes, |
|||
).values_list( |
|||
"content_type", "codename" |
|||
)) |
|||
|
|||
perms = [ |
|||
Permission(codename=codename, name=name, content_type=ct) |
|||
for ct, (codename, name) in searched_perms |
|||
if (ct.pk, codename) not in all_perms |
|||
] |
|||
Permission.objects.bulk_create(perms) |
|||
|
|||
|
|||
def test_charfield_textfield(): |
|||
for app in sapl_appconfs: |
|||
for model in app.get_models(): |
|||
fields = model._meta.local_fields |
|||
for field in fields: |
|||
if isinstance(field, (CharField, TextField)): |
|||
assert not field.null, 'This %s is null: %s.%s' % ( |
|||
type(field).__name__, |
|||
model.__name__, |
|||
field.attname) |
|||
|
|||
|
|||
def test_str_sanity(): |
|||
# this simply a sanity check |
|||
# __str__ semantics is not considered and should be tested separetely |
|||
for app in sapl_appconfs: |
|||
for model in app.get_models(): |
|||
obj = mommy.prepare(model) |
|||
try: |
|||
str(obj) |
|||
except Exception as exc: |
|||
msg = '%s.%s.__str__ is broken.' % ( |
|||
model.__module__, model.__name__) |
|||
raise AssertionError(msg, exc) |
|||
|
|||
btn_login = ('<input class="btn btn-success btn-sm" ' + |
|||
'type="submit" value="login" />') |
|||
|
|||
|
|||
@pytest.mark.parametrize('url_item', _lista_urls) |
|||
def test_crudaux_formato_inicio_urls_associadas(url_item): |
|||
|
|||
# Verifica se um crud é do tipo CrudAux, se sim, sua url deve começar |
|||
# com /sistema/ |
|||
key, url, var, app_name = url_item |
|||
url = '/' + (url % {v: 1 for v in var}) |
|||
|
|||
view_class = None |
|||
if hasattr(key, 'view_class'): |
|||
view_class = key.view_class |
|||
|
|||
# se não tem view_class, possivelmente é não é uma classed base view |
|||
if not view_class: |
|||
return |
|||
|
|||
# se não tem atributo crud, não é será nenhum tipo de crud |
|||
if not hasattr(view_class, 'crud'): |
|||
return |
|||
|
|||
# se o crud da view_class relativa a url a ser testada, |
|||
# implementa a classe CrudAux, seu link deve iniciar com /sistema |
|||
for string_class in list(map(str, type.mro(view_class.crud))): |
|||
|
|||
if 'CrudAux' in string_class: |
|||
assert url.startswith('/sistema'), """ |
|||
A url (%s) foi gerada a partir de um CrudAux, |
|||
o que diz que está é uma implementação de uma |
|||
tabela auxiliar, porém a url em questão, está fora |
|||
do padrão, que é iniciar com /sistema. |
|||
""" % (url) |
|||
|
|||
|
|||
@pytest.mark.parametrize('url_item', _lista_urls) |
|||
def test_crudaux_list_do_crud_esta_na_pagina_sistema(url_item, admin_client): |
|||
|
|||
# Verifica se um crud é do tipo CrudAux, se sim, sua url deve começar |
|||
# com /sistema/ |
|||
key, url, var, app_name = url_item |
|||
url = '/' + (url % {v: 1 for v in var}) |
|||
|
|||
view_class = None |
|||
if hasattr(key, 'view_class'): |
|||
view_class = key.view_class |
|||
|
|||
# se não tem view_class, possivelmente não é uma classed base view |
|||
if not view_class: |
|||
return |
|||
|
|||
# se não tem atributo crud, não é será nenhum tipo de crud |
|||
if not hasattr(view_class, 'crud'): |
|||
return |
|||
|
|||
herancas_crud = list(map(str, type.mro(view_class.crud))) |
|||
for string_class in herancas_crud: |
|||
if 'CrudAux' in string_class: |
|||
|
|||
herancas_view = list(map(str, type.mro(view_class))) |
|||
|
|||
for string_view_class in herancas_view: |
|||
# verifica se o link para manutenção do crud está em /sistema |
|||
if 'ListView' in string_view_class: |
|||
response = admin_client.get('/sistema', {}, follow=True) |
|||
assert url in str(response.content), """ |
|||
A url (%s) não consta nas Tabelas Auxiliares, |
|||
porem é uma implementação de ListView de CrudAux. |
|||
Se encontra em %s.urls |
|||
""" % (url, app_name) |
|||
|
|||
|
|||
@pytest.mark.parametrize('url_item', _lista_urls) |
|||
def test_urlpatterns(url_item, admin_client): |
|||
|
|||
key, url, var, app_name = url_item |
|||
url = '/' + (url % {v: 1 for v in var}) |
|||
app_name = app_name[5:] |
|||
|
|||
apps_url_patterns_prefixs = { |
|||
'base': [ |
|||
'/sistema', |
|||
'/login', |
|||
'/logout' |
|||
], |
|||
'comissoes': [ |
|||
'/comissao', |
|||
'/sistema' |
|||
], |
|||
'compilacao': [ |
|||
'/ta', |
|||
], |
|||
'lexml': [ |
|||
'/lexml', |
|||
'/sistema' |
|||
], |
|||
'materia': [ |
|||
'/materia', |
|||
'/proposicao', |
|||
'/sistema' |
|||
], |
|||
'norma': [ |
|||
'/norma', |
|||
'/sistema' |
|||
], |
|||
'painel': [ |
|||
'/painel', |
|||
'/sistema' |
|||
], |
|||
'parlamentares': [ |
|||
'/parlamentar', |
|||
'/mesa-diretora', |
|||
'/sistema' |
|||
], |
|||
'protocoloadm': [ |
|||
'/protocoloadm', |
|||
'/sistema' |
|||
], |
|||
'relatorios': [ |
|||
'/relatorios', |
|||
], |
|||
'sessao': [ |
|||
'/sessao', |
|||
'/sistema', |
|||
], |
|||
} |
|||
assert app_name in apps_url_patterns_prefixs, """ |
|||
A app (%s) da url (%s) não consta na lista de prefixos do teste |
|||
""" % (app_name, url) |
|||
|
|||
if app_name in apps_url_patterns_prefixs: |
|||
prefixs = apps_url_patterns_prefixs[app_name] |
|||
|
|||
isvalid = False |
|||
for prefix in prefixs: |
|||
if url.startswith(prefix): |
|||
isvalid = True |
|||
break |
|||
|
|||
assert isvalid, """ |
|||
A url (%s) não está no padrão de sua app (%s). |
|||
Os prefixos permitidos são: |
|||
%s |
|||
""" % (url, app_name, prefixs) |
|||
|
|||
|
|||
@pytest.mark.parametrize('urls_app', _lista_urls) |
|||
def em_construcao_crud_permissions_urls(urls_app, client): |
|||
if not get_user_model().objects.exists(): |
|||
for app in sapl_appconfs: |
|||
# readequa permissões dos models adicionando |
|||
# list e detail permissions |
|||
create_perms_post_migrate(app) |
|||
# cria usuários de perfil do sapl |
|||
cria_grupos_permissoes() |
|||
users = get_user_model().objects.values_list('username', flat=True) |
|||
|
|||
for url_item in _lista_urls[urls_app]: |
|||
|
|||
key, url, var, app_name = url_item |
|||
url = '/' + (url % {v: 1 for v in var}) |
|||
|
|||
app_labels = app_name.split('.')[1] |
|||
|
|||
view_class = None |
|||
if hasattr(key, 'view_class'): |
|||
view_class = key.view_class |
|||
|
|||
""" |
|||
A classe PermissionRequiredForAppCrudMixin pode ser usada em uma |
|||
app mas envolver permissoes para outras |
|||
como é o caso de PainelView que está na app 'sessao' |
|||
mas é um redirecionamento para 'painel'... aqui é feita |
|||
a troca a urls_app a ser testada, por essas outras possíveis |
|||
""" |
|||
if PermissionRequiredForAppCrudMixin in type.mro(view_class): |
|||
# essa classe deve informar app_label |
|||
assert hasattr(view_class, 'app_label') |
|||
# app_label deve ter conteudo |
|||
assert view_class.app_label |
|||
app_labels = view_class.app_label |
|||
|
|||
if isinstance(app_labels, str): |
|||
app_labels = app_labels, |
|||
|
|||
for app in app_labels: |
|||
|
|||
# monta o username correspondente de a app da url a ser testada |
|||
user_for_url_atual_app = 'operador_%s' |
|||
if app in ['base', 'parlamentares']: |
|||
user_for_url_atual_app = user_for_url_atual_app % 'geral' |
|||
elif app in 'protocoloadm': |
|||
user_for_url_atual_app = user_for_url_atual_app % 'administrativo' |
|||
elif app in ['compilacao']: |
|||
return # TODO implementar teste para compilacao |
|||
else: |
|||
user_for_url_atual_app = user_for_url_atual_app % app |
|||
|
|||
for username in users: |
|||
print(username, user_for_url_atual_app, url) |
|||
|
|||
client.login(username=username, password='interlegis') |
|||
|
|||
rg = None |
|||
try: |
|||
rg = client.get(url, {}, follow=True) |
|||
except: |
|||
pass |
|||
|
|||
rp = None |
|||
try: |
|||
rp = client.post(url, {}, follow=True) |
|||
except: |
|||
pass |
|||
|
|||
""" |
|||
devido às urls serem incompletas ou com pks e outras valores |
|||
inexistentes na base, iniciar a execução da view, seja por get, |
|||
post ou qualquer outro método pode causar o erro... |
|||
por isso o "try ... except" acima. |
|||
No entanto, o objetivo do teste é validar o acesso de toda url. |
|||
Independente do erro que vá acontecer, esse erro não ocorrerá |
|||
se o user não tiver permissão de acesso pelo fato de que "AS |
|||
VIEWS BEM FORMADAS PARA VALIDAÇÃO DE ACESSO DEVEM SEMPRE REDIRECIONAR PARA |
|||
LOGIN ANTES DE SUA EXECUÇÃO", desta forma nunca gerando erro |
|||
interno dada qualquer incoerência de parâmetros nas urls |
|||
""" |
|||
if rg: |
|||
""" |
|||
Se o usuário a ser testado é o usuário da app da url de get |
|||
espera-se que não tenha recebido uma tela de login |
|||
""" |
|||
if username == user_for_url_atual_app and\ |
|||
not url.startswith('/sistema/'): |
|||
assert btn_login not in str(rg.content) |
|||
elif username != 'operador_geral' and\ |
|||
url.startswith('/sistema/'): |
|||
assert btn_login in str(rg.content) |
|||
elif username == 'operador_geral' and\ |
|||
url.startswith('/sistema/'): |
|||
assert btn_login not in str(rg.content) |
|||
|
|||
if rp: |
|||
""" |
|||
Se o usuário a ser testado é o usuário da app da url de |
|||
post espera-se que não tenha recebido uma tela de login |
|||
""" |
|||
if username == user_for_url_atual_app and\ |
|||
not url.startswith('/sistema/'): |
|||
assert btn_login not in str(rp.content) |
|||
elif username != 'operador_geral' and\ |
|||
url.startswith('/sistema/'): |
|||
assert btn_login in str(rp.content) |
|||
elif username == 'operador_geral' and\ |
|||
url.startswith('/sistema/'): |
|||
assert btn_login not in str(rp.content) |
|||
|
|||
logout = client.get('/logout/', follow=True) |
Loading…
Reference in new issue