-
Notifications
You must be signed in to change notification settings - Fork 7
test: Add more integration tests #22
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
Conversation
Expand the existing test file from one happy path test to add tests for all sdk functionality.
Update doc strings for all methods to match what the tests say is the current behavior for raising errors.
|
|
||
| def test_create_cache_throws_exception_for_empty_cache_name(self): | ||
| with self.assertRaises(errors.CacheValueError): | ||
| self.client.create_cache("") |
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.
Was surprised that this was CacheValueError for create_cache("") when in the next test below it's InvalidInputError for create_cache(None)
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. This is pretty unfortunate. The custom 'None' check is needed to protect SDK from failing due to protobuf errors. The distinction between CacheValueError and InvalidInputError is that while the former is from the service while the later comes from the client.
| with self.assertRaises(errors.ClientSdkError) as cm: | ||
| self.client.create_cache(1) | ||
| self.assertEqual('{}'.format(cm.exception), | ||
| "Operation failed with error: 1 has type int, but expected one of: bytes, unicode") |
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.
Was surprised that create_cache(1) is a ClientSdkError rather than InvalidInputError.
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.
Type safety - it would be totally reasonable to add a bug that states the cache name check should ensure non- None string type.
For any unknown failures or conditions that SDK doesn't understand, we default to ClientSdkError.
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.
Opened #24
|
|
||
| def test_delete_cache_throws_exception_for_empty_cache_name(self): | ||
| with self.assertRaises(errors.CacheValueError): | ||
| self.client.delete_cache("") |
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.
Similarly here and the test above and below this: delete_cache("") is CacheValueError, delete_cache(None) is InvalidInputError, delete_cache(1) is ClientSdkError.
| cache_name = str(uuid.uuid4()) | ||
| with self.assertRaises(errors.PermissionError) as cm: | ||
| self.client.set("", "foo", "bar") | ||
| self.assertEqual('{}'.format(cm.exception), "Cache header is empty") |
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.
set with cache_name as "" throwing a PermissionError is IMO confusing as a user.
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.
Probably, may be worth opening a bug in cacheservice/ -
https://github.com/momentohq/cacheservice/blob/main/kotlin/mr2/src/main/kotlin/cacheservice/mr2/UserHeaderServerInterceptor.kt#L163-L166
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.
| with self.assertRaises(errors.ClientSdkError) as cm: | ||
| self.client.set(1, "foo", "bar") | ||
| self.assertEqual('{}'.format(cm.exception), | ||
| "Operation failed with error: Expected str, not <class 'int'>") |
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.
Another case where an integer cache_name raises ClientSdkError, but empty string or None raises InvalidInputError.
| with self.assertRaises(errors.ClientSdkError) as cm: | ||
| self.client.get(1, "foo") | ||
| self.assertEqual('{}'.format(cm.exception), | ||
| "Operation failed with error: Expected str, not <class 'int'>") |
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.
Another case where an integer cache_name raises ClientSdkError, but empty string or None raises InvalidInputError.
| cache_name = str(uuid.uuid4()) | ||
| with self.assertRaises(errors.PermissionError) as cm: | ||
| self.client.get("", "foo") | ||
| self.assertEqual('{}'.format(cm.exception), "Cache header is empty") |
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 find get with cache_name as "" throwing a PermissionError confusing as a user.
gautamomento
left a comment
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.
Thank you @rlinehan - this is great.
You have identified a pattern in our SDK side input checks. The way these validations are written always expect users to provide a correct type. Then when users don't, we end up sending a generic ClientSdkException.
I see two ways to handle this:
- Embed type-safety checks in our custom validations
- When we wrap unknown exceptions - also send include the root exception
I think we should file these bugs and make improvements.
|
|
||
| def test_create_cache_throws_exception_for_empty_cache_name(self): | ||
| with self.assertRaises(errors.CacheValueError): | ||
| self.client.create_cache("") |
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. This is pretty unfortunate. The custom 'None' check is needed to protect SDK from failing due to protobuf errors. The distinction between CacheValueError and InvalidInputError is that while the former is from the service while the later comes from the client.
| with self.assertRaises(errors.ClientSdkError) as cm: | ||
| self.client.create_cache(1) | ||
| self.assertEqual('{}'.format(cm.exception), | ||
| "Operation failed with error: 1 has type int, but expected one of: bytes, unicode") |
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.
Type safety - it would be totally reasonable to add a bug that states the cache name check should ensure non- None string type.
For any unknown failures or conditions that SDK doesn't understand, we default to ClientSdkError.
| cache_name = str(uuid.uuid4()) | ||
| with self.assertRaises(errors.PermissionError) as cm: | ||
| self.client.set("", "foo", "bar") | ||
| self.assertEqual('{}'.format(cm.exception), "Cache header is empty") |
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.
Probably, may be worth opening a bug in cacheservice/ -
https://github.com/momentohq/cacheservice/blob/main/kotlin/mr2/src/main/kotlin/cacheservice/mr2/UserHeaderServerInterceptor.kt#L163-L166
This name was derived from in-built |
Opened #23 for this |
Closes #3.
Flesh out integration tests to add full coverage for all public methods.
A few notes:
1.
ClientSdkErroris raised when cache name is an invalid type (e.g. an integer)However,
InvalidInputErroris raised for most other situations where cache name, key, or value is not a non-empty string. I would think this should be anInvalidInputErrortoo?2. The only place
CacheValueErrorseems to be used is ifcreate_cacheordelete_cacheis called with an empty string ascache_nameThe name
CacheValueErrorfeels like something should be wrong with the value being cached on aset, not with the cache name? It's also confusing because if the cache name isNonein these cases then the error isInvalidInputErrorand (as noted above) if it's an integer then it'sClientSdkError. It would be more intuitive to me if all of these caused the same type of error.3. If the cache name is empty string on
getorsetthen aPermissionErroris thrown withCache header is empty.I think this is coming from the grpc server, but that doesn't feel like the right error, especially since it's not the same error that's thrown for other operations with an empty string for cache name (although as noted in 2 above, I don't think
CacheValueErroris really correct either).I left comments inline about these cases too. I don't think these need to be fixed/changed in this PR necessarily, but wanted to at least note what I found unexpected.