Skip to content

Commit

Permalink
Merge pull request OpenAssetIO#469 from foundrytom/work/445-refineCon…
Browse files Browse the repository at this point in the history
…textCreation

[Core] Refine context creation mechanism
  • Loading branch information
foundrytom authored Jun 17, 2022
2 parents 330f330 + 33a3ec2 commit 6553bce
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 5 deletions.
7 changes: 7 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,13 @@ v1.0.0-alpha.X
language bindings.
[#445](https://github.com/OpenAssetIO/OpenAssetIO/issues/445)

- Ammended the behaviour of `ManagerInterface` such that derived classes
who implement the `createState` method _must_ also implement
`createChildState`, `persistenceTokenForState` and
`stateFromPersistenceToken`. Checks have been added to the
`openassetio.test.manager` `apiComplianceSuite` to validate manager
implementations agains this requirement.


### Improvements

Expand Down
19 changes: 14 additions & 5 deletions python/openassetio/hostAPI/Manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1037,14 +1037,18 @@ def createChildContext(self, parentContext):
@see @ref createContext
@see @fqref{Context} "Context"
"""
return Context(
context = Context(
access=parentContext.access,
retention=parentContext.retention,
locale=parentContext.locale,
managerState=self.__impl.createChildState(self.__hostSession,
parentContext.managerState)
locale=parentContext.locale
)

if parentContext.managerState:
context.managerState = \
self.__impl.createChildState(self.__hostSession, parentContext.managerState)

return context

@auditApiCall("Session")
def persistenceTokenForContext(self, context):
"""
Expand Down Expand Up @@ -1073,6 +1077,9 @@ def persistenceTokenForContext(self, context):
@see @ref stable_resolution
"""
if not context.managerState :
return ""

token = self.__impl.persistenceTokenForState(context.managerState, self.__hostSession)
return token

Expand Down Expand Up @@ -1103,7 +1110,9 @@ def contextFromPersistenceToken(self, persistenceToken):
persistenceTokenForContext so we can verify that they match?
"""
context = Context()
context.managerState = self.__impl.stateFromPersistenceToken(persistenceToken,

if persistenceToken:
context.managerState = self.__impl.stateFromPersistenceToken(persistenceToken,
self.__hostSession)
return context

Expand Down
44 changes: 44 additions & 0 deletions python/openassetio/test/manager/apiComplianceSuite.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,3 +293,47 @@ def __testResolutionError(self, fixture_name, access):
[result] = self._manager.resolve([reference], self.a_set_of_valid_traits, context)
self.assertIsInstance(result, EntityResolutionError)
self.assertEqual(str(result), str(expected_error))


class Test_createChildState(FixtureAugmentedTestCase):
"""
Tests that the createChildState method is implemented if createState
has been implemented to return a custom state object.
"""
def test_when_createState_implemented_then_createChildState_returns_state(self):
context = self._manager.createContext()
if not context.managerState:
self.skipTest("createState returned None")

child_context = self._manager.createChildState(context)
self.assertIsNotNone(child_context.managerState)


class Test_persistenceTokenForState(FixtureAugmentedTestCase):
"""
Tests that the persistenceTokenForState method is implemented if
createState has been implemented to return a custom state object.
"""
def test_when_createState_implemented_then_persistenceTokenForState_returns_string(self):
context = self._manager.createContext()
if not context.managerState:
self.skipTest("createState returned None")

token = self._manager.persistenceTokenForContext(context)
self.assertIsInstance(token, str)


class Test_stateFromPersistenceToken(FixtureAugmentedTestCase):
"""
Tests that the persistenceTokenForState method is implemented if
createState has been implemented to return a custom state object.
"""
def test_when_createState_implemented_then_stateFromPersistenceToken_returns_state(self):
context = self._manager.createContext()
if not context.managerState:
self.skipTest("createState returned None")

token = self._manager.persistenceTokenForContext(context)

restored_context = self._manager.contextFromPersistenceToken(token)
self.assertIsNotNone(restored_context.managerState)
28 changes: 28 additions & 0 deletions tests/python/openassetio/hostAPI/test_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,19 @@ def test_when_called_with_parent_then_props_copied_and_createState_called_with_p
mock_host_session, state_a)
mock_manager_interface.mock.createState.assert_not_called()

def test_when_called_with_parent_with_no_managerState_then_createChildState_is_not_called(
self, manager, mock_manager_interface):
context_a = Context()
context_a.access = Context.kWrite
context_a.retention = Context.kSession
context_a.locale = TraitsData()
context_b = manager.createChildContext(context_a)

assert context_b.access == context_a.access
assert context_b.retention == context_a.retention
assert context_b.locale == context_b.locale
mock_manager_interface.mock.createChildState.assert_not_called()


class Test_Manager_persistenceTokenForContext:

Expand All @@ -533,6 +546,14 @@ def test_when_called_then_the_managers_persistence_token_is_returned(
mock_manager_interface.mock.persistenceTokenForState.assert_called_once_with(
initial_state, mock_host_session)

def test_when_no_state_then_return_is_empty_and_persistenceTokenForState_is_not_called(
self, manager, mock_manager_interface):

a_context = Context()

assert manager.persistenceTokenForContext(a_context) == ""
mock_manager_interface.mock.persistenceTokenForState.assert_not_called()


class Test_Manager_contextFromPersistenceToken:

Expand All @@ -549,3 +570,10 @@ def test_when_called_then_the_managers_restored_state_is_set_in_the_context(

mock_manager_interface.mock.stateFromPersistenceToken.assert_called_once_with(
a_token, mock_host_session)

def test_when_empty_then_no_state_and_stateFromPersistenceToken_is_not_called(
self, manager, mock_manager_interface):

a_context = manager.contextFromPersistenceToken("")
assert a_context.managerState is None
mock_manager_interface.mock.stateFromPersistenceToken.assert_not_called()

0 comments on commit 6553bce

Please sign in to comment.