From 5cca60fdf74125f51b9e88563dffdd2fbe75e18f Mon Sep 17 00:00:00 2001 From: Luca Scheller Date: Fri, 24 Nov 2023 19:37:23 +0100 Subject: [PATCH] Cleanup tests --- src/CachedResolver/PythonExpose.py | 35 ++- src/CachedResolver/resolver.cpp | 2 - .../testenv/testCachedResolver.py | 218 +++++++++++++++++- src/CachedResolver/wrapResolver.cpp | 2 + 4 files changed, 242 insertions(+), 15 deletions(-) diff --git a/src/CachedResolver/PythonExpose.py b/src/CachedResolver/PythonExpose.py index 23616a7..c268fbe 100644 --- a/src/CachedResolver/PythonExpose.py +++ b/src/CachedResolver/PythonExpose.py @@ -9,7 +9,7 @@ # Init logger logging.basicConfig(format="%(asctime)s %(message)s", datefmt="%Y/%m/%d %I:%M:%S%p") LOG = logging.getLogger("Python | {file_name}".format(file_name=__name__)) -LOG.setLevel(level=logging.DEBUG) +LOG.setLevel(level=logging.INFO) def log_function_args(func): @@ -44,10 +44,17 @@ class Resolver: @staticmethod @log_function_args - def CreateRelativePathIdentifier(resolver, anchoredAssetPath, assetPath, anchorAssetPath, ): + def CreateRelativePathIdentifier(resolver, anchoredAssetPath, assetPath, anchorAssetPath): """Returns an identifier for the asset specified by assetPath. - If anchorAssetPath is not empty, it is the resolved asset path - that assetPath should be anchored to if it is a relative path. + + We have two options how to return relative identifiers: + - Make it absolute: Simply return the anchoredAssetPath. This means the relative identifier + will not be passed through to ResolveAndCache. + - Make it non file based: Make sure the remapped identifier does not start with "./" or "../" + by putting some sort of prefix in front of it. The path will then be + passed through to ResolveAndCache, where you need to re-construct + it to an absolute path of your liking. + Args: resolver (CachedResolver): The resolver anchoredAssetPath (str): The anchored asset path, this has to be used as the cached key. @@ -57,12 +64,12 @@ def CreateRelativePathIdentifier(resolver, anchoredAssetPath, assetPath, anchorA Returns: str: The identifier. """ - LOG.debug("::: Resolver.CreateRelativePathIdentifier") + LOG.debug("::: Resolver.CreateRelativePathIdentifier | {} | {} | {}".format(anchoredAssetPath, assetPath, anchorAssetPath)) """The code below is only needed to verify that UnitTests work.""" UnitTestHelper.create_relative_path_identifier_call_counter += 1 - remappedRelativePathIdentifier = f"{assetPath[2:]}?{anchorAssetPath}" - resolver.AddCachedRelativePathIdentifierPair(anchoredAssetPath, anchoredAssetPath) - return anchoredAssetPath + remappedRelativePathIdentifier = f"relativePath|{assetPath}?{anchorAssetPath}" + resolver.AddCachedRelativePathIdentifierPair(anchoredAssetPath, remappedRelativePathIdentifier) + return remappedRelativePathIdentifier class ResolverContext: @@ -99,11 +106,11 @@ def ResolveAndCache(context, assetPath): it will be resolved to an empty ArResolvedPath internally, but will still count as a cache hit and be stored inside the cachedPairs dict. """ - resolved_asset_path = "/some/path/to/a/file.usd" - context.AddCachingPair(assetPath, resolved_asset_path) LOG.debug( "::: ResolverContext.ResolveAndCache | {} | {}".format(assetPath, context.GetCachingPairs()) ) + resolved_asset_path = "/some/path/to/a/file.usd" + context.AddCachingPair(assetPath, resolved_asset_path) """ To clear the context cache call: context.ClearCachingPairs() @@ -116,4 +123,12 @@ def ResolveAndCache(context, assetPath): asset_b_file_path = os.path.join(current_dir_path, "assetB.usd") context.AddCachingPair("assetA.usd", asset_a_file_path) context.AddCachingPair("assetB.usd", asset_b_file_path) + if assetPath.startswith("relativePath|"): + relative_path, anchor_path = assetPath.removeprefix("relativePath|").split("?") + if anchor_path[-1] == "/": + anchor_path = anchor_path[:-1] + else: + anchor_path = anchor_path[:anchor_path.rfind("/")] + resolved_asset_path = os.path.normpath(os.path.join(anchor_path, relative_path)) + context.AddCachingPair(assetPath, resolved_asset_path) return resolved_asset_path diff --git a/src/CachedResolver/resolver.cpp b/src/CachedResolver/resolver.cpp index 531f0bb..765e449 100644 --- a/src/CachedResolver/resolver.cpp +++ b/src/CachedResolver/resolver.cpp @@ -86,9 +86,7 @@ _ResolveAnchored( } CachedResolver::CachedResolver() { - this->SetExposeRelativePathIdentifierState(TfGetenvBool(DEFINE_STRING(AR_EXPOSE_RELATIVE_PATH_IDENTIFIERS), false)); - }; CachedResolver::~CachedResolver() = default; diff --git a/src/CachedResolver/testenv/testCachedResolver.py b/src/CachedResolver/testenv/testCachedResolver.py index 64dda71..fdec956 100644 --- a/src/CachedResolver/testenv/testCachedResolver.py +++ b/src/CachedResolver/testenv/testCachedResolver.py @@ -19,9 +19,6 @@ def setUpClass(cls): def test_CreateIdentifier(self): resolver = Ar.GetResolver() - # Reset UnitTestHelper - #PythonExpose.UnitTestHelper.reset(current_directory_path=temp_dir_path) - # Test for invalid paths self.assertEqual("", resolver.CreateIdentifier("")) self.assertEqual( @@ -87,6 +84,132 @@ def test_CreateIdentifier(self): ), ) + def test_CreateRelativeIdentifier(self): + resolver = Ar.GetResolver() + cached_resolver = Ar.GetUnderlyingResolver() + + # Test expose relative path identifier state and cache + self.assertEqual(cached_resolver.GetExposeRelativePathIdentifierState(), False) + + cached_resolver.SetExposeRelativePathIdentifierState(True) + self.assertEqual(cached_resolver.GetExposeRelativePathIdentifierState(), True) + + cached_resolver.AddCachedRelativePathIdentifierPair("/some/absolute/path.usd", "some/relative/path.usd?/some/absolute") + self.assertEqual(cached_resolver.GetCachedRelativePathIdentifierPairs(), + {'/some/absolute/path.usd': 'some/relative/path.usd?/some/absolute'}) + + cached_resolver.SetExposeRelativePathIdentifierState(True) + self.assertEqual(cached_resolver.GetCachedRelativePathIdentifierPairs(), + {'/some/absolute/path.usd': 'some/relative/path.usd?/some/absolute'}) + + cached_resolver.SetExposeRelativePathIdentifierState(False) + self.assertEqual(cached_resolver.GetCachedRelativePathIdentifierPairs(), {}) + + cached_resolver.AddCachedRelativePathIdentifierPair("/some/absolute/path.usd", "some/relative/path.usd?/some/absolute") + cached_resolver.RemoveCachedRelativePathIdentifierByKey("/some/absolute/path.usd") + self.assertEqual(cached_resolver.GetCachedRelativePathIdentifierPairs(),{}) + + cached_resolver.AddCachedRelativePathIdentifierPair("/some/absolute/path.usd", "some/relative/path.usd?/some/absolute") + cached_resolver.RemoveCachedRelativePathIdentifierByValue("some/relative/path.usd?/some/absolute") + self.assertEqual(cached_resolver.GetCachedRelativePathIdentifierPairs(),{}) + + cached_resolver.AddCachedRelativePathIdentifierPair("/some/absolute/path.usd", "some/relative/path.usd?/some/absolute") + cached_resolver.ClearCachedRelativePathIdentifierPairs() + self.assertEqual(cached_resolver.GetCachedRelativePathIdentifierPairs(),{}) + + # Reset UnitTestHelper + PythonExpose.UnitTestHelper.reset() + cached_resolver.SetExposeRelativePathIdentifierState(True) + + # Test for invalid paths + self.assertEqual("", resolver.CreateIdentifier("")) + self.assertEqual( + "", resolver.CreateIdentifier("", Ar.ResolvedPath("some/relative/path.usd")) + ) + self.assertEqual( + "", + resolver.CreateIdentifier("", Ar.ResolvedPath("/some/absolute/path.usd")), + ) + + # Test for valid paths + self.assertEqual( + "/some/absolute/path.usd", + resolver.CreateIdentifier( + "/some/absolute/path.usd", Ar.ResolvedPath("some/relative/path.usd") + ), + ) + self.assertEqual( + "/some/absolute/path.usd", + resolver.CreateIdentifier( + "/some/absolute/path.usd", Ar.ResolvedPath("/some/absolute/path.usd") + ), + ) + + self.assertEqual( + "relativePath|./some/relative/path.usd?/some/absolute/", + resolver.CreateIdentifier( + "./some/relative/path.usd", Ar.ResolvedPath("/some/absolute/") + ), + ) + self.assertEqual( + "relativePath|./some/relative/path.usd?/some/absolute/", + resolver.CreateIdentifier( + "./some/relative/path.usd", Ar.ResolvedPath("/some/absolute/path.usd") + ), + ) + self.assertEqual( + PythonExpose.UnitTestHelper.create_relative_path_identifier_call_counter, + 1 + ) + + self.assertEqual( + "relativePath|./some/relative/path.usd?/some/other/absolute/path.usd", + resolver.CreateIdentifier( + "./some/relative/path.usd", Ar.ResolvedPath("/some/other/absolute/path.usd") + ), + ) + self.assertEqual( + "relativePath|./some/relative/path.usd?/some/other/absolute/path.usd", + resolver.CreateIdentifier( + "./some/relative/path.usd", Ar.ResolvedPath("/some/other/absolute/path.usd") + ), + ) + self.assertEqual( + PythonExpose.UnitTestHelper.create_relative_path_identifier_call_counter, + 2 + ) + + self.assertEqual( + "relativePath|../some/relative/path.usd?/some/absolute/", + resolver.CreateIdentifier( + "../some/relative/path.usd", Ar.ResolvedPath("/some/absolute/") + ), + ) + self.assertEqual( + "relativePath|../some/relative/path.usd?/some/absolute/", + resolver.CreateIdentifier( + "../some/relative/path.usd", Ar.ResolvedPath("/some/absolute/path.usd") + ), + ) + + self.assertEqual( + "/other/relative/path.usd", + resolver.CreateIdentifier( + "/some/../other/relative/path.usd", + Ar.ResolvedPath("/some/absolute/path.usd"), + ), + ) + + self.assertEqual( + "project/assets/asset/path.usd", + resolver.CreateIdentifier( + "project/assets/asset/path.usd", + Ar.ResolvedPath("/some/absolute/path.usd"), + ), + ) + + cached_resolver.SetExposeRelativePathIdentifierState(False) + def test_CreateIdentifierForNewAsset(self): resolver = Ar.GetResolver() @@ -152,6 +275,95 @@ def test_CreateIdentifierForNewAsset(self): ), ) + def test_CreateRelativeIdentifierWithResolverCachingMechanism(self): + with tempfile.TemporaryDirectory() as temp_dir_path: + # Get resolver + resolver = Ar.GetResolver() + cached_resolver = Ar.GetUnderlyingResolver() + # Reset UnitTestHelper + PythonExpose.UnitTestHelper.reset(current_directory_path=temp_dir_path) + # Create files + asset_a_identifier = "assetA.usd" + asset_a_layer_file_path = os.path.join(temp_dir_path, asset_a_identifier) + Sdf.Layer.CreateAnonymous().Export(asset_a_layer_file_path) + asset_b_identifier = "assetB.usd" + asset_b_layer_file_path = os.path.join(temp_dir_path, asset_b_identifier) + Sdf.Layer.CreateAnonymous().Export(asset_b_layer_file_path) + asset_c_identifier = "assetC.usd" + asset_c_layer_file_path = os.path.join(temp_dir_path, asset_c_identifier) + Sdf.Layer.CreateAnonymous().Export(asset_c_layer_file_path) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 0) + + # Check that native relative file path resolving works + # cached_resolver.SetExposeRelativePathIdentifierState(False) # The default is False + asset_a_relative_layer = Sdf.Layer.FindOrOpenRelativeToLayer(Sdf.Layer.FindOrOpen(asset_b_layer_file_path), "./" + asset_a_identifier) + self.assertEqual(asset_a_layer_file_path, asset_a_relative_layer.identifier) + + # Create context + ctx = CachedResolver.ResolverContext() + self.assertEqual(PythonExpose.UnitTestHelper.context_initialize_call_counter, 1) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 0) + resolver = Ar.GetResolver() + with Ar.ResolverContextBinder(ctx): + # Resolve + layer_identifier = "layer.usd" + resolver.Resolve(layer_identifier) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 1) + # See PythonExpose.py for more info + layer_identifier = "unittest.usd" + resolver.Resolve(layer_identifier) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 2) + # Our unittest.usd resolve call caches these test paths, + # see PythonExpose.py for more info + resolver.Resolve(layer_identifier) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 2) + self.assertEqual(ctx.GetCachingPairs(), + {'assetA.usd': asset_a_layer_file_path, + 'assetB.usd': asset_b_layer_file_path, + 'layer.usd': '/some/path/to/a/file.usd', + 'unittest.usd': '/some/path/to/a/file.usd', + 'shot.usd': '/some/path/to/a/file.usd'}) + # Verify that mapping pairs have higher loading priority than + # caching pairs. + ctx.AddCachingPair(asset_c_identifier, asset_c_layer_file_path) + self.assertEqual(resolver.Resolve(asset_c_identifier), asset_c_layer_file_path) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 2) + ctx.AddMappingPair(asset_c_identifier, asset_a_layer_file_path) + self.assertEqual(resolver.Resolve(asset_c_identifier), asset_a_layer_file_path) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 2) + ctx.RemoveMappingByKey(asset_c_identifier) + self.assertEqual(resolver.Resolve(asset_c_identifier), asset_c_layer_file_path) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 2) + # Check that re-init works + mapping_file_path = os.path.join(temp_dir_path, "mapping.usd") + mapping_layer = Sdf.Layer.CreateAnonymous() + mapping_pairs = { + asset_a_identifier: asset_c_layer_file_path, + } + mapping_array = [] + for source_path, target_path in mapping_pairs.items(): + mapping_array.extend([source_path, target_path]) + mapping_layer.customLayerData = { + CachedResolver.Tokens.mappingPairs: Vt.StringArray(mapping_array) + } + mapping_layer.Export(mapping_file_path) + ctx.SetMappingFilePath(mapping_file_path) + ctx.ClearAndReinitialize() + self.assertEqual(ctx.GetMappingPairs(), {asset_a_identifier: asset_c_layer_file_path}) + self.assertEqual(PythonExpose.UnitTestHelper.context_initialize_call_counter, 2) + + # Check that exposed relative file path resolving works + ctx.SetMappingFilePath("") + ctx.ClearAndReinitialize() + cached_resolver.SetExposeRelativePathIdentifierState(True) + self.assertEqual(PythonExpose.UnitTestHelper.create_relative_path_identifier_call_counter, 0) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 2) + asset_a_relative_layer = Sdf.Layer.FindOrOpenRelativeToLayer(Sdf.Layer.FindOrOpen(asset_b_layer_file_path), "./" + asset_a_identifier) + self.assertEqual(PythonExpose.UnitTestHelper.create_relative_path_identifier_call_counter, 1) + self.assertEqual(PythonExpose.UnitTestHelper.resolve_and_cache_call_counter, 3) + self.assertEqual(asset_a_relative_layer, Sdf.Layer.FindOrOpen(asset_a_layer_file_path)) + cached_resolver.SetExposeRelativePathIdentifierState(False) + def test_Resolve(self): with tempfile.TemporaryDirectory() as temp_dir_path: # Create files diff --git a/src/CachedResolver/wrapResolver.cpp b/src/CachedResolver/wrapResolver.cpp index a0002f3..9b5f2a1 100644 --- a/src/CachedResolver/wrapResolver.cpp +++ b/src/CachedResolver/wrapResolver.cpp @@ -18,6 +18,8 @@ wrapResolver() class_, AR_BOOST_NAMESPACE::noncopyable> ("Resolver", no_init) + .def("GetExposeRelativePathIdentifierState", &This::GetExposeRelativePathIdentifierState, return_value_policy(), "Get the state of exposing relative path identifiers") + .def("SetExposeRelativePathIdentifierState", &This::SetExposeRelativePathIdentifierState, "Set the state of exposing relative path identifiers") .def("GetCachedRelativePathIdentifierPairs", &This::GetCachedRelativePathIdentifierPairs, return_value_policy(), "Returns all cached relative path identifier pairs as a dict") .def("AddCachedRelativePathIdentifierPair", &This::AddCachedRelativePathIdentifierPair, "Remove a cached relative path identifier pair by value") .def("RemoveCachedRelativePathIdentifierByKey", &This::RemoveCachedRelativePathIdentifierByKey, "Add a cached relative path identifier pair")