Source code for khoros.utils.tests.resources
# -*- coding: utf-8 -*-
"""
:Module: khoros.utils.tests.resources
:Synopsis: Frequently used resources for performing unit testing
:Usage: ``from khoros.utils.tests import resources``
:Example: ``exceptions = resources.import_exceptions_module()``
:Created By: Jeff Shurtliff
:Last Modified: Jeff Shurtliff
:Modified Date: 25 Nov 2022
"""
import os
import sys
import json
import importlib
import yaml
import pytest
# Define global variable to store the YAML test settings
test_config = {}
# Define constants
SKIP_LOCAL_TEST_MSG = 'skipping local-only tests'
[docs]
class MockResponse:
"""This class simulates an API response for testing purposes.
.. versionchanged:: 5.2.0
The ``status_code`` attribute has been added to the object.
.. versionadded:: 5.1.2
"""
def __init__(self, json_body, status_code=200):
self.json_body = json_body
self.status_code = status_code
def json(self):
return self.json_body
[docs]
def mock_success_post(*args, **kwargs):
"""This function works with the `MockedResponse` class to simulate a successful API response.
.. versionadded:: 5.1.2
"""
return MockResponse({
"status": "success"
})
[docs]
def mock_error_post(*args, **kwargs):
"""This function works with the `MockedResponse` class to simulate a failed API response.
.. versionadded:: 5.1.2
"""
return MockResponse({
"status": "error",
"message": "There was an error",
"data": {
"code": "500",
"type": "error"
}
})
[docs]
def mock_bulk_data_json(*args, **kwargs):
"""This function works with the `MockedResponse` class to simulate a Bulk Data API JSON response.
.. versionadded:: 5.2.0
"""
return MockResponse({
"records": []
})
[docs]
def set_package_path():
"""This function adds the high-level khoros directory to the sys.path list.
.. versionchanged:: 5.0.0
Removed the redundant return statement.
.. versionadded:: 2.7.4
"""
sys.path.insert(0, os.path.abspath('../..'))
[docs]
def import_modules(*modules):
"""This function imports and returns one or more modules to utilize in a unit test.
.. versionadded:: 2.7.4
:param modules: One or more module paths (absolute) in string format
:returns: The imported module(s) as an individual object or a tuple of objects
"""
imported_modules = []
for module in modules:
imported_modules.append(importlib.import_module(module))
tuple(imported_modules)
return imported_modules if len(imported_modules) > 1 else imported_modules[0]
def _get_control_dataset_file(_dataset_name):
"""This function returns the file name associated with a particular dataset.
.. versionadded:: 5.1.0
:param _dataset_name: The name of the dataset
:type _dataset_name: str
:returns: The file name if found or a blank string
"""
# Define the dataset file mapping
_datasets = {
'categories': 'categories_control_data.json',
'communities': 'communities_control_data.json',
}
try:
_dataset_file = _datasets[_dataset_name]
except KeyError:
_dataset_file = ''
return _dataset_file
[docs]
def import_control_data(dataset_name):
"""This function imports a local control data file as a dictionary.
.. versionchanged:: 5.1.1
The function has been updated to support GitHub Workflows control data.
.. versionadded:: 5.1.0
:param dataset_name: The name of the dataset
:type dataset_name: str
:returns: The JSON data as a dictionary
:raises: :py:exc:`FileNotFoundError`
"""
data = None
dataset_file = _get_control_dataset_file(dataset_name)
file_paths = [
f'{os.environ.get("HOME")}/secrets/{dataset_file}',
f'local/tests/{dataset_file}',
]
for path in file_paths:
if os.path.isfile(path):
with open(path, 'r') as file:
data = json.load(file)
break
if data is None:
raise FileNotFoundError(f'The {dataset_name} control data cannot be found.')
return data
[docs]
def control_data_exists(dataset_name):
"""This function checks to see if a local control data file exists.
.. versionchanged:: 5.1.1
The function has been updated to support GitHub Workflow control data.
.. versionadded:: 5.1.0
:param dataset_name: The name of the dataset
:type dataset_name: str
:returns: Boolean value indicating whether the file was found
"""
data_exists = False
dataset_file = _get_control_dataset_file(dataset_name)
if dataset_file and (os.path.isfile(f'{os.environ.get("HOME")}/secrets/{dataset_file}') or
os.path.isfile(f'local/tests/{dataset_file}')):
data_exists = True
return data_exists
[docs]
def get_control_data(dataset_name):
"""This function retrieves the control data used in various tests.
.. versionadded:: 5.1.1
"""
if not control_data_exists(dataset_name):
pytest.skip('skipping tests where control data is unavailable')
# Import the control data
control_data = import_control_data(dataset_name)
# Return the control data and the core object
return control_data
[docs]
def get_core_object():
"""This function instantiates and returns the core object using a local helper file.
.. versionadded:: 5.1.1
"""
set_package_path()
if secrets_helper_exists():
khoros_object = instantiate_with_secrets_helper()
else:
if not local_test_config_exists() or not local_helper_exists():
pytest.skip('skipping tests where a valid helper file is needed')
khoros_object = instantiate_with_local_helper(production=False)
return khoros_object
[docs]
def initialize_khoros_object(use_defined_settings=False, defined_settings=None, append_to_default=False):
"""This function imports the :py:class:`khoros.core.Khoros` class and initializes an object.
.. versionchanged:: 4.3.0
Added support for utilizing the ``defined_settings`` parameter.
.. versionadded:: 2.7.4
:returns: The initialized :py:class:`khoros.core.Khoros` object
"""
set_package_path()
default_defined_settings = {
'community_url': 'https://community.example.com',
'auto_connect': False,
'tenant_id': 'example',
'auth_type': 'session_auth',
'session_auth': {
'username': 'testuser',
'password': 'fakePassword123',
},
}
core_module = importlib.import_module('khoros.core')
if use_defined_settings:
settings = default_defined_settings if defined_settings is None else defined_settings
if defined_settings and append_to_default:
settings = default_defined_settings
settings.update(defined_settings)
instantiated_object = core_module.Khoros(defined_settings=settings)
else:
instantiated_object = core_module.Khoros(community_url='https://community.example.com', auto_connect=False,
tenant_id='example', auth_type='session_auth',
session_auth={'username': 'testuser', 'password': 'fakePassword123'})
return instantiated_object
[docs]
def get_structure_collection(structure_type):
"""This function identifies the API collection for a given structure type.
.. versionadded:: 4.1.0
:param structure_type: The structure type for which to return the corresponding collection.
:returns: The appropriate collection
"""
structure_map = {
'board': 'boards',
'category': 'categories',
'community': 'community',
'grouphub': 'grouphubs',
}
if structure_type in structure_map.values():
collection = structure_type
else:
collection = structure_map.get(structure_type)
return collection
def _get_local_helper_file_name(_production=False):
"""This function defines the file name of the local helper file to be used with unit testing.
.. versionadded:: 4.1.0
:param _production: Defines whether the helper file is associated with a Production environment
:type _production: bool, None
:returns: The file name for the local helper file
"""
if _production is None:
_file_name = 'helper.yml'
else:
_file_name = 'prod_helper.yml' if _production else 'stage_helper.yml'
return _file_name
[docs]
def local_helper_exists(production=False):
"""This function checks to see if a helper file is present in the ``local/`` directory.
.. versionadded:: 4.1.0
:param production: Defines whether the helper file is associated with a Production environment
:type production: bool, None
:returns: Boolean value indicating whether the local helper file was found
"""
file_name = _get_local_helper_file_name(production)
return os.path.exists(f'local/{file_name}')
[docs]
def local_test_config_exists():
"""This function checks to see if the *khorostest.yml* file is present in the ``local/`` directory.
.. versionadded:: 4.1.0
:returns: Boolean value indicating whether the file was found
"""
return os.path.exists('local/khorostest.yml')
[docs]
def parse_testing_config_file():
"""This function parses the ``local/khorostest.yml`` file when present.
.. versionchanged:: 5.0.0
Removed the redundant return statement.
.. versionadded:: 4.1.0
"""
global test_config
if local_test_config_exists():
with open('local/khorostest.yml', 'r') as file:
test_config = yaml.safe_load(file)
[docs]
def get_testing_config():
"""This function returns the test config data from the ``local/khorostest.yml`` file when present.
.. versionadded:: 4.1.0
"""
if not test_config and local_test_config_exists():
parse_testing_config_file()
return test_config
[docs]
def secrets_helper_exists():
"""This function checks to see if the unencrypted helper file exists for GitHub Workflows.
.. versionadded:: 5.1.1
"""
helper_path = f'{os.environ.get("HOME")}/secrets/khoros_helper.yml'
return os.path.isfile(helper_path)
[docs]
def instantiate_with_local_helper(production=False):
"""This function instantiates a Khoros object using a local helper file for unit testing.
.. versionchanged:: 5.1.0
The function has been updated to raise the :py:exc:`FileNotFoundError` exception if the file is not found.
.. versionadded:: 4.1.0
:param production: Defines whether the helper file is associated with a Production environment
:type production: bool, None
:returns: The instantiated :py:class:`khoros.core.Khoros` object
:raises: :py:exc:`FileNotFoundError`
"""
file_name = _get_local_helper_file_name(production)
if not local_helper_exists():
raise FileNotFoundError('The local helper file cannot be found.')
set_package_path()
core_module = importlib.import_module('khoros.core')
return core_module.Khoros(helper=f"local/{file_name}")
[docs]
def instantiate_with_secrets_helper():
"""This function instantiates a Khoros object using the unencrypted helper file intended for GitHub Workflows.
.. versionadded:: 5.1.1
:returns: The instantiated :py:class:`khoros.core.Khoros` object
:raises: :py:exc:`FileNotFoundError`
"""
if not secrets_helper_exists():
raise FileNotFoundError('The unencrypted GitHub Workflows helper file cannot be found.')
file_name = f'{os.environ.get("HOME")}/secrets/khoros_helper.yml'
set_package_path()
core_module = importlib.import_module('khoros.core')
return core_module.Khoros(helper=file_name)
[docs]
def instantiate_with_placeholder():
"""This function instantiates a Khoros object with placeholder data.
.. versionadded:: 5.0.0
:returns: The instantiated :py:class:`khoros.core.Khoros` object
"""
set_package_path()
core_module = importlib.import_module('khoros.core')
return core_module.Khoros(placeholder=True)