Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/run-package-tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@

set -e

# USAGE:
#
# run-package-tests.sh [DIRECTORY] [PREFER_LOWEST]
#
# DIRECTORY: Optionally pass in a component directory and only run the script
#. for that component.
#
# PREFER_LOWEST: can be "--prefer-lowest" or "--prefer-lowest-strict". When the
# "--prefer-lowest-strict" flag is set, local package dependencies
# are installed according to their version number in
# `[Component]/VERSION`. This flag is set on the release PRs to
#. ensure the dependencies for the upcoming release will be
# configured correctly.

DIRS=$(find * -maxdepth 0 -type d -name '[A-Z]*')
PREFER_LOWEST=""
if [ "$#" -eq 1 ]; then
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/emulator-system-tests-spanner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ jobs:
- name: Install dependencies
run: |
# ensure composer uses local Core instead of pulling from packagist
composer config repositories.local --json '{"type":"path", "url": "../Core", "options": {"versions": {"google/cloud-core": "1.100"}}}' -d Spanner
composer config repositories.local --json '{"type":"path", "url": "../Core", "options": {"versions": {"google/cloud-core": "1.100"}},"canonical":false}' -d Spanner
composer update --prefer-dist --no-interaction --no-suggest -d Spanner/
- name: Run system tests
Expand Down
3 changes: 3 additions & 0 deletions Core/src/ApiHelperTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Google\ApiCore\Options\CallOptions;
use Google\Protobuf\Internal\Message;
use Google\Protobuf\NullValue;
use LogicException;

/**
* @internal
Expand Down Expand Up @@ -276,6 +277,8 @@ private function splitOptionalArgs(array $input, array $extraAllowedKeys = []):
* $optionTypes can be an array of string keys, a protobuf Message classname, or a
* the CallOptions classname. Parameters are split and returned in the order
* that the options types are provided.
*
* @throws LogicException
*/
private function validateOptions(array $options, array|Message|string ...$optionTypes): array
{
Expand Down
2 changes: 1 addition & 1 deletion Core/src/Iam/Iam.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*
* use Google\Cloud\Spanner\SpannerClient;
*
* $spanner = new SpannerClient();
* $spanner = new SpannerClient(['projectId' => 'my-project']);
* $instance = $spanner->instance('my-new-instance');
*
* $iam = $instance->iam();
Expand Down
123 changes: 123 additions & 0 deletions Core/src/LongRunning/LongRunningClientConnection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
<?php
/**
* Copyright 2025 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Google\Cloud\Core\LongRunning;

use Google\ApiCore\OperationResponse;
use Google\ApiCore\Serializer;
use Google\Cloud\Core\RequestProcessorTrait;
use Google\LongRunning\ListOperationsRequest;
use Google\Protobuf\Any;

/**
* Defines the calls required to manage Long Running Operations using a GAPIC
* generated client.
*
* @internal
*/
class LongRunningClientConnection implements LongRunningConnectionInterface
{
use RequestProcessorTrait;

public function __construct(
private object $gapicClient,
private Serializer $serializer
) {
}

/**
* @param array $args
* @return array
*/
public function get(array $args): array
{
$operationResponse = $this->gapicClient->resumeOperation($args['name']);

return $this->operationResponseToArray($operationResponse);
}

/**
* @param array $args
* @return array
*/
public function cancel(array $args): array
{
$operationResponse = $this->gapicClient->resumeOperation(
$args['name'],
$args['method'] ?? null
);
$operationResponse->cancel();

return $this->operationResponseToArray($operationResponse);
}

/**
* @param array $args
* @return array
*/
public function delete(array $args): array
{
$operationResponse = $this->gapicClient->resumeOperation(
$args['name'],
$args['method'] ?? null
);
$operationResponse->cancel();

return $this->operationResponseToArray($operationResponse);
}

/**
* @param array $args
* @return array
*/
public function operations(array $args): array
{
$request = ListOperationsRequest::build($args['name'], $args['filter'] ?? null);
$response = $this->gapicClient->getOperationsClient()->listOperations($request);

return $this->handleResponse($response);
}

private function operationResponseToArray(OperationResponse $operationResponse): array
{
$response = $this->handleResponse($operationResponse->getLastProtoResponse());
$metaType = $response['metadata']['typeUrl'];

// unpack result Any type
$result = $operationResponse->getResult();
if ($result instanceof Any) {
// For some reason we aren't doing this in GAX OperationResponse (but we should)
$result = $result->unpack();
}
$response['response'] = $this->handleResponse($result);

// unpack error Any type
$response['error'] = $this->handleResponse($operationResponse->getError());

$metadata = $operationResponse->getMetadata();
if ($metadata instanceof Any) {
// For some reason we aren't doing this in GAX OperationResponse (but we should)
$metadata = $metadata->unpack();
}
$response['metadata'] = $this->handleResponse($metadata);

// Used in LongRunningOperation to invoke callables
$response['metadata'] += ['typeUrl' => $metaType];

return $response;
}
}
10 changes: 5 additions & 5 deletions Core/src/LongRunning/LongRunningOperation.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

/**
* Represent and interact with a Long Running Operation.
* @template T
*/
class LongRunningOperation
{
Expand Down Expand Up @@ -180,7 +181,7 @@ public function state(array $options = [])
* ```
*
* @param array $options [optional] Configuration options.
* @return mixed|null
* @return T|mixed|null
*/
public function result(array $options = [])
{
Expand Down Expand Up @@ -252,12 +253,11 @@ public function reload(array $options = [])

$this->result = null;
$this->error = null;
if (isset($res['done']) && $res['done']) {

if ($res['done'] ?? false && isset($res['metadata']['typeUrl'])) {
$type = $res['metadata']['typeUrl'];
$this->result = $this->executeDoneCallback($type, $res['response']);
$this->error = (isset($res['error']))
? $res['error']
: null;
$this->error = $res['error'] ?? null;
}

return $this->info = $res;
Expand Down
7 changes: 5 additions & 2 deletions Core/src/OptionsValidator.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ class OptionsValidator
* @param ?Serializer $serializer use a serializer to decode protobuf messages
* instead of calling {@see Message::mergeFromJsonString()}.
*/
public function __construct(private ?Serializer $serializer = null)
{
public function __construct(
private ?Serializer $serializer = null
) {
}

/**
Expand Down Expand Up @@ -90,6 +91,8 @@ public function validateOptions(array $options, array|Message|string ...$optionT
$optionType->mergeFromJsonString(json_encode($messageOptions, JSON_FORCE_OBJECT));
}
$splitOptions[] = $optionType;
} elseif (is_string($optionType)) {
$splitOptions[] = $this->pluck($optionType, $options, false);
} else {
throw new LogicException(sprintf('Invalid option type: %s', $optionType));
}
Expand Down
15 changes: 9 additions & 6 deletions Core/src/RequestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ class RequestHandler
*/
private Serializer $serializer;

private array $clients;
private array $clients = [];

/**
* @param Serializer $serializer
* @param array $clientClasses
* @param array<string|object> $clients
* @param array $clientConfig
*/
public function __construct(
Serializer $serializer,
array $clientClasses,
array $clients,
array $clientConfig = []
) {
//@codeCoverageIgnoreStart
Expand All @@ -75,9 +75,12 @@ public function __construct(
//@codeCoverageIgnoreEnd

// Initialize the client classes and store them in memory
$this->clients = [];
foreach ($clientClasses as $className) {
$this->clients[$className] = new $className($clientConfig);
foreach ($clients as $client) {
if (is_object($client)) {
$this->clients[get_class($client)] = $client;
} else {
$this->clients[$client] = new $client($clientConfig);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Core/src/ServiceBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ public function pubsub(array $config = [])
*
* Example:
* ```
* $spanner = $cloud->spanner();
* $spanner = $cloud->spanner(['projectId' => 'my-project']);
* ```
*
* @param array $config [optional] {
Expand Down
14 changes: 7 additions & 7 deletions Core/src/TimeTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,12 @@ private function formatTimeAsString(\DateTimeInterface $dateTime, $ns)
$dateTime = $dateTime->setTimeZone(new \DateTimeZone('UTC'));
if ($ns === null) {
return $dateTime->format(Timestamp::FORMAT);
} else {
return sprintf(
$dateTime->format(Timestamp::FORMAT_INTERPOLATE),
$this->convertNanoSecondsToFraction($ns)
);
}

return sprintf(
$dateTime->format(Timestamp::FORMAT_INTERPOLATE),
$this->convertNanoSecondsToFraction($ns)
);
}

/**
Expand All @@ -95,10 +95,10 @@ private function formatTimeAsString(\DateTimeInterface $dateTime, $ns)
* $dateTime will be used instead.
* @return array
*/
private function formatTimeAsArray(\DateTimeInterface $dateTime, $ns)
private function formatTimeAsArray(\DateTimeInterface $dateTime, $ns = null)
{
if ($ns === null) {
$ns = $dateTime->format('u');
$ns = $this->convertFractionToNanoSeconds($dateTime->format('u'));
}
return [
'seconds' => (int) $dateTime->format('U'),
Expand Down
14 changes: 8 additions & 6 deletions Core/src/Timestamp.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

namespace Google\Cloud\Core;

use DateTimeInterface;

/**
* Represents a Timestamp value.
*
Expand Down Expand Up @@ -85,9 +87,9 @@ public function __construct(\DateTimeInterface $value, $nanoSeconds = null)
* $dateTime = $timestamp->get();
* ```
*
* @return \DateTimeInterface
* @return DateTimeInterface
*/
public function get()
public function get(): DateTimeInterface
{
return $this->value;
}
Expand All @@ -102,7 +104,7 @@ public function get()
*
* @return int
*/
public function nanoSeconds()
public function nanoSeconds(): int
{
return $this->nanoSeconds === null
? (int) $this->value->format('u') * 1000
Expand All @@ -119,7 +121,7 @@ public function nanoSeconds()
*
* @return string
*/
public function formatAsString()
public function formatAsString(): string
{
return $this->formatTimeAsString(
$this->value,
Expand All @@ -143,7 +145,7 @@ public function __toString()
*
* @return array
*/
public function formatForApi()
public function formatForApi(): array
{
return $this->formatTimeAsArray($this->value, $this->nanoSeconds());
}
Expand All @@ -155,7 +157,7 @@ public function formatForApi()
* @access private
*/
#[\ReturnTypeWillChange]
public function jsonSerialize()
public function jsonSerialize(): string
{
return $this->formatAsString();
}
Expand Down
3 changes: 2 additions & 1 deletion Core/tests/Snippet/Iam/IamTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

use Google\Cloud\Core\Testing\Snippet\SnippetTestCase;
use Google\Cloud\Core\Iam\Iam;
use Google\Cloud\Core\Iam\IamManager;
use Google\Cloud\Core\Iam\IamConnectionInterface;
use Google\Cloud\Core\Testing\TestHelpers;
use Google\Cloud\Spanner\SpannerClient;
Expand Down Expand Up @@ -55,7 +56,7 @@ public function testClass()
]);
$res = $snippet->invoke('iam');

$this->assertInstanceOf(Iam::class, $res->returnVal());
$this->assertInstanceOf(IamManager::class, $res->returnVal());
}

public function testPolicy()
Expand Down
Loading
Loading