|
new file 100644
|
|
|
# -*- coding: utf-8 -*-
|
|
|
#
|
|
|
# Copyright (C) 2017 Branko Majic
|
|
|
#
|
|
|
# This file is part of Django Conntrackt.
|
|
|
#
|
|
|
# Django Conntrackt is free software: you can redistribute it and/or modify it
|
|
|
# under the terms of the GNU General Public License as published by the Free
|
|
|
# Software Foundation, either version 3 of the License, or (at your option) any
|
|
|
# later version.
|
|
|
#
|
|
|
# Django Conntrackt is distributed in the hope that it will be useful, but
|
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
|
# details.
|
|
|
#
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
# Django Conntrackt. If not, see <http://www.gnu.org/licenses/>.
|
|
|
#
|
|
|
|
|
|
|
|
|
# Standard library imports.
|
|
|
import os
|
|
|
import time
|
|
|
|
|
|
# Django imports.
|
|
|
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
|
|
|
|
|
|
# Third-party library imports.
|
|
|
from selenium.common.exceptions import WebDriverException
|
|
|
from selenium import webdriver
|
|
|
|
|
|
|
|
|
# Maximum amount of time to wait before assuming a test has
|
|
|
# failed. Used as default for functions that wait.
|
|
|
MAX_WAIT = 10
|
|
|
|
|
|
# Delay between subsequent runs of function when using the wait
|
|
|
# decorator.
|
|
|
EXECUTION_DELAY = 0.5
|
|
|
|
|
|
# Base directory where the tests are located at.
|
|
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
|
|
# Base directory where the test binaries are located at.
|
|
|
TEST_BINARIES_DIR = os.path.join(BASE_DIR, "..", "..", "test_binaries")
|
|
|
|
|
|
# Location of Firefox binary.
|
|
|
FIREFOX_BINARY = os.path.join(TEST_BINARIES_DIR, "firefox", "firefox")
|
|
|
|
|
|
# Location of geckodriver binary.
|
|
|
GECKODRIVER_BINARY = os.path.join(TEST_BINARIES_DIR, "geckodriver")
|
|
|
|
|
|
|
|
|
def wait(fn, execution_delay=EXECUTION_DELAY, max_wait=MAX_WAIT):
|
|
|
"""
|
|
|
Decorator that will produce a wrapper function that will run the
|
|
|
specified function repeatedly as long as all of the following
|
|
|
conditions have been met:
|
|
|
|
|
|
- Function throws either AssertionError or
|
|
|
selenium.common.exceptions.WebDriverException.
|
|
|
- Combined runtime of all function calls does not exceed the
|
|
|
maximum wait time.
|
|
|
|
|
|
As soon as the original function returns without any thrown
|
|
|
exceptions, the wrapper function will return its result.
|
|
|
|
|
|
If the function throws any other exception beyond the ones listed
|
|
|
above, this exception will get propagated.
|
|
|
|
|
|
Arguments:
|
|
|
|
|
|
fn
|
|
|
Function that should be run.
|
|
|
|
|
|
max_wait
|
|
|
Maximum time in seconds to wait for function to execute
|
|
|
successfully.
|
|
|
|
|
|
execution_delay
|
|
|
Delay in seconds between subsequent function runs. Used to
|
|
|
prevent high CPU usage.
|
|
|
|
|
|
Returns:
|
|
|
|
|
|
Wrapper function around passed-in function. The wrapper
|
|
|
function, provided it executes without failure, returns the
|
|
|
result of original function.
|
|
|
"""
|
|
|
|
|
|
def modified_fn(*args, **kwargs):
|
|
|
start_time = time.time()
|
|
|
|
|
|
while True:
|
|
|
try:
|
|
|
return fn(*args, **kwargs)
|
|
|
except (AssertionError, WebDriverException) as e:
|
|
|
if time.time() - start_time > max_wait:
|
|
|
raise e
|
|
|
time.sleep(execution_delay)
|
|
|
|
|
|
return modified_fn
|
|
|
|
|
|
|
|
|
class FunctionalTest(StaticLiveServerTestCase):
|
|
|
"""
|
|
|
Helper test class that provides some convenience when writing
|
|
|
functional tests.
|
|
|
|
|
|
During test set-up, the class will:
|
|
|
|
|
|
- Set-up a browser instance, storing it in property self.browser.
|
|
|
|
|
|
During the test tear-down, the class will:
|
|
|
|
|
|
- Destroy the browser instance.
|
|
|
|
|
|
In addition to this, the class provides a convenience method
|
|
|
wait_for which can be used to wait for a function to execute
|
|
|
within a time slot and assert something, as described for the wait
|
|
|
decorator.
|
|
|
"""
|
|
|
|
|
|
def setUp(self):
|
|
|
self.browser = webdriver.Firefox(firefox_binary=FIREFOX_BINARY, executable_path=GECKODRIVER_BINARY)
|
|
|
|
|
|
def tearDown(self):
|
|
|
self.browser.quit()
|
|
|
super(FunctionalTest, self).tearDown()
|
|
|
|
|
|
@wait
|
|
|
def wait_for(self, fn):
|
|
|
return fn()
|