import datetime import os from functools import wraps from django.conf import settings from django.contrib.auth import BACKEND_SESSION_KEY, SESSION_KEY from django.contrib.sessions.backends.db import SessionStore from django.urls import reverse from django.test import LiveServerTestCase, TestCase from selenium.webdriver.firefox.webdriver import WebDriver from xvfbwrapper import Xvfb from orchestra.contrib.accounts.models import Account from .python import random_ascii class AppDependencyMixin(object): DEPENDENCIES = () @classmethod def setUpClass(cls): current_app = cls.__module__.split('.tests.')[0] INSTALLED_APPS = ( 'orchestra', 'orchestra.contrib.accounts', current_app ) INSTALLED_APPS += cls.DEPENDENCIES INSTALLED_APPS += ( # Third-party apps 'south', 'django_extensions', 'djcelery', 'djcelery_email', 'fluent_dashboard', 'admin_tools', 'admin_tools.theming', 'admin_tools.menu', 'admin_tools.dashboard', 'rest_framework', # Django.contrib 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.admin', ) settings.INSTALLED_APPS = INSTALLED_APPS super(AppDependencyMixin, cls).setUpClass() class BaseTestCase(TestCase, AppDependencyMixin): def create_account(self, username='', superuser=False): if not username: username = '%s_superaccount' % random_ascii(5) password = 'orchestra' if superuser: return Account.objects.create_superuser(username, password=password, email='orchestra@orchestra.org') return Account.objects.create_user(username, password=password, email='orchestra@orchestra.org') class BaseLiveServerTestCase(AppDependencyMixin, LiveServerTestCase): @classmethod def setUpClass(cls): # Avoid problems with the overlaping menu when clicking settings.ADMIN_TOOLS_MENU = 'admin_tools.menu.Menu' cls.vdisplay = Xvfb() cls.vdisplay.start() cls.selenium = WebDriver() super(BaseLiveServerTestCase, cls).setUpClass() @classmethod def tearDownClass(cls): cls.selenium.quit() cls.vdisplay.stop() super(BaseLiveServerTestCase, cls).tearDownClass() def create_account(self, username='', superuser=False): if not username: username = '%s_superaccount' % random_ascii(5) password = 'orchestra' self.account_password = password if superuser: return Account.objects.create_superuser(username, password=password, email='orchestra@orchestra.org') return Account.objects.create_user(username, password=password, email='orchestra@orchestra.org') def setUp(self): from orm.api import Api super(BaseLiveServerTestCase, self).setUp() self.rest = Api(self.live_server_url + '/api/') self.rest.enable_logging() self.account = self.create_account(superuser=True) def admin_login(self): session = SessionStore() session[SESSION_KEY] = self.account.id session[BACKEND_SESSION_KEY] = settings.AUTHENTICATION_BACKENDS[0] session.save() ## to set a cookie we need to first visit the domain. self.selenium.get(self.live_server_url + '/admin/') self.selenium.add_cookie(dict( name=settings.SESSION_COOKIE_NAME, value=session.session_key, # path='/', )) def rest_login(self): self.rest.login(username=self.account.username, password=self.account_password) def take_screenshot(self): timestamp = datetime.datetime.now().isoformat().replace(':', '') filename = 'screenshot_%s_%s.png' % (self.id(), timestamp) path = '/home/orchestra/snapshots' self.selenium.save_screenshot(os.path.join(path, filename)) def admin_delete(self, obj): opts = obj._meta app_label, model_name = opts.app_label, opts.model_name delete = reverse('admin:%s_%s_delete' % (app_label, model_name), args=(obj.pk,)) url = self.live_server_url + delete self.selenium.get(url) confirmation = self.selenium.find_element_by_name('post') confirmation.submit() self.assertNotEqual(url, self.selenium.current_url) def admin_disable(self, obj): opts = obj._meta app_label, model_name = opts.app_label, opts.model_name change = reverse('admin:%s_%s_change' % (app_label, model_name), args=(obj.pk,)) url = self.live_server_url + change self.selenium.get(url) is_active = self.selenium.find_element_by_id('id_is_active') is_active.click() save = self.selenium.find_element_by_name('_save') save.submit() self.assertNotEqual(url, self.selenium.current_url) def admin_change_password(self, obj, password): opts = obj._meta app_label, model_name = opts.app_label, opts.model_name change_password = reverse('admin:%s_%s_change_password' % (app_label, model_name), args=(obj.pk,)) url = self.live_server_url + change_password self.selenium.get(url) password_field = self.selenium.find_element_by_id('id_password1') password_field.send_keys(password) password_field = self.selenium.find_element_by_id('id_password2') password_field.send_keys(password) password_field.submit() self.assertNotEqual(url, self.selenium.current_url) def snapshot_on_error(test): @wraps(test) def inner(*args, **kwargs): try: test(*args, **kwargs) except: self = args[0] self.take_screenshot() raise return inner def save_response_on_error(test): @wraps(test) def inner(*args, **kwargs): try: test(*args, **kwargs) except: self = args[0] timestamp = datetime.datetime.now().isoformat().replace(':', '') filename = '%s_%s.html' % (self.id(), timestamp) path = '/home/orchestra/snapshots' with open(os.path.join(path, filename), 'wb') as dumpfile: dumpfile.write(self.rest.last_response.content) raise return inner