From e22e25cea07148466ac7e4a61572cf8e3e81b39f Mon Sep 17 00:00:00 2001 From: Levi Date: Mon, 4 Jul 2016 23:44:15 -0500 Subject: [PATCH] Fixed duplicated post bug , Added reset password view test, Added confirm reset password view test --- hosting/models.py | 3 +- hosting/test_views.py | 187 ++++++++++++++++++++++++++++++++++++++++-- hosting/views.py | 30 ++++--- utils/tests.py | 21 +++++ 4 files changed, 225 insertions(+), 16 deletions(-) diff --git a/hosting/models.py b/hosting/models.py index 887f0777..099b7894 100644 --- a/hosting/models.py +++ b/hosting/models.py @@ -5,6 +5,7 @@ from django.utils.translation import ugettext_lazy as _ from django.utils.functional import cached_property + from Crypto.PublicKey import RSA from stored_messages.settings import stored_messages_settings @@ -160,7 +161,7 @@ class VirtualMachinePlan(models.Model): private_key, public_key = self.generate_RSA() self.public_key = public_key self.save(update_fields=['public_key']) - return private_key + return private_key, public_key def cancel_plan(self): self.status = self.CANCELED_STATUS diff --git a/hosting/test_views.py b/hosting/test_views.py index b2deb6d7..944cabcb 100644 --- a/hosting/test_views.py +++ b/hosting/test_views.py @@ -3,15 +3,20 @@ from django.conf import settings from django.test import TestCase, RequestFactory from django.core.urlresolvers import reverse from django.core.urlresolvers import resolve +from django.contrib.auth.tokens import default_token_generator +from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode +from django.utils.encoding import force_bytes + from model_mommy import mommy +from stored_messages.models import Inbox from membership.models import CustomUser, StripeCustomer from .models import VirtualMachineType, HostingOrder, VirtualMachinePlan from .views import DjangoHostingView, RailsHostingView, NodeJSHostingView, LoginView, SignupView, \ PaymentVMView, OrdersHostingDetailView, OrdersHostingListView, VirtualMachineView, \ - VirtualMachinesPlanListView + VirtualMachinesPlanListView, PasswordResetView, PasswordResetConfirmView from utils.tests import BaseTestCase @@ -40,9 +45,12 @@ class DjangoHostingViewTest(TestCase, ProcessVMSelectionTestMixin): self.url = reverse('django.hosting') self.view = DjangoHostingView() self.expected_template = 'hosting/django.html' + HOSTING = 'django' + configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) self.expected_context = { - 'hosting': "django", + 'hosting': HOSTING, 'hosting_long': "Django", + 'configuration_detail': configuration_detail, 'domain': "django-hosting.ch", 'google_analytics': "UA-62285904-6", 'email': "info@django-hosting.ch", @@ -56,9 +64,12 @@ class RailsHostingViewTest(TestCase, ProcessVMSelectionTestMixin): self.url = reverse('rails.hosting') self.view = RailsHostingView() self.expected_template = 'hosting/rails.html' + HOSTING = 'rails' + configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) self.expected_context = { - 'hosting': "rails", + 'hosting': HOSTING, 'hosting_long': "Ruby On Rails", + 'configuration_detail': configuration_detail, 'domain': "rails-hosting.ch", 'google_analytics': "UA-62285904-5", 'email': "info@rails-hosting.ch", @@ -72,9 +83,12 @@ class NodeJSHostingViewTest(TestCase, ProcessVMSelectionTestMixin): self.url = reverse('node.hosting') self.view = NodeJSHostingView() self.expected_template = 'hosting/nodejs.html' + HOSTING = 'nodejs' + configuration_detail = dict(VirtualMachinePlan.VM_CONFIGURATION).get(HOSTING) self.expected_context = { - 'hosting': "nodejs", + 'hosting': HOSTING, 'hosting_long': "NodeJS", + 'configuration_detail': configuration_detail, 'domain': "node-hosting.ch", 'google_analytics': "UA-62285904-7", 'email': "info@node-hosting.ch", @@ -115,6 +129,7 @@ class PaymentVMViewTest(BaseTestCase): 'memory': 10, 'disk_size': 10000, 'price': 22000, + 'configuration': dict(VirtualMachinePlan.VM_CONFIGURATION).get('django') } } @@ -153,7 +168,8 @@ class PaymentVMViewTest(BaseTestCase): 'memory': hosting_order.vm_plan.memory, 'disk_size': hosting_order.vm_plan.disk_size, 'price': hosting_order.vm_plan.price, - 'hosting_company': hosting_order.vm_plan.vm_type.hosting_company + 'hosting_company': hosting_order.vm_plan.vm_type.hosting_company, + 'configuration': hosting_order.vm_plan.configuration } self.assertEqual(vm_plan, self.session_data.get('vm_specs')) @@ -172,6 +188,92 @@ class PaymentVMViewTest(BaseTestCase): settings.STRIPE_API_PUBLIC_KEY) +class NotificationsViewTest(BaseTestCase): + + def setUp(self): + super(NotificationsViewTest, self).setUp() + + self.url = reverse('hosting:notifications') + self.expected_template = 'hosting/notifications.html' + + self.inboxes = mommy.make(Inbox, user=self.customer, _quantity=2) + self.messages = list(map(lambda x: x.message, self.inboxes)) + + def test_get(self): + + # Anonymous user should get redirect to login + response = self.client.get(self.url) + expected_url = "%s?next=%s" % (reverse('hosting:login'), reverse('hosting:notifications')) + self.assertRedirects(response, expected_url=expected_url, + status_code=302, target_status_code=200) + + # Logged user should get the page + response = self.customer_client.get(self.url, follow=True) + self.assertEqual(response.status_code, 200) + self.assertEqual(response.context['all_notifications'], self.messages) + self.assertTemplateUsed(response, self.expected_template) + + +class MarkAsReadNotificationViewTest(BaseTestCase): + + def setUp(self): + super(MarkAsReadNotificationViewTest, self).setUp() + + self.url = reverse('hosting:notifications') + self.expected_template = 'hosting/notifications.html' + + self.inbox = mommy.make(Inbox, user=self.customer) + self.message = self.inbox.message + + self.url = reverse('hosting:read_notification', kwargs={'pk': self.message.id}) + + def test_post(self): + + # Anonymous user should get redirect to login + response = self.client.get(self.url) + expected_url = "%s?next=%s" % (reverse('hosting:login'), + reverse('hosting:read_notification', + kwargs={'pk': self.message.id})) + self.assertRedirects(response, expected_url=expected_url, + status_code=302, target_status_code=200) + + # Logged user should mark a message as read + response = self.customer_client.post(self.url, follow=True) + self.assertEqual(response.status_code, 200) + self.assertFalse(Inbox.objects.filter(user=self.customer).exists()) + self.assertTemplateUsed(response, self.expected_template) + + +class GenerateVMSSHKeysViewTest(BaseTestCase): + + def setUp(self): + super(GenerateVMSSHKeysViewTest, self).setUp() + + self.vm = mommy.make(VirtualMachinePlan) + self.expected_template = 'hosting/virtual_machine_key.html' + self.url = reverse('hosting:virtual_machine_key', kwargs={'pk': self.vm.id}) + + def test_get(self): + + # Anonymous user should get redirect to login + response = self.client.get(self.url) + expected_url = "%s?next=%s" % (reverse('hosting:login'), + reverse('hosting:virtual_machine_key', + kwargs={'pk': self.vm.id})) + self.assertRedirects(response, expected_url=expected_url, + status_code=302, target_status_code=200) + + # Logged user should get the page + response = self.customer_client.get(self.url, follow=True) + self.assertEqual(response.status_code, 200) + updated_vm = VirtualMachinePlan.objects.get(id=self.vm.id) + self.assertEqual(response.context['public_key'].decode("utf-8"), updated_vm.public_key) + self.assertTrue(response.context['private_key'] is not None) + self.assertEqual(len(response.context['public_key']), 380) + self.assertTrue(len(response.context['private_key']) is 1678 or 1674) + self.assertTemplateUsed(response, self.expected_template) + + class VirtualMachineViewTest(BaseTestCase): def setUp(self): @@ -357,3 +459,78 @@ class SignupViewTest(TestCase): self.user = CustomUser.objects.get(email=self.signup_data.get('email')) self.assertEqual(response.context['user'], self.user) self.assertEqual(response.status_code, 200) + + +class PasswordResetViewTest(BaseTestCase): + + def setUp(self): + super(PasswordResetViewTest, self).setUp() + + self.url = reverse('hosting:reset_password') + self.view = PasswordResetView + self.expected_template = 'hosting/reset_password.html' + self.user = mommy.make('membership.CustomUser') + self.password = 'fake_password' + self.user.set_password(self.password) + self.user.save() + + self.post_data = { + 'email': self.user.email + } + + def test_url_resolve_to_view_correctly(self): + found = resolve(self.url) + self.assertEqual(found.func.__name__, self.view.__name__) + + def test_get(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, self.expected_template) + + def test_post(self): + response = self.client.post(self.url, data=self.post_data, follow=True) + self.assertEqual(response.status_code, 200) + + def test_test_generate_email_context(self): + context = self.setup_view(self.view()).\ + test_generate_email_context(self.user) + self.assertEqual(context.get('user'), self.user) + self.assertEqual(context.get('site_name'), 'ungleich') + self.assertEqual(len(context.get('token')), 24) + + +class PasswordResetConfirmViewTest(BaseTestCase): + + def setUp(self): + super(PasswordResetConfirmViewTest, self).setUp() + + self.view = PasswordResetConfirmView + self.expected_template = 'hosting/confirm_reset_password.html' + self.user = mommy.make('membership.CustomUser') + self.password = 'fake_password' + self.user.set_password(self.password) + self.user.save() + + self.token = default_token_generator.make_token(self.user) + self.uid = urlsafe_base64_encode(force_bytes(self.user.pk)) + self.url = reverse('hosting:reset_password_confirm', + kwargs={'token': self.token, 'uidb64': self.uid}) + + self.post_data = { + 'new_password1': 'new_password', + 'new_password2': 'new_password' + } + + def test_url_resolve_to_view_correctly(self): + found = resolve(self.url) + self.assertEqual(found.func.__name__, self.view.__name__) + + def test_get(self): + response = self.client.get(self.url) + self.assertEqual(response.status_code, 200) + self.assertTemplateUsed(response, self.expected_template) + + def test_post(self): + response = self.client.post(self.url, data=self.post_data, follow=True) + self.assertEqual(response.status_code, 200) + self.assertTrue(not response.context['form'].errors) diff --git a/hosting/views.py b/hosting/views.py index c66068d1..18d8819e 100644 --- a/hosting/views.py +++ b/hosting/views.py @@ -195,13 +195,7 @@ class PasswordResetView(FormView): success_url = reverse_lazy('hosting:login') # form_valid_message = 'Thank you for registering' - def form_valid(self, form): - - email = form.cleaned_data.get('email') - user = CustomUser.objects.get(email=email) - - messages.add_message(self.request, messages.SUCCESS, self.success_message) - + def test_generate_email_context(self, user): context = { 'user': user, 'token': default_token_generator.make_token(user), @@ -210,6 +204,16 @@ class PasswordResetView(FormView): 'base_url': "{0}://{1}".format(self.request.scheme, self.request.get_host()) } + return context + + def form_valid(self, form): + + email = form.cleaned_data.get('email') + user = CustomUser.objects.get(email=email) + + messages.add_message(self.request, messages.SUCCESS, self.success_message) + + context = self.test_generate_email_context(user) email_data = { 'subject': 'Password Reset', 'to': email, @@ -246,15 +250,18 @@ class PasswordResetConfirmView(FormView): return self.form_valid(form) else: messages.error(request, 'Password reset has not been unsuccessful.') + form.add_error(None, 'Password reset has not been unsuccessful.') return self.form_invalid(form) else: messages.error(request, 'The reset password link is no longer valid.') + form.add_error(None, 'Password reset has not been unsuccessful.') return self.form_invalid(form) -class NotificationsView(TemplateView): +class NotificationsView(LoginRequiredMixin, TemplateView): template_name = 'hosting/notifications.html' + login_url = reverse_lazy('hosting:login') def get_context_data(self, **kwargs): context = super(NotificationsView, self).get_context_data(**kwargs) @@ -271,6 +278,7 @@ class NotificationsView(TemplateView): class MarkAsReadNotificationView(LoginRequiredMixin, UpdateView): model = Message success_url = reverse_lazy('hosting:notifications') + login_url = reverse_lazy('hosting:login') fields = '__all__' def post(self, *args, **kwargs): @@ -285,6 +293,7 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView): model = VirtualMachinePlan template_name = 'hosting/virtual_machine_key.html' success_url = reverse_lazy('hosting:orders') + login_url = reverse_lazy('hosting:login') context_object_name = "virtual_machine" def get_context_data(self, **kwargs): @@ -292,9 +301,10 @@ class GenerateVMSSHKeysView(LoginRequiredMixin, DetailView): context = super(GenerateVMSSHKeysView, self).get_context_data(**kwargs) vm = self.get_object() if not vm.public_key: - private_key = vm.generate_keys() + private_key, public_key = vm.generate_keys() context.update({ - 'private_key': private_key + 'private_key': private_key, + 'public_key': public_key }) return context return context diff --git a/utils/tests.py b/utils/tests.py index 83b87a85..195fc060 100644 --- a/utils/tests.py +++ b/utils/tests.py @@ -1,8 +1,13 @@ from django.test import TestCase from django.test import Client +from django.http.request import HttpRequest + from model_mommy import mommy + + + class BaseTestCase(TestCase): """ Base class to initialize the test cases @@ -28,6 +33,11 @@ class BaseTestCase(TestCase): self.customer_client = self.get_client(self.customer) self.another_customer_client = self.get_client(self.another_customer) + # Request Object + self.request = HttpRequest() + self.request.META['SERVER_NAME'] = 'ungleich.com' + self.request.META['SERVER_PORT'] = '80' + def get_client(self, user): """ Authenticate a user and return the client @@ -64,3 +74,14 @@ class BaseTestCase(TestCase): }] } } + + def setup_view(self, view, *args, **kwargs): + """Mimic as_view() returned callable, but returns view instance. + + args and kwargs are the same you would pass to ``reverse()`` + + """ + view.request = self.request + view.args = args + view.kwargs = kwargs + return view