Addon Manager: Refactor to improve testability

This commit is contained in:
Chris Hennes
2022-08-04 11:15:26 -05:00
parent db0afb08b2
commit b6e2fb17d0
3 changed files with 54 additions and 12 deletions

View File

@@ -120,6 +120,12 @@ class Addon:
class ResolutionFailed(RuntimeError):
"""An exception type for dependency resolution failure."""
# The location of Addon Manager cache files: overridden by testing code
cache_directory = os.path.join(FreeCAD.getUserCachePath(), "AddonManager")
# The location of the Mod directory: overridden by testing code
mod_directory = os.path.join(FreeCAD.getUserAppDataDir(), "Mod")
def __init__(self, name: str, url: str, status: Status, branch: str):
self.name = name.strip()
self.display_name = self.name
@@ -199,7 +205,7 @@ class Addon:
def from_cache(cls, cache_dict: Dict):
"""Load basic data from cached dict data. Does not include Macro or Metadata information, which must be populated separately."""
mod_dir = os.path.join(FreeCAD.getUserAppDataDir(), "Mod", cache_dict["name"])
mod_dir = os.path.join(cls.mod_directory, cache_dict["name"])
if os.path.isdir(mod_dir):
status = Addon.Status.UNCHECKED
else:
@@ -215,8 +221,7 @@ class Addon:
if instance.repo_type == Addon.Kind.PACKAGE:
# There must be a cached metadata file, too
cached_package_xml_file = os.path.join(
FreeCAD.getUserCachePath(),
"AddonManager",
instance.cache_directory,
"PackageMetadata",
instance.name,
)
@@ -458,7 +463,7 @@ class Addon:
_, file_extension = os.path.splitext(real_icon)
store = os.path.join(
FreeCAD.getUserCachePath(), "AddonManager", "PackageMetadata"
self.cache_directory, "PackageMetadata"
)
self.cached_icon_filename = os.path.join(
store, self.name, "cached_icon" + file_extension
@@ -513,7 +518,7 @@ class Addon:
"""Check to see if the disabling stopfile exists"""
stopfile = os.path.join(
FreeCAD.getUserAppDataDir(), "Mod", self.name, "ADDON_DISABLED"
self.mod_directory, self.name, "ADDON_DISABLED"
)
return os.path.exists(stopfile)
@@ -521,7 +526,7 @@ class Addon:
"""Disable this addon from loading when FreeCAD starts up by creating a stopfile"""
stopfile = os.path.join(
FreeCAD.getUserAppDataDir(), "Mod", self.name, "ADDON_DISABLED"
mod_directory, self.name, "ADDON_DISABLED"
)
with open(stopfile, "w", encoding="utf-8") as f:
f.write(
@@ -532,7 +537,7 @@ class Addon:
"""Re-enable loading this addon by deleting the stopfile"""
stopfile = os.path.join(
FreeCAD.getUserAppDataDir(), "Mod", self.name, "ADDON_DISABLED"
self.mod_directory, self.name, "ADDON_DISABLED"
)
try:
os.unlink(stopfile)

View File

@@ -52,9 +52,18 @@ class TestWorkersStartup(unittest.TestCase):
self.macro_counter = 0
self.workbench_counter = 0
self.prefpack_counter = 0
# Populated when the addon list is created in the first test
self.package_cache = {}
self.macro_cache = {}
self.package_cache_file = tempfile.NamedTemporaryFile(mode='w', encoding="utf-8", delete=False)
self.macro_cache_file = tempfile.NamedTemporaryFile(mode='w', encoding="utf-8", delete=False)
def test_create_addon_list_worker(self):
""" Test whether any addons are added: runs the full query, so this potentially is a SLOW test """
""" Test whether any addons are added: runs the full query, so this potentially is a SLOW
test. Note that this test must be run before any of the other tests, so that the cache gets
created. """
worker = CreateAddonListWorker()
worker.addon_repo.connect(self._addon_added)
worker.start()
@@ -65,6 +74,14 @@ class TestWorkersStartup(unittest.TestCase):
self.assertGreater(self.workbench_counter,0, "No workbenches returned")
self.assertGreater(self.prefpack_counter,0, "No preference packs returned")
# Write the cache data
if hasattr(self, "package_cache"):
self.package_cache_file.write(json.dumps(self.package_cache, indent=" "))
self.package_cache_file.close()
if hasattr(self, "macro_cache"):
self.macro_cache_file.write(json.dumps(self.macro_cache, indent=" "))
self.macro_cache_file.close()
def _addon_added(self, addon:Addon):
""" Callback for adding an Addon: tracks the list, and counts the various types """
print (f"Addon Test: {addon.name}")
@@ -76,3 +93,14 @@ class TestWorkersStartup(unittest.TestCase):
if addon.contains_preference_pack():
self.prefpack_counter += 1
# Also record the information for cache purposes
self.package_cache[addon.name] = addon.to_cache()
if addon.macro is not None:
self.macro_cache.append(addon.macro.to_cache())
def test_load_packages_from_cache_worker(self):
pass
def test_load_macros_from_cache_worker(self):
pass

View File

@@ -393,16 +393,21 @@ class CreateAddonListWorker(QtCore.QThread):
class LoadPackagesFromCacheWorker(QtCore.QThread):
""" A subthread worker that loads package information from its cache file. """
addon_repo = QtCore.Signal(object)
def __init__(self, cache_file: str):
QtCore.QThread.__init__(self)
self.cache_file = cache_file
def run(self):
metadata_cache_path = os.path.join(
self.metadata_cache_path = os.path.join(
FreeCAD.getUserCachePath(), "AddonManager", "PackageMetadata"
)
def override_metadata_cache_path(self, path):
""" For testing purposes, override the location to fetch the package metadata from. """
self.metadata_cache_path = path
def run(self):
with open(self.cache_file, "r", encoding="utf-8") as f:
data = f.read()
if data:
@@ -412,7 +417,7 @@ class LoadPackagesFromCacheWorker(QtCore.QThread):
return
repo = Addon.from_cache(item)
repo_metadata_cache_path = os.path.join(
metadata_cache_path, repo.name, "package.xml"
self.metadata_cache_path, repo.name, "package.xml"
)
if os.path.isfile(repo_metadata_cache_path):
try:
@@ -511,6 +516,10 @@ class UpdateChecker:
self.basedir = FreeCAD.getUserAppDataDir()
self.moddir = os.path.join(self.basedir, "Mod")
def override_mod_directory(self, moddir):
""" Primarily for use when testing, sets an alternate directory to use for mods """
self.moddir = moddir
def check_workbench(self, wb):
if not have_git or NOGIT:
wb.set_status(Addon.Status.CANNOT_CHECK)