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
7 changes: 7 additions & 0 deletions .github/workflows/check.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ jobs:
- uses: actions/checkout@v6
- run: PHP_IMAGE_VERSION=${{ matrix.php }} make ${{ matrix.deps == 'lowest' && 'install-lowest' || '' }} test

interop:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- run: make interop

# infect:
# runs-on: ubuntu-latest
# steps:
Expand Down
2 changes: 2 additions & 0 deletions .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
->in(__DIR__ . '/packages/client/src')
->in(__DIR__ . '/packages/server/src')
->in(__DIR__ . '/tests')
->in(__DIR__ . '/interop/src')
->in(__DIR__ . '/interop/bin')
->exclude([
'genproto',
])
Expand Down
29 changes: 28 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ test: var vendor compile-test-stub ## Run tests using PHPUnit
$(RUN) vendor/bin/phpunit $(ARGS) --colors
.PHONY: test

interop: var vendor ## Run gRPC interop tests against grpc-go
$(DOCKER_COMPOSE) --profile interop run --rm --build interop php interop/bin/matrix $(ARGS)
.PHONY: interop

infect: var vendor up ## Run mutation tests using Infection
$(RUN) infection --show-mutations $(ARGS)
.PHONY: infect
Expand All @@ -130,7 +134,7 @@ composer-normalize-check: ## Check that composer.json is normalized
fix: fixer rector composer-normalize ## Run all fixing recipes
.PHONY: fix

check: fixer-check rector-check composer-validate composer-normalize-check deps-analyze phpstan test ## Run all project checks
check: fixer-check rector-check composer-validate composer-normalize-check deps-analyze phpstan test interop ## Run all project checks
.PHONY: check

compile-test-stub:
Expand All @@ -143,6 +147,29 @@ compile-test-stub:
--php-plugin_out=tests/genproto \
tests/protos/*.proto
.PHONY: compile-test-stub

compile-interop-stub: fetch-interop-protos
docker run --rm \
--pull always \
--user $(CONTAINER_USER) \
-v $(PWD):/workspace \
-w /workspace \
ghcr.io/thesis-php/protoc-plugin:latest \
-I interop/protos \
--php-plugin_out=interop/genproto \
interop/protos/src/proto/grpc/testing/*.proto
.PHONY: compile-interop-stub

INTEROP_GRPC_COMMIT = 816d41355f831fdaec27e3d4cb4e5d3fe0d55637

fetch-interop-protos: ## Fetch interop protos and TLS test credentials from grpc/grpc at INTEROP_GRPC_COMMIT
for f in empty messages test; do \
curl --fail --silent --location --output interop/protos/src/proto/grpc/testing/$$f.proto https://raw.githubusercontent.com/grpc/grpc/$(INTEROP_GRPC_COMMIT)/src/proto/grpc/testing/$$f.proto || exit 1; \
done
for f in ca.pem server1.pem server1.key; do \
curl --fail --silent --location --output interop/tls/$$f https://raw.githubusercontent.com/grpc/grpc/$(INTEROP_GRPC_COMMIT)/src/core/tsi/test_creds/$$f || exit 1; \
done
.PHONY: fetch-interop-protos
# -----------------------

help:
Expand Down
15 changes: 15 additions & 0 deletions compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,18 @@ services:
- .:/workspace:cached
working_dir: /workspace
network_mode: host

interop:
build:
context: interop
args:
PHP_IMAGE_VERSION: ${PHP_IMAGE_VERSION}
user: ${CONTAINER_USER:-}
environment:
XDEBUG_MODE: 'off'
init: true
volumes:
- .:/workspace:cached
working_dir: /workspace
network_mode: host
profiles: [interop]
9 changes: 7 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
"amphp/http": "^2.1",
"amphp/http-client": "^5.3",
"amphp/http-server": "^3.4.7",
"amphp/pipeline": "^1.2",
"amphp/pipeline": "^1.2.1",
"amphp/socket": "^2.3",
"amphp/sync": "^2.3",
"league/uri": "^7.8",
Expand All @@ -41,6 +41,8 @@
},
"require-dev": {
"ext-bcmath": "*",
"amphp/hpack": "^3.2",
"amphp/process": "^2.1",
"phpunit/phpunit": "^12.4",
"symfony/var-dumper": "^8.0",
"thesis/grpc-client": "*@dev",
Expand Down Expand Up @@ -82,14 +84,17 @@
"Chat\\Api\\V1\\": "tests/genproto/Chat/Api/V1/",
"Echos\\Api\\V1\\": "tests/genproto/Echos/Api/V1/",
"File\\Api\\V1\\": "tests/genproto/File/Api/V1/",
"Grpc\\Testing\\": "interop/genproto/Grpc/Testing/",
"Thesis\\Grpc\\": "tests/",
"Thesis\\Grpc\\Interop\\": "interop/src/",
"Topic\\Api\\V1\\": "tests/genproto/Topic/Api/V1/"
},
"files": [
"tests/genproto/Echos/Api/V1/autoload.metadata.php",
"tests/genproto/File/Api/V1/autoload.metadata.php",
"tests/genproto/Topic/Api/V1/autoload.metadata.php",
"tests/genproto/Chat/Api/V1/autoload.metadata.php"
"tests/genproto/Chat/Api/V1/autoload.metadata.php",
"interop/genproto/Grpc/Testing/autoload.metadata.php"
]
},
"config": {
Expand Down
11 changes: 11 additions & 0 deletions interop/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
ARG PHP_IMAGE_VERSION

FROM golang:1.25-alpine AS grpc-go
ARG GRPC_GO_VERSION=v1.84.0
RUN CGO_ENABLED=0 go install \
google.golang.org/grpc/interop/client@${GRPC_GO_VERSION} \
google.golang.org/grpc/interop/server@${GRPC_GO_VERSION}

FROM ghcr.io/phpyh/php:${PHP_IMAGE_VERSION}
COPY --from=grpc-go /go/bin/client /usr/local/bin/grpc-go-interop-client
COPY --from=grpc-go /go/bin/server /usr/local/bin/grpc-go-interop-server
71 changes: 71 additions & 0 deletions interop/bin/client
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

use Thesis\Grpc\Client;
use Thesis\Grpc\Interop\AdditionalMetadata;
use Thesis\Grpc\Interop\Flags;
use Thesis\Grpc\Interop\TestCases;

require_once __DIR__ . '/../../vendor/autoload.php';

$flags = Flags::parse([
'server_host' => 'localhost',
'server_host_override' => '',
'server_port' => '10000',
'test_case' => 'large_unary',
'use_tls' => 'false',
'use_test_ca' => 'false',
'additional_metadata' => '',
'soak_iterations' => '10',
'soak_max_failures' => '0',
'soak_per_iteration_max_acceptable_latency_ms' => '1000',
'soak_overall_timeout_seconds' => '10',
'soak_min_time_ms_between_rpcs' => '0',
'soak_request_size' => '271828',
'soak_response_size' => '314159',
'soak_num_threads' => '1',
]);

$host = $flags->string('server_host');
$address = (str_contains($host, ':') ? "[{$host}]" : $host) . ":{$flags->int('server_port')}";
$metadata = AdditionalMetadata::parse($flags->string('additional_metadata'));

$builder = new Client\Builder()
->withHost($address)
->withInterceptors($metadata);

if ($flags->bool('use_tls')) {
$credentials = new Client\TransportCredentials()->withPeerName($flags->string('server_host_override') !== '' ? $flags->string('server_host_override') : $host);

if ($flags->bool('use_test_ca')) {
$credentials = $credentials->withCaCert(__DIR__ . '/../tls/ca.pem');
}

$builder = $builder->withTransportCredentials($credentials);
}

$cases = new TestCases($builder->build(...), $flags, $address);

match ($flags->string('test_case')) {
'empty_unary' => $cases->emptyUnary(),
'large_unary' => $cases->largeUnary(),
'client_streaming' => $cases->clientStreaming(),
'server_streaming' => $cases->serverStreaming(),
'ping_pong' => $cases->pingPong(),
'empty_stream' => $cases->emptyStream(),
'status_code_and_message' => $cases->statusCodeAndMessage(),
'special_status_message' => $cases->specialStatusMessage(),
'unimplemented_method' => $cases->unimplementedMethod(),
'unimplemented_service' => $cases->unimplementedService(),
'cancel_after_begin' => $cases->cancelAfterBegin(),
'cancel_after_first_response' => $cases->cancelAfterFirstResponse(),
'timeout_on_sleeping_server' => $cases->timeoutOnSleepingServer(),
'custom_metadata' => $cases->customMetadata(),
'rpc_soak' => $cases->rpcSoak(),
'channel_soak' => $cases->channelSoak(),
default => throw new InvalidArgumentException("Unsupported test case \"{$flags->string('test_case')}\"."),
};

echo "{$flags->string('test_case')}: passed\n";
Loading
Loading