CollectionFunctionalTest.php 9.34 KB
Newer Older
1 2 3 4
<?php

namespace MongoDB\Tests\Collection;

5
use MongoDB\BSON\Javascript;
6
use MongoDB\Collection;
7
use MongoDB\Driver\BulkWrite;
8
use MongoDB\Driver\ReadConcern;
9 10
use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\WriteConcern;
11
use MongoDB\Exception\InvalidArgumentException;
12
use MongoDB\Operation\Count;
13
use MongoDB\Operation\MapReduce;
14 15
use MongoDB\Tests\CommandObserver;
use stdClass;
16

17 18 19 20 21
/**
 * Functional tests for the Collection class.
 */
class CollectionFunctionalTest extends FunctionalTestCase
{
22
    /**
23
     * @dataProvider provideInvalidDatabaseAndCollectionNames
24
     */
25
    public function testConstructorDatabaseNameArgument($databaseName)
26
    {
27
        $this->expectException(InvalidArgumentException::class);
28
        // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378)
29
        new Collection($this->manager, $databaseName, $this->getCollectionName());
30 31
    }

32 33 34 35 36
    /**
     * @dataProvider provideInvalidDatabaseAndCollectionNames
     */
    public function testConstructorCollectionNameArgument($collectionName)
    {
37
        $this->expectException(InvalidArgumentException::class);
38 39 40 41 42
        // TODO: Move to unit test once ManagerInterface can be mocked (PHPC-378)
        new Collection($this->manager, $this->getDatabaseName(), $collectionName);
    }

    public function provideInvalidDatabaseAndCollectionNames()
43
    {
Jeremy Mikola's avatar
Jeremy Mikola committed
44 45 46 47
        return [
            [null],
            [''],
        ];
48 49
    }

50 51 52 53 54
    /**
     * @dataProvider provideInvalidConstructorOptions
     */
    public function testConstructorOptionTypeChecks(array $options)
    {
55
        $this->expectException(InvalidArgumentException::class);
56
        new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $options);
57 58 59 60 61 62
    }

    public function provideInvalidConstructorOptions()
    {
        $options = [];

63 64 65 66
        foreach ($this->getInvalidReadConcernValues() as $value) {
            $options[][] = ['readConcern' => $value];
        }

67 68 69 70
        foreach ($this->getInvalidReadPreferenceValues() as $value) {
            $options[][] = ['readPreference' => $value];
        }

71 72 73 74
        foreach ($this->getInvalidArrayValues() as $value) {
            $options[][] = ['typeMap' => $value];
        }

75 76 77 78 79 80 81
        foreach ($this->getInvalidWriteConcernValues() as $value) {
            $options[][] = ['writeConcern' => $value];
        }

        return $options;
    }

82 83 84 85 86
    public function testGetManager()
    {
        $this->assertSame($this->manager, $this->collection->getManager());
    }

87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
    public function testToString()
    {
        $this->assertEquals($this->getNamespace(), (string) $this->collection);
    }

    public function getGetCollectionName()
    {
        $this->assertEquals($this->getCollectionName(), $this->collection->getCollectionName());
    }

    public function getGetDatabaseName()
    {
        $this->assertEquals($this->getDatabaseName(), $this->collection->getDatabaseName());
    }

    public function testGetNamespace()
    {
        $this->assertEquals($this->getNamespace(), $this->collection->getNamespace());
    }

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
    public function testCreateIndexSplitsCommandOptions()
    {
        if (version_compare($this->getServerVersion(), '3.6.0', '<')) {
            $this->markTestSkipped('Sessions are not supported');
        }

        (new CommandObserver)->observe(
            function() {
                $this->collection->createIndex(
                    ['x' => 1],
                    [
                        'maxTimeMS' => 1000,
                        'session' => $this->manager->startSession(),
                        'sparse' => true,
                        'unique' => true,
                        'writeConcern' => new WriteConcern(1),
                    ]
                );
            },
126 127
            function(array $event) {
                $command = $event['started']->getCommand();
128 129 130 131 132 133 134 135 136
                $this->assertObjectHasAttribute('lsid', $command);
                $this->assertObjectHasAttribute('maxTimeMS', $command);
                $this->assertObjectHasAttribute('writeConcern', $command);
                $this->assertObjectHasAttribute('sparse', $command->indexes[0]);
                $this->assertObjectHasAttribute('unique', $command->indexes[0]);
            }
        );
    }

137 138
    public function testDrop()
    {
Jeremy Mikola's avatar
Jeremy Mikola committed
139
        $writeResult = $this->collection->insertOne(['x' => 1]);
140 141 142 143 144 145
        $this->assertEquals(1, $writeResult->getInsertedCount());

        $commandResult = $this->collection->drop();
        $this->assertCommandSucceeded($commandResult);
        $this->assertCollectionCount($this->getNamespace(), 0);
    }
146

147 148 149 150 151
    /**
     * @todo Move this to a unit test once Manager can be mocked
     */
    public function testDropIndexShouldNotAllowWildcardCharacter()
    {
152
        $this->expectException(InvalidArgumentException::class);
153 154 155
        $this->collection->dropIndex('*');
    }

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    public function testExplain()
    {
        if (version_compare($this->getServerVersion(), '3.0.0', '<')) {
            $this->markTestSkipped('Explain command is not supported');
        }

        $this->createFixtures(3);

        $operation = new Count($this->getDatabaseName(), $this->getCollectionName(), ['x' => ['$gte' => 1]], []);

        $result = $this->collection->explain($operation);

        $this->assertArrayHasKey('queryPlanner', $result);
    }

171 172 173 174
    public function testFindOne()
    {
        $this->createFixtures(5);

Jeremy Mikola's avatar
Jeremy Mikola committed
175 176
        $filter = ['_id' => ['$lt' => 5]];
        $options = [
177
            'skip' => 1,
Jeremy Mikola's avatar
Jeremy Mikola committed
178 179
            'sort' => ['x' => -1],
        ];
180

181
        $expected = ['_id' => 3, 'x' => 33];
182

183
        $this->assertSameDocument($expected, $this->collection->findOne($filter, $options));
184 185
    }

186
    public function testWithOptionsInheritsOptions()
187 188
    {
        $collectionOptions = [
189
            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
190
            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
191
            'typeMap' => ['root' => 'array'],
192 193 194
            'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
        ];

195
        $collection = new Collection($this->manager, $this->getDatabaseName(), $this->getCollectionName(), $collectionOptions);
196 197 198
        $clone = $collection->withOptions();
        $debug = $clone->__debugInfo();

199 200 201
        $this->assertSame($this->manager, $debug['manager']);
        $this->assertSame($this->getDatabaseName(), $debug['databaseName']);
        $this->assertSame($this->getCollectionName(), $debug['collectionName']);
202 203
        $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']);
        $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
204 205
        $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']);
        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
206 207
        $this->assertInternalType('array', $debug['typeMap']);
        $this->assertSame(['root' => 'array'], $debug['typeMap']);
208 209 210 211
        $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']);
        $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW());
    }

212
    public function testWithOptionsPassesOptions()
213 214
    {
        $collectionOptions = [
215
            'readConcern' => new ReadConcern(ReadConcern::LOCAL),
216
            'readPreference' => new ReadPreference(ReadPreference::RP_SECONDARY_PREFERRED),
217
            'typeMap' => ['root' => 'array'],
218 219 220 221 222 223
            'writeConcern' => new WriteConcern(WriteConcern::MAJORITY),
        ];

        $clone = $this->collection->withOptions($collectionOptions);
        $debug = $clone->__debugInfo();

224 225
        $this->assertInstanceOf('MongoDB\Driver\ReadConcern', $debug['readConcern']);
        $this->assertSame(ReadConcern::LOCAL, $debug['readConcern']->getLevel());
226 227
        $this->assertInstanceOf('MongoDB\Driver\ReadPreference', $debug['readPreference']);
        $this->assertSame(ReadPreference::RP_SECONDARY_PREFERRED, $debug['readPreference']->getMode());
228 229
        $this->assertInternalType('array', $debug['typeMap']);
        $this->assertSame(['root' => 'array'], $debug['typeMap']);
230 231 232 233
        $this->assertInstanceOf('MongoDB\Driver\WriteConcern', $debug['writeConcern']);
        $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW());
    }

234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
    public function testMapReduce()
    {
        $this->createFixtures(3);

        $map = new Javascript('function() { emit(1, this.x); }');
        $reduce = new Javascript('function(key, values) { return Array.sum(values); }');
        $out = ['inline' => 1];

        $result = $this->collection->mapReduce($map, $reduce, $out);

        $this->assertInstanceOf('MongoDB\MapReduceResult', $result);
        $expected = [
            [ '_id' => 1.0, 'value' => 66.0 ],
        ];

        $this->assertSameDocuments($expected, $result);

        $this->assertGreaterThanOrEqual(0, $result->getExecutionTimeMS());
        $this->assertNotEmpty($result->getCounts());
    }

255 256 257 258 259 260 261
    /**
     * Create data fixtures.
     *
     * @param integer $n
     */
    private function createFixtures($n)
    {
262
        $bulkWrite = new BulkWrite(['ordered' => true]);
263 264

        for ($i = 1; $i <= $n; $i++) {
Jeremy Mikola's avatar
Jeremy Mikola committed
265
            $bulkWrite->insert([
266 267
                '_id' => $i,
                'x' => (integer) ($i . $i),
Jeremy Mikola's avatar
Jeremy Mikola committed
268
            ]);
269 270 271 272 273 274
        }

        $result = $this->manager->executeBulkWrite($this->getNamespace(), $bulkWrite);

        $this->assertEquals($n, $result->getInsertedCount());
    }
275
}