153 lines
5.4 KiB
Python
153 lines
5.4 KiB
Python
# Copyright 2022 Red Hat
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
from __future__ import absolute_import
|
|
|
|
import dbm
|
|
import os
|
|
import shelve
|
|
|
|
from oslo_log import log
|
|
|
|
import tobiko
|
|
|
|
|
|
LOG = log.getLogger(__name__)
|
|
TEST_RUN_SHELF = 'test_run'
|
|
|
|
|
|
def get_shelves_dir():
|
|
# ensure the directory exists
|
|
from tobiko import config
|
|
shelves_dir = os.path.expanduser(config.CONF.tobiko.common.shelves_dir)
|
|
return shelves_dir
|
|
|
|
|
|
def get_shelf_path(shelf):
|
|
return os.path.join(get_shelves_dir(), shelf)
|
|
|
|
|
|
def addme_to_shared_resource(shelf, resource):
|
|
shelf_path = get_shelf_path(shelf)
|
|
# this is needed for unit tests
|
|
resource = str(resource)
|
|
testcase_id = tobiko.get_test_case().id()
|
|
for attempt in tobiko.retry(timeout=10.0,
|
|
interval=0.5):
|
|
try:
|
|
with shelve.open(shelf_path) as db:
|
|
if db.get(resource) is None:
|
|
db[resource] = set()
|
|
# the add and remove methods do not work directly on the db
|
|
auxset = db[resource]
|
|
auxset.add(testcase_id)
|
|
db[resource] = auxset
|
|
return db[resource]
|
|
except dbm.error:
|
|
LOG.exception(f"Error accessing shelf {shelf}")
|
|
if attempt.is_last:
|
|
raise
|
|
|
|
|
|
def removeme_from_shared_resource(shelf, resource):
|
|
shelf_path = get_shelf_path(shelf)
|
|
# this is needed for unit tests
|
|
resource = str(resource)
|
|
testcase_id = tobiko.get_test_case().id()
|
|
for attempt in tobiko.retry(timeout=10.0,
|
|
interval=0.5):
|
|
try:
|
|
with shelve.open(shelf_path) as db:
|
|
# the add and remove methods do not work directly on the db
|
|
db[resource] = db.get(resource) or set()
|
|
if testcase_id in db[resource]:
|
|
auxset = db[resource]
|
|
auxset.remove(testcase_id)
|
|
db[resource] = auxset
|
|
return db[resource]
|
|
except dbm.error:
|
|
LOG.exception(f"Error accessing shelf {shelf}")
|
|
if attempt.is_last:
|
|
raise
|
|
|
|
|
|
def remove_test_from_shelf_resources(testcase_id, shelf):
|
|
shelf_path = get_shelf_path(shelf)
|
|
for attempt in tobiko.retry(timeout=10.0,
|
|
interval=0.5):
|
|
try:
|
|
with shelve.open(shelf_path) as db:
|
|
if not db:
|
|
return
|
|
for resource in db.keys():
|
|
if testcase_id in db[resource]:
|
|
auxset = db[resource]
|
|
auxset.remove(testcase_id)
|
|
db[resource] = auxset
|
|
return db
|
|
except dbm.error as err:
|
|
LOG.exception(f"Error accessing shelf {shelf}")
|
|
if "db type could not be determined" in str(err):
|
|
# remove the filename extension, which depends on the specific
|
|
# DBM implementation
|
|
shelf_path = '.'.join(shelf_path.split('.')[:-1])
|
|
if attempt.is_last:
|
|
raise
|
|
|
|
|
|
def remove_test_from_all_shared_resources(testcase_id):
|
|
LOG.debug(f'Removing test {testcase_id} from all shelf resources')
|
|
shelves_dir = get_shelves_dir()
|
|
for filename in os.listdir(shelves_dir):
|
|
if TEST_RUN_SHELF not in filename:
|
|
remove_test_from_shelf_resources(testcase_id, filename)
|
|
|
|
|
|
def initialize_shelves():
|
|
shelves_dir = get_shelves_dir()
|
|
shelf_path = os.path.join(shelves_dir, TEST_RUN_SHELF)
|
|
id_key = 'PYTEST_XDIST_TESTRUNUID'
|
|
test_run_uid = os.environ.get(id_key)
|
|
|
|
tobiko.makedirs(shelves_dir)
|
|
|
|
# if no PYTEST_XDIST_TESTRUNUID ->
|
|
# pytest was executed with only one worker
|
|
# if tobiko.initialize_shelves() == True ->
|
|
# this is the first pytest worker running cleanup_shelves
|
|
# then, cleanup the shelves directory
|
|
# else, another worker did it before
|
|
for attempt in tobiko.retry(timeout=15.0,
|
|
interval=0.5):
|
|
try:
|
|
with shelve.open(shelf_path) as db:
|
|
if test_run_uid is None:
|
|
LOG.debug("Only one pytest worker - Initializing shelves")
|
|
elif test_run_uid == db.get(id_key):
|
|
LOG.debug("Another pytest worker already initialized "
|
|
"the shelves")
|
|
return
|
|
else:
|
|
LOG.debug("Initializing shelves for the "
|
|
"test run uid %s", test_run_uid)
|
|
db[id_key] = test_run_uid
|
|
for filename in os.listdir(shelves_dir):
|
|
if TEST_RUN_SHELF not in filename:
|
|
file_path = os.path.join(shelves_dir, filename)
|
|
os.unlink(file_path)
|
|
return
|
|
except dbm.error:
|
|
LOG.exception(f"Error accessing shelf {TEST_RUN_SHELF}")
|
|
if attempt.is_last:
|
|
raise
|