add test create bill, confirm pay by manager.some refactor fixtures

remotes/origin/feature/test_courses
Dmitriy Shesterkin 8 years ago
parent 3679d31293
commit 1ae3ac332d
  1. 1
      .gitignore
  2. 25
      access/groups.py
  3. 4
      access/views.py
  4. 2
      api_v1/urls.py
  5. 0
      courses/factories/__init__.py
  6. 62
      factories/courses.py
  7. 72
      factories/finance.py
  8. 12
      factories/users.py
  9. 0
      finance/tests.py
  10. 4
      finance/urls.py
  11. 6
      finance/views.py
  12. 2
      lms/settings.py
  13. 21
      lms/settings_qa.py
  14. 2
      pytest.ini
  15. 43
      tests/conftest.py
  16. 18
      tests/fixtures/courses.py
  17. 21
      tests/fixtures/finance.py
  18. 99
      tests/fixtures/users.py
  19. 134
      tests/test_finance.py
  20. 35
      tests/test_user.py

1
.gitignore vendored

@ -38,3 +38,4 @@ coverage.xml
celerybeat-schedule
/config_app/settings/dev.env
/config_app/settings/test.env
/media_qa/

@ -0,0 +1,25 @@
ADMIN = 1
STUDENTS = 2
TEACHERS = 3
MANAGERS = 4
FINANCE_MANAGERS = 5
LEAD_MANAGERS = 6
CURATORS = 7
PARTNERS = 8
SUPPORTS = 9
FINANCE = 10
PROJECT_MANAGERS = 11
STATUS_CHOICES = (
(ADMIN, 'admin'),
(STUDENTS, 'students'),
(TEACHERS, 'teachers'),
(MANAGERS, 'managers'),
(FINANCE_MANAGERS, 'finance_managers'),
(LEAD_MANAGERS, 'lead_managers'),
(CURATORS, 'curators'),
(PARTNERS, 'partners'),
(SUPPORTS, 'supports'),
(FINANCE, 'finance'),
(PROJECT_MANAGERS, 'project_managers'),
)

@ -13,7 +13,7 @@ from django.shortcuts import redirect
from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import permissions, generics
from rest_framework import permissions
from access.models.other import Invite, ResetPassword, Account
from access.serializers import (UserSelfSerializer, UserSearchSerializer)
@ -296,7 +296,7 @@ class MinUserView(APIView):
return Response("User not found", status=404)
class ManagementPassword(generics.GenericAPIView):
class ManagementPassword(APIView):
permission_classes = (permissions.IsAuthenticated, permissions.IsAdminUser)
@staticmethod

@ -7,7 +7,7 @@ urlpatterns = [
url(r'courses/', include('courses.urls')),
url(r'users/', include('access.urls', namespace='users')),
url(r'library/', include('library.urls')),
url(r'finance/', include('finance.urls')),
url(r'finance/', include('finance.urls', namespace='finance')),
url(r'storage/', include('storage.urls')),
url(r'progress/', include('progress.urls')),
url(r'^docs/$', schema_view, name='api-docs'),

@ -0,0 +1,62 @@
import uuid
import factory
import factory.fuzzy
from functools import partial
from factories.users import UserFactory
from access import groups
IMAGE_URL = 'https://dummyimage.com/240x240/000/fff.png'
BIG_IMAGE_URL = 'https://dummyimage.com/1200x800/000/fff.png'
BIG_MOBILE_IMAGE_URL = 'https://dummyimage.com/600x400/000/fff.png'
Faker = partial(factory.Faker, locale='ru_RU')
class CourseFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'courses.Course'
token = factory.LazyFunction(uuid.uuid4)
slug = factory.LazyAttribute(lambda x: factory.Faker('sentence').
generate({'nb_words': 3}).replace(' ', '-').replace('.', ''))
title = factory.LazyAttribute(lambda x: Faker('sentence').generate({'nb_words': 4}))
description = factory.LazyAttribute(
lambda x: '\n'.join(Faker('paragraphs').generate({'nb': 15}))
)
direction = factory.fuzzy.FuzzyChoice(range(1, 5))
public = True
image = IMAGE_URL
big_image = BIG_IMAGE_URL
big_mobile_image = BIG_MOBILE_IMAGE_URL
@factory.lazy_attribute
def teacher_tokens(self):
teacher = UserFactory(groups=(groups.TEACHERS,))
return [teacher.out_key]
class TopicFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'courses.Topic'
course = factory.SubFactory(CourseFactory)
title = factory.LazyAttribute(lambda x: Faker('sentence').generate({'nb_words': 4}))
description = factory.LazyAttribute(
lambda x: '\n'.join(Faker('paragraphs').generate({'nb': 15}))
)
sort = 0
class LessonFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'courses.Lesson'
token = factory.LazyFunction(uuid.uuid4)
key = factory.LazyFunction(uuid.uuid4)
topic = factory.SubFactory(TopicFactory)
title = factory.LazyAttribute(lambda x: Faker('sentence').generate({'nb_words': 4}))
sort = 0

@ -0,0 +1,72 @@
import uuid
import factory
import factory.fuzzy
from functools import partial
from django.utils import timezone
from yandex_money.models import Payment
from factories.courses import CourseFactory, TopicFactory, LessonFactory
from factories.users import UserFactory
from finance.models import Invoice
Faker = partial(factory.Faker, locale='ru_RU')
class BillFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'finance.Bill'
user = factory.SubFactory(UserFactory)
opener = factory.SubFactory(UserFactory)
description = Faker('text')
@factory.lazy_attribute
def course_token(self):
course = CourseFactory()
topic = TopicFactory(
course=course
)
LessonFactory(
topic=topic
)
return course.token
class InvoiceFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'finance.Invoice'
status = factory.fuzzy.FuzzyChoice(
(choice[0] for choice in Invoice.BILL_STATUSES)
)
price = factory.fuzzy.FuzzyDecimal(1000)
real_price = factory.fuzzy.FuzzyDecimal(1000)
method = factory.fuzzy.FuzzyChoice(
(choice[0] for choice in Invoice.BILL_METHOD)
)
key = factory.Faker('pyint')
yandex_pay = factory.SubFactory('factories.finance.PaymentFactory')
comment = Faker('word')
bill = factory.SubFactory(BillFactory)
class PaymentFactory(factory.django.DjangoModelFactory):
class Meta:
model = 'yandex_money.Payment'
user = factory.SubFactory(UserFactory)
pub_date = timezone.now()
order_amount = factory.fuzzy.FuzzyDecimal(1000)
payment_type = factory.fuzzy.FuzzyChoice(
(choice[0] for choice in Payment.PAYMENT_TYPE.CHOICES)
)
order_number = factory.LazyFunction(uuid.uuid4)
status = factory.fuzzy.FuzzyChoice(
(choice[0] for choice in Payment.STATUS.CHOICES)
)
invoice_id = factory.Faker('pyint')
shop_amount = factory.fuzzy.FuzzyDecimal(1000)
performed_datetime = timezone.now()

@ -11,7 +11,7 @@ from django.conf import settings
USER_PASSWORD = 'test'
AVATAR_SAMPLE_IMAGE = os.path.join(settings.IMAGE_SAMPLES_DIR, 'simple.jpg')
SAMPLE_IMAGE = os.path.join(settings.IMAGE_SAMPLES_DIR, 'simple.jpg')
Faker = partial(factory.Faker, locale='ru_RU')
@ -32,6 +32,14 @@ class UserFactory(factory.django.DjangoModelFactory):
class Meta:
model = get_user_model()
@factory.post_generation
def groups(self, create, extracted, **kwargs):
if not create:
return
if extracted:
for group in extracted:
self.groups.add(group)
class AccountFactory(factory.django.DjangoModelFactory):
b_day = Faker(
@ -42,7 +50,7 @@ class AccountFactory(factory.django.DjangoModelFactory):
city = Faker('city')
gender = factory.fuzzy.FuzzyChoice(range(1, 2))
owner = factory.SubFactory(UserFactory)
photo = factory.django.ImageField(from_path=AVATAR_SAMPLE_IMAGE)
photo = factory.django.ImageField(from_path=SAMPLE_IMAGE)
phone = Faker('phone_number')
class Meta:

@ -5,7 +5,7 @@ urlpatterns = [
url(r'bills/([0-9]{1,99})/$', views.BillDetailView.as_view()),
url(r'payment/([0-9]{1,99})/$', views.YandexPay.as_view()),
url(r'bills_find/$', views.FindBillView.as_view()),
url(r'bills/$', views.BillListView.as_view()),
url(r'bills/$', views.BillListView.as_view(), name='bills'),
url(r'yandex/fail/$', views.YandexFailView.as_view()),
url(r'invoices/$', views.get_invoices),
]
]

@ -28,6 +28,11 @@ class BillListView(APIView):
@staticmethod
def get(request):
"""
This API endpoint return list of bills.
---
Returns a list of accounts for an authorized user or responsible user
"""
if request.user.is_authenticated:
return Response(
[BillSerializer(i).data for i in Bill.objects.filter(Q(user=request.user) | Q(opener=request.user))],
@ -70,7 +75,6 @@ class BillListView(APIView):
)
invoice.yandex_pay = yandex_pay
invoice.save()
invoices = [j for j in invoices if not j.id == invoice.id]
[i.delete() for i in invoices]

@ -8,7 +8,7 @@ import socket
root = environ.Path(__file__) - 2
env = environ.Env()
MOD = os.environ.get('MOD', 'Prod')
MOD = os.environ.get('MOD', 'Test')
DEBUG = os.environ.get('DEBUG', 'False')
MASTER_PASSWORD = os.environ.get('MASTER_PASSWORD', '@J*1')

@ -0,0 +1,21 @@
import logging
from .settings import * # noqa
DEBUG = True
EMAIL_DEBUG = True
TEMPLATES[0]['OPTIONS']['debug'] = DEBUG # noqa
MEDIA_ROOT = os.path.join(BASE_DIR, 'media_qa') # noqa
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
PASSWORD_HASHERS = ('django.contrib.auth.hashers.MD5PasswordHasher', )
CELERY_TASK_ALWAYS_EAGER = True
# Disable cache during testing
CACHE_DISABLED = True
LOGGING = {}
LOCAL_APPS_LOGGERS = {}
# Disable all logging calls with levels less severe than or equal to CRITICAL
logging.disable(logging.CRITICAL)

@ -1,5 +1,5 @@
[pytest]
DJANGO_SETTINGS_MODULE = lms.settings
DJANGO_SETTINGS_MODULE = lms.settings_qa
norecursedirs = env/* docs/* misc/* static/*
;addopts = --flake8 -vvs

@ -1,10 +1,25 @@
import os
import shutil
import pytest
from django.db import transaction
from tests.client import BetterAPIClient
pytest_plugins = [
'tests.fixtures.users',
'tests.fixtures.finance',
'tests.fixtures.courses'
]
def pytest_sessionfinish(session, exitstatus):
""" whole test run finishes. """
print('pytest finish: cleanup')
if os.path.exists('media_qa'):
shutil.rmtree('media_qa')
@pytest.fixture
def api_client():
"""Anonymous client for REST API."""
@ -13,16 +28,32 @@ def api_client():
@pytest.fixture
def staff_client(user_staff):
"""Authorized as staff client for REST API."""
def admin_client(admin):
"""Authorized as admin(superuser) client for REST API."""
client = BetterAPIClient()
client.force_authenticate(user=admin)
return client
@pytest.fixture
def student_client(student):
"""Authorized as student client for REST API."""
client = BetterAPIClient()
client.force_authenticate(user=student)
return client
@pytest.fixture
def manager_client(manager):
"""Authorized as manager client for REST API."""
client = BetterAPIClient()
client.force_authenticate(user=user_staff)
client.force_authenticate(user=manager)
return client
@pytest.fixture
def student_client(user_student):
"""Authorized as staff client for REST API."""
def lead_manager_client(lead_manager):
"""Authorized as lead manager client for REST API."""
client = BetterAPIClient()
client.force_authenticate(user=user_student)
client.force_authenticate(user=lead_manager)
return client

@ -0,0 +1,18 @@
import pytest
from factories.courses import CourseFactory, LessonFactory, TopicFactory
@pytest.fixture
def course():
"""
Create course
"""
_course = CourseFactory()
topic = TopicFactory(
course=_course
)
LessonFactory(
topic=topic
)
return _course

@ -0,0 +1,21 @@
import pytest
from factories.finance import BillFactory, InvoiceFactory
@pytest.fixture
def bill_cash(student, manager):
"""
Create bill for the student
"""
_bill = BillFactory(
user=student,
opener=manager,
)
InvoiceFactory(
status='P',
method='C',
yandex_pay=None,
bill=_bill
)
return _bill

@ -2,62 +2,121 @@ import pytest
from factories.users import UserFactory, AccountFactory
from access import groups
@pytest.fixture
def user_staff():
def admin():
"""
Create user as staff with data:
email = 'admin@example.com'
password = 'test'
is_staff=True
is_staff = True
is_active = True
is_superuser = True
"""
admin = UserFactory(
last_name='Иванов',
first_name='Иван',
user = UserFactory(
email='admin@example.com',
is_staff=True,
is_active=True,
is_superuser=True
groups__name=(groups.ADMIN,)
)
AccountFactory(owner=admin)
return admin
AccountFactory(owner=user)
return user
@pytest.fixture
def user_student():
def student():
"""
Create user as student with data:
email = 'student@example.com'
password = 'test'
is_active = True
in groups 'students'
"""
student = UserFactory(
last_name='Иванов',
first_name='Иван',
user = UserFactory.create(
email='student@example.com',
is_staff=False,
is_active=True,
groups__name=(groups.STUDENTS,)
)
AccountFactory(owner=student)
return student
AccountFactory(owner=user)
return user
@pytest.fixture
def user_not_active_student():
def student_not_active():
"""
Create user as student with data:
email = 'notactivestudent@example.com'
password = 'test'
is_active = False
in groups 'students'
"""
student = UserFactory(
last_name='Иванов',
first_name='Иван',
user = UserFactory.create(
email='notactivestudent@example.com',
is_staff=False,
is_active=False,
groups__name=(groups.STUDENTS,)
)
return user
@pytest.fixture
def manager():
"""
Create user as manager with data:
email = 'manager@example.com'
password = 'test'
is_staff = True
is_active = True
in groups 'managers'
"""
user = UserFactory.create(
email='manager@example.com',
is_staff=True,
is_active=True,
groups=(groups.MANAGERS,)
)
AccountFactory(owner=user)
return user
@pytest.fixture
def lead_manager():
"""
Create user as lead manager with data:
email = 'lead_manager@example.com'
password = 'test'
is_staff = True
is_active = True
in groups 'lead_managers'
"""
user = UserFactory.create(
email='lead_manager@example.com',
is_staff=True,
is_active=True,
groups=(groups.LEAD_MANAGERS,)
)
AccountFactory(owner=user)
return user
@pytest.fixture
def teacher():
"""
Create user as teacher with data:
email = 'teacher@example.com'
password = 'test'
is_staff = True
is_active = True
in groups 'teachers'
"""
user = UserFactory.create(
email='teacher@example.com',
is_staff=True,
is_active=True,
groups=(groups.TEACHERS,)
)
return student
AccountFactory(owner=user)
return user

@ -0,0 +1,134 @@
import json
import mock
import pytest
from django.urls import reverse
from rest_framework import status
from finance import models
from progress.models import Progress, ProgressLesson
PRICE = 1000.00
METHOD_CASH = 'C'
STATUS_WAIT = 'W'
STATUS_PAID = 'F'
DUMMY_COMMENT = 'test comment'
DUMMY_DESCRIPTION = 'test description'
mock.patch('lms.global_decorators.transaction_decorator', lambda x: x).start()
@pytest.mark.django_db
def test_list_bills(api_client, student_client, student, manager, admin_client,
manager_client, lead_manager_client, bill_cash):
"""
Test for get list of bills
"""
assert api_client.get(
reverse('finance:bills'),
status=status.HTTP_403_FORBIDDEN
)
response = student_client.get(
reverse('finance:bills'),
status=status.HTTP_200_OK
)
results_student = json.loads(response.content)
assert len(results_student) is 1
assert results_student[0]['opener'] == manager.email
assert results_student[0]['user'] == student.email
response_admin = admin_client.get(
reverse('finance:bills'),
status=status.HTTP_200_OK
)
results_admin = json.loads(response_admin.content)
assert len(results_admin) is 0
response_manager = manager_client.get(
reverse('finance:bills'),
status=status.HTTP_200_OK
)
results_manager = json.loads(response_manager.content)
assert results_manager[0]['opener'] == manager.email
assert results_manager[0]['user'] == student.email
response_lead_manager = lead_manager_client.get(
reverse('finance:bills'),
status=status.HTTP_200_OK
)
results_lead_manager = json.loads(response_lead_manager.content)
assert len(results_lead_manager) is 0
@pytest.mark.django_db
def test_create_bill(api_client, student_client, manager_client,
manager, student, course):
"""
Test create bill
"""
data = {
'bill': {
'course_token': course.token.hex,
'opener': manager.email,
'user': student.email,
'comment': DUMMY_COMMENT,
'description': DUMMY_DESCRIPTION
},
'children': [{
'status': STATUS_WAIT,
'method': METHOD_CASH,
'price': PRICE,
'real_price': PRICE,
}]
}
response = manager_client.post(
reverse('finance:bills'),
data=data,
status=status.HTTP_200_OK
)
results = json.loads(response.content)
assert models.Bill.objects.get(user=student).id == results['bill']['id']
assert models.Invoice.objects.get(
bill=results['bill']['id']).id == results['children'][0]['id']
assert api_client.post(
reverse('finance:bills'),
data=data,
status=status.HTTP_403_FORBIDDEN
)
assert student_client.post(
reverse('finance:bills'),
data=data,
status=status.HTTP_403_FORBIDDEN
)
@pytest.mark.django_db
def test_confirm_pay_manager(manager_client, bill_cash, student):
assert Progress.objects.count() is 0
assert ProgressLesson.objects.count() is 0
data = {
'bill': {
'course_token': bill_cash.course_token.hex,
'opener': bill_cash.opener.email,
'user': bill_cash.user.email,
'comment': bill_cash.comment,
'description': bill_cash.description
},
'children': [{
'status': STATUS_PAID,
'method': METHOD_CASH,
'price': PRICE,
'real_price': PRICE,
}]
}
response = manager_client.post(
reverse('finance:bills'),
data=data,
status=status.HTTP_200_OK
)
results = json.loads(response.content)
assert models.Bill.objects.get(user=student).id == results['bill']['id']
assert Progress.objects.count() is 1
assert ProgressLesson.objects.count() is 1
progress = Progress.objects.filter(user=bill_cash.user).first()
assert Progress.objects.filter(user=bill_cash.user).exists() is True
assert ProgressLesson.objects.filter(progress=progress).exists() is True

@ -12,12 +12,12 @@ from factories.users import USER_PASSWORD
@pytest.mark.django_db
@mock.patch('django.core.mail.EmailMessage.send')
def test_generate_password_by_manager(mocked_send_mail, staff_client,
student_client, user_student):
def test_generate_password_by_manager(mocked_send_mail, manager_client,
student_client, student):
"""
Test generate new password from admin area by manager
"""
assert staff_client.get(
assert manager_client.get(
reverse('users:management-password'),
status=status.HTTP_405_METHOD_NOT_ALLOWED
)
@ -26,14 +26,14 @@ def test_generate_password_by_manager(mocked_send_mail, staff_client,
status=status.HTTP_403_FORBIDDEN
)
data = {
'email': user_student.email,
'email': student.email,
}
assert staff_client.post(
assert manager_client.post(
reverse('users:management-password'),
data=data,
status=status.HTTP_201_CREATED
)
test_user = get_object_or_404(get_user_model(), email=user_student.email)
test_user = get_object_or_404(get_user_model(), email=student.email)
assert not test_user.check_password('test')
assert mocked_send_mail.call_count == 1
assert student_client.post(
@ -44,7 +44,7 @@ def test_generate_password_by_manager(mocked_send_mail, staff_client,
wrong_data = {
'email': 'no_user@example.com',
}
assert staff_client.post(
assert manager_client.post(
reverse('users:management-password'),
data=wrong_data,
status=status.HTTP_404_NOT_FOUND
@ -52,7 +52,7 @@ def test_generate_password_by_manager(mocked_send_mail, staff_client,
wrong_email = {
'email': 'no_user@example',
}
assert staff_client.post(
assert manager_client.post(
reverse('users:management-password'),
data=wrong_email,
status=status.HTTP_404_NOT_FOUND
@ -60,16 +60,15 @@ def test_generate_password_by_manager(mocked_send_mail, staff_client,
@pytest.mark.django_db
def test_generate_password_by_manager_for_not_active_student(staff_client,
user_not_active_student):
def test_generate_password_by_manager_for_not_active_student(manager_client, student_not_active):
"""
Test generate new password from admin area by manager for not active student
"""
data = {
'email': user_not_active_student.email,
'email': student_not_active.email,
}
assert staff_client.post(
assert manager_client.post(
reverse('users:management-password'),
data=data,
status=status.HTTP_201_CREATED
@ -77,12 +76,12 @@ def test_generate_password_by_manager_for_not_active_student(staff_client,
@pytest.mark.django_db
def test_login_user(api_client, user_student):
def test_login_user(api_client, student):
"""
Test login user
"""
data = {
'email': user_student.email,
'email': student.email,
'password': USER_PASSWORD
}
assert api_client.post(
@ -93,12 +92,12 @@ def test_login_user(api_client, user_student):
@pytest.mark.django_db
def test_login_user_wrong_password(api_client, user_student):
def test_login_user_wrong_password(api_client, student):
"""
Test login user with wrong password
"""
data = {
'email': user_student.email,
'email': student.email,
'password': USER_PASSWORD + '1'
}
assert api_client.post(
@ -109,12 +108,12 @@ def test_login_user_wrong_password(api_client, user_student):
@pytest.mark.django_db
def test_login_user_wrong_user(api_client, user_student):
def test_login_user_wrong_user(api_client, student):
"""
Test login user with wrong password
"""
data = {
'email': user_student.email + '1',
'email': student.email + '1',
'password': USER_PASSWORD
}
assert api_client.post(

Loading…
Cancel
Save