From 10a1b3a552d7aab8b13609dbae382087b55a79c8 Mon Sep 17 00:00:00 2001 From: Yash Sahu <54198301+yash30201@users.noreply.github.com> Date: Wed, 8 May 2024 18:51:34 +0530 Subject: [PATCH 1/3] feat!(Firestore): Part 1 of Upgrade Firestore V2 (#7298) * Add Gapic client config * Add credentials wrapper support. * Add root serializer and request handler * Update resource classes to add serializer and request handler * Add serializer and request handler support in all the snippet and unit tests * Update core's version to a future non existent version --- Core/src/Testing/FirestoreTestHelperTrait.php | 59 ++++++++++++ Firestore/composer.json | 2 +- Firestore/src/AggregateQuery.php | 19 ++++ Firestore/src/BulkWriter.php | 41 ++++++-- Firestore/src/CollectionReference.php | 42 +++++++- Firestore/src/DocumentReference.php | 46 ++++++++- Firestore/src/FirestoreClient.php | 96 ++++++++++++++++++- Firestore/src/FirestoreSessionHandler.php | 32 +++++++ Firestore/src/Query.php | 31 ++++++ Firestore/src/SnapshotTrait.php | 59 +++++++++++- Firestore/src/Transaction.php | 41 +++++++- Firestore/src/ValueMapper.php | 50 ++++++++-- Firestore/tests/Snippet/BulkWriterTest.php | 20 +++- .../tests/Snippet/CollectionReferenceTest.php | 31 +++++- .../tests/Snippet/DocumentReferenceTest.php | 22 ++++- .../tests/Snippet/DocumentSnapshotTest.php | 14 ++- Firestore/tests/Snippet/FieldValueTest.php | 7 ++ Firestore/tests/Snippet/FilterTest.php | 20 +++- .../tests/Snippet/FirestoreClientTest.php | 7 ++ .../Snippet/FirestoreSessionHandlerTest.php | 7 ++ Firestore/tests/Snippet/QuerySnapshotTest.php | 7 ++ Firestore/tests/Snippet/QueryTest.php | 49 ++++++++-- Firestore/tests/Snippet/TransactionTest.php | 79 +++++++++++---- Firestore/tests/Snippet/WriteBatchTest.php | 22 ++++- Firestore/tests/System/BulkWriterTest.php | 13 ++- Firestore/tests/Unit/AggregateQueryTest.php | 22 ++++- Firestore/tests/Unit/BulkWriterTest.php | 60 ++++++++++-- .../tests/Unit/CollectionReferenceTest.php | 43 +++++++-- Firestore/tests/Unit/ConformanceTest.php | 9 ++ .../tests/Unit/DocumentReferenceTest.php | 32 +++++-- Firestore/tests/Unit/DocumentSnapshotTest.php | 16 +++- Firestore/tests/Unit/FirestoreClientTest.php | 7 ++ .../Unit/FirestoreSessionHandlerTest.php | 35 +++++++ Firestore/tests/Unit/QuerySnapshotTest.php | 4 +- Firestore/tests/Unit/QueryTest.php | 90 +++++++++++------ Firestore/tests/Unit/SnapshotTraitTest.php | 32 ++++++- Firestore/tests/Unit/TransactionTest.php | 41 ++++++-- Firestore/tests/Unit/ValueMapperTest.php | 11 ++- Firestore/tests/Unit/WriteBatchTest.php | 26 +++-- 39 files changed, 1086 insertions(+), 158 deletions(-) create mode 100644 Core/src/Testing/FirestoreTestHelperTrait.php diff --git a/Core/src/Testing/FirestoreTestHelperTrait.php b/Core/src/Testing/FirestoreTestHelperTrait.php new file mode 100644 index 00000000000..eac29fe50e4 --- /dev/null +++ b/Core/src/Testing/FirestoreTestHelperTrait.php @@ -0,0 +1,59 @@ + function ($v) { + return $this->flattenValue($v); + }, + 'google.protobuf.ListValue' => function ($v) { + return $this->flattenListValue($v); + }, + 'google.protobuf.Struct' => function ($v) { + return $this->flattenStruct($v); + }, + 'google.protobuf.Timestamp' => function ($v) { + return $this->formatTimestampFromApi($v); + }, + ], [], [ + 'google.protobuf.Int32Value' => function ($v) { + return ['value' => $v]; + } + ]); + } + + return self::$_serializer; + } +} diff --git a/Firestore/composer.json b/Firestore/composer.json index f5b2a2ae379..347284b4137 100644 --- a/Firestore/composer.json +++ b/Firestore/composer.json @@ -6,7 +6,7 @@ "require": { "php": "^8.0", "ext-grpc": "*", - "google/cloud-core": "^1.52.7", + "google/cloud-core": "^1.60", "google/gax": "^1.30", "ramsey/uuid": "^3.0|^4.0" }, diff --git a/Firestore/src/AggregateQuery.php b/Firestore/src/AggregateQuery.php index 79a5aeb7286..55f8d15554a 100644 --- a/Firestore/src/AggregateQuery.php +++ b/Firestore/src/AggregateQuery.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\QueryTrait; @@ -43,6 +45,16 @@ class AggregateQuery */ private $connection; + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var array */ @@ -64,17 +76,24 @@ class AggregateQuery * @param ConnectionInterface $connection A Connection to Cloud Firestore. * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param string $parent The parent of the query. * @param array $query Represents the underlying structured query. * @param Aggregate $aggregate Aggregation over the provided query. */ public function __construct( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, $parent, array $query, Aggregate $aggregate ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->parentName = $parent; $this->query = $query; $this->aggregates[] = $aggregate; diff --git a/Firestore/src/BulkWriter.php b/Firestore/src/BulkWriter.php index cd0af73888f..896650e99a2 100644 --- a/Firestore/src/BulkWriter.php +++ b/Firestore/src/BulkWriter.php @@ -17,8 +17,10 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; use Google\Cloud\Core\ArrayTrait; use Google\Cloud\Core\DebugInfoTrait; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Core\ValidateTrait; @@ -52,11 +54,11 @@ class BulkWriter use TimeTrait; use ValidateTrait; - const TYPE_UPDATE = 'update'; - const TYPE_SET = 'set'; - const TYPE_CREATE = 'create'; - const TYPE_DELETE = 'delete'; - const TYPE_TRANSFORM = 'transform'; + public const TYPE_UPDATE = 'update'; + public const TYPE_SET = 'set'; + public const TYPE_CREATE = 'create'; + public const TYPE_DELETE = 'delete'; + public const TYPE_TRANSFORM = 'transform'; /** * @var array Holds default configurations for Bulkwriter. @@ -121,6 +123,16 @@ class BulkWriter */ private $connection; + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var ValueMapper */ @@ -210,6 +222,9 @@ class BulkWriter * @param ConnectionInterface $connection A connection to Cloud Firestore * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $valueMapper A Value Mapper instance * @param string $database The current database * @param array $options [optional] { @@ -238,9 +253,17 @@ class BulkWriter * true if retryable. * } */ - public function __construct(ConnectionInterface $connection, $valueMapper, $database, $options = null) - { + public function __construct( + ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, + $valueMapper, + $database, + $options = null + ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->valueMapper = $valueMapper; $this->database = $database; $this->closed = false; @@ -1132,14 +1155,14 @@ private function createDatabaseWriteOperation($type, $document, array $options = ]; break; - // @codeCoverageIgnoreStart + // @codeCoverageIgnoreStart default: throw new \InvalidArgumentException(sprintf( 'Write operation type `%s is not valid. Allowed values are update, delete, verify, transform.', $type )); break; - // @codeCoverageIgnoreEnd + // @codeCoverageIgnoreEnd } } diff --git a/Firestore/src/CollectionReference.php b/Firestore/src/CollectionReference.php index c0d157f4145..6279d52eb84 100644 --- a/Firestore/src/CollectionReference.php +++ b/Firestore/src/CollectionReference.php @@ -17,10 +17,12 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; use Google\Cloud\Core\ArrayTrait; use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\Iterator\ItemIterator; use Google\Cloud\Core\Iterator\PageIterator; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\TimestampTrait; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -52,6 +54,16 @@ class CollectionReference extends Query */ private $connection; + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var ValueMapper */ @@ -71,20 +83,29 @@ class CollectionReference extends Query * @param ConnectionInterface $connection A Connection to Cloud Firestore. * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $valueMapper A Firestore Value Mapper. * @param string $name The absolute name of the collection. */ public function __construct( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $valueMapper, $name ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->valueMapper = $valueMapper; $this->name = $name; parent::__construct( $connection, + $requestHandler, + $serializer, $valueMapper, $this->parentPath($this->name), [ @@ -281,6 +302,18 @@ function ($document) { return $this->documentFactory($document['name']); }, [$this->connection, 'listDocuments'], + // function ($callOptions) use ($optionalArgs, $request) { + // if (isset($callOptions['pageToken'])) { + // $request->setPageToken($callOptions['pageToken']); + // } + + // return $this->requestHandler->sendRequest( + // FirestoreClient::class, + // 'listDocuments', + // $request, + // $optionalArgs + // ); + // }, $options, [ 'itemsKey' => 'documents', @@ -319,6 +352,13 @@ public function parent() */ private function documentFactory($name) { - return new DocumentReference($this->connection, $this->valueMapper, $this, $name); + return new DocumentReference( + $this->connection, + $this->requestHandler, + $this->serializer, + $this->valueMapper, + $this, + $name + ); } } diff --git a/Firestore/src/DocumentReference.php b/Firestore/src/DocumentReference.php index 843e73916ee..6eae4355364 100644 --- a/Firestore/src/DocumentReference.php +++ b/Firestore/src/DocumentReference.php @@ -17,9 +17,11 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\Iterator\ItemIterator; use Google\Cloud\Core\Iterator\PageIterator; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Firestore\Connection\ConnectionInterface; /** @@ -44,6 +46,16 @@ class DocumentReference */ private $connection; + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var ValueMapper */ @@ -63,17 +75,24 @@ class DocumentReference * @param ConnectionInterface $connection A Connection to Cloud Firestore. * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $valueMapper A Firestore Value Mapper. * @param CollectionReference $parent The collection in which this document is contained. * @param string $name The fully-qualified document name. */ public function __construct( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $valueMapper, CollectionReference $parent, $name ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->valueMapper = $valueMapper; $this->parent = $parent; $this->name = $name; @@ -347,7 +366,14 @@ public function delete(array $options = []) */ public function snapshot(array $options = []) { - return $this->createSnapshot($this->connection, $this->valueMapper, $this, $options); + return $this->createSnapshot( + $this->connection, + $this->requestHandler, + $this->serializer, + $this->valueMapper, + $this, + $options + ); } /** @@ -365,6 +391,8 @@ public function collection($collectionId) { return new CollectionReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->childPath($this->name, $collectionId) ); @@ -397,11 +425,25 @@ public function collections(array $options = []) function ($collectionId) { return new CollectionReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->childPath($this->name, $collectionId) ); }, [$this->connection, 'listCollectionIds'], + // function ($callOptions) use ($optionalArgs, $request) { + // if (isset($callOptions['pageToken'])) { + // $request->setPageToken($callOptions['pageToken']); + // } + + // return $this->requestHandler->sendRequest( + // FirestoreClient::class, + // 'listCollectionIds', + // $request, + // $optionalArgs + // ); + // }, $options + ['parent' => $this->name], [ 'itemsKey' => 'collectionIds', @@ -423,6 +465,8 @@ class_alias(BulkWriter::class, WriteBatch::class); } return new BulkWriter( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->databaseFromName($this->name) ); diff --git a/Firestore/src/FirestoreClient.php b/Firestore/src/FirestoreClient.php index e962f0e4769..d70925a7488 100644 --- a/Firestore/src/FirestoreClient.php +++ b/Firestore/src/FirestoreClient.php @@ -17,16 +17,23 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\ArrayTrait; +use Google\ApiCore\ClientOptionsTrait; +use Google\ApiCore\Serializer; +use Google\Cloud\Core\ApiHelperTrait; use Google\Cloud\Core\Blob; use Google\Cloud\Core\ClientTrait; +use Google\Cloud\Core\DetectProjectIdTrait; use Google\Cloud\Core\Exception\AbortedException; use Google\Cloud\Core\Exception\GoogleException; use Google\Cloud\Core\GeoPoint; use Google\Cloud\Core\Iterator\ItemIterator; use Google\Cloud\Core\Iterator\PageIterator; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Retry; use Google\Cloud\Core\ValidateTrait; use Google\Cloud\Firestore\Connection\Grpc; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as ClientFirestoreClient; use Psr\Cache\CacheItemPoolInterface; use Psr\Http\Message\StreamInterface; @@ -71,7 +78,10 @@ */ class FirestoreClient { - use ClientTrait; + use ClientTrait; // To remove in the end + use ApiHelperTrait; + use ClientOptionsTrait; + // use DetectProjectIdTrait; // To uncomment when ClientTrait is removed use SnapshotTrait; use ValidateTrait; @@ -83,12 +93,32 @@ class FirestoreClient const MAX_RETRIES = 5; + /** + * Keeping this consistent with veneer libraries where + * multiple clients are present. + */ + private const GAPIC_KEYS = [ + ClientFirestoreClient::class + ]; + /** * @var Connection\ConnectionInterface * @internal */ private $connection; + /** + * @var RequestHandler + * @internal + * The request handler responsible for sending requests and serializing responses into relevant classes. + */ + private $requestHandler; + + /** + * @var Serializer + */ + private Serializer $serializer; + /** * @var string */ @@ -150,14 +180,50 @@ public function __construct(array $config = []) 'emulatorHost' => $emulatorHost, ]; + + // COMMENT THIS OUT WHILE UPDATING RPCs + // $config = $this->buildClientOptions($config); + // $config['credentials'] = $this->createCredentialsWrapper( + // $config['credentials'], + // $config['credentialsConfig'], + // $config['universeDomain'] + // ); + $this->database = $config['database']; $this->connection = new Grpc($this->configureAuthentication($config) + [ 'projectId' => $this->projectId, ]); + $this->serializer = new Serializer([], [ + 'google.protobuf.Value' => function ($v) { + return $this->flattenValue($v); + }, + 'google.protobuf.ListValue' => function ($v) { + return $this->flattenListValue($v); + }, + 'google.protobuf.Struct' => function ($v) { + return $this->flattenStruct($v); + }, + 'google.protobuf.Timestamp' => function ($v) { + return $this->formatTimestampFromApi($v); + }, + ], [], [ + 'google.protobuf.Int32Value' => function ($v) { + return ['value' => $v]; + } + ]); + + $this->requestHandler = new RequestHandler( + $this->serializer, + self::GAPIC_KEYS, + $config + ); + $this->valueMapper = new ValueMapper( $this->connection, + $this->requestHandler, + $this->serializer, $config['returnInt64AsObject'] ); } @@ -183,6 +249,8 @@ class_alias(BulkWriter::class, WriteBatch::class); } return new BulkWriter( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->databaseName( $this->projectId, @@ -235,6 +303,8 @@ public function bulkWriter(array $options = []) { return new BulkWriter( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->databaseName( $this->projectId, @@ -263,6 +333,8 @@ public function collection($name) { return $this->getCollectionReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, @@ -307,6 +379,18 @@ function ($collectionId) { return $this->collection($collectionId); }, [$this->connection, 'listCollectionIds'], + // function ($callOptions) use ($optionalArgs, $request) { + // if (isset($callOptions['pageToken'])) { + // $request->setPageToken($callOptions['pageToken']); + // } + + // return $this->requestHandler->sendRequest( + // FirestoreClient::class, + // 'listCollectionIds', + // $request, + // $optionalArgs + // ); + // }, [ 'parent' => $this->fullName($this->projectId, $this->database), ] + $options, @@ -334,6 +418,8 @@ public function document($name) { return $this->getDocumentReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, @@ -385,6 +471,8 @@ public function documents(array $paths, array $options = []) { return $this->getDocumentsByPaths( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, @@ -424,6 +512,8 @@ public function collectionGroup($id) return new Query( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->fullName($this->projectId, $this->database), [ @@ -551,6 +641,8 @@ public function runTransaction(callable $callable, array $options = []) $transaction = new Transaction( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $database, $transactionId @@ -680,6 +772,8 @@ public function sessionHandler(array $options = []) { return new FirestoreSessionHandler( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, diff --git a/Firestore/src/FirestoreSessionHandler.php b/Firestore/src/FirestoreSessionHandler.php index e3c502301a0..45ec4961cc2 100644 --- a/Firestore/src/FirestoreSessionHandler.php +++ b/Firestore/src/FirestoreSessionHandler.php @@ -16,7 +16,9 @@ */ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; use Google\Cloud\Core\Exception\ServiceException; +use Google\Cloud\Core\RequestHandler; use SessionHandlerInterface; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -120,6 +122,17 @@ class FirestoreSessionHandler implements SessionHandlerInterface * @internal */ private $connection; + + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var ValueMapper */ @@ -159,6 +172,9 @@ class FirestoreSessionHandler implements SessionHandlerInterface * @param ConnectionInterface $connection A Connection to Cloud Firestore. * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $valueMapper A Firestore Value Mapper. * @param string $projectId The current project id. * @param string $database The database id. @@ -182,12 +198,16 @@ class FirestoreSessionHandler implements SessionHandlerInterface */ public function __construct( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $valueMapper, $projectId, $database, array $options = [] ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->valueMapper = $valueMapper; $this->projectId = $projectId; $this->database = $database; @@ -234,6 +254,8 @@ public function open($savePath, $sessionName) $this->transaction = new Transaction( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $database, $beginTransaction['transaction'] @@ -276,6 +298,8 @@ public function read($id) try { $docRef = $this->getDocumentReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, @@ -309,6 +333,8 @@ public function write($id, $data) { $docRef = $this->getDocumentReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, @@ -332,6 +358,8 @@ public function destroy($id) { $docRef = $this->getDocumentReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, @@ -363,6 +391,8 @@ public function gc($maxlifetime) $transaction = new Transaction( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $database, $beginTransaction['transaction'] @@ -370,6 +400,8 @@ public function gc($maxlifetime) $collectionRef = $this->getCollectionReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectId, $this->database, diff --git a/Firestore/src/Query.php b/Firestore/src/Query.php index 8147d7e8928..8eae5cd9612 100644 --- a/Firestore/src/Query.php +++ b/Firestore/src/Query.php @@ -17,8 +17,10 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\ExponentialBackoff; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldValue\FieldValueInterface; @@ -122,6 +124,16 @@ class Query */ private $connection; + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var ValueMapper */ @@ -146,6 +158,9 @@ class Query * @param ConnectionInterface $connection A Connection to Cloud Firestore. * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $valueMapper A Firestore Value Mapper. * @param string $parent The parent of the query. * @param array $query The Query object @@ -154,12 +169,16 @@ class Query */ public function __construct( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $valueMapper, $parent, array $query, $limitToLast = false ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->valueMapper = $valueMapper; $this->parentName = $parent; $this->query = $query; @@ -273,6 +292,8 @@ public function addAggregation($aggregate) { $aggregateQuery = new AggregateQuery( $this->connection, + $this->requestHandler, + $this->serializer, $this->parentName, [ 'query' => $this->query, @@ -340,6 +361,8 @@ public function documents(array $options = []) if (!isset($collections[$collectionName])) { $collections[$collectionName] = new CollectionReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $collectionName ); @@ -347,6 +370,8 @@ public function documents(array $options = []) $ref = new DocumentReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $collections[$collectionName], $result['document']['name'] @@ -973,6 +998,8 @@ private function newQuery(array $additionalConfig, $overrideTopLevelKeys = false return new self( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->parentName, $query, @@ -1010,12 +1037,16 @@ private function createDocumentReference($basePath, $document) $parent = new CollectionReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->parentPath($childPath) ); return new DocumentReference( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $parent, $childPath diff --git a/Firestore/src/SnapshotTrait.php b/Firestore/src/SnapshotTrait.php index 982a5af40de..f6512e15025 100644 --- a/Firestore/src/SnapshotTrait.php +++ b/Firestore/src/SnapshotTrait.php @@ -17,8 +17,11 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; +use Google\Cloud\Core\ApiHelperTrait; use Google\Cloud\Core\ArrayTrait; use Google\Cloud\Core\Exception\NotFoundException; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Core\TimestampTrait; @@ -30,7 +33,7 @@ */ trait SnapshotTrait { - use ArrayTrait; + use ApiHelperTrait; use PathTrait; use TimeTrait; use TimestampTrait; @@ -41,6 +44,9 @@ trait SnapshotTrait * @param ConnectionInterface $connection A Connection to Cloud Firestore. * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $valueMapper A Firestore Value Mapper. * @param DocumentReference $reference The parent document. * @param array $options { @@ -52,6 +58,8 @@ trait SnapshotTrait */ private function createSnapshot( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $valueMapper, DocumentReference $reference, array $options = [] @@ -61,7 +69,13 @@ private function createSnapshot( $exists = true; try { - $document = $this->getSnapshot($connection, $reference->name(), $options); + $document = $this->getSnapshot( + $connection, + $requestHandler, + $serializer, + $reference->name(), + $options + ); } catch (NotFoundException $e) { $exists = false; } @@ -100,6 +114,9 @@ private function createSnapshotWithData( * Send a service request for a snapshot, and return the raw data * * @param ConnectionInterface $connection A Connection to Cloud Firestore + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param string $name The document name. * @param array $options Configuration options. * @return array @@ -107,8 +124,13 @@ private function createSnapshotWithData( * specified. * @throws NotFoundException If the document does not exist. */ - private function getSnapshot(ConnectionInterface $connection, $name, array $options = []) - { + private function getSnapshot( + ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, + $name, + array $options = [] + ) { $options = $this->formatReadTimeOption($options); $snapshot = $connection->batchGetDocuments([ @@ -132,6 +154,9 @@ private function getSnapshot(ConnectionInterface $connection, $name, array $opti * not), and returns. * * @param ConnectionInterface $connection A connection to Cloud Firestore. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $mapper A Firestore value mapper. * @param string $projectId The current project id. * @param string $database The database id. @@ -142,6 +167,8 @@ private function getSnapshot(ConnectionInterface $connection, $name, array $opti */ private function getDocumentsByPaths( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $mapper, $projectId, $database, @@ -185,6 +212,8 @@ private function getDocumentsByPaths( $ref = $this->getDocumentReference( $connection, + $requestHandler, + $serializer, $mapper, $projectId, $database, @@ -211,6 +240,9 @@ private function getDocumentsByPaths( * Creates a DocumentReference object. * * @param ConnectionInterface $connection A connection to Cloud Firestore. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $mapper A Firestore value mapper. * @param string $projectId The current project id. * @param string $database The database id. @@ -220,6 +252,8 @@ private function getDocumentsByPaths( */ private function getDocumentReference( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $mapper, $projectId, $database, @@ -235,9 +269,13 @@ private function getDocumentReference( return new DocumentReference( $connection, + $requestHandler, + $serializer, $mapper, $this->getCollectionReference( $connection, + $requestHandler, + $serializer, $mapper, $projectId, $database, @@ -251,6 +289,9 @@ private function getDocumentReference( * Creates a CollectionReference object. * * @param ConnectionInterface $connection A connection to Cloud Firestore. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $mapper A Firestore value mapper. * @param string $projectId The current project id. * @param string $database The database id. @@ -260,6 +301,8 @@ private function getDocumentReference( */ private function getCollectionReference( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $mapper, $projectId, $database, @@ -276,7 +319,13 @@ private function getCollectionReference( )); } - return new CollectionReference($connection, $mapper, $name); + return new CollectionReference( + $connection, + $requestHandler, + $serializer, + $mapper, + $name + ); } /** diff --git a/Firestore/src/Transaction.php b/Firestore/src/Transaction.php index 60c86f537a8..d6de7221e54 100644 --- a/Firestore/src/Transaction.php +++ b/Firestore/src/Transaction.php @@ -17,7 +17,9 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; use Google\Cloud\Core\DebugInfoTrait; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -53,6 +55,16 @@ class Transaction */ private $connection; + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var ValueMapper */ @@ -75,22 +87,36 @@ class Transaction /** * @param ConnectionInterface $connection A connection to Cloud Firestore. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param ValueMapper $valueMapper A Firestore Value Mapper. * @param string $database The database name. * @param string $transaction The transaction ID. */ public function __construct( ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, ValueMapper $valueMapper, $database, $transaction ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->valueMapper = $valueMapper; $this->database = $database; $this->transaction = $transaction; - $this->writer = new BulkWriter($connection, $valueMapper, $database, $transaction); + $this->writer = new BulkWriter( + $connection, + $requestHandler, + $serializer, + $valueMapper, + $database, + $transaction + ); } /** @@ -107,9 +133,14 @@ public function __construct( */ public function snapshot(DocumentReference $document, array $options = []) { - return $this->createSnapshot($this->connection, $this->valueMapper, $document, [ - 'transaction' => $this->transaction, - ] + $options); + return $this->createSnapshot( + $this->connection, + $this->requestHandler, + $this->serializer, + $this->valueMapper, + $document, + ['transaction' => $this->transaction] + $options + ); } /** @@ -190,6 +221,8 @@ public function documents(array $paths, array $options = []) { return $this->getDocumentsByPaths( $this->connection, + $this->requestHandler, + $this->serializer, $this->valueMapper, $this->projectIdFromName($this->database), $this->databaseIdFromName($this->database), diff --git a/Firestore/src/ValueMapper.php b/Firestore/src/ValueMapper.php index 9cff16bb952..34915d01499 100644 --- a/Firestore/src/ValueMapper.php +++ b/Firestore/src/ValueMapper.php @@ -17,11 +17,13 @@ namespace Google\Cloud\Firestore; +use Google\ApiCore\Serializer; use Google\Cloud\Core\ArrayTrait; use Google\Cloud\Core\Blob; use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\GeoPoint; use Google\Cloud\Core\Int64; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Core\ValidateTrait; @@ -41,8 +43,8 @@ class ValueMapper use TimeTrait; use ValidateTrait; - const VALID_FIELD_PATH = '/^[^*~\/[\]]+$/'; - const UNESCAPED_FIELD_NAME = '/^[_a-zA-Z][_a-zA-Z0-9]*$/'; + public const VALID_FIELD_PATH = '/^[^*~\/[\]]+$/'; + public const UNESCAPED_FIELD_NAME = '/^[_a-zA-Z][_a-zA-Z0-9]*$/'; /** * @var ConnectionInterface @@ -50,6 +52,16 @@ class ValueMapper */ private $connection; + /** + * @var RequestHandler + */ + private $requestHandler; + + /** + * @var Serializer + */ + private $serializer; + /** * @var bool */ @@ -59,12 +71,21 @@ class ValueMapper * @param ConnectionInterface $connection A connection to Cloud Firestore * This object is created by FirestoreClient, * and should not be instantiated outside of this client. + * @param RequestHandler $requestHandler The request handler responsible for sending + * requests and serializing responses into relevant classes. + * @param Serializer $serializer The serializer instance to encode/decode messages. * @param bool $returnInt64AsObject Whether to wrap int types in a wrapper * (to preserve values in 32-bit environments). */ - public function __construct(ConnectionInterface $connection, $returnInt64AsObject) - { + public function __construct( + ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, + $returnInt64AsObject + ) { $this->connection = $connection; + $this->requestHandler = $requestHandler; + $this->serializer = $serializer; $this->returnInt64AsObject = $returnInt64AsObject; } @@ -179,8 +200,21 @@ private function decodeValue($type, $value) break; case 'referenceValue': - $parent = new CollectionReference($this->connection, $this, $this->parentPath($value)); - return new DocumentReference($this->connection, $this, $parent, $value); + $parent = new CollectionReference( + $this->connection, + $this->requestHandler, + $this->serializer, + $this, + $this->parentPath($value) + ); + return new DocumentReference( + $this->connection, + $this->requestHandler, + $this->serializer, + $this, + $parent, + $value + ); default: throw new \RuntimeException(sprintf( @@ -241,14 +275,14 @@ public function encodeValue($value) return ['nullValue' => NullValue::NULL_VALUE]; break; - // @codeCoverageIgnoreStart + // @codeCoverageIgnoreStart default: throw new \RuntimeException(sprintf( 'Invalid value type %s', $type )); break; - // @codeCoverageIgnoreEnd + // @codeCoverageIgnoreEnd } } diff --git a/Firestore/tests/Snippet/BulkWriterTest.php b/Firestore/tests/Snippet/BulkWriterTest.php index b85f3d198de..eec78785a8f 100644 --- a/Firestore/tests/Snippet/BulkWriterTest.php +++ b/Firestore/tests/Snippet/BulkWriterTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\Parser\Snippet; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; @@ -35,21 +37,33 @@ */ class BulkWriterTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; - const DATABASE = 'projects/example_project/databases/(default)'; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const DATABASE = 'projects/example_project/databases/(default)'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; private $connection; + private $requestHandler; + private $serializer; private $batch; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->batch = TestHelpers::stub(BulkWriter::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::DATABASE, [], ]); diff --git a/Firestore/tests/Snippet/CollectionReferenceTest.php b/Firestore/tests/Snippet/CollectionReferenceTest.php index 528accaf15f..511c8c92044 100644 --- a/Firestore/tests/Snippet/CollectionReferenceTest.php +++ b/Firestore/tests/Snippet/CollectionReferenceTest.php @@ -22,6 +22,8 @@ use Google\Cloud\Firestore\ValueMapper; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Iterator\ItemIterator; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\CollectionReference; @@ -34,22 +36,34 @@ */ class CollectionReferenceTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const NAME = 'projects/example_project/databases/(default)/documents/users'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const NAME = 'projects/example_project/databases/(default)/documents/users'; private $connection; + private $requestHandler; + private $serializer; private $collection; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->collection = TestHelpers::stub(CollectionReference::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::NAME ]); } @@ -75,7 +89,14 @@ public function testSubCollectionParent() { $subCollection = TestHelpers::stub(CollectionReference::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::NAME . '/doc/sub-collection', ]); diff --git a/Firestore/tests/Snippet/DocumentReferenceTest.php b/Firestore/tests/Snippet/DocumentReferenceTest.php index 8cd530ecd26..a33727577c1 100644 --- a/Firestore/tests/Snippet/DocumentReferenceTest.php +++ b/Firestore/tests/Snippet/DocumentReferenceTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; @@ -37,24 +39,36 @@ */ class DocumentReferenceTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; private $connection; + private $requestHandler; + private $serializer; private $document; private $batch; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->document = TestHelpers::stub(DocumentReferenceStub::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), $this->prophesize(CollectionReference::class)->reveal(), self::DOCUMENT - ], ['connection', 'batch']); + ], ['connection', 'requestHandler', 'batch']); $this->batch = $this->prophesize(WriteBatch::class); } @@ -207,7 +221,7 @@ public function testSnapshot() 'found' => [ 'name' => self::DOCUMENT, 'fields' => [], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ] ] ])); diff --git a/Firestore/tests/Snippet/DocumentSnapshotTest.php b/Firestore/tests/Snippet/DocumentSnapshotTest.php index c43bf1e2f1c..d99cb162f09 100644 --- a/Firestore/tests/Snippet/DocumentSnapshotTest.php +++ b/Firestore/tests/Snippet/DocumentSnapshotTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; @@ -35,10 +37,11 @@ */ class DocumentSnapshotTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; private $snapshot; @@ -52,7 +55,12 @@ public function setUp(): void $this->snapshot = TestHelpers::stub(DocumentSnapshot::class, [ $ref->reveal(), - new ValueMapper($this->prophesize(ConnectionInterface::class)->reveal(), false), + new ValueMapper( + $this->prophesize(ConnectionInterface::class)->reveal(), + $this->prophesize(RequestHandler::class)->reveal(), + $this->getSerializer(), + false + ), [], [], true @@ -130,7 +138,7 @@ public function testId() */ public function testTimestampMethods($method) { - $ts = new Timestamp(new \DateTime); + $ts = new Timestamp(new \DateTime()); $info = [$method => $ts]; $this->snapshot->___setProperty('info', $info); diff --git a/Firestore/tests/Snippet/FieldValueTest.php b/Firestore/tests/Snippet/FieldValueTest.php index 18a807aa90b..605d3cb1d36 100644 --- a/Firestore/tests/Snippet/FieldValueTest.php +++ b/Firestore/tests/Snippet/FieldValueTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; @@ -32,10 +34,13 @@ */ class FieldValueTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; private $connection; + private $requestHandler; + private $serializer; private $firestore; public function setUp(): void @@ -43,6 +48,8 @@ public function setUp(): void $this->checkAndSkipGrpcTests(); $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->firestore = TestHelpers::stub(FirestoreClient::class, [ ['projectId' => 'my-awesome-project'], ]); diff --git a/Firestore/tests/Snippet/FilterTest.php b/Firestore/tests/Snippet/FilterTest.php index f13bab5d58f..738d281de0e 100644 --- a/Firestore/tests/Snippet/FilterTest.php +++ b/Firestore/tests/Snippet/FilterTest.php @@ -17,7 +17,9 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\ArrayHasSameValuesToken; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\V1\StructuredQuery\FieldFilter\Operator as FieldFilterOperator; use Google\Cloud\Firestore\Filter; @@ -35,16 +37,21 @@ */ class FilterTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const COLLECTION = 'a'; - const QUERY_PARENT = 'projects/example_project/databases/(default)/documents'; + public const COLLECTION = 'a'; + public const QUERY_PARENT = 'projects/example_project/databases/(default)/documents'; private $connection; + private $requestHandler; + private $serializer; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); } public function testFilterClass() @@ -185,7 +192,14 @@ private function runAndAssertArray(Snippet $snippet, array $query, $allDescendan $q = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, [ 'from' => $from diff --git a/Firestore/tests/Snippet/FirestoreClientTest.php b/Firestore/tests/Snippet/FirestoreClientTest.php index ebf579c6901..41ef6c69fab 100644 --- a/Firestore/tests/Snippet/FirestoreClientTest.php +++ b/Firestore/tests/Snippet/FirestoreClientTest.php @@ -20,6 +20,8 @@ use Google\Cloud\Core\Blob; use Google\Cloud\Core\GeoPoint; use Google\Cloud\Core\Iterator\ItemIterator; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; @@ -40,6 +42,7 @@ */ class FirestoreClientTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; @@ -47,6 +50,8 @@ class FirestoreClientTest extends SnippetTestCase const DATABASE = '(default)'; private $connection; + private $requestHandler; + private $serializer; private $client; public function setUp(): void @@ -54,6 +59,8 @@ public function setUp(): void $this->checkAndSkipGrpcTests(); $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->client = TestHelpers::stub(FirestoreClient::class, [ ['projectId' => self::PROJECT] ]); diff --git a/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php b/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php index ebb869fa3d8..dec4b0e154a 100644 --- a/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php +++ b/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; @@ -33,12 +35,15 @@ */ class FirestoreSessionHandlerTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; const TRANSACTION = 'transaction-id'; private $connection; + private $requestHandler; + private $serializer; private $client; public static function setUpBeforeClass(): void @@ -59,6 +64,8 @@ public function setUp(): void $this->checkAndSkipGrpcTests(); $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->client = TestHelpers::stub(FirestoreClient::class); } diff --git a/Firestore/tests/Snippet/QuerySnapshotTest.php b/Firestore/tests/Snippet/QuerySnapshotTest.php index 440100b91c6..f447b7c5981 100644 --- a/Firestore/tests/Snippet/QuerySnapshotTest.php +++ b/Firestore/tests/Snippet/QuerySnapshotTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; @@ -33,15 +35,20 @@ */ class QuerySnapshotTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; private $connection; + private $requestHandler; + private $serializer; private $snapshot; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->snapshot = TestHelpers::stub(QuerySnapshot::class, [ $this->prophesize(Query::class)->reveal(), [] diff --git a/Firestore/tests/Snippet/QueryTest.php b/Firestore/tests/Snippet/QueryTest.php index 095104267bf..82275a6f44d 100644 --- a/Firestore/tests/Snippet/QueryTest.php +++ b/Firestore/tests/Snippet/QueryTest.php @@ -17,7 +17,9 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\ArrayHasSameValuesToken; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\Parser\Snippet; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; @@ -38,18 +40,23 @@ */ class QueryTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; - const QUERY_PARENT = 'projects/example_project/databases/(default)/documents'; - const COLLECTION = 'a'; - const NAME = 'projects/example_project/databases/(default)/documents/a/b'; + public const QUERY_PARENT = 'projects/example_project/databases/(default)/documents'; + public const COLLECTION = 'a'; + public const NAME = 'projects/example_project/databases/(default)/documents/a/b'; private $connection; + private $requestHandler; + private $serializer; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); } public function testClass() @@ -65,7 +72,14 @@ public function testDocuments() { $query = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, [ 'from' => [ @@ -92,7 +106,14 @@ public function testCount() { $query = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, [ 'from' => [ @@ -127,7 +148,14 @@ public function testAddAggregation() { $query = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, [ 'from' => [ @@ -353,7 +381,14 @@ private function runAndAssertArray(Snippet $snippet, array $query, $allDescendan $q = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, [ 'from' => $from diff --git a/Firestore/tests/Snippet/TransactionTest.php b/Firestore/tests/Snippet/TransactionTest.php index c0017893a56..f02286b7b32 100644 --- a/Firestore/tests/Snippet/TransactionTest.php +++ b/Firestore/tests/Snippet/TransactionTest.php @@ -17,6 +17,9 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\ApiCore\Serializer; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; @@ -43,17 +46,20 @@ */ class TransactionTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE_ID = '(default)'; - const TRANSACTION = 'foobar'; - const DATABASE = 'projects/example_project/databases/(default)'; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; - const DOCUMENT_TEMPLATE = 'projects/%s/databases/%s/documents/users/%s'; + public const PROJECT = 'example_project'; + public const DATABASE_ID = '(default)'; + public const TRANSACTION = 'foobar'; + public const DATABASE = 'projects/example_project/databases/(default)'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const DOCUMENT_TEMPLATE = 'projects/%s/databases/%s/documents/users/%s'; private $connection; + private $requestHandler; + private $serializer; private $transaction; private $document; private $batch; @@ -61,12 +67,21 @@ class TransactionTest extends SnippetTestCase public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->transaction = TestHelpers::stub(TransactionStub::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::DATABASE, self::TRANSACTION - ], ['connection', 'writer']); + ], ['connection', 'requestHandler', 'writer']); $this->document = $this->prophesize(DocumentReference::class); $this->document->name()->willReturn(self::DOCUMENT); @@ -103,12 +118,15 @@ public function testSnapshot() 'found' => [ 'name' => self::DOCUMENT, 'fields' => [], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ] ] ])); - $this->transaction->setConnection($this->connection->reveal()); + $this->transaction->setConnection( + $this->connection->reveal(), + $this->requestHandler->reveal() + ); $snippet = $this->snippetFromMethod(Transaction::class, 'snapshot'); $snippet->addLocal('transaction', $this->transaction); @@ -124,6 +142,8 @@ public function testRunAggregateQuery() ->willReturn(new \ArrayIterator([])); $aggregateQuery = new AggregateQuery( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::DOCUMENT, ['query' => []], Aggregate::count() @@ -246,13 +266,13 @@ public function testDocuments() 'name' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'john'), 'fields' => [] ], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ], [ 'found' => [ 'name' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'dave'), 'fields' => [] ], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ] ]); @@ -273,7 +293,7 @@ public function testDocumentsDoesntExist() ->willReturn([ [ 'missing' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'deleted-user'), - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ] ]); @@ -290,21 +310,44 @@ public function testDocumentsDoesntExist() //@codingStandardsIgnoreStart class TransactionStub extends Transaction { + use FirestoreTestHelperTrait; + private $database; - public function __construct(ConnectionInterface $connection, ValueMapper $valueMapper, $database, $transaction) - { + public function __construct( + ConnectionInterface $connection, + RequestHandler $requestHandler, + Serializer $serializer, + ValueMapper $valueMapper, + $database, + $transaction + ) { $this->database = $database; - parent::__construct($connection, $valueMapper, $database, $transaction); + parent::__construct( + $connection, + $requestHandler, + $serializer, + $valueMapper, + $database, + $transaction + ); } - public function setConnection(ConnectionInterface $connection) + public function setConnection(ConnectionInterface $connection, RequestHandler $requestHandler) { $this->connection = $connection; + $this->requestHandler = $requestHandler; $this->writer = new WriteBatch( $connection, - new ValueMapper($connection, false), + $requestHandler, + $this->getSerializer(), + new ValueMapper( + $connection, + $requestHandler, + $this->getSerializer(), + false + ), $this->database, $this->___getProperty('transaction') ); diff --git a/Firestore/tests/Snippet/WriteBatchTest.php b/Firestore/tests/Snippet/WriteBatchTest.php index cf54aae5075..c4cd2aa92fd 100644 --- a/Firestore/tests/Snippet/WriteBatchTest.php +++ b/Firestore/tests/Snippet/WriteBatchTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\Parser\Snippet; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; @@ -34,23 +36,35 @@ */ class WriteBatchTest extends SnippetTestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; - const DATABASE = 'projects/example_project/databases/(default)'; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const DATABASE = 'projects/example_project/databases/(default)'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; private $connection; + private $requestHandler; + private $serializer; private $batch; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->batch = TestHelpers::stub(WriteBatch::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::DATABASE - ], ['connection', 'transaction']); + ], ['connection', 'requestHandler', 'transaction']); } public function testClass() diff --git a/Firestore/tests/System/BulkWriterTest.php b/Firestore/tests/System/BulkWriterTest.php index 8dfe18aab80..fa2884b6ee7 100644 --- a/Firestore/tests/System/BulkWriterTest.php +++ b/Firestore/tests/System/BulkWriterTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\System; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Firestore\BulkWriter; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -31,6 +33,7 @@ */ class BulkWriterTest extends FirestoreTestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; private $document; @@ -95,9 +98,17 @@ public function testLongFailuresAreRetriedWithDelay() { $docs = $this->bulkDocuments(); $connection = $this->prophesize(ConnectionInterface::class); + $requestHandler = $this->prophesize(RequestHandler::class); $this->batch = TestHelpers::stub(BulkWriter::class, [ $connection->reveal(), - new ValueMapper($connection->reveal(), false), + $requestHandler->reveal(), + $this->getSerializer(), + new ValueMapper( + $connection->reveal(), + $requestHandler->reveal(), + $this->getSerializer(), + false + ), self::$collection->name(), [ 'initialOpsPerSecond' => 5, diff --git a/Firestore/tests/Unit/AggregateQueryTest.php b/Firestore/tests/Unit/AggregateQueryTest.php index 57fc50742ff..cc5d751f0d6 100644 --- a/Firestore/tests/Unit/AggregateQueryTest.php +++ b/Firestore/tests/Unit/AggregateQueryTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Firestore\Aggregate; use Google\Cloud\Firestore\AggregateQuery; @@ -34,6 +36,7 @@ */ class AggregateQueryTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; const QUERY_PARENT = 'projects/example_project/databases/(default)/'; @@ -45,6 +48,8 @@ class AggregateQueryTest extends TestCase ]; private $connection; + private $requestHandler; + private $serializer; private $query; private $aggregate; private $aggregateQuery; @@ -52,19 +57,30 @@ class AggregateQueryTest extends TestCase public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->query = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, $this->queryObj - ], ['connection', 'query']); + ], ['connection', 'requestHandler', 'query']); $this->aggregate = Aggregate::count(); $this->aggregateQuery = TestHelpers::stub(AggregateQuery::class, [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::QUERY_PARENT, ['query' => $this->queryObj], $this->aggregate - ], ['connection', 'query', 'aggregates']); + ], ['connection', 'requestHandler', 'query', 'aggregates']); } /** diff --git a/Firestore/tests/Unit/BulkWriterTest.php b/Firestore/tests/Unit/BulkWriterTest.php index 2418a311e1d..7cc8fcbac3a 100644 --- a/Firestore/tests/Unit/BulkWriterTest.php +++ b/Firestore/tests/Unit/BulkWriterTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\BulkWriter; @@ -38,22 +40,34 @@ */ class BulkWriterTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; - const TRANSACTION = 'foobar'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const TRANSACTION = 'foobar'; private $connection; + private $requestHandler; + private $serializer; private $batch; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->batch = TestHelpers::stub(BulkWriter::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), [], ]); @@ -67,7 +81,14 @@ public function testBulkwriterOptionsInitialOpsPerSecond() $this->expectExceptionMessageMatches('/Value for argument "initialOpsPerSecond" must be greater than 1/'); new BulkWriter( $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), "TEST_DB", ['initialOpsPerSecond' => 0] ); @@ -79,7 +100,14 @@ public function testBulkwriterOptionsMaxOpsPerSecond() $this->expectExceptionMessageMatches('/Value for argument "maxOpsPerSecond" must be greater than 1/'); new BulkWriter( $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), "TEST_DB", ['maxOpsPerSecond' => 0] ); @@ -91,7 +119,14 @@ public function testBulkwriterOptions() $this->expectExceptionMessageMatches('/\'maxOpsPerSecond\' cannot be less than \'initialOpsPerSecond\'/'); new BulkWriter( $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), "TEST_DB", [ 'maxOpsPerSecond' => 2, @@ -290,7 +325,14 @@ public function testFailuresAreRetriedInSubsequentBatches($docs) $successfulDocs = []; $this->batch = TestHelpers::stub(BulkWriter::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), ['greedilySend' => false], ]); diff --git a/Firestore/tests/Unit/CollectionReferenceTest.php b/Firestore/tests/Unit/CollectionReferenceTest.php index 649f477d075..c5f4c0799c4 100644 --- a/Firestore/tests/Unit/CollectionReferenceTest.php +++ b/Firestore/tests/Unit/CollectionReferenceTest.php @@ -24,6 +24,8 @@ use Google\Cloud\Firestore\ValueMapper; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Iterator\ItemIterator; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\CollectionReference; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -34,22 +36,34 @@ */ class CollectionReferenceTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const COLLECTION_PARENT = 'projects/example_project/databases/(default)/documents/a/doc'; - const NAME = 'projects/example_project/databases/(default)/documents/a/doc/b'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const COLLECTION_PARENT = 'projects/example_project/databases/(default)/documents/a/doc'; + public const NAME = 'projects/example_project/databases/(default)/documents/a/doc/b'; private $connection; + private $requestHandler; + private $serializer; private $collection; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->collection = TestHelpers::stub(CollectionReference::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::NAME ]); } @@ -164,9 +178,17 @@ public function testRandomNames(DocumentReference $doc) public function randomNames() { $connection = $this->prophesize(ConnectionInterface::class); + $requestHandler = $this->prophesize(RequestHandler::class); $collection = TestHelpers::stub(CollectionReference::class, [ $connection->reveal(), - new ValueMapper($connection->reveal(), false), + $requestHandler->reveal(), + $this->getSerializer(), + new ValueMapper( + $connection->reveal(), + $requestHandler->reveal(), + $this->getSerializer(), + false + ), self::NAME ]); @@ -196,7 +218,14 @@ public function testParentForRootCollection() $collectionName = 'projects/example_project/databases/(default)/documents/foo'; $collection = TestHelpers::stub(CollectionReference::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), $collectionName ]); $this->assertNull($collection->parent()); diff --git a/Firestore/tests/Unit/ConformanceTest.php b/Firestore/tests/Unit/ConformanceTest.php index 8fa332f45a7..1ebb39a94e0 100644 --- a/Firestore/tests/Unit/ConformanceTest.php +++ b/Firestore/tests/Unit/ConformanceTest.php @@ -17,7 +17,9 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\ArrayHasSameValuesToken; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; @@ -47,6 +49,7 @@ */ class ConformanceTest extends TestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use PathTrait; use ProphecyTrait; @@ -60,6 +63,8 @@ class ConformanceTest extends TestCase private $testTypes = ['get', 'create', 'set', 'update', 'updatePaths', 'delete', 'query']; private $client; private $connection; + private $requestHandler; + private $serializer; private $excludes = [ // need mergeFields support @@ -88,6 +93,8 @@ public function setUp(): void ]); $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); } /** @@ -309,6 +316,8 @@ public function testQuery($test) $mapper = new ValueMapper( $this->prophesize(ConnectionInterface::class)->reveal(), + $this->prophesize(RequestHandler::class)->reveal(), + $this->serializer, false ); diff --git a/Firestore/tests/Unit/DocumentReferenceTest.php b/Firestore/tests/Unit/DocumentReferenceTest.php index 2e670c1ab9c..a9abf6f474a 100644 --- a/Firestore/tests/Unit/DocumentReferenceTest.php +++ b/Firestore/tests/Unit/DocumentReferenceTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; @@ -36,26 +38,44 @@ */ class DocumentReferenceTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; use TimeTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const COLLECTION = 'projects/example_project/databases/(default)/documents/a'; - const NAME = 'projects/example_project/databases/(default)/documents/a/b'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const COLLECTION = 'projects/example_project/databases/(default)/documents/a'; + public const NAME = 'projects/example_project/databases/(default)/documents/a/b'; private $connection; + private $requestHandler; + private $serializer; private $document; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); - $valueMapper = new ValueMapper($this->connection->reveal(), false); + $valueMapper = new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ); $this->document = TestHelpers::stub(DocumentReference::class, [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $valueMapper, - new CollectionReference($this->connection->reveal(), $valueMapper, self::COLLECTION), + new CollectionReference( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + $valueMapper, + self::COLLECTION + ), self::NAME ]); } diff --git a/Firestore/tests/Unit/DocumentSnapshotTest.php b/Firestore/tests/Unit/DocumentSnapshotTest.php index df65fef3ae4..eb4dc0bb251 100644 --- a/Firestore/tests/Unit/DocumentSnapshotTest.php +++ b/Firestore/tests/Unit/DocumentSnapshotTest.php @@ -18,6 +18,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; use Exception; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -35,10 +37,11 @@ */ class DocumentSnapshotTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const NAME = 'projects/example_project/databases/(default)/documents/a/b'; - const ID = 'b'; + public const NAME = 'projects/example_project/databases/(default)/documents/a/b'; + public const ID = 'b'; private $snapshot; @@ -51,7 +54,12 @@ public function setUp(): void $this->snapshot = TestHelpers::stub(DocumentSnapshot::class, [ $ref->reveal(), - new ValueMapper($this->prophesize(ConnectionInterface::class)->reveal(), false), + new ValueMapper( + $this->prophesize(ConnectionInterface::class)->reveal(), + $this->prophesize(RequestHandler::class)->reveal(), + $this->getSerializer(), + false + ), [], [], true ], ['info', 'data', 'exists']); } @@ -81,7 +89,7 @@ public function testId() */ public function testTimestampMethods($method) { - $ts = new Timestamp(new \DateTime); + $ts = new Timestamp(new \DateTime()); $info = [$method => $ts]; $this->snapshot->___setProperty('info', $info); diff --git a/Firestore/tests/Unit/FirestoreClientTest.php b/Firestore/tests/Unit/FirestoreClientTest.php index 09e4afacbc5..661b43f28b9 100644 --- a/Firestore/tests/Unit/FirestoreClientTest.php +++ b/Firestore/tests/Unit/FirestoreClientTest.php @@ -21,6 +21,8 @@ use Google\Cloud\Core\Exception\AbortedException; use Google\Cloud\Core\GeoPoint; use Google\Cloud\Core\Iterator\ItemIterator; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; @@ -43,6 +45,7 @@ */ class FirestoreClientTest extends TestCase { + use FirestoreTestHelperTrait; use GrpcTestTrait; use ProphecyTrait; @@ -50,6 +53,8 @@ class FirestoreClientTest extends TestCase const DATABASE = '(default)'; private $connection; + private $requestHandler; + private $serializer; private $client; public function setUp(): void @@ -57,6 +62,8 @@ public function setUp(): void $this->checkAndSkipGrpcTests(); $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->client = TestHelpers::stub( FirestoreClient::class, [['projectId' => self::PROJECT]] diff --git a/Firestore/tests/Unit/FirestoreSessionHandlerTest.php b/Firestore/tests/Unit/FirestoreSessionHandlerTest.php index 0c775e25485..648416a7728 100644 --- a/Firestore/tests/Unit/FirestoreSessionHandlerTest.php +++ b/Firestore/tests/Unit/FirestoreSessionHandlerTest.php @@ -19,6 +19,8 @@ use Exception; use Google\Cloud\Core\Exception\ServiceException; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\ValueMapper; use Google\Cloud\Firestore\FirestoreSessionHandler; @@ -34,6 +36,7 @@ */ class FirestoreSessionHandlerTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; const SESSION_SAVE_PATH = 'sessions'; @@ -42,12 +45,16 @@ class FirestoreSessionHandlerTest extends TestCase const DATABASE = '(default)'; private $connection; + private $requestHandler; + private $serializer; private $valueMapper; private $documents; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->valueMapper = $this->prophesize(ValueMapper::class); $this->documents = $this->prophesize(Iterator::class); } @@ -59,6 +66,8 @@ public function testOpen() ->willReturn(['transaction' => null]); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -76,6 +85,8 @@ public function testOpenWithException() ->willThrow(new ServiceException('')); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -93,6 +104,8 @@ public function testReadNotAllowed() ->willReturn(['transaction' => null]); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -110,6 +123,8 @@ public function testClose() ->shouldBeCalledTimes(1); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -136,6 +151,8 @@ public function testReadNothing() ->willReturn($this->documents->reveal()); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -162,6 +179,8 @@ public function testReadWithException() ->willThrow((new ServiceException(''))); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -199,6 +218,8 @@ public function testReadEntity() ->willReturn($this->documents->reveal()); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -238,6 +259,8 @@ public function testWrite() ->shouldBeCalledTimes(1); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -273,6 +296,8 @@ public function testWriteWithException() ->willThrow((new ServiceException(''))); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -302,6 +327,8 @@ public function testDestroy() ->shouldBeCalledTimes(1); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -330,6 +357,8 @@ public function testDestroyWithException() ->shouldBeCalledTimes(1); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -349,6 +378,8 @@ public function testDefaultGcDoesNothing() $this->connection->commit()->shouldNotBeCalled(); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE @@ -414,6 +445,8 @@ public function testGc() ->shouldBeCalledTimes(1); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE, @@ -438,6 +471,8 @@ public function testGcWithException() ->willThrow(new ServiceException('')); $firestoreSessionHandler = new FirestoreSessionHandler( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper->reveal(), self::PROJECT, self::DATABASE, diff --git a/Firestore/tests/Unit/QuerySnapshotTest.php b/Firestore/tests/Unit/QuerySnapshotTest.php index f2a556d8748..e8381294903 100644 --- a/Firestore/tests/Unit/QuerySnapshotTest.php +++ b/Firestore/tests/Unit/QuerySnapshotTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\Query; @@ -32,12 +34,10 @@ class QuerySnapshotTest extends TestCase { use ProphecyTrait; - private $connection; private $snapshot; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->snapshot = TestHelpers::stub(QuerySnapshot::class, [ $this->prophesize(Query::class)->reveal(), [] diff --git a/Firestore/tests/Unit/QueryTest.php b/Firestore/tests/Unit/QueryTest.php index 36ea6943f4f..ad850d76d8d 100644 --- a/Firestore/tests/Unit/QueryTest.php +++ b/Firestore/tests/Unit/QueryTest.php @@ -17,7 +17,9 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\ArrayHasSameValuesToken; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\CollectionReference; @@ -44,12 +46,13 @@ */ class QueryTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const QUERY_PARENT = 'projects/example_project/databases/(default)/documents'; - const COLLECTION = 'foo'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const QUERY_PARENT = 'projects/example_project/databases/(default)/documents'; + public const COLLECTION = 'foo'; private $queryObj = [ 'from' => [ @@ -57,27 +60,45 @@ class QueryTest extends TestCase ] ]; private $connection; + private $requestHandler; + private $serializer; private $query; private $collectionGroupQuery; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->query = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, $this->queryObj - ], ['connection', 'query', 'transaction']); + ], ['connection', 'requestHandler', 'query', 'transaction']); $allDescendants = $this->queryObj; $allDescendants['from'][0]['allDescendants'] = true; $this->collectionGroupQuery = TestHelpers::stub(Query::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, $allDescendants - ], ['connection', 'query', 'transaction']); + ], ['connection', 'requestHandler', 'query', 'transaction']); } public function testConstructMissingFrom() @@ -86,7 +107,14 @@ public function testConstructMissingFrom() new Query( $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), self::QUERY_PARENT, [] ); @@ -108,7 +136,7 @@ public function testDocuments() ] ] ], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ], [] ])); @@ -128,7 +156,7 @@ public function testDocumentsMetadata() { $name = self::QUERY_PARENT .'/foo'; - $ts = (new \DateTime)->format(Timestamp::FORMAT); + $ts = (new \DateTime())->format(Timestamp::FORMAT); $this->connection->runQuery(Argument::any()) ->shouldBeCalled() ->willReturn(new \ArrayIterator([ @@ -271,24 +299,25 @@ public function testSelectName() public function testWhere() { - $this->runAndAssert(function (Query $q) { - $res = $q->where('user.name', '=', 'John'); - $res = $res->where('user.age', '=', 30); - $res = $res->where('user.coolness', '=', null); - $res = $res->where('user.numberOfFriends', '=', NAN); - $res = $res->where( - Filter::or([ - Filter::field('user.name', '=', 'John'), - Filter::field('user.age', '=', 30), - Filter::and([ - Filter::field('user.coolness', '=', null), - Filter::field('user.numberOfFriends', '=', NAN) + $this->runAndAssert( + function (Query $q) { + $res = $q->where('user.name', '=', 'John'); + $res = $res->where('user.age', '=', 30); + $res = $res->where('user.coolness', '=', null); + $res = $res->where('user.numberOfFriends', '=', NAN); + $res = $res->where( + Filter::or([ + Filter::field('user.name', '=', 'John'), + Filter::field('user.age', '=', 30), + Filter::and([ + Filter::field('user.coolness', '=', null), + Filter::field('user.numberOfFriends', '=', NAN) + ]) ]) - ]) - ); + ); - return $res; - }, + return $res; + }, [ 'parent' => self::QUERY_PARENT, 'structuredQuery' => [ @@ -388,7 +417,8 @@ public function testWhere() ] ] ] - ]); + ] + ); } /** @@ -915,7 +945,7 @@ public function testLimitToLastReversesResults() ] ] ], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ], [ 'document' => [ @@ -926,7 +956,7 @@ public function testLimitToLastReversesResults() ] ] ], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) + 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) ], ])); diff --git a/Firestore/tests/Unit/SnapshotTraitTest.php b/Firestore/tests/Unit/SnapshotTraitTest.php index 0c03fbca938..2f8ec711f97 100644 --- a/Firestore/tests/Unit/SnapshotTraitTest.php +++ b/Firestore/tests/Unit/SnapshotTraitTest.php @@ -18,6 +18,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; use Google\Cloud\Core\Exception\NotFoundException; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -36,13 +38,16 @@ */ class SnapshotTraitTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const NAME = 'projects/example_project/databases/(default)/documents/a/b'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const NAME = 'projects/example_project/databases/(default)/documents/a/b'; private $connection; + private $requestHandler; + private $serializer; private $mapper; private $impl; private $valueMapper; @@ -50,9 +55,16 @@ class SnapshotTraitTest extends TestCase public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->impl = TestHelpers::impl(SnapshotTrait::class); - $this->valueMapper = new ValueMapper($this->connection->reveal(), false); + $this->valueMapper = new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ); } public function testCreateSnapshot() @@ -75,6 +87,8 @@ public function testCreateSnapshot() $ref->name()->willReturn(self::NAME); $res = $this->impl->call('createSnapshot', [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper, $ref->reveal() ]); @@ -98,6 +112,8 @@ public function testCreateSnapshotNonExistence() $ref->name()->willReturn(self::NAME); $res = $this->impl->call('createSnapshot', [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper, $ref->reveal() ]); @@ -118,6 +134,8 @@ public function testGetSnapshot() $this->assertEquals('foo', $this->impl->call('getSnapshot', [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::NAME ])); } @@ -137,6 +155,8 @@ public function testGetSnapshotReadTime() $this->impl->call('getSnapshot', [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::NAME, [ 'readTime' => new Timestamp( @@ -153,6 +173,8 @@ public function testGetSnapshotReadTimeInvalidReadTime() $this->impl->call('getSnapshot', [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::NAME, ['readTime' => 'foo'] ]); @@ -171,6 +193,8 @@ public function testGetSnapshotNotFound() $this->impl->call('getSnapshot', [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::NAME ]); } diff --git a/Firestore/tests/Unit/TransactionTest.php b/Firestore/tests/Unit/TransactionTest.php index 8de6087f1d1..35570e973d0 100644 --- a/Firestore/tests/Unit/TransactionTest.php +++ b/Firestore/tests/Unit/TransactionTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -40,14 +42,17 @@ */ class TransactionTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; - const TRANSACTION = 'foobar'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const TRANSACTION = 'foobar'; private $connection; + private $requestHandler; + private $serializer; private $valueMapper; private $transaction; private $ref; @@ -55,9 +60,18 @@ class TransactionTest extends TestCase public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); - $this->valueMapper = new ValueMapper($this->connection->reveal(), false); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); + $this->valueMapper = new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ); $this->transaction = TestHelpers::stub(Transaction::class, [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, $this->valueMapper, sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), self::TRANSACTION @@ -100,7 +114,14 @@ public function testRunQuery() ->shouldBeCalled() ->willReturn(new \ArrayIterator([[]])); - $query = new Query($this->connection->reveal(), $this->valueMapper, '', ['from' => ['collectionId' => '']]); + $query = new Query( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + $this->valueMapper, + '', + ['from' => ['collectionId' => '']] + ); $res = $this->transaction->runQuery($query); $this->assertInstanceOf(QuerySnapshot::class, $res); @@ -117,6 +138,8 @@ public function testRunAggregateQuery($type, $arg) $aggregateQuery = new AggregateQuery( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::DOCUMENT, ['query' => []], $arg ? Aggregate::$type($arg) : Aggregate::$type() @@ -141,6 +164,8 @@ public function testGetAggregateSnapshotReadTime($type, $arg) $aggregateQuery = new AggregateQuery( $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, self::DOCUMENT, ['query' => []], $arg ? Aggregate::$type($arg) : Aggregate::$type() @@ -287,7 +312,7 @@ public function testDelete() */ public function testDocuments(array $input, array $names) { - $timestamp = (new Timestamp(new \DateTimeImmutable))->formatAsString(); + $timestamp = (new Timestamp(new \DateTimeImmutable()))->formatAsString(); $res = [ [ @@ -380,7 +405,7 @@ public function aggregationTypes() public function testDocumentsOrdered() { - $timestamp = (new Timestamp(new \DateTimeImmutable))->formatAsString(); + $timestamp = (new Timestamp(new \DateTimeImmutable()))->formatAsString(); $tpl = 'projects/'. self::PROJECT .'/databases/'. self::DATABASE .'/documents/a/%s'; $names = [ sprintf($tpl, 'a'), diff --git a/Firestore/tests/Unit/ValueMapperTest.php b/Firestore/tests/Unit/ValueMapperTest.php index c4e186700c8..e22e9508353 100644 --- a/Firestore/tests/Unit/ValueMapperTest.php +++ b/Firestore/tests/Unit/ValueMapperTest.php @@ -20,6 +20,8 @@ use Google\Cloud\Core\Blob; use Google\Cloud\Core\GeoPoint; use Google\Cloud\Core\Int64; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; @@ -37,19 +39,26 @@ */ class ValueMapperTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; use TimeTrait; private $connection; + private $requestHandler; + private $serializer; private $mapper; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->mapper = TestHelpers::stub(ValueMapper::class, [ $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, false - ], ['connection', 'returnInt64AsObject']); + ], ['connection', 'requestHandler', 'returnInt64AsObject']); } /** diff --git a/Firestore/tests/Unit/WriteBatchTest.php b/Firestore/tests/Unit/WriteBatchTest.php index 5e3f31ce82f..6208a0ce86a 100644 --- a/Firestore/tests/Unit/WriteBatchTest.php +++ b/Firestore/tests/Unit/WriteBatchTest.php @@ -17,6 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; +use Google\Cloud\Core\RequestHandler; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\Connection\ConnectionInterface; @@ -37,25 +39,37 @@ */ class WriteBatchTest extends TestCase { + use FirestoreTestHelperTrait; use ProphecyTrait; - const PROJECT = 'example_project'; - const DATABASE = '(default)'; - const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; - const TRANSACTION = 'foobar'; + public const PROJECT = 'example_project'; + public const DATABASE = '(default)'; + public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; + public const TRANSACTION = 'foobar'; private $connection; + private $requestHandler; + private $serializer; private $batch; public function setUp(): void { $this->connection = $this->prophesize(ConnectionInterface::class); + $this->requestHandler = $this->prophesize(RequestHandler::class); + $this->serializer = $this->getSerializer(); $this->batch = TestHelpers::stub(WriteBatch::class, [ $this->connection->reveal(), - new ValueMapper($this->connection->reveal(), false), + $this->requestHandler->reveal(), + $this->serializer, + new ValueMapper( + $this->connection->reveal(), + $this->requestHandler->reveal(), + $this->serializer, + false + ), sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) - ], ['connection', 'transaction']); + ], ['connection', 'requestHandler', 'transaction']); } /** From 53092617adf64537df944d37291cf02ba90b6f86 Mon Sep 17 00:00:00 2001 From: Yash Sahu <54198301+yash30201@users.noreply.github.com> Date: Thu, 13 Jun 2024 15:05:38 +0530 Subject: [PATCH 2/3] feat(Firestore): Part 2 of Upgrade Firestore V2 (#7300) --- Core/src/Testing/FirestoreTestHelperTrait.php | 10 +- Core/tests/Unit/ServiceBuilderTest.php | 6 - Firestore/MIGRATION.md | 43 + Firestore/src/AggregateQuery.php | 42 +- Firestore/src/AggregateQuerySnapshot.php | 11 +- Firestore/src/BulkWriter.php | 121 +- Firestore/src/CollectionReference.php | 56 +- .../src/Connection/ConnectionInterface.php | 71 - Firestore/src/Connection/Grpc.php | 359 ----- Firestore/src/DocumentReference.php | 72 +- Firestore/src/DocumentSnapshot.php | 24 +- Firestore/src/FirestoreClient.php | 140 +- Firestore/src/FirestoreSessionHandler.php | 46 +- Firestore/src/Query.php | 78 +- Firestore/src/SnapshotTrait.php | 75 +- Firestore/src/Transaction.php | 45 +- Firestore/src/V1/StructuredQuery.php | 2 +- Firestore/src/ValueMapper.php | 40 +- Firestore/tests/Snippet/BulkWriterTest.php | 43 +- .../tests/Snippet/CollectionReferenceTest.php | 31 +- .../tests/Snippet/DocumentReferenceTest.php | 49 +- .../tests/Snippet/DocumentSnapshotTest.php | 28 +- Firestore/tests/Snippet/FieldValueTest.php | 237 ++-- Firestore/tests/Snippet/FilterTest.php | 34 +- .../tests/Snippet/FirestoreClientTest.php | 181 ++- .../Snippet/FirestoreSessionHandlerTest.php | 174 ++- Firestore/tests/Snippet/QuerySnapshotTest.php | 18 +- Firestore/tests/Snippet/QueryTest.php | 87 +- Firestore/tests/Snippet/TransactionTest.php | 146 +- Firestore/tests/Snippet/WriteBatchTest.php | 242 ---- Firestore/tests/System/AggregateQueryTest.php | 12 +- Firestore/tests/System/BulkWriterTest.php | 50 +- .../System/DocumentAndCollectionTest.php | 10 +- Firestore/tests/System/FieldValueTest.php | 5 +- Firestore/tests/System/QueryTest.php | 5 +- Firestore/tests/System/TransactionTest.php | 34 +- Firestore/tests/System/ValueMapperTest.php | 14 +- Firestore/tests/System/WriteTest.php | 36 +- .../tests/Unit/AggregateQuerySnapshotTest.php | 6 +- Firestore/tests/Unit/AggregateQueryTest.php | 59 +- Firestore/tests/Unit/BulkWriterTest.php | 344 ++--- .../tests/Unit/CollectionReferenceTest.php | 69 +- Firestore/tests/Unit/ConformanceTest.php | 114 +- Firestore/tests/Unit/Connection/GrpcTest.php | 444 ------ .../tests/Unit/DocumentReferenceTest.php | 255 ++-- Firestore/tests/Unit/DocumentSnapshotTest.php | 5 +- Firestore/tests/Unit/FirestoreClientTest.php | 332 +++-- .../Unit/FirestoreSessionHandlerTest.php | 425 ++++-- Firestore/tests/Unit/QuerySnapshotTest.php | 1 - Firestore/tests/Unit/QueryTest.php | 139 +- Firestore/tests/Unit/SnapshotTraitTest.php | 114 +- Firestore/tests/Unit/TransactionTest.php | 142 +- .../tests/Unit/V1/FirestoreClientBCTest.php | 133 -- .../tests/Unit/V1/FirestoreClientTest.php | 1219 ----------------- Firestore/tests/Unit/ValueMapperTest.php | 36 +- Firestore/tests/Unit/WriteBatchTest.php | 574 -------- .../conformance/v1/create-all-transforms.json | 2 +- .../Unit/conformance/v1/create-st-alone.json | 2 +- .../Unit/conformance/v1/create-st-multi.json | 4 +- .../Unit/conformance/v1/create-st-nested.json | 2 +- .../v1/create-st-with-empty-map.json | 2 +- .../tests/Unit/conformance/v1/create-st.json | 2 +- .../conformance/v1/delete-time-precond.json | 4 +- .../v1/query-offset-limit-last-wins.json | 2 +- .../conformance/v1/query-offset-limit.json | 2 +- .../conformance/v1/set-all-transforms.json | 2 +- .../conformance/v1/set-st-alone-mergeall.json | 2 +- .../Unit/conformance/v1/set-st-alone.json | 2 +- .../conformance/v1/set-st-merge-both.json | 2 +- .../v1/set-st-merge-nonleaf-alone.json | 2 +- .../conformance/v1/set-st-merge-nonleaf.json | 2 +- .../conformance/v1/set-st-merge-nowrite.json | 2 +- .../Unit/conformance/v1/set-st-mergeall.json | 2 +- .../Unit/conformance/v1/set-st-multi.json | 4 +- .../Unit/conformance/v1/set-st-nested.json | 2 +- .../conformance/v1/set-st-with-empty-map.json | 2 +- .../tests/Unit/conformance/v1/set-st.json | 2 +- .../conformance/v1/update-all-transforms.json | 2 +- ...ate-nested-transform-and-nested-value.json | 2 +- .../v1/update-paths-all-transforms.json | 2 +- ...ths-nested-transform-and-nested-value.json | 2 +- .../conformance/v1/update-paths-st-alone.json | 2 +- .../conformance/v1/update-paths-st-multi.json | 4 +- .../v1/update-paths-st-nested.json | 2 +- .../v1/update-paths-st-with-empty-map.json | 2 +- .../Unit/conformance/v1/update-paths-st.json | 2 +- .../conformance/v1/update-paths-uptime.json | 4 +- .../Unit/conformance/v1/update-st-dot.json | 2 +- .../Unit/conformance/v1/update-st-multi.json | 2 +- .../tests/Unit/conformance/v1/update-st.json | 2 +- .../Unit/conformance/v1/update-uptime.json | 4 +- 91 files changed, 2273 insertions(+), 4897 deletions(-) create mode 100644 Firestore/MIGRATION.md delete mode 100644 Firestore/src/Connection/ConnectionInterface.php delete mode 100644 Firestore/src/Connection/Grpc.php delete mode 100644 Firestore/tests/Snippet/WriteBatchTest.php delete mode 100644 Firestore/tests/Unit/Connection/GrpcTest.php delete mode 100644 Firestore/tests/Unit/V1/FirestoreClientBCTest.php delete mode 100644 Firestore/tests/Unit/V1/FirestoreClientTest.php delete mode 100644 Firestore/tests/Unit/WriteBatchTest.php diff --git a/Core/src/Testing/FirestoreTestHelperTrait.php b/Core/src/Testing/FirestoreTestHelperTrait.php index eac29fe50e4..4359aab56ca 100644 --- a/Core/src/Testing/FirestoreTestHelperTrait.php +++ b/Core/src/Testing/FirestoreTestHelperTrait.php @@ -31,6 +31,9 @@ trait FirestoreTestHelperTrait private static $_serializer; + /** + * @return Serializer + */ private function getSerializer() { if (!self::$_serializer) { @@ -44,13 +47,6 @@ private function getSerializer() 'google.protobuf.Struct' => function ($v) { return $this->flattenStruct($v); }, - 'google.protobuf.Timestamp' => function ($v) { - return $this->formatTimestampFromApi($v); - }, - ], [], [ - 'google.protobuf.Int32Value' => function ($v) { - return ['value' => $v]; - } ]); } diff --git a/Core/tests/Unit/ServiceBuilderTest.php b/Core/tests/Unit/ServiceBuilderTest.php index 3667628bb29..cab3308a9d4 100644 --- a/Core/tests/Unit/ServiceBuilderTest.php +++ b/Core/tests/Unit/ServiceBuilderTest.php @@ -21,7 +21,6 @@ use Google\Cloud\Core\Testing\CheckForClassTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Datastore\DatastoreClient; -use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\Language\LanguageClient; use Google\Cloud\Logging\LoggingClient; use Google\Cloud\Spanner\SpannerClient; @@ -164,11 +163,6 @@ public function serviceProvider() ], [ 'datastore', DatastoreClient::class - ], [ - 'firestore', - FirestoreClient::class, - [], - [$this, 'checkAndSkipGrpcTests'] ], [ 'logging', LoggingClient::class diff --git a/Firestore/MIGRATION.md b/Firestore/MIGRATION.md new file mode 100644 index 00000000000..7fa9730334a --- /dev/null +++ b/Firestore/MIGRATION.md @@ -0,0 +1,43 @@ +# Migration Guide for V2 library + + +## Timestamp + +Throughout the exposed functionalities of the library, all the `\Google\Cloud\Core\Timestamp` usage has been replaced with `\Google\Protobuf\Timestamp`. + +Earlier usage: + +```php +use Google\Cloud\Code\Timestamp; + +$timestamp = new Timestamp(new \DateTime()); +``` + +Current usage: + +```php +use Google\Protobuf\Timestamp; + +$timestamp = new Timestamp(); +$timestamp->fromDateTime(new \DateTime()); +``` +## ListCollectionIds + +ListCollectionIds rpc is exposed via `DocumentReference::collections()` and `FirestoreClient::collections()` methods. +These method used to return an `\InvalidArgumentException` when `readTime` was invalid. Now we've removed this client +level check and exception is thrown by the Serializer when it converts the array data into Protobuf Request object. + +## ListDocuments + +ListDocuments rpc is exposed via `CollectionReference::listDocuments()` method. These method used to return an `\InvalidArgumentException` +when `readTime` was invalid. Now we've removed this client level check and exception is thrown by the Serializer +when it converts the array data into Protobuf Request object. + +## RunQuery + +RunQuery RPC is exposed via `CollectionReference::documents()` and `Transaction::runQuery()` methods. These method used to return an `\InvalidArgumentException` +when `readTime` was invalid. Now we've removed this client level check and exception is thrown by the Serializer +when it converts the array data into Protobuf Request object. + + + diff --git a/Firestore/src/AggregateQuery.php b/Firestore/src/AggregateQuery.php index 55f8d15554a..e984c329f2b 100644 --- a/Firestore/src/AggregateQuery.php +++ b/Firestore/src/AggregateQuery.php @@ -18,9 +18,11 @@ namespace Google\Cloud\Firestore; use Google\ApiCore\Serializer; +use Google\Cloud\Core\ApiHelperTrait; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\QueryTrait; +use Google\Cloud\Firestore\V1\Client\FirestoreClient; +use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; /** * A Cloud Firestore Aggregate Query. @@ -37,14 +39,9 @@ */ class AggregateQuery { + use ApiHelperTrait; use QueryTrait; - /** - * @var ConnectionInterface - * @internal - */ - private $connection; - /** * @var RequestHandler */ @@ -73,9 +70,6 @@ class AggregateQuery /** * Create an aggregation query. * - * @param ConnectionInterface $connection A Connection to Cloud Firestore. - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -84,14 +78,12 @@ class AggregateQuery * @param Aggregate $aggregate Aggregation over the provided query. */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, $parent, array $query, Aggregate $aggregate ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->parentName = $parent; @@ -114,25 +106,31 @@ public function addAggregation($aggregate) /** * Executes the AggregateQuery. * - * @param array $options [optional] { - * Configuration options is an array. + * @codingStandardsIgnoreStart + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#runaggregationqueryrequest RunAggregationqueryRequest + * @codingStandardsIgnoreEnd + * + * @param array $options [optional] Configuration options is an array. * - * @type Timestamp $readTime Reads entities as they were at the given timestamp. - * } * @return AggregateQuerySnapshot */ public function getSnapshot($options = []) { - $parsedAggregates = []; - foreach ($this->aggregates as $aggregate) { - $parsedAggregates[] = $aggregate->getProps(); - } - $snapshot = $this->connection->runAggregationQuery([ + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += $this->arrayFilterRemoveNull([ 'parent' => $this->parentName, 'structuredAggregationQuery' => $this->aggregateQueryPrepare([ 'aggregates' => $this->aggregates ] + $this->query), - ] + $options)->current(); + ]); + $request = $this->serializer->decodeMessage(new RunAggregationQueryRequest(), $data); + + $snapshot = $this->requestHandler->sendRequest( + FirestoreClient::class, + 'runAggregationQuery', + $request, + $optionalArgs + )->current(); return new AggregateQuerySnapshot($snapshot); } diff --git a/Firestore/src/AggregateQuerySnapshot.php b/Firestore/src/AggregateQuerySnapshot.php index f568c590ac8..efd2af3019f 100644 --- a/Firestore/src/AggregateQuerySnapshot.php +++ b/Firestore/src/AggregateQuerySnapshot.php @@ -17,9 +17,6 @@ namespace Google\Cloud\Firestore; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Core\TimeTrait; - /** * Represents the result set of an AggregateQuery. * @@ -36,10 +33,9 @@ */ class AggregateQuerySnapshot { - use TimeTrait; /** - * @var Timestamp + * @var array */ private $readTime; @@ -64,8 +60,7 @@ public function __construct($snapshot = []) $this->transaction = $snapshot['transaction']; } if (isset($snapshot['readTime'])) { - $time = $this->parseTimeString($snapshot['readTime']); - $this->readTime = new Timestamp($time[0], $time[1]); + $this->readTime = $snapshot['readTime']; } if (isset($snapshot['result']['aggregateFields'])) { $this->aggregateFields = $snapshot['result']['aggregateFields']; @@ -85,7 +80,7 @@ public function getTransaction() /** * Get the Aggregation read time. * - * @return Timestamp + * @return array|null */ public function getReadTime() { diff --git a/Firestore/src/BulkWriter.php b/Firestore/src/BulkWriter.php index 896650e99a2..426cfa01532 100644 --- a/Firestore/src/BulkWriter.php +++ b/Firestore/src/BulkWriter.php @@ -18,16 +18,17 @@ namespace Google\Cloud\Firestore; use Google\ApiCore\Serializer; -use Google\Cloud\Core\ArrayTrait; +use Google\Cloud\Core\ApiHelperTrait; use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Core\TimeTrait; use Google\Cloud\Core\ValidateTrait; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\FieldValue\DeleteFieldValue; use Google\Cloud\Firestore\FieldValue\DocumentTransformInterface; use Google\Cloud\Firestore\FieldValue\FieldValueInterface; +use Google\Cloud\Firestore\V1\BatchWriteRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\CommitRequest; +use Google\Cloud\Firestore\V1\RollbackRequest; use Google\Rpc\Code; /** @@ -49,9 +50,8 @@ */ class BulkWriter { - use ArrayTrait; + use ApiHelperTrait; use DebugInfoTrait; - use TimeTrait; use ValidateTrait; public const TYPE_UPDATE = 'update'; @@ -117,12 +117,6 @@ class BulkWriter 'RATE_LIMITER_MULTIPLIER_MILLIS' => 1000, ]; - /** - * @var ConnectionInterface - * @internal - */ - private $connection; - /** * @var RequestHandler */ @@ -207,7 +201,7 @@ class BulkWriter /** * @var bool Whether BulkWriter greedily sends operations via - * [https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#batchwriterequest](BatchWriteRequest) + * [https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#BatchWriteRequest](BatchWriteRequest) * as soon as sufficient number of operations are enqueued. */ private $greedilySend; @@ -219,9 +213,6 @@ class BulkWriter private $maxDelayTime; /** - * @param ConnectionInterface $connection A connection to Cloud Firestore - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -254,14 +245,12 @@ class BulkWriter * } */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, $valueMapper, $database, $options = null ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->valueMapper = $valueMapper; @@ -678,7 +667,7 @@ public function delete($document, array $options = []) * * @param bool $waitForRetryableFailures Flag to indicate whether to wait for * retryable failures. **Defaults to** `false`. - * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1beta1#BatchWriteResponse](BatchWriteResponse) + * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1#BatchWriteResponse](BatchWriteResponse) */ public function flush($waitForRetryableFailures = false) { @@ -722,37 +711,32 @@ public function flush($waitForRetryableFailures = false) * ``` * * @codingStandardsIgnoreStart - * @see https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Commit Commit + * @see https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.Commit Commit * * @internal Only supposed to be used internally in Transaction class. * @access private * @param array $options Configuration Options - * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1beta1#commitresponse](CommitResponse) + * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1#commitresponse](CommitResponse) * @codingStandardsIgnoreEnd */ public function commit(array $options = []) { unset($options['merge'], $options['precondition']); - $response = $this->connection->commit(array_filter([ + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += array_filter([ 'database' => $this->database, 'writes' => $this->writes, 'transaction' => $this->transaction, - ]) + $options); - - if (isset($response['commitTime'])) { - $time = $this->parseTimeString($response['commitTime']); - $response['commitTime'] = new Timestamp($time[0], $time[1]); - } - - if (isset($response['writeResults'])) { - foreach ($response['writeResults'] as &$result) { - if (isset($result['updateTime'])) { - $time = $this->parseTimeString($result['updateTime']); - $result['updateTime'] = new Timestamp($time[0], $time[1]); - } - } - } + ]); + $request = $this->serializer->decodeMessage(new CommitRequest(), $data); + + $response = $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + $request, + $optionalArgs + ); return $response; } @@ -778,10 +762,19 @@ public function rollback(array $options = []) throw new \RuntimeException('Cannot rollback because no transaction id was provided.'); } - $this->connection->rollback([ + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += [ 'database' => $this->database, 'transaction' => $this->transaction, - ] + $options); + ]; + $request = $this->serializer->decodeMessage(new RollbackRequest(), $data); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + $request, + $optionalArgs + ); } /** @@ -799,7 +792,7 @@ public function isEmpty() * Close the bulk writer instance for further writes. * Also, flushes all retries and pending writes. * - * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1beta1#BatchWriteResponse](BatchWriteResponse) + * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1#BatchWriteResponse](BatchWriteResponse) */ public function close() { @@ -961,7 +954,7 @@ private function createWritesBatchIds($waitForRetryableFailures = false) * @type array $labels * Labels associated with this batch write. * } - * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1beta1#BatchWriteResponse](BatchWriteResponse) + * @return array [https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1#BatchWriteResponse](BatchWriteResponse) */ private function sendBatch(array $writes, array $options = []) { @@ -977,21 +970,21 @@ private function sendBatch(array $writes, array $options = []) $this->rateLimiter->tryMakeRequest(count($writes)); unset($options['merge'], $options['precondition']); - $options += ['labels' => []]; - $response = $this->connection->batchWrite(array_filter([ + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += array_filter([ 'database' => $this->database, 'writes' => $writes, - ]) + $options); - - if (isset($response['writeResults'])) { - foreach ($response['writeResults'] as &$result) { - if (isset($result['updateTime'])) { - $time = $this->parseTimeString($result['updateTime']); - $result['updateTime'] = new Timestamp($time[0], $time[1]); - } - } - } + 'labels' => [] + ]); + $request = $this->serializer->decodeMessage(new BatchWriteRequest(), $data); + + $response = $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + $request, + $optionalArgs + ); return $response; } @@ -1025,7 +1018,7 @@ private function enqueueTransforms($document, array $transforms, array $options $operations[] = [ 'fieldPath' => $transform->fieldPath()->pathString(), - $transform->key() => $args, + $transform->key() => $args['arrayValue'] ?? $args, ]; } @@ -1082,7 +1075,7 @@ private function createDatabaseWrite($type, $document, array $options = []) * @throws \InvalidArgumentException If the precondition is invalid. * @codingStandardsIgnoreEnd */ - private function validatePrecondition(array &$options) + private function validatePrecondition(array $options) { $precondition = $options['precondition'] ?? null; @@ -1090,23 +1083,11 @@ private function validatePrecondition(array &$options) return; } - if (isset($precondition['exists'])) { - return $precondition; - } - - if (isset($precondition['updateTime'])) { - if (!($precondition['updateTime'] instanceof Timestamp)) { - throw new \InvalidArgumentException( - 'Precondition Update Time must be an instance of `Google\\Cloud\\Core\\Timestamp`' - ); - } - - return [ - 'updateTime' => $precondition['updateTime']->formatForApi(), - ]; + if (!isset($precondition['exists']) && !isset($precondition['updateTime'])) { + throw new \InvalidArgumentException('Preconditions must provide either `exists` or `updateTime`.'); } - throw new \InvalidArgumentException('Preconditions must provide either `exists` or `updateTime`.'); + return $precondition; } /** diff --git a/Firestore/src/CollectionReference.php b/Firestore/src/CollectionReference.php index 6279d52eb84..cbbb49c6775 100644 --- a/Firestore/src/CollectionReference.php +++ b/Firestore/src/CollectionReference.php @@ -18,13 +18,13 @@ namespace Google\Cloud\Firestore; use Google\ApiCore\Serializer; -use Google\Cloud\Core\ArrayTrait; +use Google\Cloud\Core\ApiHelperTrait; use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\Iterator\ItemIterator; use Google\Cloud\Core\Iterator\PageIterator; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Core\TimestampTrait; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\ListDocumentsRequest; /** * Represents a Cloud Firestore Collection. @@ -43,16 +43,9 @@ */ class CollectionReference extends Query { - use ArrayTrait; + use ApiHelperTrait; use DebugInfoTrait; use PathTrait; - use TimestampTrait; - - /** - * @var ConnectionInterface - * @internal - */ - private $connection; /** * @var RequestHandler @@ -80,9 +73,6 @@ class CollectionReference extends Query private $parent; /** - * @param ConnectionInterface $connection A Connection to Cloud Firestore. - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -90,20 +80,17 @@ class CollectionReference extends Query * @param string $name The absolute name of the collection. */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $valueMapper, $name ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->valueMapper = $valueMapper; $this->name = $name; parent::__construct( - $connection, $requestHandler, $serializer, $valueMapper, @@ -267,7 +254,7 @@ public function add(array $fields = [], array $options = []) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.ListDocumentsRequest ListDocumentsRequest + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.ListDocumentsRequest ListDocumentsRequest * @codingStandardsIgnoreEnd * * @param array $options { @@ -287,33 +274,31 @@ public function add(array $fields = [], array $options = []) public function listDocuments(array $options = []) { $resultLimit = $this->pluck('resultLimit', $options, false); - - $options += [ + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += [ 'parent' => $this->parentPath($this->name), 'collectionId' => $this->pathId($this->name), - 'mask' => [] + 'showMissing' => true ]; - - $options = $this->formatReadTimeOption($options); + $request = $this->serializer->decodeMessage(new ListDocumentsRequest(), $data); return new ItemIterator( new PageIterator( function ($document) { return $this->documentFactory($document['name']); }, - [$this->connection, 'listDocuments'], - // function ($callOptions) use ($optionalArgs, $request) { - // if (isset($callOptions['pageToken'])) { - // $request->setPageToken($callOptions['pageToken']); - // } + function ($callOptions) use ($optionalArgs, $request) { + if (isset($callOptions['pageToken'])) { + $request->setPageToken($callOptions['pageToken']); + } - // return $this->requestHandler->sendRequest( - // FirestoreClient::class, - // 'listDocuments', - // $request, - // $optionalArgs - // ); - // }, + return $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listDocuments', + $request, + $optionalArgs + ); + }, $options, [ 'itemsKey' => 'documents', @@ -353,7 +338,6 @@ public function parent() private function documentFactory($name) { return new DocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, diff --git a/Firestore/src/Connection/ConnectionInterface.php b/Firestore/src/Connection/ConnectionInterface.php deleted file mode 100644 index e7c3935febc..00000000000 --- a/Firestore/src/Connection/ConnectionInterface.php +++ /dev/null @@ -1,71 +0,0 @@ -serializer = new Serializer([], [ - 'google.protobuf.Value' => function ($v) { - return $this->flattenValue($v); - }, - 'google.protobuf.ListValue' => function ($v) { - return $this->flattenListValue($v); - }, - 'google.protobuf.Struct' => function ($v) { - return $this->flattenStruct($v); - }, - 'google.protobuf.Timestamp' => function ($v) { - return $this->formatTimestampFromApi($v); - }, - ], [], [ - 'google.protobuf.Int32Value' => function ($v) { - return ['value' => $v]; - } - ]); - //@codeCoverageIgnoreEnd - - $config['serializer'] = $this->serializer; - $this->setRequestWrapper(new GrpcRequestWrapper($config)); - - $grpcConfig = $this->getGaxConfig( - ManualFirestoreClient::VERSION, - isset($config['authHttpHandler']) - ? $config['authHttpHandler'] - : null - ); - - if (isset($config['apiEndpoint'])) { - $grpcConfig['apiEndpoint'] = $config['apiEndpoint']; - } - - //@codeCoverageIgnoreStart - $config += ['emulatorHost' => null]; - if ((bool) $config['emulatorHost']) { - $this->isUsingEmulator = true; - $grpcConfig = array_merge( - $grpcConfig, - $this->emulatorGapicConfig($config['emulatorHost']) - ); - } - //@codeCoverageIgnoreEnd - - $this->firestore = $this->constructGapic(FirestoreClient::class, $grpcConfig); - $projectId = $this->pluck('projectId', $config); - $databaseId = $this->pluck('database', $config); - - $this->resourcePrefixHeader = FirestoreClient::databaseRootName( - $projectId, - $databaseId - ); - $this->databaseRoutingHeader = sprintf( - 'project_id=%s&database_id=%s', - $projectId, - $databaseId - ); - } - - /** - * @param array $args - * @return array - */ - public function batchGetDocuments(array $args) - { - $args = $this->decodeTimestamp($args); - - return $this->send([$this->firestore, 'batchGetDocuments'], [ - $this->pluck('database', $args), - $this->pluck('documents', $args), - $this->addRequestHeaders($args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function beginTransaction(array $args) - { - $rw = new ReadWrite; - $retry = $this->pluck('retryTransaction', $args, false); - if ($retry) { - $rw->setRetryTransaction($retry); - } - - $args['options'] = new TransactionOptions; - $args['options']->setReadWrite($rw); - - return $this->send([$this->firestore, 'beginTransaction'], [ - $this->pluck('database', $args), - $this->addRequestHeaders($args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function commit(array $args) - { - $writes = $this->pluck('writes', $args); - foreach ($writes as $idx => $write) { - $writes[$idx] = $this->serializer->decodeMessage(new Write, $write); - } - - return $this->send([$this->firestore, 'commit'], [ - $this->pluck('database', $args), - $writes, - $this->addRequestHeaders($args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function batchWrite(array $args) - { - $writes = $this->pluck('writes', $args); - foreach ($writes as $idx => $write) { - $args['writes'][$idx] = $this->serializer->decodeMessage( - new Write, - $write - ); - } - - return $this->send([$this->firestore, 'batchWrite'], [ - $this->addRequestHeaders($args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function listCollectionIds(array $args) - { - $args = $this->decodeTimestamp($args); - - return $this->send([$this->firestore, 'listCollectionIds'], [ - $this->pluck('parent', $args), - $this->addRequestHeaders($args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function listDocuments(array $args) - { - $mask = $args['mask'] ?? []; - - $args['mask'] = $this->documentMask($mask); - $args = $this->decodeTimestamp($args); - - return $this->send([$this->firestore, 'listDocuments'], [ - $this->pluck('parent', $args), - $this->pluck('collectionId', $args), - $this->addRequestHeaders([ - 'showMissing' => true - ] + $args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function rollback(array $args) - { - return $this->send([$this->firestore, 'rollback'], [ - $this->pluck('database', $args), - $this->pluck('transaction', $args), - $this->addRequestHeaders($args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function runQuery(array $args) - { - $args['structuredQuery'] = $this->serializer->decodeMessage( - new StructuredQuery, - $this->pluck('structuredQuery', $args) - ); - $args = $this->decodeTimestamp($args); - - return $this->send([$this->firestore, 'runQuery'], [ - $this->pluck('parent', $args), - $this->addRequestHeaders($args) - ]); - } - - /** - * @param array $args - * @return array - */ - public function runAggregationQuery(array $args) - { - if (isset($args['readTime'])) { - $args['readTime'] = $this->serializer->decodeMessage( - new ProtobufTimestamp(), - $args['readTime'] - ); - } - $args['structuredAggregationQuery'] = $this->serializer->decodeMessage( - new StructuredAggregationQuery, - $this->pluck('structuredAggregationQuery', $args) - ); - - return $this->send([$this->firestore, 'runAggregationQuery'], [ - $this->pluck('parent', $args), - $this->addRequestHeaders($args) - ]); - } - - private function documentMask(array $mask) - { - return new DocumentMask([ - 'field_paths' => $mask - ]); - } - - /** - * Add required headers to the request. - * - * @param array $args - * @return array - */ - private function addRequestHeaders(array $args) - { - $args += [ - 'headers' => [] - ]; - - $args['headers']['google-cloud-resource-prefix'] = [$this->resourcePrefixHeader]; - $args['headers']['x-goog-request-params'] = [$this->databaseRoutingHeader]; - - // Provide authentication header for requests when emulator is enabled. - if ($this->isUsingEmulator) { - $args['headers']['Authorization'] = ['Bearer owner']; - } - - return $args; - } - - /** - * Decodes the 'readTime' API format timestamp to Protobuf timestamp if - * it is set. - * - * @param array $args - * @return array - */ - private function decodeTimestamp(array $args) - { - if (isset($args['readTime'])) { - $args['readTime'] = $this->serializer->decodeMessage( - new ProtobufTimestamp(), - $args['readTime'] - ); - } - return $args; - } - - /** - * @access private - * @codeCoverageIgnore - * @return array - */ - public function __debugInfo() - { - return [ - 'serializer' => get_class($this->serializer), - 'firestore' => get_class($this->firestore), - 'resourcePrefixHeader' => $this->resourcePrefixHeader, - 'databaseRoutingHeader' => $this->databaseRoutingHeader, - 'isUsingEmulator' => $this->isUsingEmulator - ]; - } -} diff --git a/Firestore/src/DocumentReference.php b/Firestore/src/DocumentReference.php index 6eae4355364..8f71f6e76b0 100644 --- a/Firestore/src/DocumentReference.php +++ b/Firestore/src/DocumentReference.php @@ -22,7 +22,8 @@ use Google\Cloud\Core\Iterator\ItemIterator; use Google\Cloud\Core\Iterator\PageIterator; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; /** * Represents a reference to a Firestore document. @@ -40,12 +41,6 @@ class DocumentReference use SnapshotTrait; use DebugInfoTrait; - /** - * @var ConnectionInterface - * @internal - */ - private $connection; - /** * @var RequestHandler */ @@ -72,9 +67,6 @@ class DocumentReference private $name; /** - * @param ConnectionInterface $connection A Connection to Cloud Firestore. - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -83,14 +75,12 @@ class DocumentReference * @param string $name The fully-qualified document name. */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $valueMapper, CollectionReference $parent, $name ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->valueMapper = $valueMapper; @@ -188,14 +178,14 @@ public function id() * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Commit Commit + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.Commit Commit * * @param array $fields An array containing fields, where keys are the field * names, and values are field values. Nested arrays are allowed. * Note that unlike {@see \Google\Cloud\Firestore\DocumentReference::update()}, * field paths are NOT supported by this method. * @param array $options Configuration Options. - * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.WriteResult) + * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.WriteResult) * @codingStandardsIgnoreEnd */ public function create(array $fields = [], array $options = []) @@ -223,7 +213,7 @@ public function create(array $fields = [], array $options = []) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Commit Commit + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.Commit Commit * @codingStandardsIgnoreEnd * * @param array $fields An array containing fields, where keys are the field @@ -238,7 +228,7 @@ public function create(array $fields = [], array $options = []) * `false`. * } * @codingStandardsIgnoreStart - * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.WriteResult) + * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.WriteResult) * @codingStandardsIgnoreEnd */ public function set(array $fields, array $options = []) @@ -304,12 +294,12 @@ public function set(array $fields, array $options = []) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Commit Commit + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.Commit Commit * * @param array[] $data A list of arrays of form * `[FieldPath|string $path, mixed $value]`. * @param array $options Configuration options - * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.WriteResult) + * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.WriteResult) * @throws \InvalidArgumentException If data is given in an invalid format * or is empty. * @throws \InvalidArgumentException If any field paths are empty. @@ -334,10 +324,10 @@ public function update(array $data, array $options = []) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Commit Commit + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.Commit Commit * * @param array $options Configuration Options - * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.WriteResult) + * @return array [WriteResult](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.WriteResult) * @codingStandardsIgnoreEnd */ public function delete(array $options = []) @@ -358,16 +348,15 @@ public function delete(array $options = []) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.BatchGetDocuments BatchGetDocuments + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.BatchGetDocuments BatchGetDocuments * @codingStandardsIgnoreEnd * - * @param array $options Configuration Options + * @param array $options Configuration options. * @return DocumentSnapshot */ public function snapshot(array $options = []) { return $this->createSnapshot( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -390,7 +379,6 @@ public function snapshot(array $options = []) public function collection($collectionId) { return new CollectionReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -407,44 +395,41 @@ public function collection($collectionId) * ``` * * @codingStandardsIgnoreStart - * https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.ListCollectionIds ListCollectionIds + * https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.ListCollectionIds ListCollectionIds * @codingStandardsIgnoreEnd * * @param array $options Configuration options. * @return ItemIterator - * @throws \InvalidArgumentException if an invalid `$options.readTime` is - * specified. */ public function collections(array $options = []) { - $options = $this->formatReadTimeOption($options); - $resultLimit = $this->pluck('resultLimit', $options, false); + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += ['parent' => $this->name]; + $request = $this->serializer->decodeMessage(new ListCollectionIdsRequest(), $data); return new ItemIterator( new PageIterator( function ($collectionId) { return new CollectionReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, $this->childPath($this->name, $collectionId) ); }, - [$this->connection, 'listCollectionIds'], - // function ($callOptions) use ($optionalArgs, $request) { - // if (isset($callOptions['pageToken'])) { - // $request->setPageToken($callOptions['pageToken']); - // } + function ($callOptions) use ($optionalArgs, $request) { + if (isset($callOptions['pageToken'])) { + $request->setPageToken($callOptions['pageToken']); + } - // return $this->requestHandler->sendRequest( - // FirestoreClient::class, - // 'listCollectionIds', - // $request, - // $optionalArgs - // ); - // }, - $options + ['parent' => $this->name], + return $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + $request, + $optionalArgs + ); + }, + $options, [ 'itemsKey' => 'collectionIds', 'resultLimit' => $resultLimit @@ -464,7 +449,6 @@ protected function batchFactory() class_alias(BulkWriter::class, WriteBatch::class); } return new BulkWriter( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, diff --git a/Firestore/src/DocumentSnapshot.php b/Firestore/src/DocumentSnapshot.php index f77cc329a9a..81e33ca30b3 100644 --- a/Firestore/src/DocumentSnapshot.php +++ b/Firestore/src/DocumentSnapshot.php @@ -17,8 +17,6 @@ namespace Google\Cloud\Firestore; -use Google\Cloud\Core\Timestamp; - /** * Represents the data of a document at the time of retrieval. * A snapshot is immutable and may point to a non-existing document. @@ -172,13 +170,11 @@ public function id() * $updateTime = $snapshot->updateTime(); * ``` * - * @return Timestamp|null + * @return array|null */ public function updateTime() { - return isset($this->info['updateTime']) - ? $this->info['updateTime'] - : null; + return $this->info['updateTime'] ?? null; } /** @@ -189,13 +185,11 @@ public function updateTime() * $readTime = $snapshot->readTime(); * ``` * - * @return Timestamp|null + * @return array|null */ public function readTime() { - return isset($this->info['readTime']) - ? $this->info['readTime'] - : null; + return $this->info['readTime'] ?? null; } /** @@ -206,13 +200,11 @@ public function readTime() * $createTime = $snapshot->createTime(); * ``` * - * @return Timestamp|null + * @return array|null */ public function createTime() { - return isset($this->info['createTime']) - ? $this->info['createTime'] - : null; + return $this->info['createTime'] ?? null; } /** @@ -227,9 +219,7 @@ public function createTime() */ public function data() { - return $this->exists - ? $this->data - : null; + return $this->exists ? $this->data : null; } /** diff --git a/Firestore/src/FirestoreClient.php b/Firestore/src/FirestoreClient.php index d70925a7488..c44d72f608e 100644 --- a/Firestore/src/FirestoreClient.php +++ b/Firestore/src/FirestoreClient.php @@ -17,12 +17,10 @@ namespace Google\Cloud\Firestore; -use Google\ApiCore\ArrayTrait; use Google\ApiCore\ClientOptionsTrait; use Google\ApiCore\Serializer; use Google\Cloud\Core\ApiHelperTrait; use Google\Cloud\Core\Blob; -use Google\Cloud\Core\ClientTrait; use Google\Cloud\Core\DetectProjectIdTrait; use Google\Cloud\Core\Exception\AbortedException; use Google\Cloud\Core\Exception\GoogleException; @@ -32,9 +30,9 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Retry; use Google\Cloud\Core\ValidateTrait; -use Google\Cloud\Firestore\Connection\Grpc; -use Google\Cloud\Firestore\V1\Client\FirestoreClient as ClientFirestoreClient; -use Psr\Cache\CacheItemPoolInterface; +use Google\Cloud\Firestore\V1\BeginTransactionRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; use Psr\Http\Message\StreamInterface; /** @@ -78,10 +76,9 @@ */ class FirestoreClient { - use ClientTrait; // To remove in the end use ApiHelperTrait; use ClientOptionsTrait; - // use DetectProjectIdTrait; // To uncomment when ClientTrait is removed + use DetectProjectIdTrait; use SnapshotTrait; use ValidateTrait; @@ -93,20 +90,6 @@ class FirestoreClient const MAX_RETRIES = 5; - /** - * Keeping this consistent with veneer libraries where - * multiple clients are present. - */ - private const GAPIC_KEYS = [ - ClientFirestoreClient::class - ]; - - /** - * @var Connection\ConnectionInterface - * @internal - */ - private $connection; - /** * @var RequestHandler * @internal @@ -129,6 +112,11 @@ class FirestoreClient */ private $valueMapper; + /** + * @var string + */ + private $projectId; + /** * Create a Firestore client. Please note that this client requires * [the gRPC extension](https://cloud.google.com/php/grpc). @@ -171,7 +159,14 @@ public function __construct(array $config = []) { $emulatorHost = getenv('FIRESTORE_EMULATOR_HOST'); - $this->requireGrpc(); + if (!extension_loaded('grpc')) { + throw new GoogleException( + 'The requested client requires the gRPC extension. ' . + 'Please see https://cloud.google.com/php/grpc for installation ' . + 'instructions.' + ); + } + $config += [ 'returnInt64AsObject' => false, 'scopes' => [self::FULL_CONTROL_SCOPE], @@ -181,20 +176,15 @@ public function __construct(array $config = []) ]; - // COMMENT THIS OUT WHILE UPDATING RPCs - // $config = $this->buildClientOptions($config); - // $config['credentials'] = $this->createCredentialsWrapper( - // $config['credentials'], - // $config['credentialsConfig'], - // $config['universeDomain'] - // ); + $config = $this->buildClientOptions($config); + $config['credentials'] = $this->createCredentialsWrapper( + $config['credentials'], + $config['credentialsConfig'], + $config['universeDomain'] + ); $this->database = $config['database']; - $this->connection = new Grpc($this->configureAuthentication($config) + [ - 'projectId' => $this->projectId, - ]); - $this->serializer = new Serializer([], [ 'google.protobuf.Value' => function ($v) { return $this->flattenValue($v); @@ -205,27 +195,21 @@ public function __construct(array $config = []) 'google.protobuf.Struct' => function ($v) { return $this->flattenStruct($v); }, - 'google.protobuf.Timestamp' => function ($v) { - return $this->formatTimestampFromApi($v); - }, - ], [], [ - 'google.protobuf.Int32Value' => function ($v) { - return ['value' => $v]; - } ]); $this->requestHandler = new RequestHandler( $this->serializer, - self::GAPIC_KEYS, + [V1FirestoreClient::class], $config ); $this->valueMapper = new ValueMapper( - $this->connection, $this->requestHandler, $this->serializer, $config['returnInt64AsObject'] ); + + $this->projectId = $this->detectProjectId($config); } /** @@ -248,7 +232,6 @@ public function batch() class_alias(BulkWriter::class, WriteBatch::class); } return new BulkWriter( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -302,7 +285,6 @@ class_alias(BulkWriter::class, WriteBatch::class); public function bulkWriter(array $options = []) { return new BulkWriter( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -332,7 +314,6 @@ public function bulkWriter(array $options = []) public function collection($name) { return $this->getCollectionReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -351,7 +332,7 @@ public function collection($name) * ``` * * @codingStandardsIgnoreStart - * @see https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.ListCollectionIds ListCollectionIds + * @see https://firebase.google.com/docs/firestore/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.ListCollectionIds ListCollectionIds * @codingStandardsIgnoreEnd * * @param array $options [optional] { @@ -365,35 +346,32 @@ public function collection($name) * resume the loading of results from a specific point. * } * @return ItemIterator - * @throws \InvalidArgumentException if an invalid `$options.readTime` is - * specified. */ public function collections(array $options = []) { - $options = $this->formatReadTimeOption($options); - $resultLimit = $this->pluck('resultLimit', $options, false); + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += ['parent' => $this->fullName($this->projectId, $this->database)]; + $request = $this->serializer->decodeMessage(new ListCollectionIdsRequest(), $data); + return new ItemIterator( new PageIterator( function ($collectionId) { return $this->collection($collectionId); }, - [$this->connection, 'listCollectionIds'], - // function ($callOptions) use ($optionalArgs, $request) { - // if (isset($callOptions['pageToken'])) { - // $request->setPageToken($callOptions['pageToken']); - // } - - // return $this->requestHandler->sendRequest( - // FirestoreClient::class, - // 'listCollectionIds', - // $request, - // $optionalArgs - // ); - // }, - [ - 'parent' => $this->fullName($this->projectId, $this->database), - ] + $options, + function ($callOptions) use ($optionalArgs, $request) { + if (isset($callOptions['pageToken'])) { + $request->setPageToken($callOptions['pageToken']); + } + + return $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + $request, + $optionalArgs + ); + }, + $options, [ 'itemsKey' => 'collectionIds', 'resultLimit' => $resultLimit, @@ -417,7 +395,6 @@ function ($collectionId) { public function document($name) { return $this->getDocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -460,7 +437,7 @@ public function document($name) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.BatchGetDocuments BatchGetDocuments + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.BatchGetDocuments BatchGetDocuments * @codingStandardsIgnoreEnd * * @param string[]|DocumentReference[] $paths Any combination of string paths or DocumentReference instances. @@ -470,7 +447,6 @@ public function document($name) public function documents(array $paths, array $options = []) { return $this->getDocumentsByPaths( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -511,7 +487,6 @@ public function collectionGroup($id) } return new Query( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -574,9 +549,9 @@ public function collectionGroup($id) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.BeginTransaction BeginTransaction - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Commit Commit - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.Rollback Rollback + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.BeginTransaction BeginTransaction + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.Commit Commit + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.Rollback Rollback * @codingStandardsIgnoreEnd * * @param callable $callable A callable function, allowing atomic operations @@ -632,15 +607,23 @@ public function runTransaction(callable $callable, array $options = []) ) use (&$transactionId) { $database = $this->databaseName($this->projectId, $this->database); - $beginTransaction = $this->connection->beginTransaction(array_filter([ - 'database' => $database, - 'retryTransaction' => $transactionId, - ]) + $options['begin']); + list($data, $optionalArgs) = $this->splitOptionalArgs($options['begin']); + if ($transactionId) { + $data['options']['readWrite']['retryTransaction'] = $transactionId; + } + $data['database'] = $database; + + $request = $this->serializer->decodeMessage(new BeginTransactionRequest(), $data); + $beginTransaction = $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + $request, + $optionalArgs + ); $transactionId = $beginTransaction['transaction']; $transaction = new Transaction( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -771,7 +754,6 @@ public function fieldPath(array $fieldNames) public function sessionHandler(array $options = []) { return new FirestoreSessionHandler( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, diff --git a/Firestore/src/FirestoreSessionHandler.php b/Firestore/src/FirestoreSessionHandler.php index 45ec4961cc2..9ddf99b44f7 100644 --- a/Firestore/src/FirestoreSessionHandler.php +++ b/Firestore/src/FirestoreSessionHandler.php @@ -20,7 +20,8 @@ use Google\Cloud\Core\Exception\ServiceException; use Google\Cloud\Core\RequestHandler; use SessionHandlerInterface; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\BeginTransactionRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; /** * Custom session handler backed by Cloud Firestore. @@ -117,12 +118,6 @@ class FirestoreSessionHandler implements SessionHandlerInterface { use SnapshotTrait; - /** - * @var ConnectionInterface - * @internal - */ - private $connection; - /** * @var RequestHandler */ @@ -169,9 +164,6 @@ class FirestoreSessionHandler implements SessionHandlerInterface /** * Create a custom session handler backed by Cloud Firestore. * - * @param ConnectionInterface $connection A Connection to Cloud Firestore. - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -197,7 +189,6 @@ class FirestoreSessionHandler implements SessionHandlerInterface * } */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $valueMapper, @@ -205,7 +196,6 @@ public function __construct( $database, array $options = [] ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->valueMapper = $valueMapper; @@ -242,9 +232,16 @@ public function open($savePath, $sessionName) $database = $this->databaseName($this->projectId, $this->database); try { - $beginTransaction = $this->connection->beginTransaction([ - 'database' => $database - ] + $this->options['begin']); + list($data, $optionalArgs) = $this->splitOptionalArgs($this->options['begin']); + $data['database'] = $database; + + $request = $this->serializer->decodeMessage(new BeginTransactionRequest(), $data); + $beginTransaction = $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + $request, + $optionalArgs + ); } catch (ServiceException $e) { trigger_error( sprintf('Firestore beginTransaction failed: %s', $e->getMessage()), @@ -253,7 +250,6 @@ public function open($savePath, $sessionName) } $this->transaction = new Transaction( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -297,7 +293,6 @@ public function read($id) $this->id = $id; try { $docRef = $this->getDocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -332,7 +327,6 @@ public function read($id) public function write($id, $data) { $docRef = $this->getDocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -357,7 +351,6 @@ public function write($id, $data) public function destroy($id) { $docRef = $this->getDocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -385,12 +378,18 @@ public function gc($maxlifetime) $deleteCount = 0; try { $database = $this->databaseName($this->projectId, $this->database); - $beginTransaction = $this->connection->beginTransaction([ - 'database' => $database - ] + $this->options['begin']); + list($data, $optionalArgs) = $this->splitOptionalArgs($this->options['begin']); + $data['database'] = $database; + + $request = $this->serializer->decodeMessage(new BeginTransactionRequest(), $data); + $beginTransaction = $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + $request, + $optionalArgs + ); $transaction = new Transaction( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -399,7 +398,6 @@ public function gc($maxlifetime) ); $collectionRef = $this->getCollectionReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, diff --git a/Firestore/src/Query.php b/Firestore/src/Query.php index 8eae5cd9612..d052af8d44d 100644 --- a/Firestore/src/Query.php +++ b/Firestore/src/Query.php @@ -21,15 +21,16 @@ use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\ExponentialBackoff; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldValue\FieldValueInterface; use Google\Cloud\Firestore\QueryTrait; use Google\Cloud\Firestore\SnapshotTrait; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\StructuredQuery\CompositeFilter\Operator; use Google\Cloud\Firestore\V1\StructuredQuery\Direction; use Google\Cloud\Firestore\V1\StructuredQuery\FieldFilter\Operator as FieldFilterOperator; use Google\Cloud\Firestore\V1\StructuredQuery\UnaryFilter\Operator as UnaryFilterOperator; +use Google\Cloud\Firestore\V1\RunQueryRequest; /** * A Cloud Firestore Query. @@ -118,12 +119,6 @@ class Query 'DESCENDING' => self::DIR_DESCENDING ]; - /** - * @var ConnectionInterface - * @internal - */ - private $connection; - /** * @var RequestHandler */ @@ -155,9 +150,6 @@ class Query private $limitToLast; /** - * @param ConnectionInterface $connection A Connection to Cloud Firestore. - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -168,7 +160,6 @@ class Query * @throws \InvalidArgumentException If the query does not provide a valid selector. */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $valueMapper, @@ -176,7 +167,6 @@ public function __construct( array $query, $limitToLast = false ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->valueMapper = $valueMapper; @@ -199,11 +189,11 @@ public function __construct( * $count = $query->count(); * ``` * - * @param array $options [optional] { - * Configuration options is an array. + * @codingStandardsIgnoreStart + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#runaggregationqueryrequest RunAggregationqueryRequest + * @codingStandardsIgnoreEnd * - * @type Timestamp $readTime Reads entities as they were at the given timestamp. - * } + * @param array $options [optional] Configuration options is an array. * @return int */ public function count(array $options = []) @@ -227,12 +217,12 @@ public function count(array $options = []) * Sum of data which contains `NaN` returns `NaN`. * Non numeric values are ignored. * - * @param string $field The relative path of the field to aggregate upon. - * @param array $options [optional] { - * Configuration options is an array. + * @codingStandardsIgnoreStart + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#runaggregationqueryrequest RunAggregationqueryRequest + * @codingStandardsIgnoreEnd * - * @type Timestamp $readTime Reads entities as they were at the given timestamp. - * } + * @param string $field The relative path of the field to aggregate upon. + * @param array $options [optional] Configuration options is an array. * @return int|float */ public function sum(string $field, array $options = []) @@ -256,12 +246,12 @@ public function sum(string $field, array $options = []) * Average of data which contains `NaN` returns `NaN`. * Non numeric values are ignored. * - * @param string $field The relative path of the field to aggregate upon. - * @param array $options [optional] { - * Configuration options is an array. + * @codingStandardsIgnoreStart + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#runaggregationqueryrequest RunAggregationqueryRequest + * @codingStandardsIgnoreEnd * - * @type Timestamp $readTime Reads entities as they were at the given timestamp. - * } + * @param string $field The relative path of the field to aggregate upon. + * @param array $options [optional] Configuration options is an array. * @return float|null */ public function avg(string $field, array $options = []) @@ -291,7 +281,6 @@ public function avg(string $field, array $options = []) public function addAggregation($aggregate) { $aggregateQuery = new AggregateQuery( - $this->connection, $this->requestHandler, $this->serializer, $this->parentName, @@ -314,7 +303,7 @@ public function addAggregation($aggregate) * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.RunQuery RunQuery + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.RunQuery RunQuery * @codingStandardsIgnoreEnd * @param array $options { * Configuration options. @@ -323,31 +312,33 @@ public function addAggregation($aggregate) * **Defaults to** `5`. * } * @return QuerySnapshot - * @throws \InvalidArgumentException if an invalid `$options.readTime` is - * specified. * @throws \RuntimeException If limit-to-last is enabled but no order-by has * been specified. */ public function documents(array $options = []) { - $options = $this->formatReadTimeOption($options); - $maxRetries = $this->pluck('maxRetries', $options, false); - $maxRetries = $maxRetries === null - ? FirestoreClient::MAX_RETRIES - : $maxRetries; + $maxRetries = $maxRetries ?? FirestoreClient::MAX_RETRIES; $query = $this->structuredQueryPrepare([ 'query' => $this->query, 'limitToLast' => $this->limitToLast ]); $rows = (new ExponentialBackoff($maxRetries))->execute(function () use ($query, $options) { - - $generator = $this->connection->runQuery($this->arrayFilterRemoveNull([ + list($data, $optionalArgs) = $this->splitOptionalArgs( + ['retrySettings' => ['maxRetries' => 0]] + $options + ); + $data += $this->arrayFilterRemoveNull([ 'parent' => $this->parentName, 'structuredQuery' => $query, - 'retries' => 0 - ]) + $options); + ]); + $request = $this->serializer->decodeMessage(new RunQueryRequest(), $data); + $generator = $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + $request, + $optionalArgs + ); // cache collection references $collections = []; @@ -360,7 +351,6 @@ public function documents(array $options = []) $collectionName = $this->parentPath($result['document']['name']); if (!isset($collections[$collectionName])) { $collections[$collectionName] = new CollectionReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -369,7 +359,6 @@ public function documents(array $options = []) } $ref = new DocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -574,7 +563,7 @@ public function orderBy($fieldPath, $direction = self::DIR_ASCENDING) public function limit($number) { return $this->newQuery([ - 'limit' => $number + 'limit' => ['value' => $number] ], false, false); // create a new query, explicitly setting `limitToLast` to false. } @@ -598,7 +587,7 @@ public function limit($number) public function limitToLast($number) { return $this->newQuery([ - 'limit' => $number + 'limit' => ['value' => $number] ], false, true); // create a new query, explicitly setting `limitToLast` to true. } @@ -997,7 +986,6 @@ private function newQuery(array $additionalConfig, $overrideTopLevelKeys = false $query = $this->arrayMergeRecursive($query, $additionalConfig); return new self( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -1036,7 +1024,6 @@ private function createDocumentReference($basePath, $document) } $parent = new CollectionReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, @@ -1044,7 +1031,6 @@ private function createDocumentReference($basePath, $document) ); return new DocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, diff --git a/Firestore/src/SnapshotTrait.php b/Firestore/src/SnapshotTrait.php index f6512e15025..2c5c6431660 100644 --- a/Firestore/src/SnapshotTrait.php +++ b/Firestore/src/SnapshotTrait.php @@ -19,14 +19,11 @@ use Google\ApiCore\Serializer; use Google\Cloud\Core\ApiHelperTrait; -use Google\Cloud\Core\ArrayTrait; use Google\Cloud\Core\Exception\NotFoundException; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Core\TimeTrait; -use Google\Cloud\Core\TimestampTrait; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient; /** * Methods common to representing Document Snapshots. @@ -35,15 +32,10 @@ trait SnapshotTrait { use ApiHelperTrait; use PathTrait; - use TimeTrait; - use TimestampTrait; /** * Execute a service request to retrieve a document snapshot. * - * @param ConnectionInterface $connection A Connection to Cloud Firestore. - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -57,7 +49,6 @@ trait SnapshotTrait * @return DocumentSnapshot */ private function createSnapshot( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $valueMapper, @@ -70,7 +61,6 @@ private function createSnapshot( try { $document = $this->getSnapshot( - $connection, $requestHandler, $serializer, $reference->name(), @@ -105,15 +95,12 @@ private function createSnapshotWithData( ? $valueMapper->decodeValues($this->pluck('fields', $document)) : []; - $document = $this->transformSnapshotTimestamps($document); - return new DocumentSnapshot($reference, $valueMapper, $document, $fields, $exists); } /** * Send a service request for a snapshot, and return the raw data * - * @param ConnectionInterface $connection A Connection to Cloud Firestore * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -125,18 +112,23 @@ private function createSnapshotWithData( * @throws NotFoundException If the document does not exist. */ private function getSnapshot( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, $name, array $options = [] ) { - $options = $this->formatReadTimeOption($options); - - $snapshot = $connection->batchGetDocuments([ + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += [ 'database' => $this->databaseFromName($name), 'documents' => [$name], - ] + $options)->current(); + ]; + $request = $serializer->decodeMessage(new BatchGetDocumentsRequest(), $data); + $snapshot = $requestHandler->sendRequest( + FirestoreClient::class, + 'batchGetDocuments', + $request, + $optionalArgs + )->current(); if (!isset($snapshot['found'])) { throw new NotFoundException(sprintf( @@ -153,7 +145,6 @@ private function getSnapshot( * input order, creates a list of snapshots (whether the document exists or * not), and returns. * - * @param ConnectionInterface $connection A connection to Cloud Firestore. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -166,7 +157,6 @@ private function getSnapshot( * @return DocumentSnapshot[] */ private function getDocumentsByPaths( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $mapper, @@ -194,10 +184,18 @@ private function getDocumentsByPaths( $documentNames[] = $path; } - $documents = $this->connection->batchGetDocuments([ + list($data, $optionalArgs) = $this->splitOptionalArgs($options); + $data += [ 'database' => $this->databaseName($projectId, $database), 'documents' => $documentNames, - ] + $options); + ]; + $request = $serializer->decodeMessage(new BatchGetDocumentsRequest(), $data); + $documents = $requestHandler->sendRequest( + FirestoreClient::class, + 'batchGetDocuments', + $request, + $optionalArgs + ); $res = []; foreach ($documents as $document) { @@ -211,7 +209,6 @@ private function getDocumentsByPaths( : $document['missing']; $ref = $this->getDocumentReference( - $connection, $requestHandler, $serializer, $mapper, @@ -239,7 +236,6 @@ private function getDocumentsByPaths( /** * Creates a DocumentReference object. * - * @param ConnectionInterface $connection A connection to Cloud Firestore. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -251,7 +247,6 @@ private function getDocumentsByPaths( * @throws \InvalidArgumentException if an invalid path is provided. */ private function getDocumentReference( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $mapper, @@ -268,12 +263,10 @@ private function getDocumentReference( } return new DocumentReference( - $connection, $requestHandler, $serializer, $mapper, $this->getCollectionReference( - $connection, $requestHandler, $serializer, $mapper, @@ -288,7 +281,6 @@ private function getDocumentReference( /** * Creates a CollectionReference object. * - * @param ConnectionInterface $connection A connection to Cloud Firestore. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -300,7 +292,6 @@ private function getDocumentReference( * @throws \InvalidArgumentException if an invalid path is provided. */ private function getCollectionReference( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $mapper, @@ -320,32 +311,10 @@ private function getCollectionReference( } return new CollectionReference( - $connection, $requestHandler, $serializer, $mapper, $name ); } - - /** - * Convert snapshot timestamps to Google Cloud PHP types. - * - * @param array $data The snapshot data. - * @return array - */ - private function transformSnapshotTimestamps(array $data) - { - foreach (['createTime', 'updateTime', 'readTime'] as $timestampField) { - if (!isset($data[$timestampField])) { - continue; - } - - list($dt, $nanos) = $this->parseTimeString($data[$timestampField]); - - $data[$timestampField] = new Timestamp($dt, $nanos); - } - - return $data; - } } diff --git a/Firestore/src/Transaction.php b/Firestore/src/Transaction.php index d6de7221e54..3f6a672ce2e 100644 --- a/Firestore/src/Transaction.php +++ b/Firestore/src/Transaction.php @@ -20,8 +20,6 @@ use Google\ApiCore\Serializer; use Google\Cloud\Core\DebugInfoTrait; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Firestore\Connection\ConnectionInterface; /** * Represents a Firestore transaction. @@ -50,11 +48,6 @@ class Transaction use SnapshotTrait; use DebugInfoTrait; - /** - * @var ConnectionInterface - */ - private $connection; - /** * @var RequestHandler */ @@ -86,7 +79,6 @@ class Transaction private $writer; /** - * @param ConnectionInterface $connection A connection to Cloud Firestore. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -95,14 +87,12 @@ class Transaction * @param string $transaction The transaction ID. */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $valueMapper, $database, $transaction ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->valueMapper = $valueMapper; @@ -110,7 +100,6 @@ public function __construct( $this->transaction = $transaction; $this->writer = new BulkWriter( - $connection, $requestHandler, $serializer, $valueMapper, @@ -127,19 +116,25 @@ public function __construct( * $snapshot = $transaction->snapshot($document); * ``` * + * @codingStandardsIgnoreStart + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.BatchGetDocuments BatchGetDocuments + * @codingStandardsIgnoreEnd + * * @param DocumentReference $document The document to retrieve. * @param array $options Configuration options. * @return DocumentSnapshot */ public function snapshot(DocumentReference $document, array $options = []) { + if ($this->transaction) { + $options += ['transaction' => $this->transaction]; + } return $this->createSnapshot( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, $document, - ['transaction' => $this->transaction] + $options + $options ); } @@ -151,27 +146,16 @@ public function snapshot(DocumentReference $document, array $options = []) * $snapshot = $transaction->runAggregateQuery($aggregateQuery); * ``` * - * @param AggregateQuery $aggregateQuery The aggregate query to retrieve. - * @param array $options { - * Configuration Options + * @codingStandardsIgnoreStart + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#runaggregationqueryrequest RunAggregationqueryRequest + * @codingStandardsIgnoreEnd * - * @type Timestamp $readTime Reads entities as they were at the given timestamp. - * } + * @param AggregateQuery $aggregateQuery The aggregate query to retrieve. + * @param array $options [optional] Configuration options is an array. * @return AggregateQuerySnapshot - * @throws \InvalidArgumentException if an invalid `$options.readTime` is specified. */ public function runAggregateQuery(AggregateQuery $aggregateQuery, array $options = []) { - if (isset($options['readTime'])) { - if (!($options['readTime'] instanceof Timestamp)) { - throw new \InvalidArgumentException(sprintf( - '`$options.readTime` must be an instance of %s', - Timestamp::class - )); - } - - $options['readTime'] = $options['readTime']->formatForApi(); - } return $aggregateQuery->getSnapshot([ 'transaction' => $this->transaction ] + $options); @@ -210,7 +194,7 @@ public function runAggregateQuery(AggregateQuery $aggregateQuery, array $options * ``` * * @codingStandardsIgnoreStart - * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Firestore.BatchGetDocuments BatchGetDocuments + * @see https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Firestore.BatchGetDocuments BatchGetDocuments * @codingStandardsIgnoreEnd * * @param string[]|DocumentReference[] $paths Any combination of string paths or DocumentReference instances. @@ -220,7 +204,6 @@ public function runAggregateQuery(AggregateQuery $aggregateQuery, array $options public function documents(array $paths, array $options = []) { return $this->getDocumentsByPaths( - $this->connection, $this->requestHandler, $this->serializer, $this->valueMapper, diff --git a/Firestore/src/V1/StructuredQuery.php b/Firestore/src/V1/StructuredQuery.php index 47ed315b963..693658bff2f 100644 --- a/Firestore/src/V1/StructuredQuery.php +++ b/Firestore/src/V1/StructuredQuery.php @@ -195,7 +195,7 @@ class StructuredQuery extends \Google\Protobuf\Internal\Message * @type int $offset * The number of documents to skip before returning the first result. * This applies after the constraints specified by the `WHERE`, `START AT`, & - * `END AT` but before the `LIMIT` clause. + * `END AT` but before the `LIMIT` clause. * Requires: * * The value must be greater than or equal to zero if specified. * @type \Google\Protobuf\Int32Value $limit diff --git a/Firestore/src/ValueMapper.php b/Firestore/src/ValueMapper.php index 34915d01499..acb31a3e7e5 100644 --- a/Firestore/src/ValueMapper.php +++ b/Firestore/src/ValueMapper.php @@ -24,11 +24,9 @@ use Google\Cloud\Core\GeoPoint; use Google\Cloud\Core\Int64; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Core\TimeTrait; use Google\Cloud\Core\ValidateTrait; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Protobuf\NullValue; +use Google\Protobuf\Timestamp; /** * Normalizes values between Google Cloud PHP and Cloud Firestore. @@ -40,18 +38,11 @@ class ValueMapper use ArrayTrait; use DebugInfoTrait; use PathTrait; - use TimeTrait; use ValidateTrait; public const VALID_FIELD_PATH = '/^[^*~\/[\]]+$/'; public const UNESCAPED_FIELD_NAME = '/^[_a-zA-Z][_a-zA-Z0-9]*$/'; - /** - * @var ConnectionInterface - * @internal - */ - private $connection; - /** * @var RequestHandler */ @@ -68,9 +59,6 @@ class ValueMapper private $returnInt64AsObject; /** - * @param ConnectionInterface $connection A connection to Cloud Firestore - * This object is created by FirestoreClient, - * and should not be instantiated outside of this client. * @param RequestHandler $requestHandler The request handler responsible for sending * requests and serializing responses into relevant classes. * @param Serializer $serializer The serializer instance to encode/decode messages. @@ -78,12 +66,10 @@ class ValueMapper * (to preserve values in 32-bit environments). */ public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, $returnInt64AsObject ) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->serializer = $serializer; $this->returnInt64AsObject = $returnInt64AsObject; @@ -143,6 +129,7 @@ private function decodeValue($type, $value) case 'booleanValue': case 'stringValue': case 'doubleValue': + case 'timestampValue': return $value; break; @@ -157,10 +144,7 @@ private function decodeValue($type, $value) ? new Int64($value) : (int) $value; - case 'timestampValue': - $time = $this->parseTimeString($value); - return new Timestamp($time[0], $time[1]); - break; + case 'geoPointValue': $value += [ @@ -201,14 +185,12 @@ private function decodeValue($type, $value) case 'referenceValue': $parent = new CollectionReference( - $this->connection, $this->requestHandler, $this->serializer, $this, $this->parentPath($value) ); return new DocumentReference( - $this->connection, $this->requestHandler, $this->serializer, $this, @@ -326,22 +308,8 @@ private function encodeObjectValue($value) return ['bytesValue' => (string) $value]; } - if ($value instanceof \DateTimeInterface) { - return [ - 'timestampValue' => [ - 'seconds' => $value->format('U'), - 'nanos' => (int)($value->format('u') * 1000) - ] - ]; - } - if ($value instanceof Timestamp) { - return [ - 'timestampValue' => [ - 'seconds' => $value->get()->format('U'), - 'nanos' => $value->nanoSeconds() - ] - ]; + return ['timestampValue' => $value]; } if ($value instanceof GeoPoint) { diff --git a/Firestore/tests/Snippet/BulkWriterTest.php b/Firestore/tests/Snippet/BulkWriterTest.php index eec78785a8f..dab5ab47ed1 100644 --- a/Firestore/tests/Snippet/BulkWriterTest.php +++ b/Firestore/tests/Snippet/BulkWriterTest.php @@ -24,7 +24,8 @@ use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Firestore\BulkWriter; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\BatchWriteRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\DocumentTransform\FieldTransform\ServerValue; use Google\Cloud\Firestore\ValueMapper; use Google\Rpc\Code; @@ -44,29 +45,25 @@ class BulkWriterTest extends SnippetTestCase public const DATABASE = 'projects/example_project/databases/(default)'; public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; - private $connection; private $requestHandler; private $serializer; private $batch; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->batch = TestHelpers::stub(BulkWriter::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), self::DATABASE, [], - ]); + ], ['requestHandler']); } public function testClass() @@ -219,9 +216,13 @@ public function testDelete() public function testFlush() { - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); - $this->batch->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); + $this->batch->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(BulkWriter::class, 'flush'); $snippet->addLocal('batch', $this->batch); $snippet->invoke(); @@ -229,22 +230,28 @@ public function testFlush() public function flushAndAssert(Snippet $snippet, $assertion) { - $connectionResponse = [ + $response = [ 'writeResults' => [], 'status' => [], ]; for ($i = 0; $i < count($assertion); $i++) { - $connectionResponse['writeResults'][] = []; - $connectionResponse['status'][] = [ + $response['writeResults'][] = []; + $response['status'][] = [ 'code' => Code::OK, ]; } - $this->connection->batchWrite([ - 'database' => self::DATABASE, - 'writes' => $assertion, - 'labels' => [], - ])->shouldBeCalled() - ->willReturn($connectionResponse); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($assertion) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == self::DATABASE + && array_replace_recursive($data['writes'], $assertion) == $data['writes'] + && $data['labels'] == []; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn($response); $snippet->addLocal('batch', $this->batch); $snippet->addLocal('documentName', self::DOCUMENT); diff --git a/Firestore/tests/Snippet/CollectionReferenceTest.php b/Firestore/tests/Snippet/CollectionReferenceTest.php index 511c8c92044..53ffc54ce78 100644 --- a/Firestore/tests/Snippet/CollectionReferenceTest.php +++ b/Firestore/tests/Snippet/CollectionReferenceTest.php @@ -28,7 +28,9 @@ use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\CollectionReference; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\CommitRequest; +use Google\Cloud\Firestore\V1\ListDocumentsRequest; /** * @group firestore @@ -44,28 +46,24 @@ class CollectionReferenceTest extends SnippetTestCase public const DATABASE = '(default)'; public const NAME = 'projects/example_project/databases/(default)/documents/users'; - private $connection; private $requestHandler; private $serializer; private $collection; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->collection = TestHelpers::stub(CollectionReference::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), self::NAME - ]); + ], ['requestHandler']); } public function testClass() @@ -88,11 +86,9 @@ public function testParent() public function testSubCollectionParent() { $subCollection = TestHelpers::stub(CollectionReference::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -152,10 +148,16 @@ public function testNewDocument() public function testAdd() { - $this->connection->commit(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + ) ->shouldBeCalled() ->willReturn([[]]); - $this->collection->___setProperty('connection', $this->connection->reveal()); + + $this->collection->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(CollectionReference::class, 'add'); $snippet->addLocal('collection', $this->collection); @@ -171,7 +173,12 @@ public function testListDocuments() $docName = self::NAME . '/foo'; - $this->connection->listDocuments(Argument::any())->shouldBeCalled()->willReturn([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listDocuments', + Argument::type(ListDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ 'documents' => [ [ 'name' => $docName @@ -179,7 +186,7 @@ public function testListDocuments() ] ]); - $this->collection->___setProperty('connection', $this->connection->reveal()); + $this->collection->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(CollectionReference::class, 'listDocuments'); $snippet->addLocal('collection', $this->collection); diff --git a/Firestore/tests/Snippet/DocumentReferenceTest.php b/Firestore/tests/Snippet/DocumentReferenceTest.php index a33727577c1..e322da73727 100644 --- a/Firestore/tests/Snippet/DocumentReferenceTest.php +++ b/Firestore/tests/Snippet/DocumentReferenceTest.php @@ -22,12 +22,13 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldValue; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; use Google\Cloud\Firestore\ValueMapper; use Google\Cloud\Firestore\WriteBatch; use Prophecy\Argument; @@ -45,7 +46,6 @@ class DocumentReferenceTest extends SnippetTestCase public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; - private $connection; private $requestHandler; private $serializer; private $document; @@ -53,22 +53,19 @@ class DocumentReferenceTest extends SnippetTestCase public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->document = TestHelpers::stub(DocumentReferenceStub::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), $this->prophesize(CollectionReference::class)->reveal(), self::DOCUMENT - ], ['connection', 'requestHandler', 'batch']); + ], ['requestHandler', 'batch']); $this->batch = $this->prophesize(WriteBatch::class); } @@ -214,19 +211,22 @@ public function testDelete() public function testSnapshot() { - $this->connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - [ - 'found' => [ - 'name' => self::DOCUMENT, - 'fields' => [], - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + [ + 'found' => [ + 'name' => self::DOCUMENT, + 'fields' => [], + 'readTime' => ['seconds' => 100, 'nanos' => 100] ] - ])); + ] + ])); - $this->document->___setProperty('connection', $this->connection->reveal()); + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(DocumentReference::class, 'snapshot'); $snippet->addLocal('document', $this->document); @@ -244,11 +244,14 @@ public function testCollection() public function testCollections() { - $this->connection->listCollectionIds(Argument::any()) - ->shouldBeCalled() - ->willReturn(['collectionIds' => ['foo','bar']]); - - $this->document->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + Argument::type(ListCollectionIdsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(['collectionIds' => ['foo','bar']]); + + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(DocumentReference::class, 'collections'); $snippet->addLocal('document', $this->document); $res = $snippet->invoke('collections'); diff --git a/Firestore/tests/Snippet/DocumentSnapshotTest.php b/Firestore/tests/Snippet/DocumentSnapshotTest.php index d99cb162f09..eb3d84be18d 100644 --- a/Firestore/tests/Snippet/DocumentSnapshotTest.php +++ b/Firestore/tests/Snippet/DocumentSnapshotTest.php @@ -22,11 +22,11 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FirestoreClient; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\ValueMapper; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -56,7 +56,6 @@ public function setUp(): void $this->snapshot = TestHelpers::stub(DocumentSnapshot::class, [ $ref->reveal(), new ValueMapper( - $this->prophesize(ConnectionInterface::class)->reveal(), $this->prophesize(RequestHandler::class)->reveal(), $this->getSerializer(), false @@ -71,15 +70,18 @@ public function testClass() { $this->checkAndSkipGrpcTests(); - $connection = $this->prophesize(ConnectionInterface::class); - $connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - ['missing' => self::DOCUMENT] - ])); - - $client = TestHelpers::stub(FirestoreClient::class); - $client->___setProperty('connection', $connection->reveal()); + $requestHandler = $this->prophesize(RequestHandler::class); + $requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + ['missing' => self::DOCUMENT] + ])); + + $client = TestHelpers::stub(FirestoreClient::class, [], ['requestHandler']); + $client->___setProperty('requestHandler', $requestHandler->reveal()); $snippet = $this->snippetFromClass(DocumentSnapshot::class); $snippet->setLine(2, ''); $snippet->addLocal('firestore', $client); @@ -138,7 +140,7 @@ public function testId() */ public function testTimestampMethods($method) { - $ts = new Timestamp(new \DateTime()); + $ts = ['seconds' => 100, 'nanos' => 100]; $info = [$method => $ts]; $this->snapshot->___setProperty('info', $info); diff --git a/Firestore/tests/Snippet/FieldValueTest.php b/Firestore/tests/Snippet/FieldValueTest.php index 605d3cb1d36..a1244c36361 100644 --- a/Firestore/tests/Snippet/FieldValueTest.php +++ b/Firestore/tests/Snippet/FieldValueTest.php @@ -22,10 +22,11 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\FieldValue; use Google\Cloud\Firestore\FirestoreClient; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\DocumentTransform\FieldTransform\ServerValue; +use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; /** @@ -38,7 +39,6 @@ class FieldValueTest extends SnippetTestCase use GrpcTestTrait; use ProphecyTrait; - private $connection; private $requestHandler; private $serializer; private $firestore; @@ -47,34 +47,39 @@ public function setUp(): void { $this->checkAndSkipGrpcTests(); - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->firestore = TestHelpers::stub(FirestoreClient::class, [ ['projectId' => 'my-awesome-project'], - ]); + ], ['requestHandler']); } public function testDeleteField() { - $this->connection->commit([ - "database" => "projects/my-awesome-project/databases/(default)", - "writes" => [ - [ - "updateMask" => [ - "fieldPaths" => ["hometown"], - ], - "currentDocument" => [ - "exists" => true, - ], - "update" => [ - "name" => "projects/my-awesome-project/databases/(default)/documents/users/dave", - ], - ], - ], - ])->willReturn([[]])->shouldBeCalledTimes(1); - - $this->firestore->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == "projects/my-awesome-project/databases/(default)" + && array_replace_recursive($data['writes'], [ + [ + "updateMask" => [ + "fieldPaths" => ["hometown"], + ], + "currentDocument" => [ + "exists" => true, + ], + "update" => [ + "name" => "projects/my-awesome-project/databases/(default)/documents/users/dave", + ], + ], + ]) == $data['writes']; + }), + Argument::cetera() + )->willReturn([[]])->shouldBeCalledTimes(1); + + $this->firestore->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FieldValue::class, 'deleteField'); $snippet->setLine(3, ''); @@ -85,27 +90,33 @@ public function testDeleteField() public function testServerTimestamp() { - $this->connection->commit([ - "database" => "projects/my-awesome-project/databases/(default)", - "writes" => [ - [ - "transform" => [ - "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", - "fieldTransforms" => [ - [ - "fieldPath" => "lastLogin", - "setToServerValue" => ServerValue::REQUEST_TIME, + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == "projects/my-awesome-project/databases/(default)" + && array_replace_recursive($data['writes'], [ + [ + "transform" => [ + "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", + "fieldTransforms" => [ + [ + "fieldPath" => "lastLogin", + "setToServerValue" => ServerValue::REQUEST_TIME, + ], + ], + ], + "currentDocument" => [ + "exists" => true, ], ], - ], - "currentDocument" => [ - "exists" => true, - ], - ], - ], - ])->willReturn([[]])->shouldBeCalledTimes(1); + ]) == $data['writes']; + }), + Argument::cetera() + )->willReturn([[]])->shouldBeCalledTimes(1); - $this->firestore->___setProperty('connection', $this->connection->reveal()); + $this->firestore->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FieldValue::class, 'serverTimestamp'); $snippet->setLine(3, ''); @@ -116,35 +127,41 @@ public function testServerTimestamp() public function testArrayUnion() { - $this->connection->commit([ - "database" => "projects/my-awesome-project/databases/(default)", - "writes" => [ - [ - "transform" => [ - "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", - "fieldTransforms" => [ - [ - "fieldPath" => "favoriteColors", - 'appendMissingElements' => [ - 'values' => [ - [ - 'stringValue' => 'red', - ], [ - 'stringValue' => 'blue', + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == "projects/my-awesome-project/databases/(default)" + && array_replace_recursive($data['writes'], [ + [ + "transform" => [ + "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", + "fieldTransforms" => [ + [ + "fieldPath" => "favoriteColors", + 'appendMissingElements' => [ + 'values' => [ + [ + 'stringValue' => 'red', + ], [ + 'stringValue' => 'blue', + ], + ], ], ], ], ], + "currentDocument" => [ + "exists" => true, + ], ], - ], - "currentDocument" => [ - "exists" => true, - ], - ], - ], - ])->willReturn([[]])->shouldBeCalledTimes(1); + ]) == $data['writes']; + }), + Argument::cetera() + )->willReturn([[]])->shouldBeCalledTimes(1); - $this->firestore->___setProperty('connection', $this->connection->reveal()); + $this->firestore->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FieldValue::class, 'arrayUnion'); $snippet->setLine(3, ''); @@ -155,33 +172,39 @@ public function testArrayUnion() public function testArrayRemove() { - $this->connection->commit([ - "database" => "projects/my-awesome-project/databases/(default)", - "writes" => [ - [ - "transform" => [ - "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", - "fieldTransforms" => [ - [ - "fieldPath" => "favoriteColors", - 'removeAllFromArray' => [ - 'values' => [ - [ - 'stringValue' => 'green', + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == "projects/my-awesome-project/databases/(default)" + && array_replace_recursive($data['writes'], [ + [ + "transform" => [ + "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", + "fieldTransforms" => [ + [ + "fieldPath" => "favoriteColors", + 'removeAllFromArray' => [ + 'values' => [ + [ + 'stringValue' => 'green', + ], + ], ], ], ], ], + "currentDocument" => [ + "exists" => true, + ], ], - ], - "currentDocument" => [ - "exists" => true, - ], - ], - ], - ])->willReturn([[]])->shouldBeCalledTimes(1); + ]) == $data['writes']; + }), + Argument::cetera() + )->willReturn([[]])->shouldBeCalledTimes(1); - $this->firestore->___setProperty('connection', $this->connection->reveal()); + $this->firestore->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FieldValue::class, 'arrayRemove'); $snippet->setLine(3, ''); @@ -192,29 +215,35 @@ public function testArrayRemove() public function testIncrement() { - $this->connection->commit([ - "database" => "projects/my-awesome-project/databases/(default)", - "writes" => [ - [ - "transform" => [ - "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", - "fieldTransforms" => [ - [ - "fieldPath" => "loginCount", - 'increment' => [ - 'integerValue' => 1, + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == "projects/my-awesome-project/databases/(default)" + && array_replace_recursive($data['writes'], [ + [ + "transform" => [ + "document" => "projects/my-awesome-project/databases/(default)/documents/users/dave", + "fieldTransforms" => [ + [ + "fieldPath" => "loginCount", + 'increment' => [ + 'integerValue' => 1, + ], + ], ], ], + "currentDocument" => [ + "exists" => true, + ], ], - ], - "currentDocument" => [ - "exists" => true, - ], - ], - ], - ])->willReturn([[]])->shouldBeCalledTimes(1); - - $this->firestore->___setProperty('connection', $this->connection->reveal()); + ]) == $data['writes']; + }), + Argument::cetera() + )->willReturn([[]])->shouldBeCalledTimes(1); + + $this->firestore->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FieldValue::class, 'increment'); $snippet->setLine(3, ''); diff --git a/Firestore/tests/Snippet/FilterTest.php b/Firestore/tests/Snippet/FilterTest.php index 738d281de0e..9878aa58204 100644 --- a/Firestore/tests/Snippet/FilterTest.php +++ b/Firestore/tests/Snippet/FilterTest.php @@ -18,9 +18,8 @@ namespace Google\Cloud\Firestore\Tests\Snippet; use Google\Cloud\Core\RequestHandler; -use Google\Cloud\Core\Testing\ArrayHasSameValuesToken; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\StructuredQuery\FieldFilter\Operator as FieldFilterOperator; use Google\Cloud\Firestore\Filter; use Google\Cloud\Firestore\V1\StructuredQuery\CompositeFilter\Operator; @@ -30,6 +29,7 @@ use Google\Cloud\Core\Testing\Snippet\Parser\Snippet; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Firestore\ValueMapper; +use Prophecy\Argument; /** * @group firestore @@ -43,13 +43,11 @@ class FilterTest extends SnippetTestCase public const COLLECTION = 'a'; public const QUERY_PARENT = 'projects/example_project/databases/(default)/documents'; - private $connection; private $requestHandler; private $serializer; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); } @@ -191,11 +189,9 @@ private function runAndAssertArray(Snippet $snippet, array $query, $allDescendan ]; $q = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -204,17 +200,21 @@ private function runAndAssertArray(Snippet $snippet, array $query, $allDescendan [ 'from' => $from ] - ]); - - $this->connection->runQuery(new ArrayHasSameValuesToken([ - 'parent' => self::QUERY_PARENT, - 'retries' => 0, - 'structuredQuery' => [ - 'from' => $from - ] + $query - ]))->shouldBeCalled()->willReturn(new \ArrayIterator([[]])); - - $q->___setProperty('connection', $this->connection->reveal()); + ], ['requestHandler']); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::that(function ($req) use ($query, $from) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['parent'] == self::QUERY_PARENT + && array_replace_recursive($data['structuredQuery'], ['from' => $from] + $query) + == $data['structuredQuery']; + }), + Argument::withEntry('retrySettings', ['maxRetries' => 0]) + )->shouldBeCalled()->willReturn(new \ArrayIterator([[]])); + + $q->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet->addLocal('query', $q); $res = $snippet->invoke('result'); diff --git a/Firestore/tests/Snippet/FirestoreClientTest.php b/Firestore/tests/Snippet/FirestoreClientTest.php index 41ef6c69fab..1e1d2a6e755 100644 --- a/Firestore/tests/Snippet/FirestoreClientTest.php +++ b/Firestore/tests/Snippet/FirestoreClientTest.php @@ -25,13 +25,18 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldPath; use Google\Cloud\Firestore\FirestoreClient; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\BeginTransactionRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\CommitRequest; +use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; +use Google\Cloud\Firestore\V1\RollbackRequest; +use Google\Cloud\Firestore\V1\RunQueryRequest; use Google\Cloud\Firestore\WriteBatch; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -49,7 +54,6 @@ class FirestoreClientTest extends SnippetTestCase const PROJECT = 'example_project'; const DATABASE = '(default)'; - private $connection; private $requestHandler; private $serializer; private $client; @@ -58,12 +62,11 @@ public function setUp(): void { $this->checkAndSkipGrpcTests(); - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->client = TestHelpers::stub(FirestoreClient::class, [ ['projectId' => self::PROJECT] - ]); + ], ['requestHandler']); } public function testClass() @@ -99,13 +102,17 @@ public function testCollection() public function testCollections() { - $this->connection->listCollectionIds(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - 'collectionIds' => ['users', 'accounts'] - ]); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + Argument::type(ListCollectionIdsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + 'collectionIds' => ['users', 'accounts'] + ]); + + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FirestoreClient::class, 'collections'); $snippet->addLocal('firestore', $this->client); @@ -128,25 +135,28 @@ public function testDocuments() { $tpl = 'projects/%s/databases/%s/documents/users/%s'; - $this->connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - [ - 'found' => [ - 'name' => sprintf($tpl, self::PROJECT, self::DATABASE, 'john'), - 'fields' => [] - ], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) - ], [ - 'found' => [ - 'name' => sprintf($tpl, self::PROJECT, self::DATABASE, 'dave'), - 'fields' => [] - ], - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) - ] - ]); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + [ + 'found' => [ + 'name' => sprintf($tpl, self::PROJECT, self::DATABASE, 'john'), + 'fields' => [] + ], + 'readTime' => ['seconds' => 100, 'nanos' => 100] + ], [ + 'found' => [ + 'name' => sprintf($tpl, self::PROJECT, self::DATABASE, 'dave'), + 'fields' => [] + ], + 'readTime' => ['seconds' => 100, 'nanos' => 100] + ] + ]); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FirestoreClient::class, 'documents'); $snippet->addLocal('firestore', $this->client); @@ -159,16 +169,19 @@ public function testDocuments() public function testDocumentsDoesntExist() { $tpl = 'projects/%s/databases/%s/documents/users/%s'; - $this->connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - [ - 'missing' => sprintf($tpl, self::PROJECT, self::DATABASE, 'deleted-user'), - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT) - ] - ]); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + [ + 'missing' => sprintf($tpl, self::PROJECT, self::DATABASE, 'deleted-user'), + 'readTime' => ['seconds' => 100, 'nanos' => 100] + ] + ]); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FirestoreClient::class, 'documents', 1); $snippet->addLocal('firestore', $this->client); @@ -179,7 +192,12 @@ public function testDocumentsDoesntExist() public function testCollectionGroup() { - $this->connection->runQuery(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::type(RunQueryRequest::class), + Argument::cetera() + ) ->willReturn(new \ArrayIterator([ [ 'document' => [ @@ -196,7 +214,7 @@ public function testCollectionGroup() ] ])); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FirestoreClient::class, 'collectionGroup'); $snippet->addLocal('firestore', $this->client); @@ -210,46 +228,65 @@ public function testRunTransaction() $from = sprintf('projects/%s/databases/%s/documents/users/john', self::PROJECT, self::DATABASE); $to = sprintf('projects/%s/databases/%s/documents/users/dave', self::PROJECT, self::DATABASE); - $this->connection->beginTransaction(Argument::any()) - ->shouldBeCalled() - ->willReturn(['transaction' => 'foo']); - - $this->connection->batchGetDocuments(Argument::withEntry('documents', [$from])) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - [ - 'found' => [ - 'name' => $from, - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT), - 'fields' => [ - 'balance' => [ - 'doubleValue' => 1000.00 - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::type(BeginTransactionRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(['transaction' => 'foo']); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($from) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['documents'] == [$from]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + [ + 'found' => [ + 'name' => $from, + 'readTime' => ['seconds' => 100, 'nanos' => 100], + 'fields' => [ + 'balance' => [ + 'doubleValue' => 1000.00 ] ] ] - ])); - - $this->connection->batchGetDocuments(Argument::withEntry('documents', [$to])) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - [ - 'found' => [ - 'name' => $to, - 'readTime' => (new \DateTime)->format(Timestamp::FORMAT), - 'fields' => [ - 'balance' => [ - 'doubleValue' => 1000.00 - ] + ] + ])); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($to) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['documents'] == [$to]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + [ + 'found' => [ + 'name' => $from, + 'readTime' => ['seconds' => 100, 'nanos' => 100], + 'fields' => [ + 'balance' => [ + 'doubleValue' => 1000.00 ] ] ] - ])); + ] + ])); - $this->connection->commit(Argument::any()) - ->shouldBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + )->shouldBeCalled(); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(FirestoreClient::class, 'runTransaction'); $snippet->addLocal('firestore', $this->client); diff --git a/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php b/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php index dec4b0e154a..6645c9d6a87 100644 --- a/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php +++ b/Firestore/tests/Snippet/FirestoreSessionHandlerTest.php @@ -22,9 +22,12 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\Firestore\FirestoreSessionHandler; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\BeginTransactionRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\CommitRequest; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -41,7 +44,6 @@ class FirestoreSessionHandlerTest extends SnippetTestCase const TRANSACTION = 'transaction-id'; - private $connection; private $requestHandler; private $serializer; private $client; @@ -63,10 +65,11 @@ public function setUp(): void { $this->checkAndSkipGrpcTests(); - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); - $this->client = TestHelpers::stub(FirestoreClient::class); + $this->client = TestHelpers::stub(FirestoreClient::class, [], [ + 'requestHandler' + ]); } public function testClass() @@ -74,36 +77,46 @@ public function testClass() $snippet = $this->snippetFromClass(FirestoreSessionHandler::class); $snippet->replace('$firestore = new FirestoreClient();', ''); - $this->connection->batchGetDocuments(Argument::withEntry('documents', Argument::type('array'))) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - 'found' => [ - [ - 'name' => '', - 'fields' => [] - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + 'found' => [ + [ + 'name' => '', + 'fields' => [] ] - ])); - - $this->connection->beginTransaction(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - 'transaction' => self::TRANSACTION - ]); + ] + ])); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::type(BeginTransactionRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + 'transaction' => self::TRANSACTION + ]); $value = 'name|' . serialize('Bob'); - $this->connection->commit(Argument::allOf( - Argument::that(function ($args) use ($value) { - return strpos($args['writes'][0]['update']['name'], ':PHPSESSID') !== false - && $args['writes'][0]['update']['fields']['data']['stringValue'] === $value - && isset($args['writes'][0]['update']['fields']['t']['integerValue']); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($value) { + $data = $this->getSerializer()->encodeMessage($req); + return strpos($data['writes'][0]['update']['name'], ':PHPSESSID') !== false + && $data['writes'][0]['update']['fields']['data']['stringValue'] === $value + && isset($data['writes'][0]['update']['fields']['t']['integerValue']) + && $data['transaction'] == self::TRANSACTION; }), - Argument::withEntry('transaction', self::TRANSACTION) - ))->shouldBeCalled()->willReturn([ + Argument::cetera() + )->shouldBeCalled()->willReturn([ 'writeResults' => [] ]); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet->addLocal('firestore', $this->client); $res = $snippet->invoke(); @@ -116,36 +129,46 @@ public function testSessionHandlerMethod() { $snippet = $this->snippetFromMethod(FirestoreClient::class, 'sessionHandler'); - $this->connection->batchGetDocuments(Argument::withEntry('documents', Argument::type('array'))) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - 'found' => [ - [ - 'name' => '', - 'fields' => [] - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + 'found' => [ + [ + 'name' => '', + 'fields' => [] ] - ])); - - $this->connection->beginTransaction(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - 'transaction' => self::TRANSACTION - ]); + ] + ])); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::type(BeginTransactionRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + 'transaction' => self::TRANSACTION + ]); $value = 'name|' . serialize('Bob'); - $this->connection->commit(Argument::allOf( - Argument::that(function ($args) use ($value) { - return strpos($args['writes'][0]['update']['name'], ':PHPSESSID') !== false - && $args['writes'][0]['update']['fields']['data']['stringValue'] === $value - && isset($args['writes'][0]['update']['fields']['t']['integerValue']); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($value) { + $data = $this->getSerializer()->encodeMessage($req); + return strpos($data['writes'][0]['update']['name'], ':PHPSESSID') !== false + && $data['writes'][0]['update']['fields']['data']['stringValue'] === $value + && isset($data['writes'][0]['update']['fields']['t']['integerValue']) + && $data['transaction'] == self::TRANSACTION; }), - Argument::withEntry('transaction', self::TRANSACTION) - ))->shouldBeCalled()->willReturn([ + Argument::cetera() + )->shouldBeCalled()->willReturn([ 'writeResults' => [] ]); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet->addLocal('firestore', $this->client); $res = $snippet->invoke(); @@ -161,30 +184,39 @@ public function testClassErrorHandler() $snippet = $this->snippetFromClass(FirestoreSessionHandler::class, 1); $snippet->replace('$firestore = new FirestoreClient();', ''); - $this->connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - 'found' => [ - [ - 'name' => '', - 'fields' => [] - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + 'found' => [ + [ + 'name' => '', + 'fields' => [] ] - ])); - - $this->connection->beginTransaction(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - 'transaction' => self::TRANSACTION - ]); + ] + ])); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::type(BeginTransactionRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + 'transaction' => self::TRANSACTION + ]); - $this->connection->commit(Argument::any()) - ->shouldBeCalled() - ->will(function () { - trigger_error('oops!', E_USER_WARNING); - }); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + )->shouldBeCalled()->will(function () { + trigger_error('oops!', E_USER_WARNING); + }); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet->addLocal('firestore', $this->client); $res = $snippet->invoke(); diff --git a/Firestore/tests/Snippet/QuerySnapshotTest.php b/Firestore/tests/Snippet/QuerySnapshotTest.php index f447b7c5981..ddd41e65f22 100644 --- a/Firestore/tests/Snippet/QuerySnapshotTest.php +++ b/Firestore/tests/Snippet/QuerySnapshotTest.php @@ -22,10 +22,11 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\Firestore\Query; use Google\Cloud\Firestore\QuerySnapshot; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\RunQueryRequest; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -39,14 +40,12 @@ class QuerySnapshotTest extends SnippetTestCase use GrpcTestTrait; use ProphecyTrait; - private $connection; private $requestHandler; private $serializer; private $snapshot; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->snapshot = TestHelpers::stub(QuerySnapshot::class, [ @@ -59,12 +58,15 @@ public function testClass() { $this->checkAndSkipGrpcTests(); - $this->connection->runQuery(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([])); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::type(RunQueryRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([])); - $client = TestHelpers::stub(FirestoreClient::class); - $client->___setProperty('connection', $this->connection->reveal()); + $client = TestHelpers::stub(FirestoreClient::class, [], ['requestHandler']); + $client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromClass(QuerySnapshot::class); $snippet->setLine(2, ''); diff --git a/Firestore/tests/Snippet/QueryTest.php b/Firestore/tests/Snippet/QueryTest.php index 82275a6f44d..53bfdd32831 100644 --- a/Firestore/tests/Snippet/QueryTest.php +++ b/Firestore/tests/Snippet/QueryTest.php @@ -24,9 +24,11 @@ use Google\Cloud\Core\Testing\Snippet\Parser\Snippet; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\Query; use Google\Cloud\Firestore\QuerySnapshot; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; +use Google\Cloud\Firestore\V1\RunQueryRequest; use Google\Cloud\Firestore\V1\StructuredQuery\Direction; use Google\Cloud\Firestore\ValueMapper; use Prophecy\Argument; @@ -48,13 +50,11 @@ class QueryTest extends SnippetTestCase public const COLLECTION = 'a'; public const NAME = 'projects/example_project/databases/(default)/documents/a/b'; - private $connection; private $requestHandler; private $serializer; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); } @@ -71,11 +71,9 @@ public function testClass() public function testDocuments() { $query = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -88,13 +86,16 @@ public function testDocuments() ] ] ] - ]); + ], ['requestHandler']); - $this->connection->runQuery(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([])); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::type(RunQueryRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([])); - $query->___setProperty('connection', $this->connection->reveal()); + $query->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(Query::class, 'documents'); $snippet->addLocal('query', $query); @@ -105,11 +106,9 @@ public function testDocuments() public function testCount() { $query = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -122,11 +121,14 @@ public function testCount() ] ] ] - ]); - - $this->connection->runAggregationQuery(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ + ], ['requestHandler']); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::type(RunAggregationQueryRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ [ 'result' => [ 'aggregateFields' => [ @@ -136,7 +138,7 @@ public function testCount() ] ])); - $query->___setProperty('connection', $this->connection->reveal()); + $query->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(Query::class, 'count'); $snippet->addLocal('query', $query); @@ -147,11 +149,9 @@ public function testCount() public function testAddAggregation() { $query = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -164,11 +164,14 @@ public function testAddAggregation() ] ] ] - ]); - - $this->connection->runAggregationQuery(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ + ], ['requestHandler']); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::type(RunAggregationQueryRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ [ 'result' => [ 'aggregateFields' => [ @@ -178,7 +181,7 @@ public function testAddAggregation() ] ])); - $query->___setProperty('connection', $this->connection->reveal()); + $query->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(Query::class, 'addAggregation'); $snippet->addLocal('query', $query); @@ -297,14 +300,14 @@ public function testOrderBy() public function testLimit() { $snippet = $this->snippetFromMethod(Query::class, 'limit'); - $this->runAndAssert($snippet, 'limit', 10); + $this->runAndAssert($snippet, 'limit', ['value' => 10]); } public function testLimitToLast() { $snippet = $this->snippetFromMethod(Query::class, 'limitToLast'); $this->runAndAssertArray($snippet, [ - 'limit' => 10, + 'limit' => ['value' => 10], 'orderBy' => [ [ 'field' => [ @@ -380,11 +383,9 @@ private function runAndAssertArray(Snippet $snippet, array $query, $allDescendan ]; $q = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -393,17 +394,21 @@ private function runAndAssertArray(Snippet $snippet, array $query, $allDescendan [ 'from' => $from ] - ]); - - $this->connection->runQuery(new ArrayHasSameValuesToken([ - 'parent' => self::QUERY_PARENT, - 'retries' => 0, - 'structuredQuery' => [ - 'from' => $from - ] + $query - ]))->shouldBeCalled()->willReturn(new \ArrayIterator([[]])); - - $q->___setProperty('connection', $this->connection->reveal()); + ], ['requestHandler']); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::that(function ($req) use ($query, $from) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['parent'] == self::QUERY_PARENT + && array_replace_recursive($data['structuredQuery'], ['from' => $from] + $query) + == $data['structuredQuery']; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([[]])); + + $q->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet->addLocal('query', $q); $res = $snippet->invoke('query'); diff --git a/Firestore/tests/Snippet/TransactionTest.php b/Firestore/tests/Snippet/TransactionTest.php index f02286b7b32..2c85f1c6cc3 100644 --- a/Firestore/tests/Snippet/TransactionTest.php +++ b/Firestore/tests/Snippet/TransactionTest.php @@ -23,11 +23,9 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\Aggregate; use Google\Cloud\Firestore\AggregateQuery; use Google\Cloud\Firestore\AggregateQuerySnapshot; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldValue; @@ -35,6 +33,12 @@ use Google\Cloud\Firestore\Query; use Google\Cloud\Firestore\QuerySnapshot; use Google\Cloud\Firestore\Transaction; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\BeginTransactionRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\RollbackRequest; +use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; +use Google\Cloud\Firestore\V1\RunQueryRequest; use Google\Cloud\Firestore\ValueMapper; use Google\Cloud\Firestore\WriteBatch; use Prophecy\Argument; @@ -57,7 +61,6 @@ class TransactionTest extends SnippetTestCase public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; public const DOCUMENT_TEMPLATE = 'projects/%s/databases/%s/documents/users/%s'; - private $connection; private $requestHandler; private $serializer; private $transaction; @@ -66,22 +69,19 @@ class TransactionTest extends SnippetTestCase public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->transaction = TestHelpers::stub(TransactionStub::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), self::DATABASE, self::TRANSACTION - ], ['connection', 'requestHandler', 'writer']); + ], ['requestHandler', 'writer']); $this->document = $this->prophesize(DocumentReference::class); $this->document->name()->willReturn(self::DOCUMENT); @@ -93,15 +93,24 @@ public function testClass() { $this->checkAndSkipGrpcTests(); - $this->connection->beginTransaction(Argument::any()) - ->shouldBeCalled() - ->willReturn(['transaction' => self::TRANSACTION]); - - $this->connection->rollback(Argument::any()) - ->shouldBeCalled(); - - $client = TestHelpers::stub(FirestoreClient::class); - $client->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::type(BeginTransactionRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(['transaction' => self::TRANSACTION]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::type(RollbackRequest::class), + Argument::cetera() + )->shouldBeCalled(); + + $client = TestHelpers::stub(FirestoreClient::class, [], [ + 'requestHandler' + ]); + $client->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromClass(Transaction::class); $snippet->setLine(3, ''); @@ -111,20 +120,22 @@ public function testClass() public function testSnapshot() { - $this->connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - [ - 'found' => [ - 'name' => self::DOCUMENT, - 'fields' => [], - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + [ + 'found' => [ + 'name' => self::DOCUMENT, + 'fields' => [], + 'readTime' => ['seconds' => 100, 'nanos' => 100] ] - ])); + ] + ])); - $this->transaction->setConnection( - $this->connection->reveal(), + $this->transaction->setRequestHandler( $this->requestHandler->reveal() ); @@ -137,11 +148,15 @@ public function testSnapshot() public function testRunAggregateQuery() { - $this->connection->runAggregationQuery(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::type(RunAggregationQueryRequest::class), + Argument::cetera() + ) ->shouldBeCalled() ->willReturn(new \ArrayIterator([])); $aggregateQuery = new AggregateQuery( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::DOCUMENT, @@ -258,25 +273,28 @@ public function testDelete() public function testDocuments() { - $this->connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - [ - 'found' => [ - 'name' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'john'), - 'fields' => [] - ], - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) - ], [ - 'found' => [ - 'name' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'dave'), - 'fields' => [] - ], - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) - ] - ]); - - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + [ + 'found' => [ + 'name' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'john'), + 'fields' => [] + ], + 'readTime' => ['seconds' => 100, 'nanos' => 100] + ], [ + 'found' => [ + 'name' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'dave'), + 'fields' => [] + ], + 'readTime' => ['seconds' => 100, 'nanos' => 100] + ] + ]); + + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(Transaction::class, 'documents'); $snippet->addLocal('transaction', $this->transaction); @@ -288,16 +306,19 @@ public function testDocuments() public function testDocumentsDoesntExist() { - $this->connection->batchGetDocuments(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - [ - 'missing' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'deleted-user'), - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) - ] - ]); - - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::type(BatchGetDocumentsRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + [ + 'missing' => sprintf(self::DOCUMENT_TEMPLATE, self::PROJECT, self::DATABASE_ID, 'deleted-user'), + 'readTime' => ['seconds' => 100, 'nanos' => 100] + ] + ]); + + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $snippet = $this->snippetFromMethod(Transaction::class, 'documents', 1); $snippet->addLocal('transaction', $this->transaction); @@ -315,7 +336,6 @@ class TransactionStub extends Transaction private $database; public function __construct( - ConnectionInterface $connection, RequestHandler $requestHandler, Serializer $serializer, ValueMapper $valueMapper, @@ -325,7 +345,6 @@ public function __construct( $this->database = $database; parent::__construct( - $connection, $requestHandler, $serializer, $valueMapper, @@ -334,16 +353,13 @@ public function __construct( ); } - public function setConnection(ConnectionInterface $connection, RequestHandler $requestHandler) + public function setRequestHandler(RequestHandler $requestHandler) { - $this->connection = $connection; $this->requestHandler = $requestHandler; $this->writer = new WriteBatch( - $connection, $requestHandler, $this->getSerializer(), new ValueMapper( - $connection, $requestHandler, $this->getSerializer(), false diff --git a/Firestore/tests/Snippet/WriteBatchTest.php b/Firestore/tests/Snippet/WriteBatchTest.php deleted file mode 100644 index c4cd2aa92fd..00000000000 --- a/Firestore/tests/Snippet/WriteBatchTest.php +++ /dev/null @@ -1,242 +0,0 @@ -connection = $this->prophesize(ConnectionInterface::class); - $this->requestHandler = $this->prophesize(RequestHandler::class); - $this->serializer = $this->getSerializer(); - $this->batch = TestHelpers::stub(WriteBatch::class, [ - $this->connection->reveal(), - $this->requestHandler->reveal(), - $this->serializer, - new ValueMapper( - $this->connection->reveal(), - $this->requestHandler->reveal(), - $this->serializer, - false - ), - self::DATABASE - ], ['connection', 'requestHandler', 'transaction']); - } - - public function testClass() - { - $this->checkAndSkipGrpcTests(); - - $snippet = $this->snippetFromClass(WriteBatch::class); - $res = $snippet->invoke('batch'); - $this->assertInstanceOf(WriteBatch::class, $res->returnVal()); - } - - public function testCreate() - { - $snippet = $this->snippetFromMethod(WriteBatch::class, 'create'); - $this->commitAndAssert($snippet, [ - [ - 'currentDocument' => ['exists' => false], - 'update' => [ - 'name' => self::DOCUMENT, - 'fields' => [ - 'name' => ['stringValue' => 'John'] - ] - ] - ] - ]); - } - - public function testUpdate() - { - $snippet = $this->snippetFromMethod(WriteBatch::class, 'update'); - $this->commitAndAssert($snippet, [ - [ - 'updateMask' => [ - 'fieldPaths' => [ - 'country', - 'cryptoCurrencies.bitcoin', - 'cryptoCurrencies.ethereum', - 'cryptoCurrencies.litecoin', - 'name', - ] - ], - 'currentDocument' => ['exists' => true], - 'update' => [ - 'name' => self::DOCUMENT, - 'fields' => [ - 'name' => ['stringValue' => 'John'], - 'country' => ['stringValue' => 'USA'], - 'cryptoCurrencies' => [ - 'mapValue' => [ - 'fields' => [ - 'bitcoin' => [ - 'doubleValue' => 0.5, - ], - 'ethereum' => [ - 'integerValue' => 10 - ], - 'litecoin' => [ - 'doubleValue' => 5.51 - ] - ] - ] - ] - ] - ] - ] - ]); - } - - public function testUpdateSentinels() - { - $snippet = $this->snippetFromMethod(WriteBatch::class, 'update', 1); - $this->commitAndAssert($snippet, [ - [ - 'updateMask' => [ - 'fieldPaths' => [ - 'country' - ] - ], - 'currentDocument' => ['exists' => true], - 'update' => [ - 'name' => self::DOCUMENT, - ] - ], [ - 'transform' => [ - 'document' => self::DOCUMENT, - 'fieldTransforms' => [ - [ - 'fieldPath' => 'lastLogin', - 'setToServerValue' => ServerValue::REQUEST_TIME - ] - ] - ] - ] - ]); - } - - public function testUpdateSpecialChars() - { - $snippet = $this->snippetFromMethod(WriteBatch::class, 'update', 2); - $this->commitAndAssert($snippet, [ - [ - 'updateMask' => [ - 'fieldPaths' => [ - 'cryptoCurrencies.`big$$$coin`' - ] - ], - 'currentDocument' => ['exists' => true], - 'update' => [ - 'name' => self::DOCUMENT, - 'fields' => [ - 'cryptoCurrencies' => [ - 'mapValue' => [ - 'fields' => [ - 'big$$$coin' => [ - 'doubleValue' => 5.51, - ], - ] - ] - ] - ] - ] - ] - ]); - } - - public function testSet() - { - $snippet = $this->snippetFromMethod(WriteBatch::class, 'set'); - $this->commitAndAssert($snippet, [ - [ - 'update' => [ - 'name' => self::DOCUMENT, - 'fields' => [ - 'name' => ['stringValue' => 'John'] - ] - ] - ] - ]); - } - - public function testDelete() - { - $snippet = $this->snippetFromMethod(WriteBatch::class, 'delete'); - $this->commitAndAssert($snippet, [ - [ - 'delete' => self::DOCUMENT - ] - ]); - } - - public function testCommit() - { - $this->connection->commit(Argument::any()) - ->shouldBeCalled(); - $this->batch->___setProperty('connection', $this->connection->reveal()); - $snippet = $this->snippetFromMethod(WriteBatch::class, 'commit'); - $snippet->addLocal('batch', $this->batch); - $snippet->invoke(); - } - - public function commitAndAssert(Snippet $snippet, $assertion) - { - $this->connection->commit([ - 'database' => self::DATABASE, - 'writes' => $assertion - ])->shouldBeCalled(); - $this->batch->___setProperty('connection', $this->connection->reveal()); - - $snippet->addLocal('batch', $this->batch); - $snippet->addLocal('documentName', self::DOCUMENT); - $snippet->invoke(); - - $this->batch->commit(); - } -} diff --git a/Firestore/tests/System/AggregateQueryTest.php b/Firestore/tests/System/AggregateQueryTest.php index c10afd156bd..aa0d29feeec 100644 --- a/Firestore/tests/System/AggregateQueryTest.php +++ b/Firestore/tests/System/AggregateQueryTest.php @@ -19,17 +19,21 @@ use Exception; use Google\Cloud\Core\Exception\BadRequestException; -use Google\Cloud\Core\Timestamp; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Firestore\Aggregate; use Google\Cloud\Firestore\Filter; use Google\Cloud\Firestore\Query; +use Google\Protobuf\Timestamp; /** * @group firestore * @group firestore-query + * @group curr */ class AggregateQueryTest extends FirestoreTestCase { + use FirestoreTestHelperTrait; + private $query; public function setUp(): void @@ -168,7 +172,6 @@ private function assertQueryWithMultipleAggregations(Query $query, $type, $arg, foreach ($aggregations as $aggregation) { $query = $query->addAggregation($aggregation); } - $expectedTimestamp = new Timestamp(new \DateTimeImmutable()); $snapshot = $query->getSnapshot(); @@ -179,10 +182,9 @@ private function assertQueryWithMultipleAggregations(Query $query, $type, $arg, $this->assertEquals(0, strlen($snapshot->getTransaction())); $actualTimestamp = $snapshot->getReadTime(); - $this->assertInstanceOf(Timestamp::class, $snapshot->getReadTime()); $this->assertEqualsWithDelta( - $expectedTimestamp->get()->getTimestamp(), - $actualTimestamp->get()->getTimestamp(), + time(), + $actualTimestamp['seconds'], 100 ); } diff --git a/Firestore/tests/System/BulkWriterTest.php b/Firestore/tests/System/BulkWriterTest.php index fa2884b6ee7..d79e394cc46 100644 --- a/Firestore/tests/System/BulkWriterTest.php +++ b/Firestore/tests/System/BulkWriterTest.php @@ -21,7 +21,7 @@ use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; use Google\Cloud\Firestore\BulkWriter; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\ValueMapper; use Google\Rpc\Code; use Prophecy\Argument; @@ -97,14 +97,11 @@ public function testLongCreateMultipleDocsWithDelay() public function testLongFailuresAreRetriedWithDelay() { $docs = $this->bulkDocuments(); - $connection = $this->prophesize(ConnectionInterface::class); $requestHandler = $this->prophesize(RequestHandler::class); $this->batch = TestHelpers::stub(BulkWriter::class, [ - $connection->reveal(), $requestHandler->reveal(), $this->getSerializer(), new ValueMapper( - $connection->reveal(), $requestHandler->reveal(), $this->getSerializer(), false @@ -115,16 +112,20 @@ public function testLongFailuresAreRetriedWithDelay() 'maxOpsPerSecond' => 10, 'greedilySend' => false, ], - ]); + ], ['requestHandler']); + $batchSize = 20; $successPerBatch = $batchSize * 3 / 4; $successfulDocs = []; - $connection->batchWrite(Argument::that( - function ($arg) use ($docs, $successPerBatch, &$successfulDocs) { - if (count($arg['writes']) <= 0) { + $requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($docs, $successPerBatch, &$successfulDocs) { + $data = $this->getSerializer()->encodeMessage($req); + if (count($data['writes']) <= 0) { return false; } - foreach ($arg['writes'] as $i => $write) { + foreach ($data['writes'] as $i => $write) { if (!$write['currentDocument']) { return false; } @@ -137,28 +138,27 @@ function ($arg) use ($docs, $successPerBatch, &$successfulDocs) { } } return true; - } - )) - ->shouldBeCalledTimes(10) - ->willReturn( - [ - 'writeResults' => array_fill(0, $batchSize, []), - 'status' => array_merge( - array_fill(0, $successPerBatch, [ - 'code' => Code::OK, - ]), - array_fill(0, $batchSize - $successPerBatch, [ - 'code' => Code::DATA_LOSS, - ]), - ), - ] - ); + }), + Argument::cetera() + )->shouldBeCalledTimes(10)->willReturn([ + 'writeResults' => array_fill(0, $batchSize, []), + 'status' => array_merge( + array_fill(0, $successPerBatch, [ + 'code' => Code::OK, + ]), + array_fill(0, $batchSize - $successPerBatch, [ + 'code' => Code::DATA_LOSS, + ]), + ), + ]); + foreach ($docs as $k => $v) { $this->batch->create($v, [ 'key' => $k, 'path' => $v, ]); } + $this->batch->___setProperty('requestHandler', $requestHandler->reveal()); $startTime = floor(microtime(true) * 1000); $this->batch->flush(); diff --git a/Firestore/tests/System/DocumentAndCollectionTest.php b/Firestore/tests/System/DocumentAndCollectionTest.php index 02d993dc5ff..dcd0f7bb6bd 100644 --- a/Firestore/tests/System/DocumentAndCollectionTest.php +++ b/Firestore/tests/System/DocumentAndCollectionTest.php @@ -17,9 +17,9 @@ namespace Google\Cloud\Firestore\Tests\System; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\CollectionReference; use Google\Cloud\Firestore\DocumentReference; +use Google\Protobuf\Timestamp as ProtobufTimestamp; /** * @group firestore @@ -49,7 +49,7 @@ public function testSnapshotWithReadTime() { // without sleep, test fails intermittently sleep(1); - $readTime = new Timestamp(new \DateTimeImmutable('now')); + $readTime = new ProtobufTimestamp(['seconds' => time()]); $snapshotData = $this->document->snapshot([ 'readTime' => $readTime ])->data(); @@ -206,7 +206,7 @@ public function testCollectionsWithReadTime() // without sleep, emulator system test may fail intermittently sleep(1); - $readTime = new Timestamp(new \DateTimeImmutable()); + $readTime = new ProtobufTimestamp(['seconds' => time()]); $collection = $this->document->collections([ 'readTime' => $readTime ])->current(); @@ -224,7 +224,7 @@ public function testRootCollectionsWithReadTime() // without sleep, emulator system test may fail intermittently sleep(1); - $readTime = new Timestamp(new \DateTimeImmutable()); + $readTime = new ProtobufTimestamp(['seconds' => time()]); $expectedCount = count(iterator_to_array(self::$client->collections())); // Creating a random document @@ -248,7 +248,7 @@ public function testListDocumentsWithReadTime() sleep(1); // Creating a current timestamp and then adding a document - $readTime = new Timestamp(new \DateTimeImmutable()); + $readTime = new ProtobufTimestamp(['seconds' => time()]); $collection->add(['c' => 'd']); // Reading at $readTime to get documents at that time diff --git a/Firestore/tests/System/FieldValueTest.php b/Firestore/tests/System/FieldValueTest.php index 105985df237..7520a5245c2 100644 --- a/Firestore/tests/System/FieldValueTest.php +++ b/Firestore/tests/System/FieldValueTest.php @@ -17,7 +17,6 @@ namespace Google\Cloud\Firestore\Tests\System; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\FieldValue; /** @@ -47,7 +46,9 @@ public function testServerTimestamp() ['path' => 'foo', 'value' => FieldValue::serverTimestamp()] ]); - $this->assertInstanceOf(Timestamp::class, $this->document->snapshot()['foo']); + $timestamp = $this->document->snapshot()['foo']; + $this->assertArrayHasKey('seconds', $timestamp); + $this->assertArrayHasKey('nanos', $timestamp); } public function testDelete() diff --git a/Firestore/tests/System/QueryTest.php b/Firestore/tests/System/QueryTest.php index 1c761a1d970..371ac27274f 100644 --- a/Firestore/tests/System/QueryTest.php +++ b/Firestore/tests/System/QueryTest.php @@ -17,9 +17,9 @@ namespace Google\Cloud\Firestore\Tests\System; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\FieldPath; use Google\Cloud\Firestore\Filter; +use Google\Protobuf\Timestamp; /** * @group firestore @@ -354,7 +354,8 @@ public function testDocumentsWithReadTime() sleep(1); // Creating a current timestamp and then inserting another document - $readTime = new Timestamp(new \DateTimeImmutable()); + $timeSeconds = time(); + $readTime = new Timestamp(['seconds' => $timeSeconds]); $this->insertDoc(['foo' => $randomVal]); $resultCount = $this->query diff --git a/Firestore/tests/System/TransactionTest.php b/Firestore/tests/System/TransactionTest.php index b42a3ed229e..cc86043b216 100644 --- a/Firestore/tests/System/TransactionTest.php +++ b/Firestore/tests/System/TransactionTest.php @@ -18,7 +18,7 @@ namespace Google\Cloud\Firestore\Tests\System; use Google\Cloud\Firestore\Aggregate; -use Google\Cloud\Core\Timestamp; +use Google\Protobuf\Timestamp; /** * @group firestore @@ -144,9 +144,15 @@ public function testAggregateQuery($type, $arg, $expected, $docsToAdd) // without sleep, test fails intermittently sleep(1); - $readTime = new Timestamp(new \DateTimeImmutable('now')); - - self::$client->runTransaction(function ($t) use ($query, $readTime, $expected) { + $timeSeconds = time(); + $readTime = new Timestamp(['seconds' => $timeSeconds]); + + self::$client->runTransaction(function ($t) use ( + $query, + $readTime, + $expected, + $timeSeconds + ) { $snapshot = $t->runAggregateQuery($query, [ 'readTime' => $readTime ]); @@ -154,8 +160,8 @@ public function testAggregateQuery($type, $arg, $expected, $docsToAdd) $this->assertEquals($expected, $snapshot->get('res')); $this->assertEqualsWithDelta( - $readTime->get()->getTimestamp(), - $snapshot->getReadTime()->get()->getTimestamp(), + $timeSeconds, + $snapshot->getReadTime()['seconds'], 100 ); }); @@ -185,9 +191,15 @@ public function testAggregateQueryWithMultipleAggregation($type, $arg, $expected // without sleep, test fails intermittently sleep(1); - $readTime = new Timestamp(new \DateTimeImmutable('now')); - - self::$client->runTransaction(function ($t) use ($query, $readTime, $expected) { + $timeSeconds = time(); + $readTime = new Timestamp(['seconds' => $timeSeconds]); + + self::$client->runTransaction(function ($t) use ( + $query, + $readTime, + $expected, + $timeSeconds + ) { $snapshot = $t->runAggregateQuery($query, [ 'readTime' => $readTime ]); @@ -197,8 +209,8 @@ public function testAggregateQueryWithMultipleAggregation($type, $arg, $expected $this->assertEquals($expected, $snapshot->get('res_3')); $this->assertEqualsWithDelta( - $readTime->get()->getTimestamp(), - $snapshot->getReadTime()->get()->getTimestamp(), + $timeSeconds, + $snapshot->getReadTime()['seconds'], 100 ); }); diff --git a/Firestore/tests/System/ValueMapperTest.php b/Firestore/tests/System/ValueMapperTest.php index d9b68201397..1f403573f92 100644 --- a/Firestore/tests/System/ValueMapperTest.php +++ b/Firestore/tests/System/ValueMapperTest.php @@ -19,7 +19,8 @@ use Google\Cloud\Core\Blob; use Google\Cloud\Core\GeoPoint; -use Google\Cloud\Core\Timestamp; +use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; +use Google\Protobuf\Timestamp; /** * @group firestore @@ -27,10 +28,11 @@ */ class ValueMapperTest extends FirestoreTestCase { + use FirestoreTestHelperTrait; private static $document; private static $isSetup = false; - const FIELD = 'testedField'; + public const FIELD = 'testedField'; public static function setUpBeforeClass(): void { @@ -50,12 +52,14 @@ public function testValue($input, callable $expectation = null) self::$document->update([ ['path' => self::FIELD, 'value' => $input] ]); - $snapshot = self::$document->snapshot(); if ($expectation) { $this->assertTrue($expectation($snapshot[self::FIELD])); } elseif ($input instanceof Timestamp) { - $this->assertEquals($input->formatAsString(), $snapshot[self::FIELD]->formatAsString()); + $this->assertEquals( + $this->getSerializer()->encodeMessage($input), + $snapshot[self::FIELD] + ); } else { $this->assertEquals($input, $snapshot[self::FIELD]); } @@ -72,7 +76,7 @@ public function values() [10], [2147483647], [3.1415], - [new Timestamp(\DateTime::createFromFormat('U', time()))], + [new Timestamp(['seconds' => time()])], ['foo'], [self::$document], [new GeoPoint(10, -10)], diff --git a/Firestore/tests/System/WriteTest.php b/Firestore/tests/System/WriteTest.php index 119a12a19f7..9dd18792807 100644 --- a/Firestore/tests/System/WriteTest.php +++ b/Firestore/tests/System/WriteTest.php @@ -17,8 +17,8 @@ namespace Google\Cloud\Firestore\Tests\System; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; +use Google\Protobuf\Timestamp; /** * @group firestore @@ -26,7 +26,6 @@ */ class WriteTest extends FirestoreTestCase { - use TimeTrait; /** * @dataProvider timestamps @@ -46,13 +45,9 @@ public function testTimestampPrecision($timestamp) $res2 = $doc->snapshot()['timestampField']; - $this->assertEquals($timestamp->get()->format('U'), $res->get()->format('U')); - $this->assertEquals($timestamp->nanoSeconds(), $res->nanoSeconds()); - $this->assertEquals($timestamp->formatAsString(), $res->formatAsString()); - - $this->assertEquals($timestamp->get()->format('U'), $res2->get()->format('U')); - $this->assertEquals($timestamp->nanoSeconds(), $res2->nanoSeconds()); - $this->assertEquals($timestamp->formatAsString(), $res2->formatAsString()); + $expected = ['seconds' => $timestamp->getSeconds(), 'nanos' => $timestamp->getNanos()]; + $this->assertEquals($expected, $res); + $this->assertEquals($expected, $res2); } /** @@ -75,13 +70,9 @@ public function testTimestampPrecisionLocale($timestamp) $res2 = $doc->snapshot()['timestampField']; - $this->assertEquals($timestamp->get()->format('U'), $res->get()->format('U')); - $this->assertEquals($timestamp->nanoSeconds(), $res->nanoSeconds()); - $this->assertEquals($timestamp->formatAsString(), $res->formatAsString()); - - $this->assertEquals($timestamp->get()->format('U'), $res2->get()->format('U')); - $this->assertEquals($timestamp->nanoSeconds(), $res2->nanoSeconds()); - $this->assertEquals($timestamp->formatAsString(), $res2->formatAsString()); + $expected = ['seconds' => $timestamp->getSeconds(), 'nanos' => $timestamp->getNanos()]; + $this->assertEquals($expected, $res); + $this->assertEquals($expected, $res2); } finally { setlocale(LC_ALL, null); } @@ -89,17 +80,10 @@ public function testTimestampPrecisionLocale($timestamp) public function timestamps() { - $today = new \DateTime; - $str = $today->format('Y-m-d\TH:i:s'); - - $r = new \ReflectionClass(Timestamp::class); + $time = time(); return [ - [new Timestamp($today)], - [new Timestamp($today, 0)], - [new Timestamp($today, 1000)], - [$r->newInstanceArgs($this->parseTimeString($str .'.100000000Z'))], - [$r->newInstanceArgs($this->parseTimeString($str .'.000001Z'))], - [$r->newInstanceArgs($this->parseTimeString($str .'.101999Z'))], + [new Timestamp(['seconds' => $time])], + [new Timestamp(['seconds' => $time, 'nanos' => 1000])], ]; } } diff --git a/Firestore/tests/Unit/AggregateQuerySnapshotTest.php b/Firestore/tests/Unit/AggregateQuerySnapshotTest.php index 7cb321f17a1..51b643315ac 100644 --- a/Firestore/tests/Unit/AggregateQuerySnapshotTest.php +++ b/Firestore/tests/Unit/AggregateQuerySnapshotTest.php @@ -17,8 +17,8 @@ namespace Google\Cloud\Firestore\Tests\Unit; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\AggregateQuerySnapshot; +use Google\Protobuf\Timestamp; use PHPUnit\Framework\TestCase; /** @@ -42,7 +42,9 @@ public function testTransactionId() public function testReadTime() { - $readTime = (new \DateTime())->format(Timestamp::FORMAT); + $readTime = new Timestamp(); + $readTime->fromDateTime(new \DateTime()); + $readTime = json_decode($readTime->serializeToJsonString()); $aggregationQuerySnapshot = new AggregateQuerySnapshot([ 'readTime' => $readTime ]); diff --git a/Firestore/tests/Unit/AggregateQueryTest.php b/Firestore/tests/Unit/AggregateQueryTest.php index cc5d751f0d6..76cb870f83b 100644 --- a/Firestore/tests/Unit/AggregateQueryTest.php +++ b/Firestore/tests/Unit/AggregateQueryTest.php @@ -23,8 +23,9 @@ use Google\Cloud\Firestore\Aggregate; use Google\Cloud\Firestore\AggregateQuery; use Google\Cloud\Firestore\AggregateQuerySnapshot; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\Query; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; use Google\Cloud\Firestore\ValueMapper; use PHPUnit\Framework\TestCase; use Prophecy\Argument; @@ -47,7 +48,6 @@ class AggregateQueryTest extends TestCase ] ]; - private $connection; private $requestHandler; private $serializer; private $query; @@ -56,31 +56,27 @@ class AggregateQueryTest extends TestCase public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->query = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), self::QUERY_PARENT, $this->queryObj - ], ['connection', 'requestHandler', 'query']); + ], ['requestHandler', 'query']); $this->aggregate = Aggregate::count(); $this->aggregateQuery = TestHelpers::stub(AggregateQuery::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::QUERY_PARENT, ['query' => $this->queryObj], $this->aggregate - ], ['connection', 'requestHandler', 'query', 'aggregates']); + ], ['requestHandler', 'query', 'aggregates']); } /** @@ -94,18 +90,24 @@ public function testGetSnapshot($type, $arg, $expected) $aggregate = $arg ? Aggregate::$type($arg) : Aggregate::$type(); $this->aggregateQuery->___setProperty('aggregates', [$aggregate]); - $this->connection->runAggregationQuery(Argument::that(function ($args) use ($expectedProps) { - return $expectedProps == $args['structuredAggregationQuery']['aggregations']; - })) - ->shouldBeCalledTimes(1) - ->willReturn(new \ArrayIterator([[ - 'result' => [ - 'aggregateFields' => [ - $type => ['testResultType' => 123456] - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::that(function ($req) use ($expectedProps) { + $data = $this->getSerializer()->encodeMessage($req); + $x = $data['structuredAggregationQuery']['aggregations']; + return array_replace_recursive($x, $expectedProps) == $x; + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(new \ArrayIterator([[ + 'result' => [ + 'aggregateFields' => [ + $type => ['testResultType' => 123456] ] - ]])); - $this->aggregateQuery->___setProperty('connection', $this->connection->reveal()); + ] + ]])); + + $this->aggregateQuery->___setProperty('requestHandler', $this->requestHandler->reveal()); $response = $this->aggregateQuery->getSnapshot(); $this->assertInstanceOf(AggregateQuerySnapshot::class, $response); @@ -131,12 +133,19 @@ public function testAddAggregation($type, $arg, $expected) ($arg ? Aggregate::$type($arg) : Aggregate::$type())->alias('type_with_another_alias') ]; $this->aggregateQuery->___setProperty('aggregates', $aggregates); - $this->connection->runAggregationQuery(Argument::that(function ($args) use ($expectedProps) { - return $expectedProps == $args['structuredAggregationQuery']['aggregations']; - })) - ->shouldBeCalledTimes(1) - ->willReturn(new \ArrayIterator([])); - $this->aggregateQuery->___setProperty('connection', $this->connection->reveal()); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::that(function ($req) use ($expectedProps) { + $data = $this->getSerializer()->encodeMessage($req); + $x = $data['structuredAggregationQuery']['aggregations']; + return array_replace_recursive($x, $expectedProps) == $x; + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(new \ArrayIterator([])); + + $this->aggregateQuery->___setProperty('requestHandler', $this->requestHandler->reveal()); $response = $this->aggregateQuery->getSnapshot(); diff --git a/Firestore/tests/Unit/BulkWriterTest.php b/Firestore/tests/Unit/BulkWriterTest.php index 7cc8fcbac3a..5701977ad96 100644 --- a/Firestore/tests/Unit/BulkWriterTest.php +++ b/Firestore/tests/Unit/BulkWriterTest.php @@ -20,19 +20,21 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\BulkWriter; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\FieldPath; use Google\Cloud\Firestore\FieldValue; +use Google\Cloud\Firestore\V1\BatchWriteRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\DocumentTransform\FieldTransform\ServerValue; use Google\Cloud\Firestore\ValueMapper; +use Google\Protobuf\Timestamp as ProtobufTimestamp; use Google\Rpc\Code; use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; +use RuntimeException; /** * @group firestore @@ -48,22 +50,18 @@ class BulkWriterTest extends TestCase public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; public const TRANSACTION = 'foobar'; - private $connection; private $requestHandler; private $serializer; private $batch; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->batch = TestHelpers::stub(BulkWriter::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -80,11 +78,9 @@ public function testBulkwriterOptionsInitialOpsPerSecond() $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Value for argument "initialOpsPerSecond" must be greater than 1/'); new BulkWriter( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -99,11 +95,9 @@ public function testBulkwriterOptionsMaxOpsPerSecond() $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/Value for argument "maxOpsPerSecond" must be greater than 1/'); new BulkWriter( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -118,11 +112,9 @@ public function testBulkwriterOptions() $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/\'maxOpsPerSecond\' cannot be less than \'initialOpsPerSecond\'/'); new BulkWriter( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -164,28 +156,30 @@ public function testCreate($name, $ref) */ public function testCreateMultipleDocs($docs) { - $this->connection->batchWrite(Argument::that(function ($arg) use ($docs) { - if (count($arg['writes']) <= 0) { - return false; - } - foreach ($arg['writes'] as $write) { - if (!$write['currentDocument']) { + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($docs) { + $data = $this->getSerializer()->encodeMessage($req); + if (count($data['writes']) <= 0) { return false; } - if ($docs[$write['update']['fields']['key']['integerValue']] !== - $write['update']['fields']['path']['stringValue']) { - return false; + foreach ($data['writes'] as $write) { + if (!$write['currentDocument']) { + return false; + } + if ($docs[$write['update']['fields']['key']['integerValue']] !== + $write['update']['fields']['path']['stringValue']) { + return false; + } } - } - return true; - })) - ->shouldBeCalledTimes(3) - ->willReturn( - [ - 'writeResults' => array_fill(0, 20, []), - 'status' => array_fill(0, 20, ['code' => Code::OK]), - ] - ); + return true; + }), + Argument::cetera() + )->shouldBeCalledTimes(3)->willReturn([ + 'writeResults' => array_fill(0, 20, []), + 'status' => array_fill(0, 20, ['code' => Code::OK]), + ]); foreach ($docs as $k => $v) { $this->batch->create($v, [ @@ -201,28 +195,30 @@ public function testCreateMultipleDocs($docs) */ public function testFailuresAreRetriedTillMaxAttempts($docs) { - $this->connection->batchWrite(Argument::that(function ($arg) use ($docs) { - if (count($arg['writes']) <= 0) { - return false; - } - foreach ($arg['writes'] as $write) { - if (!$write['currentDocument']) { + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($docs) { + $data = $this->getSerializer()->encodeMessage($req); + if (count($data['writes']) <= 0) { return false; } - if ($docs[$write['update']['fields']['key']['integerValue']] !== - $write['update']['fields']['path']['stringValue']) { - return false; + foreach ($data['writes'] as $write) { + if (!$write['currentDocument']) { + return false; + } + if ($docs[$write['update']['fields']['key']['integerValue']] !== + $write['update']['fields']['path']['stringValue']) { + return false; + } } - } - return true; - })) - ->shouldBeCalledTimes(3) - ->willReturn( - [ - 'writeResults' => array_fill(0, 20, []), - 'status' => array_fill(0, 20, ['code' => Code::OK]), - ] - ); + return true; + }), + Argument::cetera() + )->shouldBeCalledTimes(3)->willReturn([ + 'writeResults' => array_fill(0, 20, []), + 'status' => array_fill(0, 20, ['code' => Code::OK]), + ]); foreach ($docs as $k => $v) { $this->batch->create($v, [ @@ -238,27 +234,30 @@ public function testFailuresAreRetriedTillMaxAttempts($docs) */ public function testFlushReturnsAllResponses($docs) { - $this->connection->batchWrite(Argument::that(function ($arg) use ($docs) { - if (count($arg['writes']) <= 0) { - return false; - } - foreach ($arg['writes'] as $write) { - if (!$write['currentDocument']) { + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($docs) { + $data = $this->getSerializer()->encodeMessage($req); + if (count($data['writes']) <= 0) { return false; } - if ($docs[$write['update']['fields']['key']['integerValue']] !== - $write['update']['fields']['path']['stringValue']) { - return false; + foreach ($data['writes'] as $write) { + if (!$write['currentDocument']) { + return false; + } + if ($docs[$write['update']['fields']['key']['integerValue']] !== + $write['update']['fields']['path']['stringValue']) { + return false; + } } - } - return true; - })) - ->willReturn( - [ - 'writeResults' => array_fill(0, 20, []), - 'status' => array_fill(0, 20, ['code' => Code::OK]), - ] - ); + return true; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + 'writeResults' => array_fill(0, 50, []), + 'status' => array_fill(0, 50, ['code' => Code::OK]), + ]); foreach ($docs as $k => $v) { $this->batch->create($v, [ @@ -279,27 +278,30 @@ public function testFlushReturnsAllResponses($docs) */ public function testCloseReturnsAllResponses($docs) { - $this->connection->batchWrite(Argument::that(function ($arg) use ($docs) { - if (count($arg['writes']) <= 0) { - return false; - } - foreach ($arg['writes'] as $write) { - if (!$write['currentDocument']) { + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($docs) { + $data = $this->getSerializer()->encodeMessage($req); + if (count($data['writes']) <= 0) { return false; } - if ($docs[$write['update']['fields']['key']['integerValue']] !== - $write['update']['fields']['path']['stringValue']) { - return false; + foreach ($data['writes'] as $write) { + if (!$write['currentDocument']) { + return false; + } + if ($docs[$write['update']['fields']['key']['integerValue']] !== + $write['update']['fields']['path']['stringValue']) { + return false; + } } - } - return true; - })) - ->willReturn( - [ - 'writeResults' => array_fill(0, 20, []), - 'status' => array_fill(0, 20, ['code' => Code::OK]), - ] - ); + return true; + }), + Argument::cetera() + )->willReturn([ + 'writeResults' => array_fill(0, 20, []), + 'status' => array_fill(0, 20, ['code' => Code::OK]), + ]); foreach ($docs as $k => $v) { $this->batch->create($v, [ @@ -324,25 +326,26 @@ public function testFailuresAreRetriedInSubsequentBatches($docs) $successPerBatch = $batchSize * 3 / 4; $successfulDocs = []; $this->batch = TestHelpers::stub(BulkWriter::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), ['greedilySend' => false], - ]); - - $this->connection->batchWrite(Argument::that( - function ($arg) use ($docs, $successPerBatch, &$successfulDocs) { - if (count($arg['writes']) <= 0) { + ], ['requestHandler']); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($docs, $successPerBatch, &$successfulDocs) { + $data = $this->getSerializer()->encodeMessage($req); + if (count($data['writes']) <= 0) { return false; } - foreach ($arg['writes'] as $i => $write) { + foreach ($data['writes'] as $i => $write) { if (!$write['currentDocument']) { return false; } @@ -355,22 +358,19 @@ function ($arg) use ($docs, $successPerBatch, &$successfulDocs) { } } return true; - } - )) - ->shouldBeCalledTimes(4) - ->willReturn( - [ - 'writeResults' => array_fill(0, $batchSize, []), - 'status' => array_merge( - array_fill(0, $successPerBatch, [ - 'code' => Code::OK, - ]), - array_fill(0, $batchSize - $successPerBatch, [ - 'code' => Code::DATA_LOSS, - ]) - ), - ] - ); + }), + Argument::cetera() + )->shouldBeCalledTimes(4)->willReturn([ + 'writeResults' => array_fill(0, $batchSize, []), + 'status' => array_merge( + array_fill(0, $successPerBatch, [ + 'code' => Code::OK, + ]), + array_fill(0, $batchSize - $successPerBatch, [ + 'code' => Code::DATA_LOSS, + ]) + ), + ]); foreach ($docs as $k => $v) { $this->batch->create($v, [ @@ -832,10 +832,7 @@ public function testWriteUpdateTimePrecondition($name, $ref) $this->batch->delete($ref, [ 'precondition' => [ - 'updateTime' => new Timestamp( - \DateTimeImmutable::createFromFormat('U', (string) $ts['seconds']), - $ts['nanos'] - ), + 'updateTime' => $ts, ], ]); @@ -875,17 +872,6 @@ public function bulkDocuments() return [[$docs]]; } - public function testWriteUpdateTimePreconditionInvalidType() - { - $this->expectException(InvalidArgumentException::class); - - $this->batch->delete(self::DOCUMENT, [ - 'precondition' => [ - 'updateTime' => 'foobar', - ], - ]); - } - public function testWritePreconditionMissingStuff() { $this->expectException(InvalidArgumentException::class); @@ -899,8 +885,12 @@ public function testCreateAfterClosed() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: BulkWriter has been closed/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->close(); $this->batch->create(self::DOCUMENT, [ 'hello' => 'world', @@ -911,8 +901,12 @@ public function testUpdateAfterClosed() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: BulkWriter has been closed/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->close(); $this->batch->update(self::DOCUMENT, [ [ @@ -926,8 +920,12 @@ public function testSetAfterClosed() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: BulkWriter has been closed/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->close(); $this->batch->set(self::DOCUMENT, [ 'hello' => 'world', @@ -938,8 +936,12 @@ public function testDeleteAfterClosed() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: BulkWriter has been closed/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->close(); $this->batch->delete(self::DOCUMENT); } @@ -948,8 +950,12 @@ public function testDuplicateCreate() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: bulkwriter: received duplicate mutations for path/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->create(self::DOCUMENT, [ 'hello' => 'world', ]); @@ -962,8 +968,12 @@ public function testDuplicateUpdate() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: bulkwriter: received duplicate mutations for path/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->update(self::DOCUMENT, [ [ 'path' => 'hello.world', @@ -982,8 +992,12 @@ public function testDuplicateSet() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: bulkwriter: received duplicate mutations for path/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->set(self::DOCUMENT, [ 'hello' => 'world', ]); @@ -996,8 +1010,12 @@ public function testDuplicateDelete() { $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageMatches('/firestore: bulkwriter: received duplicate mutations for path/'); - $this->connection->batchWrite(Argument::any()) - ->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::type(BatchWriteRequest::class), + Argument::cetera() + )->shouldNotBeCalled(); $this->batch->delete(self::DOCUMENT); $this->batch->delete(self::DOCUMENT); } @@ -1012,32 +1030,42 @@ public function testUpdateEmptyFails() private function flushAndAssert($assertion) { if (is_callable($assertion)) { - $this->connection->batchWrite(Argument::that($assertion)) - ->shouldBeCalled() - ->willReturn( + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($assertion) { + $data = $this->getSerializer()->encodeMessage($req); + return $assertion($data); + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([ + 'writeResults' => [[]], + 'status' => [ [ - 'writeResults' => [[]], - 'status' => [ - [ - 'code' => Code::OK, - ], - ], - ] - ); + 'code' => Code::OK, + ], + ], + ]); } elseif (is_array($assertion)) { - $connectionResponse = [ + $response = [ 'writeResults' => [], 'status' => [], ]; for ($i = 0; $i < count($assertion); $i++) { - $connectionResponse['writeResults'][] = []; - $connectionResponse['status'][] = [ + $response['writeResults'][] = []; + $response['status'][] = [ 'code' => Code::OK, ]; } - $this->connection->batchWrite($assertion) - ->shouldBeCalled() - ->willReturn($connectionResponse); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchWrite', + Argument::that(function ($req) use ($assertion) { + $data = $this->getSerializer()->encodeMessage($req); + return array_replace_recursive($data, $assertion) == $data; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn($response); } else { throw new \Exception('bad assertion'); } diff --git a/Firestore/tests/Unit/CollectionReferenceTest.php b/Firestore/tests/Unit/CollectionReferenceTest.php index c5f4c0799c4..a49ca42a799 100644 --- a/Firestore/tests/Unit/CollectionReferenceTest.php +++ b/Firestore/tests/Unit/CollectionReferenceTest.php @@ -28,7 +28,9 @@ use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; +use Google\Cloud\Firestore\V1\ListDocumentsRequest; /** * @group firestore @@ -44,28 +46,24 @@ class CollectionReferenceTest extends TestCase public const COLLECTION_PARENT = 'projects/example_project/databases/(default)/documents/a/doc'; public const NAME = 'projects/example_project/databases/(default)/documents/a/doc/b'; - private $connection; private $requestHandler; private $serializer; private $collection; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->collection = TestHelpers::stub(CollectionReference::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), self::NAME - ]); + ], ['requestHandler']); } public function testName() @@ -105,29 +103,33 @@ public function testNewDocument() public function testAdd() { - $this->connection->commit(Argument::that(function ($args) { - $expected = [ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'currentDocument' => ['exists' => false], - 'update' => [ - 'fields' => [ - 'hello' => [ - 'stringValue' => 'world' + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + $expected = [ + 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), + 'writes' => [ + [ + 'currentDocument' => ['exists' => false], + 'update' => [ + 'fields' => [ + 'hello' => [ + 'stringValue' => 'world' + ] ] ] ] ] - ] - ]; - - unset($args['writes'][0]['update']['name']); + ]; - return $args === $expected; - }))->shouldBeCalled()->willReturn([[]]); + return array_replace_recursive($data, $expected) == $data; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([[]]); - $this->collection->___setProperty('connection', $this->connection->reveal()); + $this->collection->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->collection->add(['hello' => 'world']); } @@ -139,11 +141,15 @@ public function testListDocuments() $docName = self::NAME . '/foo'; - $this->connection->listDocuments(Argument::allOf( - Argument::withEntry('parent', self::COLLECTION_PARENT), - Argument::withEntry('collectionId', $id), - Argument::withEntry('mask', []) - ))->shouldBeCalled()->willReturn([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listDocuments', + Argument::that(function ($req) use ($id) { + return $req->getParent() === self::COLLECTION_PARENT + && $req->getCollectionId() === $id; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([ 'documents' => [ [ 'name' => $docName @@ -151,7 +157,7 @@ public function testListDocuments() ] ]); - $this->collection->___setProperty('connection', $this->connection->reveal()); + $this->collection->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->collection->listDocuments(); $docs = iterator_to_array($res); @@ -177,14 +183,11 @@ public function testRandomNames(DocumentReference $doc) public function randomNames() { - $connection = $this->prophesize(ConnectionInterface::class); $requestHandler = $this->prophesize(RequestHandler::class); $collection = TestHelpers::stub(CollectionReference::class, [ - $connection->reveal(), $requestHandler->reveal(), $this->getSerializer(), new ValueMapper( - $connection->reveal(), $requestHandler->reveal(), $this->getSerializer(), false @@ -217,11 +220,9 @@ public function testParentForRootCollection() { $collectionName = 'projects/example_project/databases/(default)/documents/foo'; $collection = TestHelpers::stub(CollectionReference::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false diff --git a/Firestore/tests/Unit/ConformanceTest.php b/Firestore/tests/Unit/ConformanceTest.php index 1ebb39a94e0..ec403c88850 100644 --- a/Firestore/tests/Unit/ConformanceTest.php +++ b/Firestore/tests/Unit/ConformanceTest.php @@ -22,17 +22,17 @@ use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldPath; use Google\Cloud\Firestore\FieldValue; use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\Firestore\PathTrait; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\DocumentTransform\FieldTransform\ServerValue; +use Google\Cloud\Firestore\V1\Precondition; use Google\Cloud\Firestore\V1\StructuredQuery\CompositeFilter\Operator as CompositFilterOperator; use Google\Cloud\Firestore\V1\StructuredQuery\Direction; use Google\Cloud\Firestore\V1\StructuredQuery\FieldFilter\Operator as FieldFilterOperator; @@ -53,7 +53,6 @@ class ConformanceTest extends TestCase use GrpcTestTrait; use PathTrait; use ProphecyTrait; - use TimeTrait; const SUITE_FILENAME = 'firestore-test-suite.binproto'; @@ -62,9 +61,7 @@ class ConformanceTest extends TestCase private $testTypes = ['get', 'create', 'set', 'update', 'updatePaths', 'delete', 'query']; private $client; - private $connection; private $requestHandler; - private $serializer; private $excludes = [ // need mergeFields support @@ -90,11 +87,9 @@ public function setUp(): void [ 'projectId' => 'projectID' ] - ]); + ], ['requestHandler']); - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); - $this->serializer = $this->getSerializer(); } /** @@ -103,10 +98,16 @@ public function setUp(): void */ public function testGet($test) { - $this->connection->batchGetDocuments(Argument::withEntry('documents', [$test['request']['name']])) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([[]])); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($test) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['documents'] == [$test['request']['name']]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([[]])); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->client->document($this->relativeName($test['docRefPath']))->snapshot(); } @@ -114,6 +115,7 @@ public function testGet($test) /** * @dataProvider cases * @group firestore-conformance-create + * @group mystic */ public function testCreate($test) { @@ -123,8 +125,16 @@ public function testCreate($test) unset($request['transaction']); } - $this->connection->commit(new ArrayHasSameValuesToken($this->injectPbValues($request))) - ->shouldBeCalled()->willReturn([]); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($request) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == $request['database'] + && array_replace_recursive($data['writes'], $request['writes']) == $data['writes']; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([]); }); $this->executeAndHandleError($test, function ($test) { @@ -145,11 +155,20 @@ public function testSet($test) unset($request['transaction']); } - $this->connection->commit(new ArrayHasSameValuesToken($this->injectPbValues($request))) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($request) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] === $request['database'] + && array_replace_recursive($data['writes'], $request['writes']) == $data['writes']; + }), + Argument::cetera() + ) ->shouldBeCalled()->willReturn([]); }); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->executeAndHandleError($test, function ($test) { $options = []; @@ -174,7 +193,16 @@ public function testUpdatePaths($test) unset($request['transaction']); } - $this->connection->commit(new ArrayHasSameValuesToken($this->injectPbValues($request))) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($request) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] === $request['database'] + && array_replace_recursive($data['writes'], $request['writes']) == $data['writes']; + }), + Argument::cetera() + ) ->shouldBeCalled()->willReturn([]); }); @@ -208,7 +236,16 @@ public function testDelete($test) unset($request['transaction']); } - $this->connection->commit(new ArrayHasSameValuesToken($this->injectPbValues($request))) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($request) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == $request['database'] + && array_replace_recursive($data['writes'], $request['writes']) == $data['writes']; + }), + Argument::cetera() + ) ->shouldBeCalled()->willReturn([]); }); @@ -234,13 +271,20 @@ public function testQuery($test) } $times = (isset($test['isError']) && $test['isError']) ? 0 : 1; - $this->connection->runQuery(new ArrayHasSameValuesToken([ - 'parent' => $this->parentPath($test['collPath']), - 'structuredQuery' => $query, - 'retries' => 0 - ]))->shouldBeCalledTimes($times)->willReturn(new \ArrayIterator([])); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::that(function ($req) use ($query, $test) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['parent'] == $this->parentPath($test['collPath']) + && array_replace_recursive($data['structuredQuery'], $query) + == $data['structuredQuery']; + }), + Argument::cetera() + )->shouldBeCalledTimes($times)->willReturn(new \ArrayIterator([])); + + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $query = $this->client->collection($this->relativeName($test['collPath'])); @@ -315,9 +359,8 @@ public function testQuery($test) $ref->name()->willReturn($clause[$name]['docSnapshot']['path']); $mapper = new ValueMapper( - $this->prophesize(ConnectionInterface::class)->reveal(), $this->prophesize(RequestHandler::class)->reveal(), - $this->serializer, + $this->getSerializer(), false ); @@ -351,11 +394,15 @@ private function setupCommitRequest(array $test, callable $call) if (!$test['isError']) { $call($test); } else { - $this->connection->commit(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::cetera() + ) ->shouldNotBeCalled()->willReturn([]); } - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); } private function executeAndHandleError(array $test, callable $executeTest) @@ -387,17 +434,8 @@ private function formatOptions(array $test) } if (isset($test['precondition']['updateTime'])) { - $updateTime = $this->parseTimeString($test['precondition']['updateTime']); - $test['precondition']['updateTime'] = [ - 'seconds' => $updateTime[0]->format('U'), - 'nanos' => $updateTime[1] - ]; - $options['precondition'] = [ - 'updateTime' => new Timestamp( - \DateTime::createFromFormat('U', (string) $test['precondition']['updateTime']['seconds']), - $test['precondition']['updateTime']['nanos'] - ) + 'updateTime' => $test['precondition']['updateTime'] ]; } } diff --git a/Firestore/tests/Unit/Connection/GrpcTest.php b/Firestore/tests/Unit/Connection/GrpcTest.php deleted file mode 100644 index a05499f7981..00000000000 --- a/Firestore/tests/Unit/Connection/GrpcTest.php +++ /dev/null @@ -1,444 +0,0 @@ -checkAndSkipGrpcTests(); - - $this->requestWrapper = $this->prophesize(GrpcRequestWrapper::class); - $this->successMessage = 'success'; - } - - public function testApiEndpoint() - { - $expected = 'foobar.com'; - - $grpc = new GrpcStub([ - 'apiEndpoint' => $expected, - 'projectId' => 'test', - 'database' => 'test' - ]); - - $this->assertEquals($expected, $grpc->config['apiEndpoint']); - } - - public function testBatchGetDocuments() - { - $documents = [ - sprintf('projects/%s/databases/%s/documents/%s', self::PROJECT, self::DATABASE, 'a/b'), - sprintf('projects/%s/databases/%s/documents/%s', self::PROJECT, self::DATABASE, 'a/c') - ]; - - $args = [ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'documents' => $documents - ]; - - $expected = [$args['database'], $args['documents'], $this->header()]; - - $this->sendAndAssert('batchGetDocuments', $args, $expected); - } - - public function testBatchGetDocumentsWithReadTime() - { - $documents = [ - sprintf( - 'projects/%s/databases/%s/documents/%s', - self::PROJECT, - self::DATABASE, - 'a/b' - ), - sprintf( - 'projects/%s/databases/%s/documents/%s', - self::PROJECT, - self::DATABASE, - 'a/c' - ) - ]; - - $args = [ - 'database' => sprintf( - 'projects/%s/databases/%s', - self::PROJECT, - self::DATABASE - ), - 'documents' => $documents, - 'readTime' => [ - 'seconds' => 202320232, - 'nanos' => 0 - ] - ]; - - $protobufTimestamp = new ProtobufTimestamp(); - $protobufTimestamp->setSeconds($args['readTime']['seconds']); - $expected = [ - $args['database'], - $args['documents'], - $this->header() + ['readTime' => $protobufTimestamp] - ]; - - $this->sendAndAssert('batchGetDocuments', $args, $expected); - } - - public function testBeginTransaction() - { - $args = [ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - ]; - - $rw = new ReadWrite(); - - $options = new TransactionOptions; - $options->setReadWrite($rw); - - $expected = [ - $args['database'], - ['options' => $options] + $this->header() - ]; - - $this->sendAndAssert('beginTransaction', $args, $expected); - } - - public function testBeginTransactionWithPreviousTransactionId() - { - $args = [ - 'retryTransaction' => 'foo', - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - ]; - - $rw = new ReadWrite(); - $rw->setRetryTransaction($args['retryTransaction']); - - $options = new TransactionOptions; - $options->setReadWrite($rw); - - $expected = [ - $args['database'], - ['options' => $options] + $this->header() - ]; - - $this->sendAndAssert('beginTransaction', $args, $expected); - } - - public function testCommit() - { - $args = [ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'updateMask' => ['fieldPaths' => ['foo']], - 'currentDocument' => ['exists' => true], - 'update' => [ - 'name' => 'foo', - 'fields' => [ - 'foo' => [ - 'stringValue' => 'bar' - ] - ] - ] - ] - ], - 'transaction' => 'bar' - ]; - - $write = new Write; - - $mask = new DocumentMask; - $mask->setFieldPaths(['foo']); - $write->setUpdateMask($mask); - - $precondition = new Precondition; - $precondition->setExists(true); - $write->setCurrentDocument($precondition); - - $document = new Document; - $document->setName('foo'); - - $field = new Value; - $field->setStringValue('bar'); - - $document->setFields(['foo' => $field]); - $write->setUpdate($document); - - $expected = [ - $args['database'], - [$write], - [ - 'transaction' => $args['transaction'] - ] + $this->header() - ]; - - $this->sendAndAssert('commit', $args, $expected); - } - - public function testListCollectionIds() - { - $args = [ - 'parent' => sprintf('projects/%s/databases/%s/documents', self::PROJECT, self::DATABASE) - ]; - - $expected = [$args['parent'], $this->header()]; - - $this->sendAndAssert('listCollectionIds', $args, $expected); - } - - public function testListCollectionIdsWithReadTime() - { - $args = [ - 'parent' => sprintf( - 'projects/%s/databases/%s/documents', - self::PROJECT, - self::DATABASE - ), - 'readTime' => [ - 'seconds' => 123456789, - 'nanos' => 0 - ] - ]; - $protobufTimestamp = new ProtobufTimestamp(); - $protobufTimestamp->setSeconds($args['readTime']['seconds']); - $expected = [ - $args['parent'], - $this->header() + ['readTime' => $protobufTimestamp] - ]; - - $this->sendAndAssert('listCollectionIds', $args, $expected); - } - - public function testListDocuments() - { - $args = [ - 'parent' => sprintf('projects/%s/databases/%s/documents', self::PROJECT, self::DATABASE), - 'collectionId' => 'coll1', - 'mask' => [], - ]; - - $expected = [ - $args['parent'], - $args['collectionId'], - [ - 'showMissing' => true, - 'mask' => new DocumentMask(['field_paths' => []]), - ] + $this->header() - ]; - - $this->sendAndAssert('listDocuments', $args, $expected); - } - - public function testListDocumentsWithReadTime() - { - $args = [ - 'parent' => sprintf('projects/%s/databases/%s/documents', self::PROJECT, self::DATABASE), - 'collectionId' => 'coll1', - 'mask' => [], - 'readTime' => [ - 'seconds' => 123456789, - 'nanos' => 0 - ] - ]; - - $protobufTimestamp = new ProtobufTimestamp(); - $protobufTimestamp->setSeconds($args['readTime']['seconds']); - $expected = [ - $args['parent'], - $args['collectionId'], - [ - 'showMissing' => true, - 'mask' => new DocumentMask(['field_paths' => []]), - 'readTime' => $protobufTimestamp - ] + $this->header() - ]; - - $this->sendAndAssert('listDocuments', $args, $expected); - } - - public function testRollback() - { - $args = [ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'transaction' => 'foo' - ]; - - $expected = [$args['database'], $args['transaction'], $this->header()]; - - $this->sendAndAssert('rollback', $args, $expected); - } - - public function testRunQuery() - { - $args = [ - 'parent' => 'parent!', - 'structuredQuery' => ['from' => [['collectionId' => 'parent']]] - ]; - - $from = new CollectionSelector(); - $from->setCollectionId('parent'); - $q = new StructuredQuery; - $q->setFrom([$from]); - - $expected = [ - $args['parent'], - ['structuredQuery' => $q] + $this->header() - ]; - - $this->sendAndAssert('runQuery', $args, $expected); - } - - public function testRunQueryWithReadTime() - { - $args = [ - 'parent' => 'parent!', - 'structuredQuery' => ['from' => [['collectionId' => 'parent']]], - 'readTime' => [ - 'seconds' => 123456789, - 'nanos' => 0 - ] - ]; - - $from = new CollectionSelector(); - $from->setCollectionId('parent'); - $q = new StructuredQuery; - $q->setFrom([$from]); - - $protobufTimestamp = new ProtobufTimestamp(); - $protobufTimestamp->setSeconds($args['readTime']['seconds']); - $expected = [ - $args['parent'], - [ - 'structuredQuery' => $q, - 'readTime' => $protobufTimestamp - ] + $this->header() - ]; - - $this->sendAndAssert('runQuery', $args, $expected); - } - - public function testCustomRequestHeaders() - { - $args = [ - 'parent' => sprintf('projects/%s/databases/%s/documents', self::PROJECT, self::DATABASE), - 'headers' => [ - 'foo' => ['bar'] - ] - ]; - - $headers = $this->header(); - $headers['headers']['foo'] = ['bar']; - $expected = [$args['parent'], $headers]; - - $this->sendAndAssert('listCollectionIds', $args, $expected); - } - - public function testProvidesAuthorizationHeaderWithEmulator() - { - $args = [ - 'parent' => sprintf('projects/%s/databases/%s/documents', self::PROJECT, self::DATABASE), - ]; - - $headers = $this->header(); - $headers['headers']['Authorization'] = ['Bearer owner']; - $expected = [$args['parent'], $headers]; - - $connection = TestHelpers::stub(Grpc::class, [ - [ - 'projectId' => 'test', - 'database' => '(default)' - ] - ], ['isUsingEmulator']); - - $connection->___setProperty('isUsingEmulator', true); - $this->sendAndAssert('listCollectionIds', $args, $expected, $connection); - } - - private function header() - { - return [ - "headers" => [ - "google-cloud-resource-prefix" => ["projects/test/databases/(default)"], - "x-goog-request-params" => ["project_id=test&database_id=(default)"] - ] - ]; - } - - private function sendAndAssert($method, array $args, array $expectedArgs, Grpc $connection = null) - { - $connection = $connection ?: new Grpc([ - 'projectId' => 'test', - 'database' => '(default)' - ]); - - $this->requestWrapper->send( - Argument::type('callable'), - $expectedArgs, - Argument::type('array') - )->willReturn($this->successMessage); - - $connection->setRequestWrapper($this->requestWrapper->reveal()); - - $this->assertEquals($this->successMessage, $connection->$method($args)); - } -} - -//@codingStandardsIgnoreStart -class GrpcStub extends Grpc -{ - public $config; - - protected function constructGapic($gapicName, array $config) - { - $this->config = $config; - - return parent::constructGapic($gapicName, $config); - } -} -//@codingStandardsIgnoreEnd diff --git a/Firestore/tests/Unit/DocumentReferenceTest.php b/Firestore/tests/Unit/DocumentReferenceTest.php index a9abf6f474a..c1514804ebe 100644 --- a/Firestore/tests/Unit/DocumentReferenceTest.php +++ b/Firestore/tests/Unit/DocumentReferenceTest.php @@ -20,14 +20,17 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldPath; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\CommitRequest; +use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; use Google\Cloud\Firestore\ValueMapper; +use Google\Protobuf\Timestamp; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -40,44 +43,38 @@ class DocumentReferenceTest extends TestCase { use FirestoreTestHelperTrait; use ProphecyTrait; - use TimeTrait; public const PROJECT = 'example_project'; public const DATABASE = '(default)'; public const COLLECTION = 'projects/example_project/databases/(default)/documents/a'; public const NAME = 'projects/example_project/databases/(default)/documents/a/b'; - private $connection; private $requestHandler; private $serializer; private $document; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $valueMapper = new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ); $this->document = TestHelpers::stub(DocumentReference::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $valueMapper, new CollectionReference( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $valueMapper, self::COLLECTION ), self::NAME - ]); + ], ['requestHandler']); } public function testParent() @@ -103,90 +100,119 @@ public function testId() public function testCreate() { - $this->connection->commit([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'currentDocument' => ['exists' => false], - 'update' => [ - 'name' => self::NAME, - 'fields' => [ - 'hello' => [ - 'stringValue' => 'world' + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + $expected = [ + 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), + 'writes' => [ + [ + 'currentDocument' => ['exists' => false], + 'update' => [ + 'name' => self::NAME, + 'fields' => [ + 'hello' => [ + 'stringValue' => 'world' + ] + ] ] ] ] - ] - ] - ])->shouldBeCalled()->willReturn([[]]); + ]; - $this->document->___setProperty('connection', $this->connection->reveal()); + return array_replace_recursive($data, $expected) == $data; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([[]]); + + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->document->create(['hello' => 'world']); } public function testSet() { - $this->connection->commit([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'update' => [ - 'name' => self::NAME, - 'fields' => [ - 'hello' => [ - 'stringValue' => 'world' + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + $expected = [ + 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), + 'writes' => [ + [ + 'update' => [ + 'name' => self::NAME, + 'fields' => [ + 'hello' => [ + 'stringValue' => 'world' + ] + ] ] ] ] - ] - ] - ])->shouldBeCalled()->willReturn([[]]); + ]; - $this->document->___setProperty('connection', $this->connection->reveal()); + return array_replace_recursive($data, $expected) == $data; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([[]]); + + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->document->set(['hello' => 'world']); } public function testUpdate() { - $this->connection->commit([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'updateMask' => [ - 'fieldPaths' => [ - "foo.bar", - "foo.baz", - "hello", - ] - ], - 'currentDocument' => ['exists' => true], - 'update' => [ - 'name' => self::NAME, - 'fields' => [ - 'hello' => [ - 'stringValue' => 'world' + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + $expected = [ + 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), + 'writes' => [ + [ + 'updateMask' => [ + 'fieldPaths' => [ + "foo.bar", + "foo.baz", + "hello", + ] ], - 'foo' => [ - 'mapValue' => [ - 'fields' => [ - 'bar' => [ - 'stringValue' => 'val' - ], - 'baz' => [ - 'stringValue' => 'val' + 'currentDocument' => ['exists' => true], + 'update' => [ + 'name' => self::NAME, + 'fields' => [ + 'hello' => [ + 'stringValue' => 'world' + ], + 'foo' => [ + 'mapValue' => [ + 'fields' => [ + 'bar' => [ + 'stringValue' => 'val' + ], + 'baz' => [ + 'stringValue' => 'val' + ] + ] ] ] ] ] ] ] - ] - ] - ])->shouldBeCalled()->willReturn([[]]); + ]; + return array_replace_recursive($data, $expected) == $data; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([[]]); - $this->document->___setProperty('connection', $this->connection->reveal()); + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->document->update([ ['path' => 'hello', 'value' => 'world'], @@ -197,26 +223,42 @@ public function testUpdate() public function testDelete() { - $this->connection->commit([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'delete' => self::NAME - ] - ] - ])->shouldBeCalled()->willReturn([[]]); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + $expected = [ + 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), + 'writes' => [ + [ + 'delete' => self::NAME + ] + ] + ]; + return array_replace_recursive($data, $expected) == $data; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([[]]); - $this->document->___setProperty('connection', $this->connection->reveal()); + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->document->delete(); } public function testSnapshot() { - $this->connection->batchGetDocuments([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'documents' => [self::NAME] - ])->shouldBeCalled()->willReturn(new \ArrayIterator([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + + return $data['database'] == sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) + && $data['documents'] == [self::NAME]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ [ 'found' => [ 'name' => self::NAME, @@ -229,7 +271,7 @@ public function testSnapshot() ] ])); - $this->document->___setProperty('connection', $this->connection->reveal()); + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $snapshot = $this->document->snapshot(); $this->assertInstanceOf(DocumentSnapshot::class, $snapshot); @@ -247,13 +289,24 @@ public function testCollection() public function testCollections() { - $this->connection->listCollectionIds([ - 'parent' => self::NAME - ])->shouldBeCalled()->will(function ($args, $mock) { - $mock->listCollectionIds([ - 'parent' => self::NAME, - 'pageToken' => 'token' - ])->shouldBeCalled()->willReturn([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + Argument::that(function ($req) { + return $req->getParent() === self::NAME + && empty($req->getPageToken()); + }), + Argument::cetera() + )->shouldBeCalled()->will(function ($args, $mock) { + $mock->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + Argument::that(function ($req) { + return $req->getParent() === self::NAME + && $req->getPageToken() === 'token'; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([ 'collectionIds' => ['e'] ]); @@ -263,7 +316,7 @@ public function testCollections() ]; }); - $this->document->___setProperty('connection', $this->connection->reveal()); + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $collections = iterator_to_array($this->document->collections()); $this->assertContainsOnlyInstancesOf(CollectionReference::class, $collections); @@ -275,27 +328,33 @@ public function testCollections() public function testWriteResult() { - $time = time(); - $ts = \DateTime::createFromFormat('U', $time)->format(Timestamp::FORMAT); - $ts2 = \DateTime::createFromFormat('U', $time+100)->format(Timestamp::FORMAT); - - $this->connection->commit(Argument::any()) + $time = [ + 'seconds' => 100, + 'nanos' => 10 + ]; + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + ) ->shouldBeCalled() ->willReturn([ 'writeResults' => [ [ - 'updateTime' => $ts + 'updateTime' => $time ], [ - 'updateTime' => $ts2 + 'updateTime' => ['seconds' => 200] + $time ] ], - 'commitTime' => $ts + 'commitTime' => $time ]); - $this->document->___setProperty('connection', $this->connection->reveal()); + $this->document->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->document->set(['foo' => 'bar']); - $this->assertInstanceOf(Timestamp::class, $res['updateTime']); - $this->assertEqualsWithDelta($time + 100, $res['updateTime']->get()->format('U'), 3); + $this->assertIsArray($res['updateTime']); + $this->assertEqualsWithDelta($time['seconds'], $res['updateTime']['seconds'], 100); } } diff --git a/Firestore/tests/Unit/DocumentSnapshotTest.php b/Firestore/tests/Unit/DocumentSnapshotTest.php index eb4dc0bb251..849cc7e6c4a 100644 --- a/Firestore/tests/Unit/DocumentSnapshotTest.php +++ b/Firestore/tests/Unit/DocumentSnapshotTest.php @@ -21,8 +21,6 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldPath; @@ -55,7 +53,6 @@ public function setUp(): void $this->snapshot = TestHelpers::stub(DocumentSnapshot::class, [ $ref->reveal(), new ValueMapper( - $this->prophesize(ConnectionInterface::class)->reveal(), $this->prophesize(RequestHandler::class)->reveal(), $this->getSerializer(), false @@ -89,7 +86,7 @@ public function testId() */ public function testTimestampMethods($method) { - $ts = new Timestamp(new \DateTime()); + $ts = ['seconds' => 100, 'nanos' => 100]; $info = [$method => $ts]; $this->snapshot->___setProperty('info', $info); diff --git a/Firestore/tests/Unit/FirestoreClientTest.php b/Firestore/tests/Unit/FirestoreClientTest.php index 661b43f28b9..78558716698 100644 --- a/Firestore/tests/Unit/FirestoreClientTest.php +++ b/Firestore/tests/Unit/FirestoreClientTest.php @@ -25,14 +25,20 @@ use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\FieldPath; use Google\Cloud\Firestore\FirestoreClient; use Google\Cloud\Firestore\FirestoreSessionHandler; use Google\Cloud\Firestore\Query; +use Google\Cloud\Firestore\V1\BeginTransactionRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\CommitRequest; +use Google\Cloud\Firestore\V1\FirestoreClient as V1FirestoreGapicClient; +use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; +use Google\Cloud\Firestore\V1\RollbackRequest; +use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; +use Google\Cloud\Firestore\V1\RunQueryRequest; use Google\Cloud\Firestore\WriteBatch; use InvalidArgumentException; use PHPUnit\Framework\TestCase; @@ -52,7 +58,6 @@ class FirestoreClientTest extends TestCase const PROJECT = 'example_project'; const DATABASE = '(default)'; - private $connection; private $requestHandler; private $serializer; private $client; @@ -61,12 +66,12 @@ public function setUp(): void { $this->checkAndSkipGrpcTests(); - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->client = TestHelpers::stub( FirestoreClient::class, - [['projectId' => self::PROJECT]] + [['projectId' => self::PROJECT]], + ['requestHandler'] ); } @@ -79,11 +84,18 @@ public function testBatch() public function testBatchCorrectDatabaseName() { $db = sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE); - $this->connection->commit(Argument::withEntry('database', $db)) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($db) { + return $req->getDatabase() == $db; + }), + Argument::cetera() + ) ->shouldBeCalled() ->willReturn([[]]); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $batch = $this->client->batch(); $batch->commit(); } @@ -104,16 +116,18 @@ public function testCollections() 'collection-c', ]; - $this->connection->listCollectionIds(Argument::withEntry('foo', 'bar')) - ->willReturn([ - 'collectionIds' => $collectionIds - ])->shouldBeCalledTimes(1); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + Argument::type(ListCollectionIdsRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn([ + 'collectionIds' => $collectionIds + ]); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); - $collections = $this->client->collections([ - 'foo' => 'bar' - ]); + $collections = $this->client->collections([]); $this->assertInstanceOf(ItemIterator::class, $collections); @@ -132,25 +146,21 @@ public function testCollectionsPaged() 'collection-c', ]; - $this->connection->listCollectionIds(Argument::allOf( - Argument::withEntry('foo', 'bar'), - Argument::that(function ($options) { - if (isset($options['pageToken']) && $options['pageToken'] !== 'foo') { - return false; - } - - return true; - }) - ))->willReturn([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'listCollectionIds', + Argument::that(function ($req) { + return empty($req->getPageToken()) || $req->getPageToken() == 'foo'; + }), + Argument::cetera() + )->willReturn([ 'collectionIds' => $collectionIds, 'nextPageToken' => 'foo' ])->shouldBeCalledTimes(2); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); - $collections = $this->client->collections([ - 'foo' => 'bar' - ]); + $collections = $this->client->collections([]); // enumerate the iterator and kill after it loops twice. $arr = []; @@ -208,6 +218,7 @@ public function paths() */ public function testDocuments(array $input, array $names) { + $ts = ['seconds' => 100, 'nanos' => 100]; $res = [ [ 'found' => [ @@ -218,21 +229,28 @@ public function testDocuments(array $input, array $names) ] ] ], - 'readTime' => new Timestamp(new \DateTimeImmutable) + 'readTime' => $ts ], [ 'missing' => $names[1], - 'readTime' => new Timestamp(new \DateTimeImmutable) + 'readTime' => $ts ], [ 'missing' => $names[2], - 'readTime' => new Timestamp(new \DateTimeImmutable) + 'readTime' => $ts ] ]; - $this->connection->batchGetDocuments(Argument::withEntry('documents', $names)) - ->shouldBeCalled() - ->willReturn($res); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($names) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['documents'] == $names; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn($res); - $this->client->___setProperty('connection', $this->connection->reveal()); + + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->client->documents($input); @@ -302,24 +320,32 @@ public function testDocumentsOrdered() sprintf($tpl, 'c'), ]; + $ts = ['seconds' => 100, 'nanos' => 100]; $res = [ [ 'missing' => $names[2], - 'readTime' => new Timestamp(new \DateTimeImmutable) + 'readTime' => $ts ], [ 'missing' => $names[1], - 'readTime' => new Timestamp(new \DateTimeImmutable) + 'readTime' => $ts ], [ 'missing' => $names[0], - 'readTime' => new Timestamp(new \DateTimeImmutable) + 'readTime' => $ts ] ]; - $this->connection->batchGetDocuments(Argument::withEntry('documents', $names)) - ->shouldBeCalled() - ->willReturn($res); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($names) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['documents'] == $names; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn($res); - $this->client->___setProperty('connection', $this->connection->reveal()); + + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->client->documents($names); $this->assertEquals($names[0], $res[0]->name()); @@ -329,17 +355,24 @@ public function testDocumentsOrdered() public function testCollectionGroup() { - $this->connection->runQuery(Argument::allOf( - Argument::withEntry('structuredQuery', [ - 'from' => [ - [ - 'collectionId' => 'foo', - 'allDescendants' => true - ] - ] - ]), - Argument::withEntry('parent', 'projects/'. self::PROJECT .'/databases/'. self::DATABASE .'/documents') - ))->shouldBeCalled()->willReturn(new \ArrayIterator([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['structuredQuery']['from'] == [ + [ + 'collectionId' => 'foo', + 'allDescendants' => true + ] + ] && $data['parent'] == sprintf( + 'projects/%s/databases/%s/documents', + self::PROJECT, + self::DATABASE + ); + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ [ 'document' => [ 'name' => 'a/b/c/d', @@ -355,7 +388,7 @@ public function testCollectionGroup() ] ])); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $query = $this->client->collectionGroup('foo'); $this->assertInstanceOf(Query::class, $query); @@ -372,20 +405,30 @@ public function testCollectionGroupInvalidId() public function testRunTransaction() { $transactionId = 'foobar'; - $timestamp = new Timestamp(new \DateTimeImmutable); - $this->connection->beginTransaction([ - 'database' => 'projects/'. self::PROJECT .'/databases/'. self::DATABASE - ])->shouldBeCalled()->willReturn([ + $databaseName = V1FirestoreGapicClient::databaseRootName(self::PROJECT, self::DATABASE); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) use ($databaseName) { + return $request->getDatabase() == $databaseName; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([ 'transaction' => $transactionId ]); - $this->connection->rollback([ - 'database' => 'projects/'. self::PROJECT .'/databases/'. self::DATABASE, - 'transaction' => $transactionId - ])->shouldBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::that(function ($request) use ($databaseName, $transactionId) { + return $request->getDatabase() == $databaseName + && $request->getTransaction() == $transactionId; + }), + Argument::cetera() + )->shouldBeCalled(); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->client->runTransaction($this->noop()); } @@ -394,44 +437,73 @@ public function testRunTransactionRetryable() { $transactionId = 'foobar'; $transactionId2 = 'barfoo'; - $timestamp = new Timestamp(new \DateTimeImmutable); - - $this->connection->beginTransaction([ - 'database' => 'projects/'. self::PROJECT .'/databases/'. self::DATABASE - ])->shouldBeCalled()->will(function ($args, $mock) use ($transactionId, $transactionId2) { - $mock->beginTransaction(Argument::withEntry('retryTransaction', $transactionId))->willReturn([ - 'transaction' => $transactionId2 - ]); + $timestamp = ['seconds' => 100, 'nanos' => 100]; + + $databaseName = V1FirestoreGapicClient::databaseRootName(self::PROJECT, self::DATABASE); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) use ($databaseName) { + return $request->getDatabase() == $databaseName + && !$request->hasOptions(); + }), + Argument::cetera() + )->shouldBeCalledOnce()->will(function ($args, $mock) use ($transactionId, $transactionId2) { + $mock->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($req) use ($transactionId) { + return $req->getOptions()->getReadWrite()->getRetryTransaction() == $transactionId; + }), + Argument::cetera() + )->willReturn(['transaction' => $transactionId2]); return [ 'transaction' => $transactionId ]; }); - $this->connection->commit(Argument::allOf( - Argument::withEntry('database', 'projects/'. self::PROJECT .'/databases/'. self::DATABASE), - Argument::withEntry('transaction', $transactionId) - ))->shouldBeCalled()->will(function ($args, $mock) use ($timestamp, $transactionId2) { - $mock->commit(Argument::allOf( - Argument::withEntry('database', 'projects/'. self::PROJECT .'/databases/'. self::DATABASE), - Argument::withEntry('transaction', $transactionId2) - ))->willReturn([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($transactionId) { + $db = sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE); + return $req->getDatabase() == $db + && $req->getTransaction() == $transactionId; + }), + Argument::cetera() + )->shouldBeCalled()->will(function ($_, $mock) use ($timestamp, $transactionId2) { + $mock->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req2) use ($transactionId2) { + $db = sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE); + return $req2->getDatabase() == $db + && $req2->getTransaction() == $transactionId2; + }), + Argument::cetera() + )->willReturn([ 'commitTime' => $timestamp, ]); throw new AbortedException(''); }); - $this->connection->rollback([ - 'database' => 'projects/'. self::PROJECT .'/databases/'. self::DATABASE, - 'transaction' => $transactionId - ])->shouldBeCalledTimes(1); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::that(function ($request) use ($databaseName, $transactionId) { + return $request->getDatabase() == $databaseName + && $request->getTransaction() == $transactionId; + }), + Argument::cetera() + )->shouldBeCalledTimes(1); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->client->runTransaction(function ($t) { $doc = $this->prophesize(DocumentReference::class); - $doc->name('foo'); + $doc->name()->willReturn('foo'); $t->create($doc->reveal(), ['foo'=>'bar']); return 'foo'; @@ -445,22 +517,36 @@ public function testRunTransactionNotRetryable() $this->expectExceptionMessage('foo'); $transactionId = 'foobar'; - $timestamp = new Timestamp(new \DateTimeImmutable); - $this->connection->beginTransaction([ - 'database' => 'projects/'. self::PROJECT .'/databases/'. self::DATABASE - ])->shouldBeCalled()->willReturn([ + $databaseName = V1FirestoreGapicClient::databaseRootName(self::PROJECT, self::DATABASE); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) use ($databaseName) { + return $request->getDatabase() == $databaseName; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn([ 'transaction' => $transactionId ]); - $this->connection->commit()->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::cetera() + )->shouldNotBeCalled(); - $this->connection->rollback([ - 'database' => 'projects/'. self::PROJECT .'/databases/'. self::DATABASE, - 'transaction' => $transactionId - ])->shouldBeCalledTimes(1); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::that(function ($request) use ($databaseName, $transactionId) { + return $request->getDatabase() == $databaseName + && $request->getTransaction() == $transactionId; + }), + Argument::cetera() + )->shouldBeCalledTimes(1); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->client->runTransaction(function ($t) { throw new \RangeException('foo'); @@ -472,23 +558,37 @@ public function testRunTransactionExceedsMaxRetries() $this->expectException(AbortedException::class); $transactionId = 'foobar'; - $timestamp = new Timestamp(new \DateTimeImmutable); - $this->connection->beginTransaction(Argument::any())->shouldBeCalledTimes(6)->willReturn([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::type(BeginTransactionRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(6)->willReturn([ 'transaction' => $transactionId ]); - $this->connection->commit(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + ) ->shouldBeCalledTimes(6) ->willThrow(new AbortedException('foo')); - $this->connection->rollback(Argument::any())->shouldBeCalledTimes(6); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::type(RollbackRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(6); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->client->runTransaction(function ($t) { $doc = $this->prophesize(DocumentReference::class); - $doc->name('foo'); + $doc->name()->willReturn('foo'); $t->create($doc->reveal(), ['foo'=>'bar']); }); } @@ -498,23 +598,35 @@ public function testRunTransactionExceedsMaxRetriesLowerLimit() $this->expectException(AbortedException::class); $transactionId = 'foobar'; - $timestamp = new Timestamp(new \DateTimeImmutable); - $this->connection->beginTransaction(Argument::any())->shouldBeCalledTimes(3)->willReturn([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::type(BeginTransactionRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(3)->willReturn([ 'transaction' => $transactionId ]); - $this->connection->commit(Argument::any()) - ->shouldBeCalledTimes(3) - ->willThrow(new AbortedException('foo')); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(3)->willThrow(new AbortedException('foo')); - $this->connection->rollback(Argument::any())->shouldBeCalledTimes(3); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::type(RollbackRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(3); - $this->client->___setProperty('connection', $this->connection->reveal()); + $this->client->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->client->runTransaction(function ($t) { $doc = $this->prophesize(DocumentReference::class); - $doc->name('foo'); + $doc->name()->willReturn('foo'); $t->create($doc->reveal(), ['foo'=>'bar']); }, ['maxRetries' => 2]); } diff --git a/Firestore/tests/Unit/FirestoreSessionHandlerTest.php b/Firestore/tests/Unit/FirestoreSessionHandlerTest.php index 648416a7728..c32191b7993 100644 --- a/Firestore/tests/Unit/FirestoreSessionHandlerTest.php +++ b/Firestore/tests/Unit/FirestoreSessionHandlerTest.php @@ -21,9 +21,14 @@ use Google\Cloud\Core\Exception\ServiceException; use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\ValueMapper; use Google\Cloud\Firestore\FirestoreSessionHandler; +use Google\Cloud\Firestore\V1\BatchGetDocumentsRequest; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\CommitRequest; +use Google\Cloud\Firestore\V1\FirestoreClient as V1FirestoreGapicClient; +use Google\Cloud\Firestore\V1\RollbackRequest; +use Google\Cloud\Firestore\V1\RunQueryRequest; use InvalidArgumentException; use Iterator; use PHPUnit\Framework\TestCase; @@ -44,7 +49,6 @@ class FirestoreSessionHandlerTest extends TestCase const PROJECT = 'example_project'; const DATABASE = '(default)'; - private $connection; private $requestHandler; private $serializer; private $valueMapper; @@ -52,7 +56,6 @@ class FirestoreSessionHandlerTest extends TestCase public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->valueMapper = $this->prophesize(ValueMapper::class); @@ -61,11 +64,16 @@ public function setUp(): void public function testOpen() { - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => null]); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => null]); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -80,11 +88,16 @@ public function testOpenWithException() { $this->expectWarningUsingErrorhandler(); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willThrow(new ServiceException('')); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willThrow(new ServiceException('')); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -99,11 +112,16 @@ public function testReadNotAllowed() { $this->expectException(InvalidArgumentException::class); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => null]); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => null]); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -116,13 +134,23 @@ public function testReadNotAllowed() public function testClose() { - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => 123]); - $this->connection->rollback(Argument::any()) - ->shouldBeCalledTimes(1); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => 123]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::type(RollbackRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(1); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -139,18 +167,28 @@ public function testReadNothing() $this->documents->current() ->shouldBeCalledTimes(1) ->willReturn(null); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => null]); - $this->connection->batchGetDocuments([ - 'database' => $this->dbName(), - 'documents' => [$this->documentName()], - 'transaction' => null, - ]) - ->shouldBeCalledTimes(1) - ->willReturn($this->documents->reveal()); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => null]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == $this->dbName() + && $data['documents'] == [$this->documentName()] + && !isset($data['transaction']); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn($this->documents->reveal()); $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -167,18 +205,27 @@ public function testReadWithException() { $this->expectWarningUsingErrorhandler(); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => null]); - $this->connection->batchGetDocuments([ - 'database' => $this->dbName(), - 'documents' => [$this->documentName()], - 'transaction' => null, - ]) - ->shouldBeCalledTimes(1) - ->willThrow((new ServiceException(''))); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => null]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == $this->dbName() + && $data['documents'] == [$this->documentName()] + && !isset($data['transaction']); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willThrow((new ServiceException(''))); $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -206,18 +253,28 @@ public function testReadEntity() $this->valueMapper->decodeValues(['data' => 'sessiondata']) ->shouldBeCalledTimes(1) ->willReturn(['data' => 'sessiondata']); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => null]); - $this->connection->batchGetDocuments([ - 'database' => $this->dbName(), - 'documents' => [$this->documentName()], - 'transaction' => null, - ]) - ->shouldBeCalledTimes(1) - ->willReturn($this->documents->reveal()); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => null]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == $this->dbName() + && $data['documents'] == [$this->documentName()] + && !isset($data['transaction']); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn($this->documents->reveal()); $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -240,25 +297,41 @@ public function testWrite() $phpunit->assertTrue(is_int($args[0]['t'])); return ['data' => ['stringValue' => 'sessiondata']]; }); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => null]); - $this->connection->commit([ - 'database' => $this->dbName(), - 'writes' => [ - [ - 'update' => [ - 'name' => $this->documentName(), - 'fields' => [ - 'data' => ['stringValue' => 'sessiondata'] + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => null]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + $expected = [ + 'database' => $this->dbName(), + 'writes' => [ + [ + 'update' => [ + 'name' => $this->documentName(), + 'fields' => [ + 'data' => ['stringValue' => 'sessiondata'] + ] + ] ] ] - ] - ] - ]) - ->shouldBeCalledTimes(1); + ]; + + return array_replace_recursive($data, $expected) == $data; + }), + Argument::cetera() + )->shouldBeCalledTimes(1); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -283,19 +356,35 @@ public function testWriteWithException() $phpunit->assertTrue(is_int($args[0]['t'])); return ['data' => ['stringValue' => 'sessiondata']]; }); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => 123]); - $this->connection->rollback([ - 'database' => $this->dbName(), - 'transaction' => 123 - ]) - ->shouldBeCalledTimes(1); - $this->connection->commit(Argument::any()) + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => 123]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName() + && $request->getTransaction() == 123; + }), + Argument::cetera() + )->shouldBeCalledTimes(1); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + ) ->shouldBeCalledTimes(1) ->willThrow((new ServiceException(''))); $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -312,21 +401,28 @@ public function testWriteWithException() public function testDestroy() { - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => 123]); - $this->connection->commit([ - 'database' => $this->dbName(), - 'writes' => [ - [ - 'delete' => $this->documentName() - ] - ], - 'transaction' => 123 - ]) - ->shouldBeCalledTimes(1); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => 123]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == $this->dbName() + && $data['writes'][0]['delete'] == $this->documentName() + && $data['transaction'] == 123; + }), + Argument::cetera() + )->shouldBeCalledTimes(1); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -344,19 +440,33 @@ public function testDestroyWithException() { $this->expectWarningUsingErrorhandler(); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => 123]); - $this->connection->commit(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => 123]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::type(CommitRequest::class), + Argument::cetera() + ) ->shouldBeCalledTimes(1) ->willThrow(new ServiceException('')); - $this->connection->rollback([ - 'database' => $this->dbName(), - 'transaction' => 123 - ]) - ->shouldBeCalledTimes(1); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'rollback', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName() + && $request->getTransaction() == 123; + }), + Argument::cetera() + )->shouldBeCalledTimes(1); $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -372,12 +482,22 @@ public function testDestroyWithException() public function testDefaultGcDoesNothing() { - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(1) - ->willReturn(['transaction' => 123]); - $this->connection->commit()->shouldNotBeCalled(); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn(['transaction' => 123]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::cetera() + )->shouldNotBeCalled(); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -409,42 +529,55 @@ public function testGc() ]); $this->documents->next() ->shouldBeCalledTimes(1); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(2) - ->willReturn(['transaction' => 123]); - $this->connection->runQuery(Argument::any()) - ->shouldBeCalledTimes(1) - ->will(function ($args) use ($phpunit) { - $options = $args[0]; + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(2)->willReturn(['transaction' => 123]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::that(function ($req) use ($phpunit) { + $data = $this->getSerializer()->encodeMessage($req); $phpunit->assertEquals( $phpunit->dbName() . '/documents', - $options['parent'] + $data['parent'] ); - $phpunit->assertEquals(499, $options['structuredQuery']['limit']); + $phpunit->assertEquals(['value' => 499], $data['structuredQuery']['limit']); $phpunit->assertEquals( self::SESSION_SAVE_PATH . ':' . self::SESSION_NAME, - $options['structuredQuery']['from'][0]['collectionId'] + $data['structuredQuery']['from'][0]['collectionId'] ); - $phpunit->assertEquals(123, $options['transaction']); - return $phpunit->documents->reveal(); - }); + $phpunit->assertEquals(123, $data['transaction']); + return true; + }), + Argument::cetera() + )->shouldBeCalledTimes(1)->willReturn($this->documents->reveal()); + $this->valueMapper->decodeValues([]) ->shouldBeCalledTimes(1) ->willReturn(['data' => 'sessiondata']); $this->valueMapper->encodeValue(Argument::type('integer')) - ->shouldBeCalledTimes(1); - $this->connection->commit([ - 'database' => $this->dbName(), - 'writes' => [ - [ - 'delete' => $this->documentName() - ] - ], - 'transaction' => 123 - ]) - ->shouldBeCalledTimes(1); + ->shouldBeCalledTimes(1)->will(fn ($arg) => ['integerValue' => $arg[0]]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == $this->dbName() + && $data['writes'][0]['delete'] == $this->documentName() + && $data['transaction'] == 123; + }), + Argument::cetera() + )->shouldBeCalledTimes(1); + $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), @@ -463,14 +596,26 @@ public function testGcWithException() { $this->expectWarningUsingErrorhandler(); - $this->connection->beginTransaction(['database' => $this->dbName()]) - ->shouldBeCalledTimes(2) - ->willReturn(['transaction' => 123]); - $this->connection->runQuery(Argument::any()) - ->shouldBeCalledTimes(1) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'beginTransaction', + Argument::that(function ($request) { + return $request->getDatabase() == $this->dbName(); + }), + Argument::cetera() + )->shouldBeCalledTimes(2)->willReturn(['transaction' => 123]); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::type(RunQueryRequest::class), + Argument::cetera() + )->shouldBeCalledTimes(1) ->willThrow(new ServiceException('')); + + $this->valueMapper->encodeValue(Argument::type('integer')) + ->will(fn ($arg) => ['integerValue' => $arg[0]]); $firestoreSessionHandler = new FirestoreSessionHandler( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper->reveal(), diff --git a/Firestore/tests/Unit/QuerySnapshotTest.php b/Firestore/tests/Unit/QuerySnapshotTest.php index e8381294903..d658571f9bb 100644 --- a/Firestore/tests/Unit/QuerySnapshotTest.php +++ b/Firestore/tests/Unit/QuerySnapshotTest.php @@ -20,7 +20,6 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\Query; use Google\Cloud\Firestore\QuerySnapshot; use PHPUnit\Framework\TestCase; diff --git a/Firestore/tests/Unit/QueryTest.php b/Firestore/tests/Unit/QueryTest.php index ad850d76d8d..809965cd052 100644 --- a/Firestore/tests/Unit/QueryTest.php +++ b/Firestore/tests/Unit/QueryTest.php @@ -21,14 +21,13 @@ use Google\Cloud\Core\Testing\ArrayHasSameValuesToken; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldPath; use Google\Cloud\Firestore\FieldValue; use Google\Cloud\Firestore\Query; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\FirestoreClient as FirestoreGapicClient; use Google\Cloud\Firestore\V1\StructuredQuery\CompositeFilter\Operator; use Google\Cloud\Firestore\V1\StructuredQuery\Direction; @@ -39,6 +38,9 @@ use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Google\Cloud\Firestore\Filter; +use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; +use Google\Cloud\Firestore\V1\RunQueryRequest; +use Google\Protobuf\Timestamp as ProtobufTimestamp; /** * @group firestore @@ -59,7 +61,6 @@ class QueryTest extends TestCase ['collectionId' => self::COLLECTION] ] ]; - private $connection; private $requestHandler; private $serializer; private $query; @@ -67,38 +68,33 @@ class QueryTest extends TestCase public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->query = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), self::QUERY_PARENT, $this->queryObj - ], ['connection', 'requestHandler', 'query', 'transaction']); + ], ['requestHandler', 'query', 'transaction']); $allDescendants = $this->queryObj; $allDescendants['from'][0]['allDescendants'] = true; $this->collectionGroupQuery = TestHelpers::stub(Query::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ), self::QUERY_PARENT, $allDescendants - ], ['connection', 'requestHandler', 'query', 'transaction']); + ], ['requestHandler', 'query', 'transaction']); } public function testConstructMissingFrom() @@ -106,11 +102,9 @@ public function testConstructMissingFrom() $this->expectException(InvalidArgumentException::class); new Query( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -124,7 +118,12 @@ public function testDocuments() { $name = self::QUERY_PARENT .'/foo'; - $this->connection->runQuery(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::type(RunQueryRequest::class), + Argument::cetera() + ) ->shouldBeCalled() ->willReturn(new \ArrayIterator([ [ @@ -136,12 +135,12 @@ public function testDocuments() ] ] ], - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) + 'readTime' => ['seconds' => 100, 'nanos' => 100] ], [] ])); - $this->query->___setProperty('connection', $this->connection->reveal()); + $this->query->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->query->documents(['maxRetries' => 0]); $this->assertContainsOnlyInstancesOf(DocumentSnapshot::class, $res); @@ -156,8 +155,14 @@ public function testDocumentsMetadata() { $name = self::QUERY_PARENT .'/foo'; - $ts = (new \DateTime())->format(Timestamp::FORMAT); - $this->connection->runQuery(Argument::any()) + $ts = ['seconds' => 500, 'nanos' => 0]; + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::type(RunQueryRequest::class), + Argument::cetera() + ) ->shouldBeCalled() ->willReturn(new \ArrayIterator([ [ @@ -176,12 +181,12 @@ public function testDocumentsMetadata() [] ])); - $this->query->___setProperty('connection', $this->connection->reveal()); + $this->query->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->query->documents()->rows()[0]; - $this->assertInstanceOf(Timestamp::class, $res->createTime()); - $this->assertInstanceOf(Timestamp::class, $res->updateTime()); - $this->assertInstanceOf(Timestamp::class, $res->readTime()); + $this->assertArrayHasKey('seconds', $res->createTime()); + $this->assertArrayHasKey('seconds', $res->updateTime()); + $this->assertArrayHasKey('seconds', $res->readTime()); } /** @@ -189,19 +194,22 @@ public function testDocumentsMetadata() */ public function testAggregation($type, $arg) { - $this->connection->runAggregationQuery(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - [ - 'result' => [ - 'aggregateFields' => [ - $type => ['integerValue' => 1] - ] + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::type(RunAggregationQueryRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + [ + 'result' => [ + 'aggregateFields' => [ + $type => ['integerValue' => 1] ] ] - ])); + ] + ])); - $this->query->___setProperty('connection', $this->connection->reveal()); + $this->query->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $arg ? $this->query->$type($arg) : $this->query->$type(); $this->assertEquals(1, $res); @@ -212,20 +220,25 @@ public function testAggregation($type, $arg) */ public function testAggregationWithReadTime($type, $arg) { - $readTime = new Timestamp(new \DateTimeImmutable('now')); - $this->connection->runAggregationQuery(Argument::withEntry('readTime', $readTime)) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - [ - 'result' => [ - 'aggregateFields' => [ - $type => ['testValue' => 1] - ] + $readTime = new ProtobufTimestamp(); + $readTime->fromDateTime(new \DateTime()); + + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::type(RunAggregationQueryRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + [ + 'result' => [ + 'aggregateFields' => [ + $type => ['testValue' => 1] ] ] - ])); + ] + ])); - $this->query->___setProperty('connection', $this->connection->reveal()); + $this->query->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $arg ? $this->query->$type($arg, ['readTime' => $readTime]) : @@ -786,7 +799,7 @@ public function testLimit() 'parent' => self::QUERY_PARENT, 'structuredQuery' => [ 'from' => $this->queryFrom(), - 'limit' => $limit + 'limit' => ['value' => $limit] ] ]); } @@ -805,7 +818,7 @@ public function testLimitToLast(callable $filter, array $query) 'parent' => self::QUERY_PARENT, 'structuredQuery' => [ 'from' => $this->queryFrom(), - 'limit' => 1 + 'limit' => ['value' => 1] ] + $query ]); } @@ -933,7 +946,12 @@ public function testLimitToLastReversesResults() $name1 = self::QUERY_PARENT .'/foo'; $name2 = self::QUERY_PARENT .'/bar'; - $this->connection->runQuery(Argument::any()) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::type(RunQueryRequest::class), + Argument::cetera() + ) ->shouldBeCalled() ->willReturn(new \ArrayIterator([ [ @@ -945,7 +963,7 @@ public function testLimitToLastReversesResults() ] ] ], - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) + 'readTime' => ['seconds' => 100, 'nanos' => 100] ], [ 'document' => [ @@ -956,11 +974,11 @@ public function testLimitToLastReversesResults() ] ] ], - 'readTime' => (new \DateTime())->format(Timestamp::FORMAT) + 'readTime' => ['seconds' => 100, 'nanos' => 100] ], ])); - $this->query->___setProperty('connection', $this->connection->reveal()); + $this->query->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->query->orderBy('foo', 'DESC') ->limitToLast(2) @@ -1599,20 +1617,23 @@ public function testBuildPositionAllDescendantsDocument() private function runAndAssert(callable $filters, $assertion, Query $query = null) { - if (is_array($assertion)) { - $this->connection->runQuery( - new ArrayHasSameValuesToken($assertion + ['retries' => 0]) - )->shouldBeCalledTimes(1)->willReturn(new \ArrayIterator([ - [] - ])); - } elseif (is_callable($assertion)) { - $this->connection->runQuery(Argument::that($assertion)) - ->shouldBeCalledTimes(1); - } + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::that(function ($req) use ($assertion) { + $data = $this->getSerializer()->encodeMessage($req); + if (is_callable($assertion)) { + return $assertion($data); + } else { + return array_replace_recursive($data, $assertion) == $data; + } + }), + Argument::withEntry('retrySettings', ['maxRetries' => 0]) + )->shouldBeCalledTimes(1)->willReturn(new \ArrayIterator([[]])); $query = $query ?: $this->query; $immutable = clone $query; - $immutable->___setProperty('connection', $this->connection->reveal()); + $immutable->___setProperty('requestHandler', $this->requestHandler->reveal()); $query = $filters($immutable); $this->assertInstanceOf(Query::class, $query); diff --git a/Firestore/tests/Unit/SnapshotTraitTest.php b/Firestore/tests/Unit/SnapshotTraitTest.php index 2f8ec711f97..dd7b5f98b93 100644 --- a/Firestore/tests/Unit/SnapshotTraitTest.php +++ b/Firestore/tests/Unit/SnapshotTraitTest.php @@ -21,16 +21,16 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\SnapshotTrait; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\ValueMapper; -use InvalidArgumentException; +use Google\Protobuf\Timestamp as ProtobufTimestamp; use PHPUnit\Framework\TestCase; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; +use TypeError; /** * @group firestore @@ -45,7 +45,6 @@ class SnapshotTraitTest extends TestCase public const DATABASE = '(default)'; public const NAME = 'projects/example_project/databases/(default)/documents/a/b'; - private $connection; private $requestHandler; private $serializer; private $mapper; @@ -54,13 +53,11 @@ class SnapshotTraitTest extends TestCase public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->impl = TestHelpers::impl(SnapshotTrait::class); $this->valueMapper = new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false @@ -69,24 +66,32 @@ public function setUp(): void public function testCreateSnapshot() { - $this->connection->batchGetDocuments([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'documents' => [self::NAME] - ])->shouldBeCalled()->willReturn(new \ArrayIterator([ - ['found' => [ - 'name' => self::NAME, - 'fields' => [ - 'hello' => [ - 'stringValue' => 'world' + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + + return $data['database'] == sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) + && $data['documents'] == [self::NAME]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + [ + 'found' => [ + 'name' => self::NAME, + 'fields' => [ + 'hello' => [ + 'stringValue' => 'world' + ] ] ] - ]] + ] ])); $ref = $this->prophesize(DocumentReference::class); $ref->name()->willReturn(self::NAME); $res = $this->impl->call('createSnapshot', [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper, @@ -101,17 +106,23 @@ public function testCreateSnapshot() public function testCreateSnapshotNonExistence() { - $this->connection->batchGetDocuments([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'documents' => [self::NAME] - ])->shouldBeCalled()->willReturn(new \ArrayIterator([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + + return $data['database'] == sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) + && $data['documents'] == [self::NAME]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ ['missing' => self::NAME] ])); $ref = $this->prophesize(DocumentReference::class); $ref->name()->willReturn(self::NAME); $res = $this->impl->call('createSnapshot', [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper, @@ -125,15 +136,21 @@ public function testCreateSnapshotNonExistence() public function testGetSnapshot() { - $this->connection->batchGetDocuments([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'documents' => [self::NAME] - ])->shouldBeCalled()->willReturn(new \ArrayIterator([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + + return $data['database'] == sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) + && $data['documents'] == [self::NAME]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ ['found' => 'foo'] ])); $this->assertEquals('foo', $this->impl->call('getSnapshot', [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::NAME @@ -147,32 +164,31 @@ public function testGetSnapshotReadTime() 'nanos' => 501 ]; - $this->connection->batchGetDocuments(Argument::withEntry('readTime', $timestamp)) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([ - ['found' => 'foo'] - ])); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($timestamp) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['readTime'] == $timestamp; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ + ['found' => 'foo'] + ])); $this->impl->call('getSnapshot', [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::NAME, - [ - 'readTime' => new Timestamp( - \DateTimeImmutable::createFromFormat('U', (string) $timestamp['seconds']), - $timestamp['nanos'] - ) - ] + ['readTime' => $timestamp] ]); } public function testGetSnapshotReadTimeInvalidReadTime() { - $this->expectException(InvalidArgumentException::class); + $this->expectException(TypeError::class); $this->impl->call('getSnapshot', [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::NAME, @@ -184,15 +200,21 @@ public function testGetSnapshotNotFound() { $this->expectException(NotFoundException::class); - $this->connection->batchGetDocuments([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'documents' => [self::NAME] - ])->shouldBeCalled()->willReturn(new \ArrayIterator([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + + return $data['database'] == sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) + && $data['documents'] == [self::NAME]; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ ['missing' => self::NAME] ])); $this->impl->call('getSnapshot', [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::NAME diff --git a/Firestore/tests/Unit/TransactionTest.php b/Firestore/tests/Unit/TransactionTest.php index 35570e973d0..91570b00f12 100644 --- a/Firestore/tests/Unit/TransactionTest.php +++ b/Firestore/tests/Unit/TransactionTest.php @@ -20,8 +20,6 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldPath; @@ -31,6 +29,9 @@ use Google\Cloud\Firestore\Query; use Google\Cloud\Firestore\QuerySnapshot; use Google\Cloud\Firestore\Transaction; +use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; +use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; +use Google\Cloud\Firestore\V1\RunQueryRequest; use Google\Cloud\Firestore\ValueMapper; use PHPUnit\Framework\TestCase; use Prophecy\Argument; @@ -50,7 +51,6 @@ class TransactionTest extends TestCase public const DOCUMENT = 'projects/example_project/databases/(default)/documents/a/b'; public const TRANSACTION = 'foobar'; - private $connection; private $requestHandler; private $serializer; private $valueMapper; @@ -59,23 +59,20 @@ class TransactionTest extends TestCase public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->valueMapper = new ValueMapper( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false ); $this->transaction = TestHelpers::stub(Transaction::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper, sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), self::TRANSACTION - ]); + ], ['requestHandler']); $this->ref = $this->prophesize(DocumentReference::class); $this->ref->name()->willReturn(self::DOCUMENT); @@ -83,11 +80,17 @@ public function setUp(): void public function testSnapshot() { - $this->connection->batchGetDocuments([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'documents' => [self::DOCUMENT], - 'transaction' => self::TRANSACTION - ])->shouldBeCalled()->willReturn(new \ArrayIterator([ + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) + && $data['documents'] == [self::DOCUMENT] + && $data['transaction'] == self::TRANSACTION; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([ [ 'found' => [ 'name' => self::DOCUMENT, @@ -100,7 +103,7 @@ public function testSnapshot() ] ])); - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->transaction->snapshot($this->ref->reveal()); $this->assertInstanceOf(DocumentSnapshot::class, $res); @@ -110,19 +113,24 @@ public function testSnapshot() public function testRunQuery() { - $this->connection->runQuery(Argument::withEntry('transaction', self::TRANSACTION)) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([[]])); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runQuery', + Argument::that(function ($req) { + return $req->getTransaction() == self::TRANSACTION; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([[]])); $query = new Query( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, $this->valueMapper, - '', - ['from' => ['collectionId' => '']] + 'foo_parent', + ['from' => [['collectionId' => 'foo_collection']]] ); + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->transaction->runQuery($query); $this->assertInstanceOf(QuerySnapshot::class, $res); } @@ -132,12 +140,14 @@ public function testRunQuery() */ public function testRunAggregateQuery($type, $arg) { - $this->connection->runAggregationQuery(Argument::any()) - ->shouldBeCalled() - ->willReturn(new \ArrayIterator([])); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::type(RunAggregationQueryRequest::class), + Argument::cetera() + )->shouldBeCalled()->willReturn(new \ArrayIterator([])); $aggregateQuery = new AggregateQuery( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::DOCUMENT, @@ -145,7 +155,7 @@ public function testRunAggregateQuery($type, $arg) $arg ? Aggregate::$type($arg) : Aggregate::$type() ); - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->transaction->runAggregateQuery($aggregateQuery); @@ -163,15 +173,20 @@ public function testGetAggregateSnapshotReadTime($type, $arg) ]; $aggregateQuery = new AggregateQuery( - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, self::DOCUMENT, ['query' => []], $arg ? Aggregate::$type($arg) : Aggregate::$type() ); - $this->connection->runAggregationQuery( - Argument::withEntry('readTime', $timestamp) + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'runAggregationQuery', + Argument::that(function ($req) use ($timestamp) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['readTime'] == $timestamp; + }), + Argument::cetera() )->shouldBeCalled()->willReturn(new \ArrayIterator([ [ 'result' => [ @@ -182,28 +197,15 @@ public function testGetAggregateSnapshotReadTime($type, $arg) ] ])); - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->transaction->runAggregateQuery($aggregateQuery, [ - 'readTime' => new Timestamp( - \DateTimeImmutable::createFromFormat('U', (string) $timestamp['seconds']), - $timestamp['nanos'] - ) + 'readTime' => $timestamp ]); $this->assertEquals(1, $res->get($type)); } - public function testGetAggregateSnapshotReadTimeInvalidReadTime() - { - $this->expectException('InvalidArgumentException'); - $q = $this->prophesize(AggregateQuery::class); - - $res = $this->transaction->runAggregateQuery($q->reveal(), [ - 'readTime' => 'invalid_time' - ]); - } - public function testCreate() { $this->transaction->create($this->ref->reveal(), [ @@ -312,7 +314,10 @@ public function testDelete() */ public function testDocuments(array $input, array $names) { - $timestamp = (new Timestamp(new \DateTimeImmutable()))->formatAsString(); + $timestamp = [ + 'seconds' => 100, + 'nanos' => 100 + ]; $res = [ [ @@ -334,12 +339,18 @@ public function testDocuments(array $input, array $names) ] ]; - $this->connection->batchGetDocuments(Argument::allOf( - Argument::withEntry('documents', $names), - Argument::withEntry('transaction', self::TRANSACTION) - ))->shouldBeCalled()->willReturn($res); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($names) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['documents'] == $names + && $data['transaction'] == self::TRANSACTION; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn($res); - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->transaction->documents($input); @@ -405,7 +416,7 @@ public function aggregationTypes() public function testDocumentsOrdered() { - $timestamp = (new Timestamp(new \DateTimeImmutable()))->formatAsString(); + $timestamp = ['seconds' => 100, 'nanos' => 100]; $tpl = 'projects/'. self::PROJECT .'/databases/'. self::DATABASE .'/documents/a/%s'; $names = [ sprintf($tpl, 'a'), @@ -426,11 +437,17 @@ public function testDocumentsOrdered() ] ]; - $this->connection->batchGetDocuments(Argument::withEntry('documents', $names)) - ->shouldBeCalled() - ->willReturn($res); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'batchGetDocuments', + Argument::that(function ($req) use ($names) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['documents'] == $names; + }), + Argument::cetera() + )->shouldBeCalled()->willReturn($res); - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $res = $this->transaction->documents($names); $this->assertEquals($names[0], $res[0]->name()); @@ -440,12 +457,19 @@ public function testDocumentsOrdered() private function expectAndInvoke(array $writes) { - $this->connection->commit([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => $writes, - 'transaction' => self::TRANSACTION - ])->shouldBeCalled(); - $this->transaction->___setProperty('connection', $this->connection->reveal()); + $this->requestHandler->sendRequest( + V1FirestoreClient::class, + 'commit', + Argument::that(function ($req) use ($writes) { + $data = $this->getSerializer()->encodeMessage($req); + return $data['database'] == sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) + && array_replace_recursive($data['writes'], $writes) == $data['writes'] + && $data['transaction'] == self::TRANSACTION; + }), + Argument::cetera() + )->shouldBeCalled(); + + $this->transaction->___setProperty('requestHandler', $this->requestHandler->reveal()); $this->transaction->writer()->commit(); } } diff --git a/Firestore/tests/Unit/V1/FirestoreClientBCTest.php b/Firestore/tests/Unit/V1/FirestoreClientBCTest.php deleted file mode 100644 index 5ad245ecb7b..00000000000 --- a/Firestore/tests/Unit/V1/FirestoreClientBCTest.php +++ /dev/null @@ -1,133 +0,0 @@ -getMockBuilder(CredentialsWrapper::class)->disableOriginalConstructor()->getMock(); - } - - /** - * @return FirestoreClient - */ - private function createClient(array $options = []) - { - $options += [ - 'credentials' => $this->createCredentials(), - ]; - return new FirestoreClient($options); - } - - /** - * @test - */ - public function partitionQueryTest() - { - $transport = $this->createTransport(); - $client = $this->createClient(['transport' => $transport]); - - $this->assertTrue($transport->isExhausted()); - - // Mock response - $nextPageToken = 'nextPageToken-1530815211'; - $expectedResponse = new PartitionQueryResponse(); - $expectedResponse->setNextPageToken($nextPageToken); - $transport->addResponse($expectedResponse); - - $response = $client->partitionQuery(); - $this->assertEquals($expectedResponse, $response); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/PartitionQuery', $actualFuncCall); - - $this->assertTrue($transport->isExhausted()); - } - - /** - * @test - */ - public function partitionQueryExceptionTest() - { - $transport = $this->createTransport(); - $client = $this->createClient(['transport' => $transport]); - - $this->assertTrue($transport->isExhausted()); - - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - - try { - $client->partitionQuery(); - // If the $client method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } -} diff --git a/Firestore/tests/Unit/V1/FirestoreClientTest.php b/Firestore/tests/Unit/V1/FirestoreClientTest.php deleted file mode 100644 index cea65bb4e60..00000000000 --- a/Firestore/tests/Unit/V1/FirestoreClientTest.php +++ /dev/null @@ -1,1219 +0,0 @@ -getMockBuilder(CredentialsWrapper::class)->disableOriginalConstructor()->getMock(); - } - - /** @return FirestoreClient */ - private function createClient(array $options = []) - { - $options += [ - 'credentials' => $this->createCredentials(), - ]; - return new FirestoreClient($options); - } - - /** @test */ - public function batchGetDocumentsTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $missing = 'missing1069449574'; - $transaction2 = '17'; - $expectedResponse = new BatchGetDocumentsResponse(); - $expectedResponse->setMissing($missing); - $expectedResponse->setTransaction($transaction2); - $transport->addResponse($expectedResponse); - $missing2 = 'missing21243859865'; - $transaction3 = '18'; - $expectedResponse2 = new BatchGetDocumentsResponse(); - $expectedResponse2->setMissing($missing2); - $expectedResponse2->setTransaction($transaction3); - $transport->addResponse($expectedResponse2); - $missing3 = 'missing31243859866'; - $transaction4 = '19'; - $expectedResponse3 = new BatchGetDocumentsResponse(); - $expectedResponse3->setMissing($missing3); - $expectedResponse3->setTransaction($transaction4); - $transport->addResponse($expectedResponse3); - // Mock request - $database = 'database1789464955'; - $documents = []; - $serverStream = $gapicClient->batchGetDocuments($database, $documents); - $this->assertInstanceOf(ServerStream::class, $serverStream); - $responses = iterator_to_array($serverStream->readAll()); - $expectedResponses = []; - $expectedResponses[] = $expectedResponse; - $expectedResponses[] = $expectedResponse2; - $expectedResponses[] = $expectedResponse3; - $this->assertEquals($expectedResponses, $responses); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/BatchGetDocuments', $actualFuncCall); - $actualValue = $actualRequestObject->getDatabase(); - $this->assertProtobufEquals($database, $actualValue); - $actualValue = $actualRequestObject->getDocuments(); - $this->assertProtobufEquals($documents, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function batchGetDocumentsExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->setStreamingStatus($status); - $this->assertTrue($transport->isExhausted()); - // Mock request - $database = 'database1789464955'; - $documents = []; - $serverStream = $gapicClient->batchGetDocuments($database, $documents); - $results = $serverStream->readAll(); - try { - iterator_to_array($results); - // If the close stream method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function batchWriteTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $expectedResponse = new BatchWriteResponse(); - $transport->addResponse($expectedResponse); - $response = $gapicClient->batchWrite(); - $this->assertEquals($expectedResponse, $response); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/BatchWrite', $actualFuncCall); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function batchWriteExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - try { - $gapicClient->batchWrite(); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function beginTransactionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $transaction = '-34'; - $expectedResponse = new BeginTransactionResponse(); - $expectedResponse->setTransaction($transaction); - $transport->addResponse($expectedResponse); - // Mock request - $database = 'database1789464955'; - $response = $gapicClient->beginTransaction($database); - $this->assertEquals($expectedResponse, $response); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/BeginTransaction', $actualFuncCall); - $actualValue = $actualRequestObject->getDatabase(); - $this->assertProtobufEquals($database, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function beginTransactionExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $database = 'database1789464955'; - try { - $gapicClient->beginTransaction($database); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function commitTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $expectedResponse = new CommitResponse(); - $transport->addResponse($expectedResponse); - // Mock request - $database = 'database1789464955'; - $writes = []; - $response = $gapicClient->commit($database, $writes); - $this->assertEquals($expectedResponse, $response); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/Commit', $actualFuncCall); - $actualValue = $actualRequestObject->getDatabase(); - $this->assertProtobufEquals($database, $actualValue); - $actualValue = $actualRequestObject->getWrites(); - $this->assertProtobufEquals($writes, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function commitExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $database = 'database1789464955'; - $writes = []; - try { - $gapicClient->commit($database, $writes); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function createDocumentTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $name = 'name3373707'; - $expectedResponse = new Document(); - $expectedResponse->setName($name); - $transport->addResponse($expectedResponse); - // Mock request - $parent = 'parent-995424086'; - $collectionId = 'collectionId-821242276'; - $documentId = 'documentId506676927'; - $document = new Document(); - $response = $gapicClient->createDocument($parent, $collectionId, $documentId, $document); - $this->assertEquals($expectedResponse, $response); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/CreateDocument', $actualFuncCall); - $actualValue = $actualRequestObject->getParent(); - $this->assertProtobufEquals($parent, $actualValue); - $actualValue = $actualRequestObject->getCollectionId(); - $this->assertProtobufEquals($collectionId, $actualValue); - $actualValue = $actualRequestObject->getDocumentId(); - $this->assertProtobufEquals($documentId, $actualValue); - $actualValue = $actualRequestObject->getDocument(); - $this->assertProtobufEquals($document, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function createDocumentExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $parent = 'parent-995424086'; - $collectionId = 'collectionId-821242276'; - $documentId = 'documentId506676927'; - $document = new Document(); - try { - $gapicClient->createDocument($parent, $collectionId, $documentId, $document); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function deleteDocumentTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $expectedResponse = new GPBEmpty(); - $transport->addResponse($expectedResponse); - // Mock request - $name = 'name3373707'; - $gapicClient->deleteDocument($name); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/DeleteDocument', $actualFuncCall); - $actualValue = $actualRequestObject->getName(); - $this->assertProtobufEquals($name, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function deleteDocumentExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $name = 'name3373707'; - try { - $gapicClient->deleteDocument($name); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function getDocumentTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $name2 = 'name2-1052831874'; - $expectedResponse = new Document(); - $expectedResponse->setName($name2); - $transport->addResponse($expectedResponse); - // Mock request - $name = 'name3373707'; - $response = $gapicClient->getDocument($name); - $this->assertEquals($expectedResponse, $response); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/GetDocument', $actualFuncCall); - $actualValue = $actualRequestObject->getName(); - $this->assertProtobufEquals($name, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function getDocumentExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $name = 'name3373707'; - try { - $gapicClient->getDocument($name); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function listCollectionIdsTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $nextPageToken = ''; - $collectionIdsElement = 'collectionIdsElement1368994900'; - $collectionIds = [ - $collectionIdsElement, - ]; - $expectedResponse = new ListCollectionIdsResponse(); - $expectedResponse->setNextPageToken($nextPageToken); - $expectedResponse->setCollectionIds($collectionIds); - $transport->addResponse($expectedResponse); - // Mock request - $parent = 'parent-995424086'; - $response = $gapicClient->listCollectionIds($parent); - $this->assertEquals($expectedResponse, $response->getPage()->getResponseObject()); - $resources = iterator_to_array($response->iterateAllElements()); - $this->assertSame(1, count($resources)); - $this->assertEquals($expectedResponse->getCollectionIds()[0], $resources[0]); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/ListCollectionIds', $actualFuncCall); - $actualValue = $actualRequestObject->getParent(); - $this->assertProtobufEquals($parent, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function listCollectionIdsExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $parent = 'parent-995424086'; - try { - $gapicClient->listCollectionIds($parent); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function listDocumentsTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $nextPageToken = ''; - $documentsElement = new Document(); - $documents = [ - $documentsElement, - ]; - $expectedResponse = new ListDocumentsResponse(); - $expectedResponse->setNextPageToken($nextPageToken); - $expectedResponse->setDocuments($documents); - $transport->addResponse($expectedResponse); - // Mock request - $parent = 'parent-995424086'; - $collectionId = 'collectionId-821242276'; - $response = $gapicClient->listDocuments($parent, $collectionId); - $this->assertEquals($expectedResponse, $response->getPage()->getResponseObject()); - $resources = iterator_to_array($response->iterateAllElements()); - $this->assertSame(1, count($resources)); - $this->assertEquals($expectedResponse->getDocuments()[0], $resources[0]); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/ListDocuments', $actualFuncCall); - $actualValue = $actualRequestObject->getParent(); - $this->assertProtobufEquals($parent, $actualValue); - $actualValue = $actualRequestObject->getCollectionId(); - $this->assertProtobufEquals($collectionId, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function listDocumentsExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $parent = 'parent-995424086'; - $collectionId = 'collectionId-821242276'; - try { - $gapicClient->listDocuments($parent, $collectionId); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function listenTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $expectedResponse = new ListenResponse(); - $transport->addResponse($expectedResponse); - $expectedResponse2 = new ListenResponse(); - $transport->addResponse($expectedResponse2); - $expectedResponse3 = new ListenResponse(); - $transport->addResponse($expectedResponse3); - // Mock request - $database = 'database1789464955'; - $request = new ListenRequest(); - $request->setDatabase($database); - $database2 = 'database21688906350'; - $request2 = new ListenRequest(); - $request2->setDatabase($database2); - $database3 = 'database31688906351'; - $request3 = new ListenRequest(); - $request3->setDatabase($database3); - $bidi = $gapicClient->listen(); - $this->assertInstanceOf(BidiStream::class, $bidi); - $bidi->write($request); - $responses = []; - $responses[] = $bidi->read(); - $bidi->writeAll([ - $request2, - $request3, - ]); - foreach ($bidi->closeWriteAndReadAll() as $response) { - $responses[] = $response; - } - - $expectedResponses = []; - $expectedResponses[] = $expectedResponse; - $expectedResponses[] = $expectedResponse2; - $expectedResponses[] = $expectedResponse3; - $this->assertEquals($expectedResponses, $responses); - $createStreamRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($createStreamRequests)); - $streamFuncCall = $createStreamRequests[0]->getFuncCall(); - $streamRequestObject = $createStreamRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/Listen', $streamFuncCall); - $this->assertNull($streamRequestObject); - $callObjects = $transport->popCallObjects(); - $this->assertSame(1, count($callObjects)); - $bidiCall = $callObjects[0]; - $writeRequests = $bidiCall->popReceivedCalls(); - $expectedRequests = []; - $expectedRequests[] = $request; - $expectedRequests[] = $request2; - $expectedRequests[] = $request3; - $this->assertEquals($expectedRequests, $writeRequests); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function listenExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->setStreamingStatus($status); - $this->assertTrue($transport->isExhausted()); - $bidi = $gapicClient->listen(); - $results = $bidi->closeWriteAndReadAll(); - try { - iterator_to_array($results); - // If the close stream method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function partitionQueryTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $nextPageToken = ''; - $partitionsElement = new Cursor(); - $partitions = [ - $partitionsElement, - ]; - $expectedResponse = new PartitionQueryResponse(); - $expectedResponse->setNextPageToken($nextPageToken); - $expectedResponse->setPartitions($partitions); - $transport->addResponse($expectedResponse); - $response = $gapicClient->partitionQueryPaginated(); - $this->assertEquals($expectedResponse, $response->getPage()->getResponseObject()); - $resources = iterator_to_array($response->iterateAllElements()); - $this->assertSame(1, count($resources)); - $this->assertEquals($expectedResponse->getPartitions()[0], $resources[0]); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/PartitionQuery', $actualFuncCall); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function partitionQueryExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - try { - $gapicClient->partitionQueryPaginated(); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function rollbackTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $expectedResponse = new GPBEmpty(); - $transport->addResponse($expectedResponse); - // Mock request - $database = 'database1789464955'; - $transaction = '-34'; - $gapicClient->rollback($database, $transaction); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/Rollback', $actualFuncCall); - $actualValue = $actualRequestObject->getDatabase(); - $this->assertProtobufEquals($database, $actualValue); - $actualValue = $actualRequestObject->getTransaction(); - $this->assertProtobufEquals($transaction, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function rollbackExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $database = 'database1789464955'; - $transaction = '-34'; - try { - $gapicClient->rollback($database, $transaction); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function runAggregationQueryTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $transaction2 = '17'; - $expectedResponse = new RunAggregationQueryResponse(); - $expectedResponse->setTransaction($transaction2); - $transport->addResponse($expectedResponse); - $transaction3 = '18'; - $expectedResponse2 = new RunAggregationQueryResponse(); - $expectedResponse2->setTransaction($transaction3); - $transport->addResponse($expectedResponse2); - $transaction4 = '19'; - $expectedResponse3 = new RunAggregationQueryResponse(); - $expectedResponse3->setTransaction($transaction4); - $transport->addResponse($expectedResponse3); - // Mock request - $parent = 'parent-995424086'; - $serverStream = $gapicClient->runAggregationQuery($parent); - $this->assertInstanceOf(ServerStream::class, $serverStream); - $responses = iterator_to_array($serverStream->readAll()); - $expectedResponses = []; - $expectedResponses[] = $expectedResponse; - $expectedResponses[] = $expectedResponse2; - $expectedResponses[] = $expectedResponse3; - $this->assertEquals($expectedResponses, $responses); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/RunAggregationQuery', $actualFuncCall); - $actualValue = $actualRequestObject->getParent(); - $this->assertProtobufEquals($parent, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function runAggregationQueryExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->setStreamingStatus($status); - $this->assertTrue($transport->isExhausted()); - // Mock request - $parent = 'parent-995424086'; - $serverStream = $gapicClient->runAggregationQuery($parent); - $results = $serverStream->readAll(); - try { - iterator_to_array($results); - // If the close stream method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function runQueryTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $transaction2 = '17'; - $skippedResults = 880286183; - $done = true; - $expectedResponse = new RunQueryResponse(); - $expectedResponse->setTransaction($transaction2); - $expectedResponse->setSkippedResults($skippedResults); - $expectedResponse->setDone($done); - $transport->addResponse($expectedResponse); - $transaction3 = '18'; - $skippedResults2 = 153532454; - $done2 = false; - $expectedResponse2 = new RunQueryResponse(); - $expectedResponse2->setTransaction($transaction3); - $expectedResponse2->setSkippedResults($skippedResults2); - $expectedResponse2->setDone($done2); - $transport->addResponse($expectedResponse2); - $transaction4 = '19'; - $skippedResults3 = 153532453; - $done3 = true; - $expectedResponse3 = new RunQueryResponse(); - $expectedResponse3->setTransaction($transaction4); - $expectedResponse3->setSkippedResults($skippedResults3); - $expectedResponse3->setDone($done3); - $transport->addResponse($expectedResponse3); - // Mock request - $parent = 'parent-995424086'; - $serverStream = $gapicClient->runQuery($parent); - $this->assertInstanceOf(ServerStream::class, $serverStream); - $responses = iterator_to_array($serverStream->readAll()); - $expectedResponses = []; - $expectedResponses[] = $expectedResponse; - $expectedResponses[] = $expectedResponse2; - $expectedResponses[] = $expectedResponse3; - $this->assertEquals($expectedResponses, $responses); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/RunQuery', $actualFuncCall); - $actualValue = $actualRequestObject->getParent(); - $this->assertProtobufEquals($parent, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function runQueryExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->setStreamingStatus($status); - $this->assertTrue($transport->isExhausted()); - // Mock request - $parent = 'parent-995424086'; - $serverStream = $gapicClient->runQuery($parent); - $results = $serverStream->readAll(); - try { - iterator_to_array($results); - // If the close stream method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function updateDocumentTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $name = 'name3373707'; - $expectedResponse = new Document(); - $expectedResponse->setName($name); - $transport->addResponse($expectedResponse); - // Mock request - $document = new Document(); - $updateMask = new DocumentMask(); - $response = $gapicClient->updateDocument($document, $updateMask); - $this->assertEquals($expectedResponse, $response); - $actualRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($actualRequests)); - $actualFuncCall = $actualRequests[0]->getFuncCall(); - $actualRequestObject = $actualRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/UpdateDocument', $actualFuncCall); - $actualValue = $actualRequestObject->getDocument(); - $this->assertProtobufEquals($document, $actualValue); - $actualValue = $actualRequestObject->getUpdateMask(); - $this->assertProtobufEquals($updateMask, $actualValue); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function updateDocumentExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->addResponse(null, $status); - // Mock request - $document = new Document(); - $updateMask = new DocumentMask(); - try { - $gapicClient->updateDocument($document, $updateMask); - // If the $gapicClient method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function writeTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $this->assertTrue($transport->isExhausted()); - // Mock response - $streamId = 'streamId-315624902'; - $streamToken = '122'; - $expectedResponse = new WriteResponse(); - $expectedResponse->setStreamId($streamId); - $expectedResponse->setStreamToken($streamToken); - $transport->addResponse($expectedResponse); - $streamId2 = 'streamId21627150189'; - $streamToken2 = '-83'; - $expectedResponse2 = new WriteResponse(); - $expectedResponse2->setStreamId($streamId2); - $expectedResponse2->setStreamToken($streamToken2); - $transport->addResponse($expectedResponse2); - $streamId3 = 'streamId31627150190'; - $streamToken3 = '-82'; - $expectedResponse3 = new WriteResponse(); - $expectedResponse3->setStreamId($streamId3); - $expectedResponse3->setStreamToken($streamToken3); - $transport->addResponse($expectedResponse3); - // Mock request - $database = 'database1789464955'; - $request = new WriteRequest(); - $request->setDatabase($database); - $database2 = 'database21688906350'; - $request2 = new WriteRequest(); - $request2->setDatabase($database2); - $database3 = 'database31688906351'; - $request3 = new WriteRequest(); - $request3->setDatabase($database3); - $bidi = $gapicClient->write(); - $this->assertInstanceOf(BidiStream::class, $bidi); - $bidi->write($request); - $responses = []; - $responses[] = $bidi->read(); - $bidi->writeAll([ - $request2, - $request3, - ]); - foreach ($bidi->closeWriteAndReadAll() as $response) { - $responses[] = $response; - } - - $expectedResponses = []; - $expectedResponses[] = $expectedResponse; - $expectedResponses[] = $expectedResponse2; - $expectedResponses[] = $expectedResponse3; - $this->assertEquals($expectedResponses, $responses); - $createStreamRequests = $transport->popReceivedCalls(); - $this->assertSame(1, count($createStreamRequests)); - $streamFuncCall = $createStreamRequests[0]->getFuncCall(); - $streamRequestObject = $createStreamRequests[0]->getRequestObject(); - $this->assertSame('/google.firestore.v1.Firestore/Write', $streamFuncCall); - $this->assertNull($streamRequestObject); - $callObjects = $transport->popCallObjects(); - $this->assertSame(1, count($callObjects)); - $bidiCall = $callObjects[0]; - $writeRequests = $bidiCall->popReceivedCalls(); - $expectedRequests = []; - $expectedRequests[] = $request; - $expectedRequests[] = $request2; - $expectedRequests[] = $request3; - $this->assertEquals($expectedRequests, $writeRequests); - $this->assertTrue($transport->isExhausted()); - } - - /** @test */ - public function writeExceptionTest() - { - $transport = $this->createTransport(); - $gapicClient = $this->createClient([ - 'transport' => $transport, - ]); - $status = new stdClass(); - $status->code = Code::DATA_LOSS; - $status->details = 'internal error'; - $expectedExceptionMessage = json_encode([ - 'message' => 'internal error', - 'code' => Code::DATA_LOSS, - 'status' => 'DATA_LOSS', - 'details' => [], - ], JSON_PRETTY_PRINT); - $transport->setStreamingStatus($status); - $this->assertTrue($transport->isExhausted()); - $bidi = $gapicClient->write(); - $results = $bidi->closeWriteAndReadAll(); - try { - iterator_to_array($results); - // If the close stream method call did not throw, fail the test - $this->fail('Expected an ApiException, but no exception was thrown.'); - } catch (ApiException $ex) { - $this->assertEquals($status->code, $ex->getCode()); - $this->assertEquals($expectedExceptionMessage, $ex->getMessage()); - } - // Call popReceivedCalls to ensure the stub is exhausted - $transport->popReceivedCalls(); - $this->assertTrue($transport->isExhausted()); - } -} diff --git a/Firestore/tests/Unit/ValueMapperTest.php b/Firestore/tests/Unit/ValueMapperTest.php index e22e9508353..edbc1fd75bf 100644 --- a/Firestore/tests/Unit/ValueMapperTest.php +++ b/Firestore/tests/Unit/ValueMapperTest.php @@ -23,10 +23,8 @@ use Google\Cloud\Core\RequestHandler; use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\TestHelpers; -use Google\Cloud\Core\Timestamp; use Google\Cloud\Core\TimeTrait; use Google\Cloud\Firestore\CollectionReference; -use Google\Cloud\Firestore\Connection\ConnectionInterface; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\ValueMapper; use Google\Protobuf\NullValue; @@ -41,24 +39,20 @@ class ValueMapperTest extends TestCase { use FirestoreTestHelperTrait; use ProphecyTrait; - use TimeTrait; - private $connection; private $requestHandler; private $serializer; private $mapper; public function setUp(): void { - $this->connection = $this->prophesize(ConnectionInterface::class); $this->requestHandler = $this->prophesize(RequestHandler::class); $this->serializer = $this->getSerializer(); $this->mapper = TestHelpers::stub(ValueMapper::class, [ - $this->connection->reveal(), $this->requestHandler->reveal(), $this->serializer, false - ], ['connection', 'requestHandler', 'returnInt64AsObject']); + ], ['requestHandler', 'returnInt64AsObject']); } /** @@ -111,13 +105,6 @@ function ($val) { function ($val) { $this->assertEquals(15, $val); } - ], [ - ['timestampValue' => new Timestamp($this->createDateTimeFromSeconds($now), 10)], - function ($val) use ($now) { - $this->assertInstanceOf(Timestamp::class, $val); - $ts = new Timestamp(\DateTimeImmutable::createFromFormat('U', (string) $now), 10); - $this->assertEquals($ts, $val); - } ], [ ['geoPointValue' => ['latitude' => 100.01, 'longitude' => 500.5]], function ($val) { @@ -215,11 +202,6 @@ public function decodedValues() $blobValue = 'hello world'; $blob = new Blob($blobValue); - $datetime = \DateTimeImmutable::createFromFormat('U.u', (string) microtime(true)); - $timestamp = new Timestamp($datetime); - $now = (string) $datetime->format('U'); - $nanos = (int) $datetime->format('u') * 1000; - $lat = 100.01; $lng = 100.25; $geo = new GeoPoint($lat, $lng); @@ -322,22 +304,6 @@ function ($val) { function ($val) use ($blobValue) { $this->assertEquals($blobValue, $val['bytesValue']); } - ], [ - $datetime, - function ($val) use ($now, $nanos) { - $this->assertEquals([ - 'seconds' => $now, - 'nanos' => $nanos - ], $val['timestampValue']); - } - ], [ - $timestamp, - function ($val) use ($now, $nanos) { - $this->assertEquals([ - 'seconds' => $now, - 'nanos' => $nanos - ], $val['timestampValue']); - } ], [ $geo, function ($val) use ($lat, $lng) { diff --git a/Firestore/tests/Unit/WriteBatchTest.php b/Firestore/tests/Unit/WriteBatchTest.php deleted file mode 100644 index 6208a0ce86a..00000000000 --- a/Firestore/tests/Unit/WriteBatchTest.php +++ /dev/null @@ -1,574 +0,0 @@ -connection = $this->prophesize(ConnectionInterface::class); - $this->requestHandler = $this->prophesize(RequestHandler::class); - $this->serializer = $this->getSerializer(); - $this->batch = TestHelpers::stub(WriteBatch::class, [ - $this->connection->reveal(), - $this->requestHandler->reveal(), - $this->serializer, - new ValueMapper( - $this->connection->reveal(), - $this->requestHandler->reveal(), - $this->serializer, - false - ), - sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE) - ], ['connection', 'requestHandler', 'transaction']); - } - - /** - * @dataProvider documents - */ - public function testCreate($name, $ref) - { - $this->batch->create($ref, [ - 'hello' => 'world' - ]); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'currentDocument' => ['exists' => false], - 'update' => [ - 'name' => $name, - 'fields' => ['hello' => ['stringValue' => 'world']] - ] - ] - ] - ]); - } - - /** - * @dataProvider documents - */ - public function testUpdate($name, $ref) - { - $this->batch->update($ref, [ - [ - 'path' => 'hello.world', - 'value' => 'world' - ], [ - 'path' => new FieldPath(['hello', 'house']), - 'value' => 'house' - ] - ]); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'updateMask' => [ - 'fieldPaths' => [ - 'hello.house', - 'hello.world', - ] - ], - 'currentDocument' => ['exists' => true], - 'update' => [ - 'name' => $name, - 'fields' => [ - 'hello' => [ - 'mapValue' => [ - 'fields' => [ - 'world' => [ - 'stringValue' => 'world' - ], - 'house' => [ - 'stringValue' => 'house' - ] - ] - ] - ] - ] - ] - ] - ] - ]); - } - - /** - * @dataProvider updateBadInput - */ - public function testUpdateBadInput($data) - { - $this->expectException(InvalidArgumentException::class); - - $this->batch->update(self::DOCUMENT, $data); - } - - public function updateBadInput() - { - return [ - [['foo' => 'bar']], - [[['path' => 'foo']]], - [[['value' => 'bar']]], - [[[]]] - ]; - } - - /** - * @dataProvider documents - */ - public function testUpdateSentinels($name, $ref) - { - $this->batch->update($ref, [ - ['path' => 'foo', 'value' => 'bar'], - ['path' => 'hello', 'value' => FieldValue::deleteField()], - ['path' => 'world', 'value' => FieldValue::serverTimestamp()], - ['path' => 'arr', 'value' => FieldValue::arrayUnion(['a'])], - ['path' => 'arr2', 'value' => FieldValue::arrayRemove(['b'])], - ['path' => 'int', 'value' => FieldValue::increment(2)], - ]); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'updateMask' => ['fieldPaths' => ['foo', 'hello']], - 'currentDocument' => ['exists' => true], - 'update' => [ - 'name' => $name, - 'fields' => [ - 'foo' => ['stringValue' => 'bar'] - ] - ] - ], [ - 'transform' => [ - 'document' => $name, - 'fieldTransforms' => [ - [ - 'fieldPath' => 'world', - 'setToServerValue' => ServerValue::REQUEST_TIME - ], [ - 'fieldPath' => 'arr', - 'appendMissingElements' => [ - 'values' => [ - [ - 'stringValue' => 'a' - ] - ] - ] - ], [ - 'fieldPath' => 'arr2', - 'removeAllFromArray' => [ - 'values' => [ - [ - 'stringValue' => 'b' - ] - ] - ] - ], [ - 'fieldPath' => 'int', - 'increment' => [ - 'integerValue' => 2 - ] - ] - ] - ] - ] - ] - ]); - } - - /** - * @dataProvider noUpdateSentinels - */ - public function testSentinelsOmitUpdateWrite($val) - { - $ref = $this->prophesize(DocumentReference::class); - $ref->name()->willReturn(self::DOCUMENT); - - $this->batch->update($ref->reveal(), [ - ['path' => 'foo', 'value' => $val], - ]); - - $this->commitAndAssert(function ($arg) { - if (count($arg['writes']) > 1) { - return false; - } - - if (!isset($arg['writes'][0]['transform']['fieldTransforms'][0])) { - return false; - } - - return $arg['writes'][0]['transform']['fieldTransforms'][0]['fieldPath'] === 'foo'; - }); - } - - public function noUpdateSentinels() - { - return [ - [FieldValue::serverTimestamp()], - [FieldValue::arrayUnion([])], - [FieldValue::arrayRemove([])] - ]; - } - - /** - * @dataProvider documents - */ - public function testSet($name, $ref) - { - $this->batch->set($ref, [ - 'hello' => 'world' - ]); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'update' => [ - 'name' => $name, - 'fields' => ['hello' => ['stringValue' => 'world']] - ] - ] - ] - ]); - } - - /** - * @dataProvider documents - */ - public function testSetMerge($name, $ref) - { - $this->batch->set($ref, [ - 'hello' => 'world', - 'foobar' => ['foo' => 'bar'], - 'emptiness' => [] - ], ['merge' => true]); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'updateMask' => ['fieldPaths' => ['emptiness', 'foobar.foo', 'hello']], - 'update' => [ - 'name' => $name, - 'fields' => [ - 'hello' => ['stringValue' => 'world'], - 'foobar' => ['mapValue' => ['fields' => ['foo' => ['stringValue' => 'bar']]]], - 'emptiness' => ['arrayValue' => ['values' => []]] - ] - ] - ] - ] - ]); - } - - /** - * @dataProvider documents - */ - public function testSetSentinels($name, $ref) - { - $this->batch->set($ref, [ - 'world' => FieldValue::serverTimestamp(), - 'foo' => 'bar' - ]); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'update' => [ - 'name' => $name, - 'fields' => [ - 'foo' => [ - 'stringValue' => 'bar' - ] - ] - ] - ], [ - 'transform' => [ - 'document' => $name, - 'fieldTransforms' => [ - [ - 'fieldPath' => 'world', - 'setToServerValue' => ServerValue::REQUEST_TIME - ] - ] - ] - ] - ] - ]); - } - - public function testSentinelsInArray() - { - $this->expectException(InvalidArgumentException::class); - - $this->batch->set('name', [ - 'foo' => [ - FieldValue::serverTimestamp() - ] - ]); - } - - public function testSentinelsAfterArray() - { - $ret = $this->batch->set('name', [ - 'foo' => [ - 'a', 'b', 'c' - ], - 'bar' => FieldValue::serverTimestamp() - ]); - - $this->assertInstanceOf(\Google\Cloud\Firestore\BulkWriter::class, $ret); - } - - public function testSentinelsAfterArrayNested() - { - $ret = $this->batch->set('name', [ - 'foo' => [ - 'a' => [ - 'a', 'b', 'c', - ], - 'b' => FieldValue::serverTimestamp() - ] - ]); - - $this->assertInstanceOf(\Google\Cloud\Firestore\BulkWriter::class, $ret); - } - - public function testSentinelCannotContainSentinel() - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessageMatches('/Document transforms cannot contain/'); - $this->batch->set('name', [ - 'foo' => FieldValue::arrayRemove([FieldValue::arrayUnion([])]) - ]); - } - - /** - * @dataProvider documents - */ - public function testSetSentinelsDeleteRequiresMerge($name, $ref) - { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('Delete cannot appear in data unless `$options[\'merge\']` is set.'); - - $this->batch->set($ref, [ - 'hello' => FieldValue::deleteField(), - ]); - } - - /** - * @dataProvider documents - */ - public function testDelete($name, $ref) - { - $this->batch->delete($ref); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'delete' => $name - ] - ] - ]); - } - - /** - * @dataProvider documents - */ - public function testWriteUpdateTimePrecondition($name, $ref) - { - $ts = [ - 'seconds' => 10000, - 'nanos' => 5 - ]; - - $this->batch->delete($ref, [ - 'precondition' => [ - 'updateTime' => new Timestamp( - \DateTimeImmutable::createFromFormat('U', (string) $ts['seconds']), - $ts['nanos'] - ) - ] - ]); - - $this->commitAndAssert([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'writes' => [ - [ - 'delete' => $name, - 'currentDocument' => [ - 'updateTime' => $ts - ] - ] - ] - ]); - } - - public function documents() - { - $ref = $this->prophesize(DocumentReference::class); - $ref->name()->willReturn(self::DOCUMENT); - $doc = $ref->reveal(); - - return [ - [self::DOCUMENT, self::DOCUMENT], - [self::DOCUMENT, $doc] - ]; - } - - public function testWriteUpdateTimePreconditionInvalidType() - { - $this->expectException(InvalidArgumentException::class); - - $this->batch->delete(self::DOCUMENT, [ - 'precondition' => [ - 'updateTime' => 'foobar' - ] - ]); - } - - public function testWritePreconditionMissingStuff() - { - $this->expectException(InvalidArgumentException::class); - - $this->batch->delete(self::DOCUMENT, [ - 'precondition' => ['foo' => 'bar'] - ]); - } - - public function testCommitResponse() - { - $now = time(); - $nanos = 10; - - $timestamp = new Timestamp(\DateTimeImmutable::createFromFormat('U', (string) $now), $nanos); - - $this->connection->commit(Argument::any()) - ->shouldBeCalled() - ->willReturn([ - 'commitTime' => $timestamp, - 'writeResults' => [ - [ - 'updateTime' => $timestamp - ], [ - 'updateTime' => $timestamp - ] - ] - ]); - - $this->batch->___setProperty('connection', $this->connection->reveal()); - - $res = $this->batch->commit(); - - $this->assertEquals($timestamp, $res['commitTime']); - $this->assertEquals($timestamp, $res['writeResults'][0]['updateTime']); - $this->assertEquals($timestamp, $res['writeResults'][1]['updateTime']); - } - - public function testCommitWithTransaction() - { - $this->connection->commit(Argument::withEntry('transaction', self::TRANSACTION)) - ->shouldBeCalled(); - - $this->batch->___setProperty('connection', $this->connection->reveal()); - $this->batch->___setProperty('transaction', self::TRANSACTION); - - $this->batch->commit(); - } - - public function testRollback() - { - $this->connection->rollback([ - 'database' => sprintf('projects/%s/databases/%s', self::PROJECT, self::DATABASE), - 'transaction' => self::TRANSACTION - ])->shouldBeCalled(); - - $this->batch->___setProperty('connection', $this->connection->reveal()); - $this->batch->___setProperty('transaction', self::TRANSACTION); - - $this->batch->rollback(); - } - - public function testRollbackFailsWithoutTransaction() - { - $this->expectException(\RuntimeException::class); - - $this->batch->rollback(); - } - - public function testUpdateEmptyFails() - { - $this->expectException(InvalidArgumentException::class); - - $this->batch->update(self::DOCUMENT, []); - } - - private function commitAndAssert($assertion) - { - if (is_callable($assertion)) { - $this->connection->commit(Argument::that($assertion)) - ->shouldBeCalled(); - } elseif (is_array($assertion)) { - $this->connection->commit($assertion)->shouldBeCalled(); - } else { - throw new \Exception('bad assertion'); - } - - $this->batch->___setProperty('connection', $this->connection->reveal()); - - $this->batch->commit(); - } -} diff --git a/Firestore/tests/Unit/conformance/v1/create-all-transforms.json b/Firestore/tests/Unit/conformance/v1/create-all-transforms.json index 82831624bb1..23eb5131870 100644 --- a/Firestore/tests/Unit/conformance/v1/create-all-transforms.json +++ b/Firestore/tests/Unit/conformance/v1/create-all-transforms.json @@ -28,7 +28,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" }, { "fieldPath": "c", diff --git a/Firestore/tests/Unit/conformance/v1/create-st-alone.json b/Firestore/tests/Unit/conformance/v1/create-st-alone.json index 20c5e8ec32a..86397f6e13c 100644 --- a/Firestore/tests/Unit/conformance/v1/create-st-alone.json +++ b/Firestore/tests/Unit/conformance/v1/create-st-alone.json @@ -15,7 +15,7 @@ "fieldTransforms": [ { "fieldPath": "a", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] }, diff --git a/Firestore/tests/Unit/conformance/v1/create-st-multi.json b/Firestore/tests/Unit/conformance/v1/create-st-multi.json index 89430e2b64d..cb2bef7aabf 100644 --- a/Firestore/tests/Unit/conformance/v1/create-st-multi.json +++ b/Firestore/tests/Unit/conformance/v1/create-st-multi.json @@ -28,11 +28,11 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" }, { "fieldPath": "c.d", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/create-st-nested.json b/Firestore/tests/Unit/conformance/v1/create-st-nested.json index f2a3a8d1f62..32e7e8da0ea 100644 --- a/Firestore/tests/Unit/conformance/v1/create-st-nested.json +++ b/Firestore/tests/Unit/conformance/v1/create-st-nested.json @@ -28,7 +28,7 @@ "fieldTransforms": [ { "fieldPath": "b.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/create-st-with-empty-map.json b/Firestore/tests/Unit/conformance/v1/create-st-with-empty-map.json index 730afd154fd..4a88a7943f8 100644 --- a/Firestore/tests/Unit/conformance/v1/create-st-with-empty-map.json +++ b/Firestore/tests/Unit/conformance/v1/create-st-with-empty-map.json @@ -36,7 +36,7 @@ "fieldTransforms": [ { "fieldPath": "a.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/create-st.json b/Firestore/tests/Unit/conformance/v1/create-st.json index 705f76ed16a..7ebec022e9c 100644 --- a/Firestore/tests/Unit/conformance/v1/create-st.json +++ b/Firestore/tests/Unit/conformance/v1/create-st.json @@ -28,7 +28,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/delete-time-precond.json b/Firestore/tests/Unit/conformance/v1/delete-time-precond.json index 160defb3fed..42006cf38ac 100644 --- a/Firestore/tests/Unit/conformance/v1/delete-time-precond.json +++ b/Firestore/tests/Unit/conformance/v1/delete-time-precond.json @@ -6,7 +6,7 @@ "delete": { "docRefPath": "projects/projectID/databases/(default)/documents/C/d", "precondition": { - "updateTime": "1970-01-01T00:00:42Z" + "updateTime": {"seconds": "42", "nanos": "0"} }, "request": { "database": "projects/projectID/databases/(default)", @@ -14,7 +14,7 @@ { "delete": "projects/projectID/databases/(default)/documents/C/d", "currentDocument": { - "updateTime": "1970-01-01T00:00:42Z" + "updateTime": {"seconds": "42", "nanos": "0"} } } ] diff --git a/Firestore/tests/Unit/conformance/v1/query-offset-limit-last-wins.json b/Firestore/tests/Unit/conformance/v1/query-offset-limit-last-wins.json index 8788826081e..24710ed6cf9 100644 --- a/Firestore/tests/Unit/conformance/v1/query-offset-limit-last-wins.json +++ b/Firestore/tests/Unit/conformance/v1/query-offset-limit-last-wins.json @@ -26,7 +26,7 @@ } ], "offset": 5, - "limit": 4 + "limit": {"value": 4} } } } diff --git a/Firestore/tests/Unit/conformance/v1/query-offset-limit.json b/Firestore/tests/Unit/conformance/v1/query-offset-limit.json index 3429dce0e89..c88ce22ea29 100644 --- a/Firestore/tests/Unit/conformance/v1/query-offset-limit.json +++ b/Firestore/tests/Unit/conformance/v1/query-offset-limit.json @@ -20,7 +20,7 @@ } ], "offset": 2, - "limit": 3 + "limit": {"value": 3} } } } diff --git a/Firestore/tests/Unit/conformance/v1/set-all-transforms.json b/Firestore/tests/Unit/conformance/v1/set-all-transforms.json index 5c8b1373d4c..f24f9b1c268 100644 --- a/Firestore/tests/Unit/conformance/v1/set-all-transforms.json +++ b/Firestore/tests/Unit/conformance/v1/set-all-transforms.json @@ -25,7 +25,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" }, { "fieldPath": "c", diff --git a/Firestore/tests/Unit/conformance/v1/set-st-alone-mergeall.json b/Firestore/tests/Unit/conformance/v1/set-st-alone-mergeall.json index d95bf0973b7..f514ee35228 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-alone-mergeall.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-alone-mergeall.json @@ -18,7 +18,7 @@ "fieldTransforms": [ { "fieldPath": "a", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-alone.json b/Firestore/tests/Unit/conformance/v1/set-st-alone.json index 3fe931394b0..484b2245172 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-alone.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-alone.json @@ -21,7 +21,7 @@ "fieldTransforms": [ { "fieldPath": "a", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-merge-both.json b/Firestore/tests/Unit/conformance/v1/set-st-merge-both.json index a39ada55f73..2d5b7da2a14 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-merge-both.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-merge-both.json @@ -44,7 +44,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf-alone.json b/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf-alone.json index 4193b00ea68..98ca78047e6 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf-alone.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf-alone.json @@ -34,7 +34,7 @@ "fieldTransforms": [ { "fieldPath": "h.g", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf.json b/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf.json index 5e91d663b8c..ffb279c440a 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-merge-nonleaf.json @@ -45,7 +45,7 @@ "fieldTransforms": [ { "fieldPath": "h.g", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-merge-nowrite.json b/Firestore/tests/Unit/conformance/v1/set-st-merge-nowrite.json index 08fa8b52f54..36f87ad0d8d 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-merge-nowrite.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-merge-nowrite.json @@ -24,7 +24,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-mergeall.json b/Firestore/tests/Unit/conformance/v1/set-st-mergeall.json index 26883c03820..324b3912a1b 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-mergeall.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-mergeall.json @@ -33,7 +33,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-multi.json b/Firestore/tests/Unit/conformance/v1/set-st-multi.json index 23c06f4976f..52761246fe9 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-multi.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-multi.json @@ -25,11 +25,11 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" }, { "fieldPath": "c.d", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-nested.json b/Firestore/tests/Unit/conformance/v1/set-st-nested.json index 5c94c33f943..267c9845748 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-nested.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-nested.json @@ -25,7 +25,7 @@ "fieldTransforms": [ { "fieldPath": "b.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st-with-empty-map.json b/Firestore/tests/Unit/conformance/v1/set-st-with-empty-map.json index 063c94a0e6c..7173e65863f 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st-with-empty-map.json +++ b/Firestore/tests/Unit/conformance/v1/set-st-with-empty-map.json @@ -33,7 +33,7 @@ "fieldTransforms": [ { "fieldPath": "a.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/set-st.json b/Firestore/tests/Unit/conformance/v1/set-st.json index 42f2b14f1c7..9f7d1959aad 100644 --- a/Firestore/tests/Unit/conformance/v1/set-st.json +++ b/Firestore/tests/Unit/conformance/v1/set-st.json @@ -25,7 +25,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-all-transforms.json b/Firestore/tests/Unit/conformance/v1/update-all-transforms.json index 6f6a725df0f..079051dba2d 100644 --- a/Firestore/tests/Unit/conformance/v1/update-all-transforms.json +++ b/Firestore/tests/Unit/conformance/v1/update-all-transforms.json @@ -33,7 +33,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" }, { "fieldPath": "c", diff --git a/Firestore/tests/Unit/conformance/v1/update-nested-transform-and-nested-value.json b/Firestore/tests/Unit/conformance/v1/update-nested-transform-and-nested-value.json index ff7bfc6ee94..04538ed09b7 100644 --- a/Firestore/tests/Unit/conformance/v1/update-nested-transform-and-nested-value.json +++ b/Firestore/tests/Unit/conformance/v1/update-nested-transform-and-nested-value.json @@ -39,7 +39,7 @@ "fieldTransforms": [ { "fieldPath": "a.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-all-transforms.json b/Firestore/tests/Unit/conformance/v1/update-paths-all-transforms.json index 01a4c1143dc..0463734de00 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-all-transforms.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-all-transforms.json @@ -60,7 +60,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" }, { "fieldPath": "c", diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-nested-transform-and-nested-value.json b/Firestore/tests/Unit/conformance/v1/update-paths-nested-transform-and-nested-value.json index 927d783aee4..deb9a549865 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-nested-transform-and-nested-value.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-nested-transform-and-nested-value.json @@ -56,7 +56,7 @@ "fieldTransforms": [ { "fieldPath": "a.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-st-alone.json b/Firestore/tests/Unit/conformance/v1/update-paths-st-alone.json index 085d0498771..c0535bc6b78 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-st-alone.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-st-alone.json @@ -24,7 +24,7 @@ "fieldTransforms": [ { "fieldPath": "a", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] }, diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-st-multi.json b/Firestore/tests/Unit/conformance/v1/update-paths-st-multi.json index 2d813801ac3..0b6deef1966 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-st-multi.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-st-multi.json @@ -55,11 +55,11 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" }, { "fieldPath": "c.d", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-st-nested.json b/Firestore/tests/Unit/conformance/v1/update-paths-st-nested.json index 8bd35c9111b..6a99f21d9d7 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-st-nested.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-st-nested.json @@ -49,7 +49,7 @@ "fieldTransforms": [ { "fieldPath": "b.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-st-with-empty-map.json b/Firestore/tests/Unit/conformance/v1/update-paths-st-with-empty-map.json index ac60b2771d3..188678c7b2e 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-st-with-empty-map.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-st-with-empty-map.json @@ -50,7 +50,7 @@ "fieldTransforms": [ { "fieldPath": "a.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-st.json b/Firestore/tests/Unit/conformance/v1/update-paths-st.json index 011405b9bf7..9cc9a91bce1 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-st.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-st.json @@ -48,7 +48,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-paths-uptime.json b/Firestore/tests/Unit/conformance/v1/update-paths-uptime.json index 96801a0cd8e..0774af8dd68 100644 --- a/Firestore/tests/Unit/conformance/v1/update-paths-uptime.json +++ b/Firestore/tests/Unit/conformance/v1/update-paths-uptime.json @@ -6,7 +6,7 @@ "updatePaths": { "docRefPath": "projects/projectID/databases/(default)/documents/C/d", "precondition": { - "updateTime": "1970-01-01T00:00:42Z" + "updateTime": {"seconds": "42", "nanos": "0"} }, "fieldPaths": [ { @@ -36,7 +36,7 @@ ] }, "currentDocument": { - "updateTime": "1970-01-01T00:00:42Z" + "updateTime": {"seconds": "42", "nanos": "0"} } } ] diff --git a/Firestore/tests/Unit/conformance/v1/update-st-dot.json b/Firestore/tests/Unit/conformance/v1/update-st-dot.json index 83422ca5271..5357a10bd58 100644 --- a/Firestore/tests/Unit/conformance/v1/update-st-dot.json +++ b/Firestore/tests/Unit/conformance/v1/update-st-dot.json @@ -15,7 +15,7 @@ "fieldTransforms": [ { "fieldPath": "a.b.c", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] }, diff --git a/Firestore/tests/Unit/conformance/v1/update-st-multi.json b/Firestore/tests/Unit/conformance/v1/update-st-multi.json index 8105ec27f54..15937cfcd9a 100644 --- a/Firestore/tests/Unit/conformance/v1/update-st-multi.json +++ b/Firestore/tests/Unit/conformance/v1/update-st-multi.json @@ -38,7 +38,7 @@ }, { "fieldPath": "c.d", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-st.json b/Firestore/tests/Unit/conformance/v1/update-st.json index 6249d8bda90..08e4e347b54 100644 --- a/Firestore/tests/Unit/conformance/v1/update-st.json +++ b/Firestore/tests/Unit/conformance/v1/update-st.json @@ -33,7 +33,7 @@ "fieldTransforms": [ { "fieldPath": "b", - "setToServerValue": "REQUEST_TIME" + "setToServerValue": "1" } ] } diff --git a/Firestore/tests/Unit/conformance/v1/update-uptime.json b/Firestore/tests/Unit/conformance/v1/update-uptime.json index 9210a2cf032..064d7e3f6f1 100644 --- a/Firestore/tests/Unit/conformance/v1/update-uptime.json +++ b/Firestore/tests/Unit/conformance/v1/update-uptime.json @@ -6,7 +6,7 @@ "update": { "docRefPath": "projects/projectID/databases/(default)/documents/C/d", "precondition": { - "updateTime": "1970-01-01T00:00:42Z" + "updateTime": {"seconds": "42", "nanos": "0"} }, "jsonData": "{\"a\": 1}", "request": { @@ -27,7 +27,7 @@ ] }, "currentDocument": { - "updateTime": "1970-01-01T00:00:42Z" + "updateTime": {"seconds": "42", "nanos": "0"} } } ] From 6f6f5dbd6729cb1faee5abc62b34c89bc103a83b Mon Sep 17 00:00:00 2001 From: Yash Sahu <54198301+yash30201@users.noreply.github.com> Date: Thu, 13 Jun 2024 15:57:59 +0530 Subject: [PATCH 3/3] feat(Firestore): Upgrade Firestore to V2 part 3 (#7418) - Update Migration guide - Update documentation - Remove class aliases --- Firestore/MIGRATION.md | 127 +++++++++++++++++- Firestore/src/Admin/V1/Backup/State.php | 4 - Firestore/src/Admin/V1/Backup/Stats.php | 4 - .../V1/Database/AppEngineIntegrationMode.php | 4 - .../src/Admin/V1/Database/ConcurrencyMode.php | 4 - .../src/Admin/V1/Database/DatabaseType.php | 4 - .../V1/Database/DeleteProtectionState.php | 4 - .../PointInTimeRecoveryEnablement.php | 4 - .../V1/Database_AppEngineIntegrationMode.php | 16 --- .../src/Admin/V1/Database_ConcurrencyMode.php | 16 --- .../src/Admin/V1/Database_DatabaseType.php | 16 --- Firestore/src/Admin/V1/Field/IndexConfig.php | 4 - Firestore/src/Admin/V1/Field/TtlConfig.php | 4 - .../src/Admin/V1/Field/TtlConfig/State.php | 4 - .../IndexConfigDelta.php | 4 - .../IndexConfigDelta/ChangeType.php | 4 - .../FieldOperationMetadata/TtlConfigDelta.php | 4 - .../TtlConfigDelta/ChangeType.php | 4 - ...ieldOperationMetadata_IndexConfigDelta.php | 16 --- ...onMetadata_IndexConfigDelta_ChangeType.php | 16 --- .../FieldOperationMetadata_TtlConfigDelta.php | 16 --- ...tionMetadata_TtlConfigDelta_ChangeType.php | 16 --- Firestore/src/Admin/V1/Field_IndexConfig.php | 16 --- Firestore/src/Admin/V1/Field_TtlConfig.php | 16 --- .../src/Admin/V1/Field_TtlConfig_State.php | 16 --- Firestore/src/Admin/V1/Index/ApiScope.php | 4 - Firestore/src/Admin/V1/Index/IndexField.php | 4 - .../Admin/V1/Index/IndexField/ArrayConfig.php | 4 - .../src/Admin/V1/Index/IndexField/Order.php | 4 - .../V1/Index/IndexField/VectorConfig.php | 4 - .../IndexField/VectorConfig/FlatIndex.php | 4 - Firestore/src/Admin/V1/Index/QueryScope.php | 4 - Firestore/src/Admin/V1/Index/State.php | 4 - Firestore/src/Admin/V1/Index_ApiScope.php | 16 --- Firestore/src/Admin/V1/Index_IndexField.php | 16 --- .../Admin/V1/Index_IndexField_ArrayConfig.php | 16 --- .../src/Admin/V1/Index_IndexField_Order.php | 16 --- Firestore/src/Admin/V1/Index_QueryScope.php | 16 --- Firestore/src/Admin/V1/Index_State.php | 16 --- Firestore/src/BulkWriter.php | 2 +- Firestore/src/DocumentReference.php | 5 +- Firestore/src/FirestoreClient.php | 59 ++++---- Firestore/src/SnapshotTrait.php | 2 +- .../V1/DocumentTransform/FieldTransform.php | 4 - .../FieldTransform/ServerValue.php | 4 - .../V1/DocumentTransform_FieldTransform.php | 16 --- ...ntTransform_FieldTransform_ServerValue.php | 16 --- .../Aggregation.php | 4 - .../Aggregation/Avg.php | 4 - .../Aggregation/Count.php | 4 - .../Aggregation/Sum.php | 4 - ...StructuredAggregationQuery_Aggregation.php | 16 --- ...uredAggregationQuery_Aggregation_Count.php | 16 --- .../V1/StructuredQuery/CollectionSelector.php | 4 - .../V1/StructuredQuery/CompositeFilter.php | 4 - .../CompositeFilter/Operator.php | 4 - .../src/V1/StructuredQuery/Direction.php | 4 - .../src/V1/StructuredQuery/FieldFilter.php | 4 - .../StructuredQuery/FieldFilter/Operator.php | 4 - .../src/V1/StructuredQuery/FieldReference.php | 4 - Firestore/src/V1/StructuredQuery/Filter.php | 4 - .../src/V1/StructuredQuery/FindNearest.php | 4 - .../FindNearest/DistanceMeasure.php | 4 - Firestore/src/V1/StructuredQuery/Order.php | 4 - .../src/V1/StructuredQuery/Projection.php | 4 - .../src/V1/StructuredQuery/UnaryFilter.php | 4 - .../StructuredQuery/UnaryFilter/Operator.php | 4 - .../V1/StructuredQuery_CollectionSelector.php | 16 --- .../V1/StructuredQuery_CompositeFilter.php | 16 --- ...ructuredQuery_CompositeFilter_Operator.php | 16 --- .../src/V1/StructuredQuery_Direction.php | 16 --- .../src/V1/StructuredQuery_FieldFilter.php | 16 --- .../StructuredQuery_FieldFilter_Operator.php | 16 --- .../src/V1/StructuredQuery_FieldReference.php | 16 --- Firestore/src/V1/StructuredQuery_Filter.php | 16 --- Firestore/src/V1/StructuredQuery_Order.php | 16 --- .../src/V1/StructuredQuery_Projection.php | 16 --- .../src/V1/StructuredQuery_UnaryFilter.php | 16 --- .../StructuredQuery_UnaryFilter_Operator.php | 16 --- Firestore/src/V1/Target/DocumentsTarget.php | 4 - Firestore/src/V1/Target/QueryTarget.php | 4 - .../src/V1/TargetChange/TargetChangeType.php | 4 - .../src/V1/TargetChange_TargetChangeType.php | 16 --- Firestore/src/V1/Target_DocumentsTarget.php | 16 --- Firestore/src/V1/Target_QueryTarget.php | 16 --- .../src/V1/TransactionOptions/PBReadOnly.php | 5 - .../src/V1/TransactionOptions/ReadWrite.php | 4 - .../src/V1/TransactionOptions_ReadOnly.php | 16 --- .../src/V1/TransactionOptions_ReadWrite.php | 16 --- .../DocumentTransform/FieldTransform.php | 4 - .../FieldTransform/ServerValue.php | 4 - .../DocumentTransform_FieldTransform.php | 16 --- ...ntTransform_FieldTransform_ServerValue.php | 16 --- .../StructuredQuery/CollectionSelector.php | 4 - .../StructuredQuery/CompositeFilter.php | 4 - .../CompositeFilter/Operator.php | 4 - .../src/V1beta1/StructuredQuery/Direction.php | 4 - .../V1beta1/StructuredQuery/FieldFilter.php | 4 - .../StructuredQuery/FieldFilter/Operator.php | 4 - .../StructuredQuery/FieldReference.php | 4 - .../src/V1beta1/StructuredQuery/Filter.php | 4 - .../src/V1beta1/StructuredQuery/Order.php | 4 - .../V1beta1/StructuredQuery/Projection.php | 4 - .../V1beta1/StructuredQuery/UnaryFilter.php | 4 - .../StructuredQuery/UnaryFilter/Operator.php | 4 - .../StructuredQuery_CollectionSelector.php | 16 --- .../StructuredQuery_CompositeFilter.php | 16 --- ...ructuredQuery_CompositeFilter_Operator.php | 16 --- .../src/V1beta1/StructuredQuery_Direction.php | 16 --- .../V1beta1/StructuredQuery_FieldFilter.php | 16 --- .../StructuredQuery_FieldFilter_Operator.php | 16 --- .../StructuredQuery_FieldReference.php | 16 --- .../src/V1beta1/StructuredQuery_Filter.php | 16 --- .../src/V1beta1/StructuredQuery_Order.php | 16 --- .../V1beta1/StructuredQuery_Projection.php | 16 --- .../V1beta1/StructuredQuery_UnaryFilter.php | 16 --- .../StructuredQuery_UnaryFilter_Operator.php | 16 --- .../src/V1beta1/Target/DocumentsTarget.php | 4 - Firestore/src/V1beta1/Target/QueryTarget.php | 4 - .../V1beta1/TargetChange/TargetChangeType.php | 4 - .../V1beta1/TargetChange_TargetChangeType.php | 16 --- .../src/V1beta1/Target_DocumentsTarget.php | 16 --- Firestore/src/V1beta1/Target_QueryTarget.php | 16 --- .../V1beta1/TransactionOptions/PBReadOnly.php | 5 - .../V1beta1/TransactionOptions/ReadWrite.php | 4 - .../V1beta1/TransactionOptions_ReadOnly.php | 16 --- .../V1beta1/TransactionOptions_ReadWrite.php | 16 --- Firestore/src/ValueMapper.php | 10 +- Firestore/src/WriteBatch.php | 49 ------- .../tests/Snippet/DocumentReferenceTest.php | 4 +- .../tests/Snippet/FirestoreClientTest.php | 4 +- Firestore/tests/Snippet/TransactionTest.php | 9 +- Firestore/tests/Unit/FirestoreClientTest.php | 4 +- 133 files changed, 178 insertions(+), 1259 deletions(-) delete mode 100644 Firestore/src/Admin/V1/Database_AppEngineIntegrationMode.php delete mode 100644 Firestore/src/Admin/V1/Database_ConcurrencyMode.php delete mode 100644 Firestore/src/Admin/V1/Database_DatabaseType.php delete mode 100644 Firestore/src/Admin/V1/FieldOperationMetadata_IndexConfigDelta.php delete mode 100644 Firestore/src/Admin/V1/FieldOperationMetadata_IndexConfigDelta_ChangeType.php delete mode 100644 Firestore/src/Admin/V1/FieldOperationMetadata_TtlConfigDelta.php delete mode 100644 Firestore/src/Admin/V1/FieldOperationMetadata_TtlConfigDelta_ChangeType.php delete mode 100644 Firestore/src/Admin/V1/Field_IndexConfig.php delete mode 100644 Firestore/src/Admin/V1/Field_TtlConfig.php delete mode 100644 Firestore/src/Admin/V1/Field_TtlConfig_State.php delete mode 100644 Firestore/src/Admin/V1/Index_ApiScope.php delete mode 100644 Firestore/src/Admin/V1/Index_IndexField.php delete mode 100644 Firestore/src/Admin/V1/Index_IndexField_ArrayConfig.php delete mode 100644 Firestore/src/Admin/V1/Index_IndexField_Order.php delete mode 100644 Firestore/src/Admin/V1/Index_QueryScope.php delete mode 100644 Firestore/src/Admin/V1/Index_State.php delete mode 100644 Firestore/src/V1/DocumentTransform_FieldTransform.php delete mode 100644 Firestore/src/V1/DocumentTransform_FieldTransform_ServerValue.php delete mode 100644 Firestore/src/V1/StructuredAggregationQuery_Aggregation.php delete mode 100644 Firestore/src/V1/StructuredAggregationQuery_Aggregation_Count.php delete mode 100644 Firestore/src/V1/StructuredQuery_CollectionSelector.php delete mode 100644 Firestore/src/V1/StructuredQuery_CompositeFilter.php delete mode 100644 Firestore/src/V1/StructuredQuery_CompositeFilter_Operator.php delete mode 100644 Firestore/src/V1/StructuredQuery_Direction.php delete mode 100644 Firestore/src/V1/StructuredQuery_FieldFilter.php delete mode 100644 Firestore/src/V1/StructuredQuery_FieldFilter_Operator.php delete mode 100644 Firestore/src/V1/StructuredQuery_FieldReference.php delete mode 100644 Firestore/src/V1/StructuredQuery_Filter.php delete mode 100644 Firestore/src/V1/StructuredQuery_Order.php delete mode 100644 Firestore/src/V1/StructuredQuery_Projection.php delete mode 100644 Firestore/src/V1/StructuredQuery_UnaryFilter.php delete mode 100644 Firestore/src/V1/StructuredQuery_UnaryFilter_Operator.php delete mode 100644 Firestore/src/V1/TargetChange_TargetChangeType.php delete mode 100644 Firestore/src/V1/Target_DocumentsTarget.php delete mode 100644 Firestore/src/V1/Target_QueryTarget.php delete mode 100644 Firestore/src/V1/TransactionOptions_ReadOnly.php delete mode 100644 Firestore/src/V1/TransactionOptions_ReadWrite.php delete mode 100644 Firestore/src/V1beta1/DocumentTransform_FieldTransform.php delete mode 100644 Firestore/src/V1beta1/DocumentTransform_FieldTransform_ServerValue.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_CollectionSelector.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_CompositeFilter.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_CompositeFilter_Operator.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_Direction.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_FieldFilter.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_FieldFilter_Operator.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_FieldReference.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_Filter.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_Order.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_Projection.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_UnaryFilter.php delete mode 100644 Firestore/src/V1beta1/StructuredQuery_UnaryFilter_Operator.php delete mode 100644 Firestore/src/V1beta1/TargetChange_TargetChangeType.php delete mode 100644 Firestore/src/V1beta1/Target_DocumentsTarget.php delete mode 100644 Firestore/src/V1beta1/Target_QueryTarget.php delete mode 100644 Firestore/src/V1beta1/TransactionOptions_ReadOnly.php delete mode 100644 Firestore/src/V1beta1/TransactionOptions_ReadWrite.php delete mode 100644 Firestore/src/WriteBatch.php diff --git a/Firestore/MIGRATION.md b/Firestore/MIGRATION.md index 7fa9730334a..2eb30866ea4 100644 --- a/Firestore/MIGRATION.md +++ b/Firestore/MIGRATION.md @@ -1,5 +1,89 @@ # Migration Guide for V2 library +## How to upgrade + +Update your `google/cloud-firestore` dependency to `^2.0`: + +``` +{ + "require": { + "google/cloud-firestore": "^2.0" + } +} +``` + +## Changes + +### Client Options changes + +The following client options are removed/replaced with other options present in +[`ClientOptions`][ClientOptions]. This was done to ensure client options are consistent across all +Google Cloud clients. + +- `authCache` -> Moved to `credentialsConfig.authCache` +- `authCacheOptions` -> Moved to `credentialsConfig.authCacheOptions` +- `credentialsFetcher` -> Moved to `credentials` +- `keyFile` -> Moved to `credentials` +- `keyFilePath` -> Moved to `credentials` +- `requestTimeout` -> Removed from client options and moved to a call option `timeoutMillis` +- `scopes` -> Moved to `credentialsConfig.scopes` +- `defaultScopes` -> Moved to `credentialsConfig.defaultScopes` +- `quotaProject` -> Moved to `credentialsConfig.quotaProject` +- `httpHandler` -> Moved to `transportConfig.rest.httpHandler` +- `authHttpHandler` -> Moved to `credentialsConfig.authHttpHandler` +- `asyncHttpHandler` -> Removed in favour of a single httpHandler option. +- `restOptions` -> Moved to `transportConfig.rest` +- `grpcOptions` -> Moved to `transportConfig.grpc` +- `accessToken` -> Removed +- `shouldSignRequest` -> Removed +- `preferNumericProjectId` -> Removed + +### Retry Options changes + +The retry options have been moved to use [`RetrySettings`][RetrySettings] in Client Options and in +call options. + +- `retries` -> Renamed to `retrySettings.maxRetries` +- `restRetryFunction` -> Renamed to `retrySettings.retryFunction` +- `grpcRetryFunction` -> Renamed to `retrySettings.retryFunction` +- `delayFunc`/`calcDelayFunction` -> Removed in favor of the properties + `retrySettings.initialRetryDelayMillis`, `retrySettings.retryDelayMultiplier` and + `retrySettings.maxRetryDelayMillis`. + +[RetrySettings]: https://googleapis.github.io/gax-php/v1.26.1/Google/ApiCore/RetrySettings.html + +[ClientOptions]: https://googleapis.github.io/gax-php/v1.26.1/Google/ApiCore/Options/ClientOptions.html + +### Connection classes are not used anymore. + +This is a major change with this major version but one that we hope won't break most users. When one +created a `FirestoreClient`, behind the scenes a connection adapter was initialized based on your +transport preferences and then forwarded to resource classes internally. This connection adapter was used +to deliver requests internally: + +```php +use Google\Cloud\Firestore\FirestoreClient; + +// This initialized a connection object and passed it internally to resource classes. +$client = new FirestoreClient(); +// This used the connection object internally to deliver the `batchGetDocuments` request. +$docRef = $client->document('DOCUMENT_NAME'); +$docSnapshot = $docRef->snapshot(); +``` + +As you can see the connection object was handled internally. If you used the library in this way, +you will not need to make any changes. However, if you created the connection classes directly +and passed it to a Resource class, this will break in Firestore `v2`: + +```php +// Not intended +$connObj = new Grpc([]); +$docRef = new DocumentReference( + $connObj, + // other operation options +); +$docRef->snapshot(); +``` ## Timestamp @@ -10,17 +94,55 @@ Earlier usage: ```php use Google\Cloud\Code\Timestamp; +// Create a current timestamp $timestamp = new Timestamp(new \DateTime()); + +// Create a timestamp from a timestamp string +$timestamp = new Timestamp(new \DateTime('2003-02-05 11:15:02.421827Z')); + +// Create a timestamp with nanoseconds precision as seconds argument +$timestamp = new Timestamp(new \DateTime('2003-02-05 11:15:02.421827Z'), 100); ``` -Current usage: +New timestamp usages: ```php use Google\Protobuf\Timestamp; +// Create a current timestamp + +// Method 1 $timestamp = new Timestamp(); $timestamp->fromDateTime(new \DateTime()); + +// Method 2 +$timestamp = new Timestamp(['seconds' => time()]); + +// Create a timestamp from a timestamp string +$timestamp = new Timestamp(); +$timestamp->fromDateTime(new \DateTime('2003-02-05 11:15:02.421827Z')); + +// Create a timestamp with from timestamp string with nanoseconds +$timestamp = new Timestamp(); +$timestamp->fromDateTime(new \DateTime('2003-02-05 11:15:02.421827Z')); +$timestamp->setNanos(100); + +// Create a current from seconds since epoch and nanos directly + +// Method 1 +$secondsSinceEpoch = time(); +$timestamp = new Timestamp([ + 'seconds' => $secondsSinceEpoch, + 'nanos' => 100 +]) + +// Method 2 +$secondsSinceEpoch = time(); +$timestamp = (new Timestamp()) + ->setSeconds($secondsSinceEpoch) + ->setNanos(100); ``` + ## ListCollectionIds ListCollectionIds rpc is exposed via `DocumentReference::collections()` and `FirestoreClient::collections()` methods. @@ -39,5 +161,6 @@ RunQuery RPC is exposed via `CollectionReference::documents()` and `Transaction: when `readTime` was invalid. Now we've removed this client level check and exception is thrown by the Serializer when it converts the array data into Protobuf Request object. +# WriteBatch class - +This class has been removed as it was already deprecated. Users should use the bulkwriter feature instead. diff --git a/Firestore/src/Admin/V1/Backup/State.php b/Firestore/src/Admin/V1/Backup/State.php index b868abc3699..bbe0c27c4aa 100644 --- a/Firestore/src/Admin/V1/Backup/State.php +++ b/Firestore/src/Admin/V1/Backup/State.php @@ -66,7 +66,3 @@ public static function value($name) return constant($const); } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(State::class, \Google\Cloud\Firestore\Admin\V1\Backup_State::class); - diff --git a/Firestore/src/Admin/V1/Backup/Stats.php b/Firestore/src/Admin/V1/Backup/Stats.php index 4132e9fbd38..9544a47f263 100644 --- a/Firestore/src/Admin/V1/Backup/Stats.php +++ b/Firestore/src/Admin/V1/Backup/Stats.php @@ -136,7 +136,3 @@ public function setIndexCount($var) } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(Stats::class, \Google\Cloud\Firestore\Admin\V1\Backup_Stats::class); - diff --git a/Firestore/src/Admin/V1/Database/AppEngineIntegrationMode.php b/Firestore/src/Admin/V1/Database/AppEngineIntegrationMode.php index 2a871f5971f..a2009947836 100644 --- a/Firestore/src/Admin/V1/Database/AppEngineIntegrationMode.php +++ b/Firestore/src/Admin/V1/Database/AppEngineIntegrationMode.php @@ -63,7 +63,3 @@ public static function value($name) return constant($const); } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(AppEngineIntegrationMode::class, \Google\Cloud\Firestore\Admin\V1\Database_AppEngineIntegrationMode::class); - diff --git a/Firestore/src/Admin/V1/Database/ConcurrencyMode.php b/Firestore/src/Admin/V1/Database/ConcurrencyMode.php index 2e88fde688f..0721d940dfa 100644 --- a/Firestore/src/Admin/V1/Database/ConcurrencyMode.php +++ b/Firestore/src/Admin/V1/Database/ConcurrencyMode.php @@ -71,7 +71,3 @@ public static function value($name) return constant($const); } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(ConcurrencyMode::class, \Google\Cloud\Firestore\Admin\V1\Database_ConcurrencyMode::class); - diff --git a/Firestore/src/Admin/V1/Database/DatabaseType.php b/Firestore/src/Admin/V1/Database/DatabaseType.php index 18bfd4d8e66..5d002b67d3d 100644 --- a/Firestore/src/Admin/V1/Database/DatabaseType.php +++ b/Firestore/src/Admin/V1/Database/DatabaseType.php @@ -61,7 +61,3 @@ public static function value($name) return constant($const); } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(DatabaseType::class, \Google\Cloud\Firestore\Admin\V1\Database_DatabaseType::class); - diff --git a/Firestore/src/Admin/V1/Database/DeleteProtectionState.php b/Firestore/src/Admin/V1/Database/DeleteProtectionState.php index 34ade3e2333..409c97809a6 100644 --- a/Firestore/src/Admin/V1/Database/DeleteProtectionState.php +++ b/Firestore/src/Admin/V1/Database/DeleteProtectionState.php @@ -58,7 +58,3 @@ public static function value($name) return constant($const); } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(DeleteProtectionState::class, \Google\Cloud\Firestore\Admin\V1\Database_DeleteProtectionState::class); - diff --git a/Firestore/src/Admin/V1/Database/PointInTimeRecoveryEnablement.php b/Firestore/src/Admin/V1/Database/PointInTimeRecoveryEnablement.php index 14a69b79b17..33a09c6958d 100644 --- a/Firestore/src/Admin/V1/Database/PointInTimeRecoveryEnablement.php +++ b/Firestore/src/Admin/V1/Database/PointInTimeRecoveryEnablement.php @@ -64,7 +64,3 @@ public static function value($name) return constant($const); } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(PointInTimeRecoveryEnablement::class, \Google\Cloud\Firestore\Admin\V1\Database_PointInTimeRecoveryEnablement::class); - diff --git a/Firestore/src/Admin/V1/Database_AppEngineIntegrationMode.php b/Firestore/src/Admin/V1/Database_AppEngineIntegrationMode.php deleted file mode 100644 index 8edb982a880..00000000000 --- a/Firestore/src/Admin/V1/Database_AppEngineIntegrationMode.php +++ /dev/null @@ -1,16 +0,0 @@ -requestHandler, $this->serializer, diff --git a/Firestore/src/FirestoreClient.php b/Firestore/src/FirestoreClient.php index 88b3eac46e0..228c7f323bd 100644 --- a/Firestore/src/FirestoreClient.php +++ b/Firestore/src/FirestoreClient.php @@ -129,25 +129,40 @@ class FirestoreClient * @type string $projectId The project ID from the Google Developer's * Console. * @type string $database The database name to use, if different from - the default. - * @type CacheItemPoolInterface $authCache A cache for storing access - * tokens. **Defaults to** a simple in memory implementation. - * @type array $authCacheOptions Cache configuration options. - * @type callable $authHttpHandler A handler used to deliver Psr7 - * requests specifically for authentication. - * @type callable $httpHandler A handler used to deliver Psr7 requests. - * Only valid for requests sent over REST. - * @type array $keyFile The contents of the service account credentials - * .json file retrieved from the Google Developer's Console. - * Ex: `json_decode(file_get_contents($path), true)`. - * @type string $keyFilePath The full path to your service account - * credentials .json file retrieved from the Google Developers - * Console. - * @type int $retries Number of retries for a failed request. **Defaults - * to** `3`. - * @type array $scopes Scopes to be used for the request. - * @type string $quotaProject Specifies a user project to bill for - * access charges associated with the request. + * the default. + * @type array $credentialsConfig Options used to configure credentials, including + * auth token caching, http handler, for the client. For a full list of + * supporting configuration options, see + * {@see \Google\ApiCore\CredentialsWrapper::build()} . + * @type string|array|FetchAuthTokenInterface|CredentialsWrapper $credentials + * The credentials to be used by the client to authorize API calls. This option + * accepts either a path to a credentials file, or a decoded credentials file as a + * PHP array. + * *Advanced usage*: In addition, this option can also accept a pre-constructed + * {@see \Google\Auth\FetchAuthTokenInterface} object or + * {@see \Google\ApiCore\CredentialsWrapper} object. Note that when one of these + * objects are provided, any settings in $credentialsConfig will be ignored. + * @type array $transportConfig + * Configuration options that will be used to construct the transport. Options for + * each supported transport type should be passed in a key for that transport. For + * example: + * $transportConfig = [ + * 'grpc' => [...], + * ]; + * See the {@see \Google\ApiCore\Transport\GrpcTransport::build()} method for the + * supported options. + * @type string|TransportInterface $transport + * The transport used for executing network requests. May be either the string + * `grpc`. `rest` is not supported in Firestore. + * *Advanced usage*: Additionally, it is possible to pass in an already + * instantiated {@see \Google\ApiCore\Transport\TransportInterface} object. Note + * that when this object is provided, any settings in $transportConfig, and any + * $apiEndpoint setting, will be ignored. + * @type string|array $clientConfig + * Client method configuration, including retry settings. This option can be either + * a path to a JSON file, or a PHP array containing the decoded JSON data. By + * default this settings points to the default client config file, which is + * provided in the resources folder. * @type bool $returnInt64AsObject If true, 64 bit integers will be * returned as a {@see \Google\Cloud\Core\Int64} object for 32 bit * platform compatibility. **Defaults to** false. @@ -223,14 +238,10 @@ public function __construct(array $config = []) * $batch = $firestore->batch(); * ``` * - * @return WriteBatch - * @deprecated Please use {@see \Google\Cloud\Firestore\BulkWriter} instead. + * @return BulkWriter */ public function batch() { - if (!class_exists(WriteBatch::class)) { - class_alias(BulkWriter::class, WriteBatch::class); - } return new BulkWriter( $this->requestHandler, $this->serializer, diff --git a/Firestore/src/SnapshotTrait.php b/Firestore/src/SnapshotTrait.php index 2c5c6431660..ac00e45ff6a 100644 --- a/Firestore/src/SnapshotTrait.php +++ b/Firestore/src/SnapshotTrait.php @@ -81,7 +81,7 @@ private function createSnapshot( * @codingStandardsIgnoreStart * @param ValueMapper $valueMapper A Firestore Value Mapper. * @param DocumentReference $reference The parent document. - * @param array $document [Document](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1beta1#google.firestore.v1beta1.Document) + * @param array $document [Document](https://cloud.google.com/firestore/docs/reference/rpc/google.firestore.v1#google.firestore.v1.Document) * @param bool $exists Whether the document exists. **Defaults to** `true`. * @codingStandardsIgnoreEnd */ diff --git a/Firestore/src/V1/DocumentTransform/FieldTransform.php b/Firestore/src/V1/DocumentTransform/FieldTransform.php index 3374ff310f0..c0cde4df2f1 100644 --- a/Firestore/src/V1/DocumentTransform/FieldTransform.php +++ b/Firestore/src/V1/DocumentTransform/FieldTransform.php @@ -411,7 +411,3 @@ public function getTransformType() } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(FieldTransform::class, \Google\Cloud\Firestore\V1\DocumentTransform_FieldTransform::class); - diff --git a/Firestore/src/V1/DocumentTransform/FieldTransform/ServerValue.php b/Firestore/src/V1/DocumentTransform/FieldTransform/ServerValue.php index 47d3356c025..403fd0fd446 100644 --- a/Firestore/src/V1/DocumentTransform/FieldTransform/ServerValue.php +++ b/Firestore/src/V1/DocumentTransform/FieldTransform/ServerValue.php @@ -53,7 +53,3 @@ public static function value($name) return constant($const); } } - -// Adding a class alias for backwards compatibility with the previous class name. -class_alias(ServerValue::class, \Google\Cloud\Firestore\V1\DocumentTransform_FieldTransform_ServerValue::class); - diff --git a/Firestore/src/V1/DocumentTransform_FieldTransform.php b/Firestore/src/V1/DocumentTransform_FieldTransform.php deleted file mode 100644 index 3dcdd419d30..00000000000 --- a/Firestore/src/V1/DocumentTransform_FieldTransform.php +++ /dev/null @@ -1,16 +0,0 @@ -batch(); - * ``` - * This class is deprecated. Use Google\Cloud\Firestore\BulkWriter instead. - * @deprecated - */ - class WriteBatch - { - } -} - -class_alias(BulkWriter::class, WriteBatch::class); -@trigger_error( - "Google\Cloud\Firestore\WriteBatch is deprecated and will be removed in the next major release. - Use Google\Cloud\Firestore\BulkWriter instead", - E_USER_DEPRECATED -); diff --git a/Firestore/tests/Snippet/DocumentReferenceTest.php b/Firestore/tests/Snippet/DocumentReferenceTest.php index e322da73727..bd352acffce 100644 --- a/Firestore/tests/Snippet/DocumentReferenceTest.php +++ b/Firestore/tests/Snippet/DocumentReferenceTest.php @@ -22,6 +22,7 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; +use Google\Cloud\Firestore\BulkWriter; use Google\Cloud\Firestore\CollectionReference; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; @@ -30,7 +31,6 @@ use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; use Google\Cloud\Firestore\ValueMapper; -use Google\Cloud\Firestore\WriteBatch; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -66,7 +66,7 @@ public function setUp(): void $this->prophesize(CollectionReference::class)->reveal(), self::DOCUMENT ], ['requestHandler', 'batch']); - $this->batch = $this->prophesize(WriteBatch::class); + $this->batch = $this->prophesize(BulkWriter::class); } public function testClass() diff --git a/Firestore/tests/Snippet/FirestoreClientTest.php b/Firestore/tests/Snippet/FirestoreClientTest.php index 1e1d2a6e755..03875197dd5 100644 --- a/Firestore/tests/Snippet/FirestoreClientTest.php +++ b/Firestore/tests/Snippet/FirestoreClientTest.php @@ -25,6 +25,7 @@ use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\Snippet\SnippetTestCase; use Google\Cloud\Core\Testing\TestHelpers; +use Google\Cloud\Firestore\BulkWriter; use Google\Cloud\Firestore\CollectionReference; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; @@ -37,7 +38,6 @@ use Google\Cloud\Firestore\V1\ListCollectionIdsRequest; use Google\Cloud\Firestore\V1\RollbackRequest; use Google\Cloud\Firestore\V1\RunQueryRequest; -use Google\Cloud\Firestore\WriteBatch; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -89,7 +89,7 @@ public function testBatch() $snippet = $this->snippetFromMethod(FirestoreClient::class, 'batch'); $snippet->addLocal('firestore', $this->client); $res = $snippet->invoke('batch'); - $this->assertInstanceOf(WriteBatch::class, $res->returnVal()); + $this->assertInstanceOf(BulkWriter::class, $res->returnVal()); } public function testCollection() diff --git a/Firestore/tests/Snippet/TransactionTest.php b/Firestore/tests/Snippet/TransactionTest.php index 2c85f1c6cc3..09b4ee99097 100644 --- a/Firestore/tests/Snippet/TransactionTest.php +++ b/Firestore/tests/Snippet/TransactionTest.php @@ -26,6 +26,7 @@ use Google\Cloud\Firestore\Aggregate; use Google\Cloud\Firestore\AggregateQuery; use Google\Cloud\Firestore\AggregateQuerySnapshot; +use Google\Cloud\Firestore\BulkWriter; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\DocumentSnapshot; use Google\Cloud\Firestore\FieldValue; @@ -38,9 +39,7 @@ use Google\Cloud\Firestore\V1\Client\FirestoreClient as V1FirestoreClient; use Google\Cloud\Firestore\V1\RollbackRequest; use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; -use Google\Cloud\Firestore\V1\RunQueryRequest; use Google\Cloud\Firestore\ValueMapper; -use Google\Cloud\Firestore\WriteBatch; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -86,7 +85,7 @@ public function setUp(): void $this->document = $this->prophesize(DocumentReference::class); $this->document->name()->willReturn(self::DOCUMENT); - $this->batch = $this->prophesize(WriteBatch::class); + $this->batch = $this->prophesize(BulkWriter::class); } public function testClass() @@ -356,7 +355,7 @@ public function __construct( public function setRequestHandler(RequestHandler $requestHandler) { $this->requestHandler = $requestHandler; - $this->writer = new WriteBatch( + $this->writer = new BulkWriter( $requestHandler, $this->getSerializer(), new ValueMapper( @@ -369,7 +368,7 @@ public function setRequestHandler(RequestHandler $requestHandler) ); } - public function setWriter(WriteBatch $writer) + public function setWriter(BulkWriter $writer) { $this->___setProperty('writer', $writer); } diff --git a/Firestore/tests/Unit/FirestoreClientTest.php b/Firestore/tests/Unit/FirestoreClientTest.php index 78558716698..87219e08bd0 100644 --- a/Firestore/tests/Unit/FirestoreClientTest.php +++ b/Firestore/tests/Unit/FirestoreClientTest.php @@ -25,6 +25,7 @@ use Google\Cloud\Core\Testing\FirestoreTestHelperTrait; use Google\Cloud\Core\Testing\GrpcTestTrait; use Google\Cloud\Core\Testing\TestHelpers; +use Google\Cloud\Firestore\BulkWriter; use Google\Cloud\Firestore\CollectionReference; use Google\Cloud\Firestore\DocumentReference; use Google\Cloud\Firestore\FieldPath; @@ -39,7 +40,6 @@ use Google\Cloud\Firestore\V1\RollbackRequest; use Google\Cloud\Firestore\V1\RunAggregationQueryRequest; use Google\Cloud\Firestore\V1\RunQueryRequest; -use Google\Cloud\Firestore\WriteBatch; use InvalidArgumentException; use PHPUnit\Framework\TestCase; use Prophecy\Argument; @@ -78,7 +78,7 @@ public function setUp(): void public function testBatch() { $batch = $this->client->batch(); - $this->assertInstanceOf(WriteBatch::class, $batch); + $this->assertInstanceOf(BulkWriter::class, $batch); } public function testBatchCorrectDatabaseName()