-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pass a UserClientSet into SDKMethodRunner #296
Conversation
UCS contains the clients that need to be instantiated on a per user basis. UCS is passed in to SDKMR to allow for eventual unit testing of SDKMR, since the UCS and workspace client can be mocked via create_autospec.
Huh. The failing tests were marked as failing immediately, and failing after [2, 8]m, even thought they couldn't have started yet |
lib/execution_engine2/constants.py
Outdated
@@ -0,0 +1,5 @@ | |||
''' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to pull the constants into a separate file to avoid an import cycle
return self._workspace_auth | ||
|
||
|
||
class ClientSet: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently unused, but is the next step in the unit-testability work
This pull request introduces 3 alerts when merging 5c01612 into 441293c - view on LGTM.com new alerts:
|
Also added pre-commit instructions
Surprised flake8 didn't highlight these
... a 1 line triple quoted comment unless the quotes are one the same line.
I see a fix I can make for the workspace-url check in the client set, give me a sec |
@bio-boris ok, all set, ready for re-review |
self._workspace = Workspace(ws_url, token=token) | ||
self._workspace_auth = WorkspaceAuth(user_id, self._workspace) | ||
|
||
# create_autospec can't mock instance variables, so we add some boilerplate |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems we just need to pass spec_set=True to magicmocks to achieve the same functionality as createautospec and then there is no need to create setters and getters for instance variables just for testing purposes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you verified that with a @patch
decorator with spec_set=True
that it detects instance variables? My understanding is that the spec_set
mocks can't see instance variables regardless of how the mock is created. I'll update the comment to that effect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, No, instance variables are not detected at all, so nevermind.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed getters, no longer needed
@@ -41,6 +42,10 @@ class execution_engine2: | |||
|
|||
ADMIN_ROLES_CACHE_SIZE = 500 | |||
ADMIN_ROLES_CACHE_EXPIRE_TIME = 300 # seconds | |||
|
|||
def get_user_clients(self, ctx) -> UserClientSet: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an advantage of having this here instead of inside the SDKMethodRunner?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, instantiating the client set outside of SDKMR is what allows for passing mock objects into SDKMR rather than monkey patching (although you can still do that if you want) and enables constructor-based dependency injection. The major change for this PR is exactly that - making the code that creates SDKMR responsible for the creation of SDKMR's dependencies rather than SDKMR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should have said inside the SDKMethodRunner file, defined outside of the SDKMethodRunner class, or moving this function to its own file. We should probably move out everything from the BEGIN_CLASS_HEADER section to its own file, as there are often issues with editing code in the impl file, and we have the common KBase pattern of doing as little as possible in the IMPL file itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see. I'll make an APIHelper class that holds a reference to the config so we don't have to pass it around all over place and put the method there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
self.auth_admin = AdminAuthUtil(auth_url, [ADMIN_READ_ROLE, ADMIN_WRITE_ROLE]) | ||
|
||
# KafkaClient has a nice error message when the arg is None | ||
self.kafka_client = KafkaClient(cfg.get("kafka-host")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should follow the fail fast with Keyerror way to handling dictionaries by doing the following
cfg['key'] == required value
cfg.get('key') == optionally None
cfg.get('key','default') == explicitly set default
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we wanted to do something like this the way it'd do it is something like:
if not cfg.get('key') or not cfg.get('key').strip():
raise ValueError('configuration is missing key "key"')
Just getting a KeyError("key") is not very helpful to someone trying to figure out why the service won't start, especially if they're not familiar with it.
I actually did use your first approach in cases where the client I was instantiating ignored missing arguments, although there could still be issues if the argument was whitespace or a bad url, etc. Where the clients had readable error messages (like Kafka and Slack) I went with those.
In most of my repos all the config args are checked for correctness, and urls used to make requests to the service and check the results, before the service starts. The checking is mostly delegated to the clients / objects that use them since they understand the semantics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add dict['key'] vs dict.get('') to the style guide at #303
# Could make these properties but then they return MagicMocks which don't update with API | ||
# changes | ||
|
||
def user_id(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems strange to do it this way. Are other kbase codebases doing it this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so. You only need to do this when you have a mock where you need to mock the instance variables, which doesn't happen all that often in my experience.
A better way to do this might be to make a constructor that takes a workspace client, user id, and token, and then you can just mock the workspace client and you don't need to mock the client set. I think I'll do that, then this becomes a non-issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did that, this is now moot, no more getters
# Regular User | ||
lowly_user = "Access Denied: You are not an administrator" | ||
runner = self.getRunner() | ||
ucs, wsa = self.get_mocks() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would help with readability to write out
user_client_set
and ws_auth
instead of these 3 letter variables names
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
Effectively makes it a value class which doesn't need to be mocked. Just pass mocks into the UCS instead.
Keeping as much code as possible out of the Impl file is good practice
I'm looking at my console right now, and I see a black run with no issues, and then the current black run with this problem. I don't understand why black didn't catch this the first time.
It's needed in a couple of places, most notably EE2RunJob
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created new issues, questions answered, LGTM
Travis CI should be deleted per Boris |
* Remove cruft.py (#279) I suspect it may contain some cruft. * Correct spec, improve documentation (#284) * Remove cruft.py I suspect it may contain some cruft. * Correct spec, improve documentation Corrected / improved spec and spec documentation for date range methods * Fix spec typo. Also clarify what needs to be done to run tests after making code changes * make WorkspaceAuth and authstrategy unit-testable (#288) * Remove cruft.py I suspect it may contain some cruft. * Correct spec, improve documentation Corrected / improved spec and spec documentation for date range methods * Fix spec typo. Also clarify what needs to be done to run tests after making code changes * make WorkspaceAuth and authstrategy unit-testable Inject dependencies so they can be mocked. * Fix flake8 * python formatting rules are stupid * more flake8 fixes really, flake8? really? * Make token and user id required for sdkmr (#294) Always provided, so no reason to be optional, and makes the code easier to understand. * pass a UserClientSet into SDKMethodRunner (#296) * pass a UserClientSet into SDKMethodRunner UCS contains the clients that need to be instantiated on a per user basis. UCS is passed in to SDKMR to allow for eventual unit testing of SDKMR, since the UCS and workspace client can be mocked via create_autospec * remove extraneous period Co-authored-by: MrCreosote <[email protected]> Co-authored-by: Gavin <[email protected]>
Description of PR purpose/changes
UCS contains the clients that need to be instantiated on a per user basis.
UCS is passed in to SDKMR to 1) simplify the SDKMR constructor, and 2) allow for eventual unit testing of SDKMR, since the UCS and workspace client can be mocked via create_autospec.
Also add instructions for running pre-commit hooks.
Jira Ticket / Github Issue
Testing Instructions
Dev Checklist:
Updating Version and Release Notes (if applicable)