-
Notifications
You must be signed in to change notification settings - Fork 263
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
PHPLIB-722: Ignore writeConcern option for read-only aggregations #1100
Conversation
Failing test:
Ignoring the mongo-php-library/src/Operation/Aggregate.php Lines 264 to 273 in 316d6d6
|
Can you try changing "rw" there to "r" and creating a second copy with an actual write stage (e.g. |
bb0ed0e
to
50533da
Compare
} | ||
); | ||
} | ||
|
||
/** @dataProvider collectionMethodClosures */ | ||
public function testMethodDoesNotInheritReadWriteConcernInTranasaction(Closure $method): void | ||
public function testMethodDoesNotInheritReadWriteConcernInTransaction(Closure $method): void |
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.
Fixed a typo
} catch (CommandException $exception) { | ||
// Write aggregates are not supported in transactions | ||
if ($exception->getResultDocument()->codeName === 'OperationNotSupportedInTransaction') { | ||
$this->markTestSkipped('OperationNotSupportedInTransaction: ' . $exception->getMessage()); |
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.
$out
and $merge
operators aren't supported in transaction. They throw a server error. I have a doubt on the best solution to exclude the new "read-write aggregate" method:
- This solution: skip the test in case of exception. But unlike tests skipped due to a temporary incompatiblity with the running environment, this test will never pass.
- Ignores the error and still run the assertions on command options. Even if that does not make sense to test a failing command. That could hide other errors and make debugging more difficult.
- exclude this case from the test cases by adding a
collectionTransactionMethodClosures
data provider and add a new chart
in$rw
to exclude methods incompatible with transactions.
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 solution: skip the test in case of exception. But unlike tests skipped due to a temporary incompatiblity with the running environment, this test will never pass.
Ignores the error and still run the assertions on command options. Even if that does not make sense to test a failing command. That could hide other errors and make debugging more difficult.
I don't think conditionally skipping the test makes sense, given that the test only cares about asserting that readConcern
and writeConcern
are omitted on the outgoing command.
Catching and ignoring OperationNotSupportedInTransaction
seems preferable. For consistency, I would suggest defining a private constant for its numeric code (263).
That said, I don't think that's a permanent solution. Read on.
- exclude this case from the test cases by adding a collectionTransactionMethodClosures data provider and add a new char t in $rw to exclude methods incompatible with transactions.
I don't think this is necessary. collectionMethodClosures()
already comments out various methods that cannot be run within a transaction. I was going to suggest removing all of those comments after adding logic to ignore OperationNotSupportedInTransaction, but then I realized that would only fix testMethodDoesNotInheritReadWriteConcernInTransaction
.
testMethodInTransactionWithWriteConcernOption
and testMethodInTransactionWithReadConcernOption
use derivative data providers that filter for strings containing "w" and "r", respectively. Those tests would never work with the unsupported operations because we never added logic to check for active transactions and throw UnsupportedException.
Aggregate is a special case because pipelines are generally supported in transactions and only write operators are unsupported.
With all of that in mind, I think the most sensible solution is removing the pipeline with a write stage and just leaving a comment above read-only pipeline to explain that we're intentionally not testing a pipeline with a write stage since those are unsupported.
That would mean we have no test coverage for the following logic near the top of Aggregate::execute()
:
if (isset($this->options['writeConcern'])) {
throw UnsupportedException::writeConcernNotSupportedInTransaction();
}
If you'd like to cover that, I'd suggest doing one of the following:
- Create a second data provider for
testMethodDoesNotInheritReadWriteConcernInTransaction()
that only includes the write pipeline. The test only takes one parameter so there'd be no reason to include "rw" in the data provider. This would still require modifying the test to catch and ignore OperationNotSupportedInTransaction errors. - Create a separate test similar to
testMethodDoesNotInheritReadWriteConcernInTransaction()
that tests Aggregate directly with the write pipeline. A doc block for that test would be a good opportunity to explain why we couldn't do this with the common data provider.
Alternatively, just remove the write pipeline and leave this untested. I'm not too concerned about doing so since we know this code path will lead to an exception anyway.
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.
You're right, there's no point in testing behavior on a command that's going to fail anyway.
@@ -447,16 +448,28 @@ public function testMapReduce(): void | |||
public function collectionMethodClosures() | |||
{ | |||
return [ | |||
[ | |||
'read-only aggregate' => [ |
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.
Debugging is simplified when the data provider uses names. Even more so because of the filter applied in collectionReadMethodClosures
and collectionWriteMethodClosures
.
if (strchr($rw[1], 'r') !== false) { | ||
return true; | ||
} | ||
return str_contains($rw[1], 'r'); |
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.
Small refactoring to use the PHP 8 function, provided by the polyfill for older versions.
function ($collection, $session, $options = []): void { | ||
$collection->aggregate( | ||
[['$match' => ['_id' => ['$lt' => 3]]]], | ||
['session' => $session] + $options | ||
); | ||
}, 'r', |
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 pipeline is actually read-only. I added a write pipeline as @jmikola recommended.
Fix PHPLIB-722
This does not change anything functionally, but cleanup
$options
in the constructor instead of picking thewriteOption
conditionally inexecuteCommand()
. There is no impact ongetCommandDocument()
which already ignoreswriteConcern
.