Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 4608a73

Browse files
jmikolaalcaeus
andauthored
PHPLIB-493: Unified test runner POC (#783)
* Reduce isShardedCluster to a one-liner * wip * wip * wip * wip * Clean up constraints and add test coverage * Code fixes and fall back to assertInternalType for PHPUnit 6.x * phpcs fixes * Use Matches for CollectionData and validate operator syntax * Fix var usage * Fix static method call and allow empty string in $$matchesHexBytes * CS fixes * Include PHPUnit functions via autoload-dev * CR feedback * IsBsonType helpers and new IsStream constraint * Changes to get CRUD POC tests running * Implement expectEvents and change stream tests * Implement GridFS, transactions, and collate events by client * Remove stream entities and update GridFS operations * Todo items for Matches constraint * Assert basic structure of test files in data provider * Use assertion for testFailingTests * Implement session tests * Consider PHPUnit Warnings for expectError in GridFS tests * Disable fail points after tests * Fix targetedFailPoint operation * Fix MatchesTest and make EntityMap optional * Note cycling references and killAllSessions before each test * Sync unified spec tests * Fix phpcs validation * assertHasOnlyKeys requires array or stdClass * Add missing valid-fail test * Fix phpcs error * Remove nullable return type hint for PHP 7.0 * Update session test * Sync returnDocument-enum-invalid.json * Handle issues from code review * fix phpcs * fix tests * Fix wrong continue statement * Handle readPreferenceTags in URI options Co-authored-by: Andreas Braun <git@alcaeus.org>
1 parent 10b578f commit 4608a73

34 files changed

+7959
-7
lines changed

‎composer.json‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"jean85/pretty-package-versions": "^1.2"
1717
},
1818
"require-dev": {
19-
"phpunit/phpunit": "^6.4",
19+
"phpunit/phpunit": "^6.5",
2020
"sebastian/comparator": "^2.0 || ^3.0",
2121
"squizlabs/php_codesniffer": "^3.5, <3.5.5",
2222
"symfony/phpunit-bridge": "^4.4@dev"
@@ -26,7 +26,10 @@
2626
"files": [ "src/functions.php" ]
2727
},
2828
"autoload-dev": {
29-
"psr-4": { "MongoDB\\Tests\\": "tests/" }
29+
"psr-4": { "MongoDB\\Tests\\": "tests/" },
30+
"// Manually include assertion functions for PHPUnit 8.x and earlier ":"",
31+
"// See: https://github.com/sebastianbergmann/phpunit/issues/3746 ":"",
32+
"files": [ "vendor/phpunit/phpunit/src/Framework/Assert/Functions.php" ]
3033
},
3134
"extra": {
3235
"branch-alias": {

‎tests/FunctionalTestCase.php‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -308,11 +308,7 @@ protected function isReplicaSet()
308308

309309
protected function isShardedCluster()
310310
{
311-
if ($this->getPrimaryServer()->getType() == Server::TYPE_MONGOS) {
312-
return true;
313-
}
314-
315-
return false;
311+
return $this->getPrimaryServer()->getType() == Server::TYPE_MONGOS;
316312
}
317313

318314
protected function isShardedClusterUsingReplicasets()
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\UnifiedSpecTests;
4+
5+
use ArrayIterator;
6+
use IteratorIterator;
7+
use MongoDB\Client;
8+
use MongoDB\Driver\ReadConcern;
9+
use MongoDB\Driver\ReadPreference;
10+
use MongoDB\Driver\WriteConcern;
11+
use MongoDB\Tests\UnifiedSpecTests\Constraint\Matches;
12+
use MultipleIterator;
13+
use stdClass;
14+
use function assertContainsOnly;
15+
use function assertInternalType;
16+
use function assertNotNull;
17+
use function assertThat;
18+
use function sprintf;
19+
20+
class CollectionData
21+
{
22+
/** @var string */
23+
private $collectionName;
24+
25+
/** @var string */
26+
private $databaseName;
27+
28+
/** @var array */
29+
private $documents;
30+
31+
public function __construct(stdClass $o)
32+
{
33+
assertInternalType('string', $o->collectionName);
34+
$this->collectionName = $o->collectionName;
35+
36+
assertInternalType('string', $o->databaseName);
37+
$this->databaseName = $o->databaseName;
38+
39+
assertInternalType('array', $o->documents);
40+
assertContainsOnly('object', $o->documents);
41+
$this->documents = $o->documents;
42+
}
43+
44+
public function prepareInitialData(Client $client)
45+
{
46+
$database = $client->selectDatabase(
47+
$this->databaseName,
48+
['writeConcern' => new WriteConcern(WriteConcern::MAJORITY)]
49+
);
50+
51+
$database->dropCollection($this->collectionName);
52+
53+
if (empty($this->documents)) {
54+
$database->createCollection($this->collectionName);
55+
56+
return;
57+
}
58+
59+
$database->selectCollection($this->collectionName)->insertMany($this->documents);
60+
}
61+
62+
public function assertOutcome(Client $client)
63+
{
64+
$collection = $client->selectCollection(
65+
$this->databaseName,
66+
$this->collectionName,
67+
[
68+
'readConcern' => new ReadConcern(ReadConcern::LOCAL),
69+
'readPreference' => new ReadPreference(ReadPreference::PRIMARY),
70+
]
71+
);
72+
73+
$cursor = $collection->find([], ['sort' => ['_id' => 1]]);
74+
75+
$mi = new MultipleIterator(MultipleIterator::MIT_NEED_ANY);
76+
$mi->attachIterator(new ArrayIterator($this->documents));
77+
$mi->attachIterator(new IteratorIterator($cursor));
78+
79+
foreach ($mi as $i => $documents) {
80+
list($expectedDocument, $actualDocument) = $documents;
81+
assertNotNull($expectedDocument);
82+
assertNotNull($actualDocument);
83+
84+
/* Prohibit extra root keys and disable operators to enforce exact
85+
* matching of documents. Key order variation is still allowed. */
86+
$constraint = new Matches($expectedDocument, null, false, false);
87+
assertThat($actualDocument, $constraint, sprintf('documents[%d] match', $i));
88+
}
89+
}
90+
}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
<?php
2+
3+
namespace MongoDB\Tests\UnifiedSpecTests\Constraint;
4+
5+
use LogicException;
6+
use MongoDB\BSON\BinaryInterface;
7+
use MongoDB\BSON\DBPointer;
8+
use MongoDB\BSON\Decimal128Interface;
9+
use MongoDB\BSON\Int64;
10+
use MongoDB\BSON\JavascriptInterface;
11+
use MongoDB\BSON\MaxKeyInterface;
12+
use MongoDB\BSON\MinKeyInterface;
13+
use MongoDB\BSON\ObjectIdInterface;
14+
use MongoDB\BSON\RegexInterface;
15+
use MongoDB\BSON\Serializable;
16+
use MongoDB\BSON\Symbol;
17+
use MongoDB\BSON\TimestampInterface;
18+
use MongoDB\BSON\Type;
19+
use MongoDB\BSON\Undefined;
20+
use MongoDB\BSON\UTCDateTimeInterface;
21+
use MongoDB\Model\BSONArray;
22+
use MongoDB\Model\BSONDocument;
23+
use PHPUnit\Framework\Constraint\Constraint;
24+
use PHPUnit\Framework\Constraint\LogicalOr;
25+
use RuntimeException;
26+
use Symfony\Bridge\PhpUnit\ConstraintTrait;
27+
use function array_keys;
28+
use function array_map;
29+
use function count;
30+
use function in_array;
31+
use function is_array;
32+
use function is_bool;
33+
use function is_float;
34+
use function is_int;
35+
use function is_object;
36+
use function is_string;
37+
use function range;
38+
use function sprintf;
39+
use const PHP_INT_SIZE;
40+
41+
final class IsBsonType extends Constraint
42+
{
43+
use ConstraintTrait;
44+
45+
/** @var array */
46+
private static $types = [
47+
'double',
48+
'string',
49+
'object',
50+
'array',
51+
'binData',
52+
'undefined',
53+
'objectId',
54+
'bool',
55+
'date',
56+
'null',
57+
'regex',
58+
'dbPointer',
59+
'javascript',
60+
'symbol',
61+
'javascriptWithScope',
62+
'int',
63+
'timestamp',
64+
'long',
65+
'decimal',
66+
'minKey',
67+
'maxKey',
68+
];
69+
70+
/** @var string */
71+
private $type;
72+
73+
public function __construct(string $type)
74+
{
75+
if (! in_array($type, self::$types)) {
76+
throw new RuntimeException(sprintf('Type specified for %s <%s> is not a valid type', self::class, $type));
77+
}
78+
79+
$this->type = $type;
80+
}
81+
82+
public static function any() : LogicalOr
83+
{
84+
return self::anyOf(...self::$types);
85+
}
86+
87+
public static function anyOf(string ...$types) : Constraint
88+
{
89+
if (count($types) === 1) {
90+
return new self(...$types);
91+
}
92+
93+
return LogicalOr::fromConstraints(...array_map(function ($type) {
94+
return new self($type);
95+
}, $types));
96+
}
97+
98+
private function doMatches($other) : bool
99+
{
100+
switch ($this->type) {
101+
case 'double':
102+
return is_float($other);
103+
case 'string':
104+
return is_string($other);
105+
case 'object':
106+
return self::isObject($other);
107+
case 'array':
108+
return self::isArray($other);
109+
case 'binData':
110+
return $other instanceof BinaryInterface;
111+
case 'undefined':
112+
return $other instanceof Undefined;
113+
case 'objectId':
114+
return $other instanceof ObjectIdInterface;
115+
case 'bool':
116+
return is_bool($other);
117+
case 'date':
118+
return $other instanceof UTCDateTimeInterface;
119+
case 'null':
120+
return $other === null;
121+
case 'regex':
122+
return $other instanceof RegexInterface;
123+
case 'dbPointer':
124+
return $other instanceof DBPointer;
125+
case 'javascript':
126+
return $other instanceof JavascriptInterface && $other->getScope() === null;
127+
case 'symbol':
128+
return $other instanceof Symbol;
129+
case 'javascriptWithScope':
130+
return $other instanceof JavascriptInterface && $other->getScope() !== null;
131+
case 'int':
132+
return is_int($other);
133+
case 'timestamp':
134+
return $other instanceof TimestampInterface;
135+
case 'long':
136+
if (PHP_INT_SIZE == 4) {
137+
return $other instanceof Int64;
138+
}
139+
140+
return is_int($other);
141+
case 'decimal':
142+
return $other instanceof Decimal128Interface;
143+
case 'minKey':
144+
return $other instanceof MinKeyInterface;
145+
case 'maxKey':
146+
return $other instanceof MaxKeyInterface;
147+
default:
148+
// This should already have been caught in the constructor
149+
throw new LogicException('Unsupported type: ' . $this->type);
150+
}
151+
}
152+
153+
private function doToString() : string
154+
{
155+
return sprintf('is of BSON type "%s"', $this->type);
156+
}
157+
158+
private static function isArray($other) : bool
159+
{
160+
if ($other instanceof BSONArray) {
161+
return true;
162+
}
163+
164+
// Serializable can produce an array or object, so recurse on its output
165+
if ($other instanceof Serializable) {
166+
return self::isArray($other->bsonSerialize());
167+
}
168+
169+
if (! is_array($other)) {
170+
return false;
171+
}
172+
173+
// Empty and indexed arrays serialize as BSON arrays
174+
return self::isArrayEmptyOrIndexed($other);
175+
}
176+
177+
private static function isObject($other) : bool
178+
{
179+
if ($other instanceof BSONDocument) {
180+
return true;
181+
}
182+
183+
// Serializable can produce an array or object, so recurse on its output
184+
if ($other instanceof Serializable) {
185+
return self::isObject($other->bsonSerialize());
186+
}
187+
188+
// Non-empty, associative arrays serialize as BSON objects
189+
if (is_array($other)) {
190+
return ! self::isArrayEmptyOrIndexed($other);
191+
}
192+
193+
if (! is_object($other)) {
194+
return false;
195+
}
196+
197+
/* Serializable has already been handled, so any remaining instances of
198+
* Type will not serialize as BSON objects */
199+
return ! $other instanceof Type;
200+
}
201+
202+
private static function isArrayEmptyOrIndexed(array $a) : bool
203+
{
204+
if (empty($a)) {
205+
return true;
206+
}
207+
208+
return array_keys($a) === range(0, count($a) - 1);
209+
}
210+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /