Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion _ui_tests/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright: 2012 MoinMoin:HughPerkins
# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.

"""Contains global configuration for functional tests"""
"""Contains global configuration for functional tests."""

BASE_URL = "http://localhost:8080/"
26 changes: 15 additions & 11 deletions _ui_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.

"""
Contains events called by pytest during the life-cycle of the test suite
Pytest hook definitions used during the lifecycle of the test suite.

This module is automatically loaded by pytest, which looks for a file
of this name
with this name.
"""

import os
Expand All @@ -16,15 +17,18 @@

def pytest_runtest_makereport(item, call):
"""
Entry point for event which occurs after each test has run
The parameters are:
- item: the method called
- call: an object of type CallInfo, which has two properties, of which
excinfo contains info about any exception that got thrown by the method
This method is called automatically by pytest. The name of the method
is used by pytest to locate it, and decide when to call it
This specific method instance is used to take a screenshot whenever a test
fails, ie whenever the method throws an exception
Entry point for the event that occurs after each test has run.

Parameters:
- item: the test function being executed
- call: a CallInfo object; its excinfo attribute contains information about
any exception raised by the test

This function is called automatically by pytest. The function name is used
by pytest to locate it and to decide when to call it.

This hook is used to take a screenshot whenever a test fails, i.e., whenever
the test raises an exception.
"""
if call.excinfo is not None:
if driver_register.get_driver() is not None and hasattr(item, "obj"):
Expand Down
9 changes: 4 additions & 5 deletions _ui_tests/driver_register.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,24 @@
# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.

"""
This module is used to register the webdriver driver module as a global
variable, so that it can be used by conftest methods, eg for doing a
printscreen when a test fails
Register the WebDriver instance as a global so it can be accessed by
conftest hooks, e.g., to take a screenshot when a test fails.
"""

driver = None


def register_driver(driver_):
"""
set the driver global variable to driver_
Set the global driver variable to driver_.
"""
global driver
driver = driver_


def get_driver():
"""
get the value of the driver global variable
Get the value of the global driver variable.
"""
global driver
return driver
18 changes: 9 additions & 9 deletions _ui_tests/test_subitems.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
# Copyright: 2012 MoinMoin:HughPerkins
# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.

"""Functional test: create subitem"""
"""Functional test: create subitem."""

import config
import utils


class TestSubitems:
"""Functional test: create subitem"""
"""Functional test: create subitem."""

def setup_class(self):
"""opens browser and creates some random item names for these tests"""
"""Open the browser and create random item names for these tests."""
self.driver = utils.create_browser()
self.base_url = config.BASE_URL
self.base_item_name = "page_" + utils.generate_random_word(5)
self.subitem_name = "subitem_" + utils.generate_random_word(5)

def create_wiki_item(self, item_name):
"""Creates a new wiki item with name 'item_name'"""
"""Create a new wiki item with the name 'item_name'."""
driver = self.driver

driver.get(self.base_url + "/" + item_name)
Expand All @@ -29,7 +29,7 @@ def create_wiki_item(self, item_name):
driver.find_element_by_id("f_submit").click()

def test_createsubitem(self):
"""Test create subitem"""
"""Test creating a subitem."""
driver = self.driver

self.create_wiki_item(self.base_item_name)
Expand All @@ -48,14 +48,14 @@ def test_createsubitem(self):
assert driver.title.split(" - ")[0] == self.base_item_name + "/" + self.subitem_name

def teardown_class(self):
"""shuts down browser"""
"""Shut down the browser."""
self.driver.quit()


if __name__ == "__main__":
# This lets us run the test directly, without using pytest
# This is useful for example for being able to call help, eg
# 'help(driver)', or 'help(driver.find_element_by_id("f_submit"))'
# This lets us run the test directly, without using pytest.
# This is useful, for example, for being able to call help, e.g.,
# 'help(driver)' or 'help(driver.find_element_by_id("f_submit"))'.
testSubitems = TestSubitems()
testSubitems.setup_class()
testSubitems.test_createsubitem()
Expand Down
17 changes: 8 additions & 9 deletions _ui_tests/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Copyright: 2012 MoinMoin:HughPerkins
# License: GNU GPL v3 (or any later version), see LICENSE.txt for details.

"""Functions to facilitate functional testing"""
"""Functions to facilitate functional testing."""

import random
import urllib.request, urllib.parse, urllib.error
Expand All @@ -24,31 +24,30 @@

def create_browser():
"""
Instantiates a firefox browser object, and configures it for English language
and registers it for screenshots, and sets the timeout
Instantiate a Firefox browser object, configure it for English,
register it for screenshots, and set the timeout.
"""
profile = webdriver.FirefoxProfile()
profile.set_preference("intl.accept_languages", "en")
driver = webdriver.Firefox(firefox_profile=profile)
driver_register.register_driver(driver) # register with
# driver_register, which is needed so that printscreen on test
# failure works
driver_register.register_driver(driver) # Register with driver_register so that
# taking a screenshot on test failure works.
driver.implicitly_wait(20)
return driver


def generate_random_word(length):
"""
generates a random string containing numbers, of length 'length'
Generate a random numeric string of length 'length'.
"""
word = str(random.randint(10 ** (length - 1), 10**length))
return word


def generate_random_name(prefix, totallength):
"""
create a random name, starting with 'prefix'
of total length 'totallength'
Create a random name starting with 'prefix',
with a total length of 'totallength'.
"""
length = totallength - len(prefix)
numberword = generate_random_word(length)
Expand Down
10 changes: 5 additions & 5 deletions contrib/css-lint/lint-prep.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
"""
Reads a variables.css file and a common.css (or theme.css) file, outputs a lint.css file
similar to the common.css file but having all var(...) expressions replaced with the values
within the variables.css file. The output file can then be submitted to a css validator.
Reads a variables.css file and a common.css (or theme.css) file, and outputs a lint.css file
similar to common.css but with all var(...) expressions replaced with the values
from variables.css. The output file can then be submitted to a CSS validator.

This program will be obsolete when a css lint program supports variables.
This program will be obsolete when a CSS lint program supports variables.
"""

variables_in = "../../src/moin/static/css/variables.css"
Expand Down Expand Up @@ -37,7 +37,7 @@ def parse_variables():

def create_lint(vars):
"""
Read css file and replace variable names with values.
Read the CSS file and replace variable names with values.
"""
with open(css_in) as f:
lines = f.readlines()
Expand Down
40 changes: 20 additions & 20 deletions contrib/loadtesting/locust/locustfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@
These comments are also used as content when moin items are created; the result is
a small load is placed upon the Whoosh indexer.

The primary goal of this test is to create a server overload. A server overload will likely take the
The primary goal of this test is to create a server overload. A server overload will likely take the
form of a LockError in the Whoosh AsyncWriter (/whoosh/writing.py). Each thread attempting
to update the Whoosh index tries to obtain the write lock for a short period of time (~5
seconds). If the lock is not obtained, a LockError exception is raised and the console log
will show a traceback with the message "server overload or corrupt index". The item was
saved but cannot be accessed because it is not in the index - to correct the error,
stop the server, rebuild the indexes, restart the server.
saved but cannot be accessed because it is not in the index to correct the error,
stop the server, rebuild the indexes, and restart the server.

The maximum load that the wiki server can process is established by trial and error.
With the default wait_time of 2-3 seconds running 3 symultaneous users will create a load of about
With the default wait_time of 23 seconds, running 3 simultaneous users will create a load of about
one transaction per second. Running 30 users could create a load of about 10
transactions per second - but this may be reduced because the wiki server will have slow responses.

Expand All @@ -39,13 +39,13 @@
and create wiki items as part of the test. It is best to start with
an empty wiki (./m new-wiki).

Each locust user registers a new id, creates and updates a home page in the user namespace,
creates and updates a <username> item in the default namespace, and logs-out.
Each Locust user registers a new ID, creates and updates a home page in the user namespace,
creates and updates a <username> item in the default namespace, and logs out.

Because each locust user is working on unique items, it does not test edit locking. Use locustfile2.py
to stress test edit locking.
Because each Locust user is working on unique items, it does not test edit locking. Use locustfile2.py
to stress-test edit locking.

To load test Moin2:
To load-test Moin 2:
* read about Locust at https://docs.locust.io/en/stable/index.html - last tested with Locust 2.9.0
* install Locust per the docs in its own venv
* open a terminal window and start the Moin built-in server (./m run)
Expand All @@ -62,28 +62,28 @@
* customize and repeat:
* ./m del-wiki
* ./m new-wiki
* restart Moin2 buit-in server
* restart the Moin 2 built-in server
* restart Locust server
* refresh browser window
"""


# used to create unique user IDs
# Used to create unique user IDs
user_number = 0
# min and max wait time in seconds between user transactions, ignored, there is only 1 task
# Min and max wait time in seconds between user transactions; ignored, there is only 1 task
wait_time = between(2, 3)
# sleep time between GET, POST requests in seconds
# Sleep time between GET and POST requests, in seconds
sleep_time = 0


class LoadTest(HttpUser):
"""
First, create a Home page in the default and user namespaces.

Next create a workflow for each locust user that will
register a new user, login, create a user home page,
modify user home page several times,
create a new item, modify new item several times, and logout.
Next, create a workflow for each Locust user that will
register a new user, log in, create a user home page,
modify the user home page several times,
create a new item, modify the new item several times, and log out.
"""

@events.test_start.add_listener
Expand Down Expand Up @@ -207,7 +207,7 @@ def click_post_login(self):
print("%s: response.status_code = %s" % (sys._getframe().f_lineno, response.status_code))

def create_home_page(self):
# click link to users home page (home page has not been created: 404 expected)
# Click link to the user's home page (home page has not been created: 404 expected)
with self.client.get(self.user_home_page, catch_response=True) as response:
if response.status_code == 404:
response.success()
Expand Down Expand Up @@ -249,7 +249,7 @@ def create_home_page(self):
print("%s: response.status_code = %s" % (sys._getframe().f_lineno, response.status_code))

def modify_home_page(self, idx):
# get users home page
# Get the user's home page
with self.client.get(self.user_home_page, catch_response=True) as response:
if response.status_code != 200:
print("%s: response.status_code = %s" % (sys._getframe().f_lineno, response.status_code))
Expand All @@ -267,7 +267,7 @@ def modify_home_page(self, idx):
home_page,
{
"content_form_data_text": test_content % (self.user_name, self.get_time() + " idx=%s" % idx),
"comment": "my homepage comment",
"comment": "my home page comment",
"submit": "OK",
"meta_form_contenttype": "text/x.moin.wiki;charset=utf-8",
"meta_form_itemtype": "default",
Expand Down
Loading
Loading