Skip to content

Commit

Permalink
MAYA-105597 Refactor common test utilities
Browse files Browse the repository at this point in the history
  • Loading branch information
Krystian Ligenza committed Oct 16, 2020
1 parent bad3130 commit 7e951ed
Show file tree
Hide file tree
Showing 70 changed files with 335 additions and 349 deletions.
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
add_subdirectory(lib)
add_subdirectory(testSamples)
add_subdirectory(testUtils)
286 changes: 7 additions & 279 deletions test/lib/testMayaUsdProxyAccessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,290 +23,18 @@

import maya.cmds as cmds

import usdUtils, mayaUtils, testUtils

from cachingUtils import NonCachingScope, CachingScope
from ufeUtils import makeUfePath, selectUfeItems
from mayaUtils import createProxyAndStage, createProxyFromFile, createAnimatedHierarchy

from mayaUsd import lib as mayaUsdLib
from mayaUsd.lib import GetPrim
from mayaUsd.lib import proxyAccessor as pa

from pxr import Usd, UsdGeom, Sdf, Tf, Vt

from maya.debug.emModeManager import emModeManager
from maya.plugin.evaluator.CacheEvaluatorManager import CacheEvaluatorManager, CACHE_STANDARD_MODE_EVAL

class NonCachingScope(object):
'''
Scope object responsible for setting up non cached mode and restoring default settings after
'''
def __enter__(self):
'''Enter the scope, setting up the evaluator managers and initial states'''
self.em_mgr = emModeManager()
self.em_mgr.setMode('emp')
self.em_mgr.setMode('-cache')

return self

def __init__(self, unit_test):
'''Initialize everything to be empty - only use the "with" syntax with this object'''
self.em_mgr = None
self.unit_test = unit_test

def __exit__(self,exit_type,value,traceback):
'''Exit the scope, restoring all of the state information'''
if self.em_mgr:
self.em_mgr.restore_state()
self.em_mgr = None

def verifyScopeSetup(self):
'''
Meta-test to check that the scope was defined correctly
:param unit_test: The test object from which this method was called
'''
self.unit_test.assertTrue( cmds.evaluationManager( mode=True, query=True )[0] == 'parallel' )
if cmds.pluginInfo('cacheEvaluator', loaded=True, query=True):
self.unit_test.assertFalse( cmds.evaluator( query=True, en=True, name='cache' ) )

def checkValidFrames(self, expected_valid_frames, layers_mask = 0b01):
return True

def waitForCache(self, wait_time=5):
return

@staticmethod
def is_caching_scope():
'''
Method to determine whether caching is on or off in this object's scope
:return: False, since this is the non-caching scope
'''
return False

class CachingScope(object):
'''
Scope object responsible for setting up caching and restoring original setup after
'''
def __enter__(self):
'''Enter the scope, setting up the evaluator managers and initial states'''
self.em_mgr = emModeManager()
self.em_mgr.setMode('emp')
self.em_mgr.setMode('+cache')
# Enable idle build to make sure we can rebuild the graph when waiting.
self.em_mgr.idle_action = emModeManager.idle_action_build

# Setup caching options
self.cache_mgr = CacheEvaluatorManager()
self.cache_mgr.save_state()
self.cache_mgr.plugin_loaded = True
self.cache_mgr.enabled = True
self.cache_mgr.cache_mode = CACHE_STANDARD_MODE_EVAL
self.cache_mgr.resource_guard = False
self.cache_mgr.fill_mode = 'syncAsync'

# Setup autokey options
self.auto_key_state = cmds.autoKeyframe(q=True, state=True)
self.auto_key_chars = cmds.autoKeyframe(q=True, characterOption=True)
cmds.autoKeyframe(e=True, state=False)

self.waitForCache()

return self

def __init__(self, unit_test):
'''Initialize everything to be empty - only use the "with" syntax with this object'''
self.em_mgr = None
self.cache_mgr = None
self.auto_key_state = None
self.auto_key_chars = None
self.unit_test = unit_test

def __exit__(self,exit_type,value,traceback):
'''Exit the scope, restoring all of the state information'''
if self.cache_mgr:
self.cache_mgr.restore_state()
if self.em_mgr:
self.em_mgr.restore_state()
cmds.autoKeyframe(e=True, state=self.auto_key_state, characterOption=self.auto_key_chars)

def verifyScopeSetup(self):
'''
Meta-test to check that the scope was defined correctly
:param unit_test: The test object from which this method was called
'''
self.unit_test.assertTrue( cmds.evaluationManager( mode=True, query=True )[0] == 'parallel' )
self.unit_test.assertTrue( cmds.pluginInfo('cacheEvaluator', loaded=True, query=True) )
self.unit_test.assertTrue( cmds.evaluator( query=True, en=True, name='cache' ) )

def checkValidFrames(self, expected_valid_frames, layers_mask = 0b01):
'''
:param unit_test: The test object from which this method was called
:param expected_valid_frames: The list of frames the text expected to be cached
:return: True if the cached frame list matches the expected frame list
'''
current_valid_frames = list(self.cache_mgr.get_valid_frames(layers_mask))
if len(expected_valid_frames) == len(current_valid_frames):
for current, expected in zip(current_valid_frames,expected_valid_frames):
if current[0] != expected[0] or current[1] != expected[1]:
self.unit_test.fail( "{} != {} (current,expected)".format( current_valid_frames, expected_valid_frames) )
return False

return True
self.unit_test.fail( "{} != {} (current,expected)".format( current_valid_frames, expected_valid_frames) )
return False

def waitForCache(self, wait_time=5):
'''
Fill the cache in the background, waiting for a maximum time
:param unit_test: The test object from which this method was called
:param wait_time: Time the test is willing to wait for cache completion (in seconds)
'''
cmds.currentTime( cmds.currentTime(q=True) )
cmds.currentTime( cmds.currentTime(q=True) )
cache_is_ready = cmds.cacheEvaluator( waitForCache=wait_time )
self.unit_test.assertTrue( cache_is_ready )

@staticmethod
def is_caching_scope():
'''
Method to determine whether caching is on or off in this object's scope
:return: True, since this is the caching scope
'''
return True

def isPluginLoaded(pluginName):
"""
Verifies that the given plugin is loaded
Args:
pluginName (str): The plugin name to verify
Returns:
True if the plugin is loaded. False if a plugin failed to load
"""
return cmds.pluginInfo( pluginName, loaded=True, query=True)

def loadPlugin(pluginName):
"""
Load all given plugins created or needed by maya-ufe-plugin
Args:
pluginName (str): The plugin name to load
Returns:
True if all plugins are loaded. False if a plugin failed to load
"""
try:
if not isPluginLoaded(pluginName):
cmds.loadPlugin( pluginName, quiet = True )
return True
except:
print(sys.exc_info()[1])
print("Unable to load %s" % pluginName)
return False

def isMayaUsdPluginLoaded():
"""
Load plugins needed by tests.
Returns:
True if plugins loaded successfully. False if a plugin failed to load
"""
# Load the mayaUsdPlugin first.
if not loadPlugin("mayaUsdPlugin"):
return False

# Load the UFE support plugin, for ufeSelectCmd support. If this plugin
# isn't included in the distribution of Maya (e.g. Maya 2019 or 2020), use
# fallback test plugin.
if not (loadPlugin("ufeSupport") or loadPlugin("ufeTestCmdsPlugin")):
return False

# The renderSetup Python plugin registers a file new callback to Maya. On
# test application exit (in TbaseApp::cleanUp()), a file new is done and
# thus the file new callback is invoked. Unfortunately, this occurs after
# the Python interpreter has been finalized, which causes a crash. Since
# renderSetup is not needed for mayaUsd tests, unload it.
rs = 'renderSetup'
if cmds.pluginInfo(rs, q=True, loaded=True):
unloaded = cmds.unloadPlugin(rs)
return (unloaded[0] == rs)

return True

def makeUfePath(dagPath, sdfPath=None):
"""
Make ufe item out of dag path and sdfpath
"""
ufePath = ufe.PathString.path('{},{}'.format(dagPath,sdfPath) if sdfPath != None else '{}'.format(dagPath))
ufeItem = ufe.Hierarchy.createItem(ufePath)
return ufeItem

def selectUfeItems(selectItems):
"""
Add given UFE item or list of items to a UFE global selection list
"""
ufeSelectionList = ufe.Selection()

realListToSelect = selectItems if type(selectItems) is list else [selectItems]
for item in realListToSelect:
ufeSelectionList.append(item)

ufe.GlobalSelection.get().replaceWith(ufeSelectionList)

def createProxyAndStage():
"""
Create in-memory stage
"""
cmds.createNode('mayaUsdProxyShape', name='stageShape')

shapeNode = cmds.ls(sl=True,l=True)[0]
shapeStage = mayaUsdLib.GetPrim(shapeNode).GetStage()

cmds.select( clear=True )
cmds.connectAttr('time1.outTime','{}.time'.format(shapeNode))

return shapeNode,shapeStage

def createProxyFromFile(filePath):
"""
Load stage from file
"""
cmds.createNode('mayaUsdProxyShape', name='stageShape')

shapeNode = cmds.ls(sl=True,l=True)[0]
cmds.setAttr('{}.filePath'.format(shapeNode), filePath, type='string')

shapeStage = mayaUsdLib.GetPrim(shapeNode).GetStage()

cmds.select( clear=True )
cmds.connectAttr('time1.outTime','{}.time'.format(shapeNode))

return shapeNode,shapeStage

def createAnimatedHierarchy(stage):
"""
Create simple hierarchy in the stage:
/ParentA
/Sphere
/Cube
/ParenB
Entire ParentA hierarchy will receive time samples on translate for time 1 and 100
"""
parentA = "/ParentA"
parentB = "/ParentB"
childSphere = "/ParentA/Sphere"
childCube = "/ParentA/Cube"

parentPrimA = stage.DefinePrim(parentA, 'Xform')
parentPrimB = stage.DefinePrim(parentB, 'Xform')
childPrimSphere = stage.DefinePrim(childSphere, 'Sphere')
childPrimCube = stage.DefinePrim(childCube, 'Cube')

UsdGeom.XformCommonAPI(parentPrimA).SetRotate((0,0,0))
UsdGeom.XformCommonAPI(parentPrimB).SetTranslate((1,10,0))

time1 = Usd.TimeCode(1.)
UsdGeom.XformCommonAPI(parentPrimA).SetTranslate((0,0,0),time1)
UsdGeom.XformCommonAPI(childPrimSphere).SetTranslate((5,0,0),time1)
UsdGeom.XformCommonAPI(childPrimCube).SetTranslate((0,0,5),time1)

time2 = Usd.TimeCode(100.)
UsdGeom.XformCommonAPI(parentPrimA).SetTranslate((0,5,0),time2)
UsdGeom.XformCommonAPI(childPrimSphere).SetTranslate((-5,0,0),time2)
UsdGeom.XformCommonAPI(childPrimCube).SetTranslate((0,0,-5),time2)

class MayaUsdProxyAccessorTestCase(unittest.TestCase):
"""
Verify mayaUsd ProxyAccessor.
Expand All @@ -324,7 +52,7 @@ def setUpClass(cls):
Load mayaUsdPlugin on class initialization (before any test is executed)
"""
if not cls.pluginsLoaded:
cls.pluginsLoaded = isMayaUsdPluginLoaded()
cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded()

# Useful for debugging accessor
#Tf.Debug.SetDebugSymbolsByName("USDMAYA_PROXYACCESSOR", 1)
Expand Down
7 changes: 3 additions & 4 deletions test/lib/ufe/testAttribute.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
# limitations under the License.
#

from ufeTestUtils import usdUtils, mayaUtils
import ufeTestUtils.testUtils
import usdUtils, mayaUtils, testUtils
import ufe
from pxr import UsdGeom
import random
Expand Down Expand Up @@ -51,7 +50,7 @@ def setUpClass(cls):
if not cls.pluginsLoaded:
cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded()

# Open top_layer.ma scene in test-samples
# Open top_layer.ma scene in testSamples
mayaUtils.openTopLayerScene()

random.seed()
Expand All @@ -66,7 +65,7 @@ def setUp(self):
self.assertTrue(self.pluginsLoaded)

def assertVectorAlmostEqual(self, ufeVector, usdVector):
ufeTestUtils.testUtils.assertVectorAlmostEqual(
testUtils.assertVectorAlmostEqual(
self, ufeVector.vector, usdVector)

def assertColorAlmostEqual(self, ufeColor, usdColor):
Expand Down
4 changes: 2 additions & 2 deletions test/lib/ufe/testAttributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# limitations under the License.
#

from ufeTestUtils import usdUtils, mayaUtils
import usdUtils, mayaUtils
import ufe
from pxr import UsdGeom

Expand All @@ -37,7 +37,7 @@ def setUp(self):
''' Called initially to set up the maya test environment '''
self.assertTrue(self.pluginsLoaded)

# Open top_layer.ma scene in test-samples
# Open top_layer.ma scene in testSamples
mayaUtils.openTopLayerScene()

def testAttributes(self):
Expand Down
4 changes: 2 additions & 2 deletions test/lib/ufe/testChildFilter.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import maya.cmds as cmds

from ufeTestUtils import mayaUtils
import mayaUtils
import ufe

import unittest
Expand All @@ -43,7 +43,7 @@ def setUp(self):
# Load plugins
self.assertTrue(self.pluginsLoaded)

# Open ballset.ma scene in test-samples
# Open ballset.ma scene in testSamples
mayaUtils.openGroupBallsScene()

# Clear selection to start off
Expand Down
6 changes: 3 additions & 3 deletions test/lib/ufe/testComboCmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import maya.cmds as cmds
from math import radians, degrees

from ufeTestUtils import usdUtils, mayaUtils, ufeUtils
from ufeTestUtils.testUtils import assertVectorAlmostEqual
import usdUtils, mayaUtils, ufeUtils
from testUtils import assertVectorAlmostEqual
import testTRSBase
import ufe

Expand Down Expand Up @@ -120,7 +120,7 @@ def setUp(self):
self.noSpace = None
self.spaces = [om.MSpace.kObject, om.MSpace.kWorld]

# Open top_layer.ma scene in test-samples
# Open top_layer.ma scene in testSamples
mayaUtils.openTopLayerScene()

# Create some extra Maya nodes
Expand Down
Loading

0 comments on commit 7e951ed

Please sign in to comment.