Database¶
About¶
We use CouchDB because it's a simple document-oriented NoSQL database. The database has two main purposes:
- Saving test report;
- Data synchronization with the web interface.
The CouchDB version must be equal to or greater than the 3.2 version.
Database in pytest-hardpy¶
Description of databases¶
The pytest plugin has 2 databases: statestore and runstore.
- The statestore database uses for frontend data synchronization.
- The runstore database contains the document current, which is a JSON object that stores the current state of the test run.
A separate database is required to store the list of reports.
The report database is used as an example of storing reports on past testing runs.
It can be launched in the same instance as the statestore, runstore database, or in a different one.
The database is accessed through the CouchdbLoader class, which can be called at the end of each launch.
To read the current report, use the get_current_report()
function.
Sample code for saving a report at the end of testing:
# conftest.py
def save_report_to_couchdb():
report = get_current_report()
if report:
loader = CouchdbLoader(CouchdbConfig())
loader.load(report)
@pytest.fixture(scope="session", autouse=True)
def fill_actions_after_test(post_run_functions: list):
post_run_functions.append(save_report_to_couchdb)
yield
HardPy users have the flexibility to choose their preferred database. They can write custom classes to record reports at the end of testing.
Runstore scheme¶
The runstore and report databases have the same schema, as runstore stores the current report and report stores reports.
The current document of runstore database contains some section.
main¶
- _rev: a CouchDB revision MVCC token; The variable is assigned automatically.
- _id: unique document identifier. The variable is assigned automatically.
- stop_time: the end time of the test in Unix seconds. The variable is assigned automatically.
- start_time: the start time of the test in Unix seconds. The variable is assigned automatically.
- status: test execution status from pytest: passed, failed, skipped, stopped. The variable is assigned automatically.
- name: the name of the test suite. It is displayed in the header of the operator panel.
The user can specify the name using the
tests_name
variable in the hardpy.toml file. If this variable is not set, the name will be taken from the directory name containing the tests. - dut: DUT information. See the dut section for more information.
- test_stand: test stand information. See the test_stand section for more information.
- artifact: an object that contains information about the artifacts created during the test run. The user can specify the run artifact by using set_run_artifact function. The artifact contains a dictionary where the user can store any data at the test run level. The artifacts are not displayed on the operator panel.
- modules: module (pytest files) information. See the modules section for more information.
test_stand¶
The test_stand section contains information about the test stand. It is a computer on which HardPy is running and to which the DUT test equipment is connected.
- name - test stand name. It can only be set once per test run. The user can specify the stand name by using set_stand_name function.
- drivers: information about drivers in the form of a dictionary, including test equipment and test equipment software. The user can specify the driver info by using set_driver_info function.
- info: dictionary containing additional information about the test stand. The user can specify the additional info by using set_stand_info function.
- timezone: timezone of test stand as a string. The variable is assigned automatically.
- location: the location of the test stand, e.g., the country, city, or laboratory number. It can only be set once per test run. The user can specify the location by using set_stand_location function.
- number: test stand number. Some stands may have the same name and run on the same computer but have different numbers. It can only be set once per test run. The user can specify the stand number by using set_stand_number function.
- hw_id: test stand machine id (GUID) or host name. The variable is assigned automatically by the py-machineid package.
test_stand examples¶
Two stands on one computer:
// test stand 1
"test_stand": {
"hw_id": "840982098ca2459a7b22cc608eff65d4",
"name": "Test stand A",
"info": {},
"timezone": "Europe/Helsinki",
"drivers": {
"driver_1": {
"state": "active",
"port": 3000
}
},
"location": "Helsinki",
"number": 1
},
// test stand 2
"test_stand": {
"hw_id": "840982098ca2459a7b22cc608eff65d4",
"name": "Test stand A",
"info": {},
"timezone": "Europe/Helsinki",
"drivers": {
"driver_1": {
"state": "active",
"port": 3000
}
},
"location": "Helsinki",
"number": 2
},
Two different stands:
// test stand 1
"test_stand": {
"hw_id": "840982098ca2459a7b22cc608eff65d4",
"name": "ABC",
"info": {},
"timezone": "Europe/Helsinki",
"drivers": {
"voltmeter": {
"sw_version": "1.1.3",
"hw_version": "2.0.1"
}
},
"location": "Laboratory 1",
"number": null
},
// test stand 2
"test_stand": {
"hw_id": "156731093ab759a7b11ac108eaf69d2",
"name": "DEF",
"info": {},
"timezone": "Europe/Helsinki",
"drivers": {},
"location": "Laboratory 2",
"number": null
},
dut¶
The device under test section contains information about the DUT.
- serial_number: DUT serial number. This identifier is unique to the testing device or board. It can only be set once per test run. The user can specify the DUT serial number by using set_dut_serial_number function.
- part_number: DUT part number. This identifier of a particular part design, board or device. It can only be set once per test run. The user can specify the DUT part number by using set_dut_part_number function.
- info: dictionary containing additional information about the the DUT, such as batch, board revision, etc. The user can specify the additional info by using set_dut_info function.
dut examples¶
Testing of two devices of the same type (same part number):
// dut 1
"dut": {
"serial_number": "1000-10",
"part_number": "ABC11",
"info": {
"board_rev": "rev_1"
}
}
// dut 2
"dut": {
"serial_number": "1000-11",
"part_number": "ABC11",
"info": {
"board_rev": "rev_1"
}
}
modules¶
The modules section contains the information about tests. Each module contains information from a single test file. The module's name is the same as the file's name.
- test_{module_name}: an object containing information about a specific module.
The
{module_name}
variable is assigned automatically. Contains the following fields: - status: module test execution status. The variable is assigned automatically.
- name: module name, by default the same as module_id. The user can specify the module name by using module_name marker.
- start_time: start time of module testing in Unix seconds. The variable is assigned automatically.
- stop_time: end time of module testing in Unix seconds. The variable is assigned automatically.
- artifact: an object that contains information about the artifacts created during the test module. The user can specify the module artifact by using set_module_artifact function. The artifact contains a dictionary where the user can store any data at the test module level. The artifacts are not displayed on the operator panel.
- cases: an object that contains information about each test case within the module.
- test_{case_name}: an object containing information about a specific case.
The
{case_name}
variable is assigned automatically. Contains the following fields: - status: test case execution status. The variable is assigned automatically.
- name: case name, by default the same as case_id. The user can specify the case name by using case_name marker.
- start_time: start time of case testing in Unix seconds. The variable is assigned automatically.
- stop_time: end time of case testing in Unix seconds. The variable is assigned automatically.
- assertion_msg: assert or error message if the test case fails. The variable is assigned automatically.
However, the user can write their own message in case of an assertion, which will be written to this variable.
For example:
The assertion_msg is displayed in the operator panel next to the test case in which it was called.
assert False, "This is an example"
- msg: the log message is displayed in the operator panel next to the test case in which it was called. The user can specify and update current message by using set_message function.
- artifact: an object that contains information about the artifacts created during the test case. The user can specify the case artifact by using set_case_artifact function. The artifact contains a dictionary where the user can store any data at the test case level. The artifacts are not displayed on the operator panel.
- test_{case_name}: an object containing information about a specific case.
The
Report example¶
Example of a current document:
{
"_rev": "44867-3888ae85c19c428cc46685845953b483",
"_id": "current",
"stop_time": 1695817266,
"start_time": 1695817263,
"status": "failed",
"name": "hardpy-stand",
"dut": {
"serial_number": "92c5a4bb-ecb0-42c5-89ac-e0caca0919fd",
"part_number": "part_1",
"info": {
"batch": "test_batch",
"board_rev": "rev_1"
}
},
"test_stand": {
"hw_id": "840982098ca2459a7b22cc608eff65d4",
"name": "test_stand_1",
"info": {
"geo": "Belgrade"
},
"timezone": "Europe/Belgrade",
"drivers": {
"driver_1": "driver info",
"driver_2": {
"state": "active",
"port": 8000
}
},
"location": "Belgrade_1",
"number": 2
},
"artifact": {},
"modules": {
"test_1_a": {
"status": "failed",
"name": "Module 1",
"start_time": 1695816884,
"stop_time": 1695817265,
"artifact": {},
"cases": {
"test_dut_info": {
"status": "passed",
"name": "DUT info",
"start_time": 1695817263,
"stop_time": 1695817264,
"assertion_msg": null,
"msg": null,
"artifact": {}
},
"test_minute_parity": {
"status": "failed",
"name": "Test 1",
"start_time": 1695817264,
"stop_time": 1695817264,
"assertion_msg": "The test failed because minute 21 is odd! Try again!",
"msg": [
"Current minute 21"
],
"artifact": {
"data_str": "123DATA",
"data_int": 12345,
"data_dict": {
"test_key": "456DATA"
}
}
}
}
}
}
}
CouchDB instance¶
This section explains how to launch and manage a CouchDB instance. After launching the database, it becomes available at the following address:
The internal settings of the database are contained in the couchDB.ini configuration file. It contains settings that define the behavior and operating parameters of the database.
Running CouchDB with Docker Compose¶
An example configuration for running CouchDB via Docker Compose is located in
the example/database/couchdb
folder.
A shortened version of the instructions is described below.
- Create a
docker
directory in the project's root directory. - Create a
couchdb.ini
file in thedocker
directory.
[chttpd]
enable_cors=true
[cors]
origins = *
methods = GET, PUT, POST, HEAD, DELETE
credentials = true
headers = accept, authorization, content-type, origin, referer, x-csrf-token
docker-compose.yaml
file in project's root directory.
version: "3.8"
services:
couchserver:
image: couchdb:3.4
ports:
- "5984:5984"
environment:
COUCHDB_USER: dev
COUCHDB_PASSWORD: dev
volumes:
- ./docker/dbdata:/opt/couchdb/data
- ./docker/couchdb.ini:/opt/couchdb/etc/local.ini
docker compose up
docker compose down
Running CouchDB with Docker¶
- Create
couchdb.ini
file.
[chttpd]
enable_cors=true
[cors]
origins = *
methods = GET, PUT, POST, HEAD, DELETE
credentials = true
headers = accept, authorization, content-type, origin, referer, x-csrf-token
docker run --rm --name couchdb -p 5984:5984 -e COUCHDB_USER=dev -e COUCHDB_PASSWORD=dev -v ./couchdb.ini:/opt/couchdb/etc/local.ini couchdb:3.4
Command for Windows:
docker run --rm --name couchdb -p 5984:5984 -e COUCHDB_USER=dev -e COUCHDB_PASSWORD=dev -v .\couchdb.ini:/opt/couchdb/etc/local.ini couchdb:3.4
The container will be deleted after use.
Running CouchDB with binary packages in Linux¶
- Use this instruction to install CouchDB.
- The installer asks you if you want to install CouchDB as a standalone
application or in a clustered configuration.
Select
Standalone
and press Enter. - You are prompted to enter the Erlang Node Name.
You can ask it in Terminal with the command
hostname -f
. - Set the Erlang Magic Cookie.
This is a unique identifier, for example,
test1234
. - Configure the network interfaces on which CouchDB will be bound
localhost
is fine. - Enter an admin password of your choice for CouchDB, press
Enter
, re-type the password and pressEnter
again to continue the installation. - After launching the database, it becomes available at the following address http://localhost:5984/_utils/. Open it.
- First of all, in the
User Management
section in theCreate Admins
tab, create a user with the logindev
and passworddev
. - In the
Config
chooseCORS
and appointEnable CORS
withAll domains
.
To disable the CouchDB service:¶
Remove packages:
sudo apt remove --purge couchdb
sudo rm /usr/share/keyrings/couchdb-archive-keyring.gpg
sudo rm /etc/apt/sources.list.d/couchdb.list
sudo apt clean
systemctl stop couchdb.service
systemctl disable couchdb.service
systemctl daemon-reload
systemctl reset-failed
Running CouchDB with binary packages in Windows¶
- Use this instruction to install CouchDB.
- Be sure to install CouchDB to a path with no spaces, such as
C:\CouchDB
. - Create a user with the login
dev
and passworddev
during the installation steps. Validate Credentials. - Generate Random Cookie.
- After launching the database, it becomes available at the following address http://localhost:5984/_utils/. Open it.
- In the
Config
chooseCORS
and appointEnable CORS
withAll domains
.