From 33b57f3ae8c068d9a1cc19d5f75c40729abe34b5 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 7 Oct 2026 02:00:00 +0000 Subject: [PATCH 1/5] fix: track workspace srcs and composer.json in Bazel php_binary --- .github/workflows/bazel_example.yml | 6 ++---- BUILD.bazel | 11 +++++++++++ rules_php_gapic/php.bzl | 16 ++++++++++------ rules_php_gapic/php_repo.bzl | 1 + 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/.github/workflows/bazel_example.yml b/.github/workflows/bazel_example.yml index fad5ba28f..f3e5a0b1c 100644 --- a/.github/workflows/bazel_example.yml +++ b/.github/workflows/bazel_example.yml @@ -68,8 +68,6 @@ jobs: - name: Integration Tests run: | - # Clear the cached files. Remove this workaround when the Bazel build is fixed. - rm -rf ~/.cache/bazel/*/*/*/gapic_generator_php/bazel-out/host/bin/rules_php_gapic/* bazel --batch test tests/Integration:asset \ tests/Integration:compute_small \ tests/Integration:container \ @@ -83,11 +81,11 @@ jobs: tests/Integration:speech \ tests/Integration:securitycenter \ tests/Integration:talent \ - tests/Integration:videointelligence --noshow_progress --cache_test_results=no + tests/Integration:videointelligence --noshow_progress --cache_test_results=no --test_output=errors - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 if: ${{ failure() }} with: name: test-artifacts - path: ~/.cache/bazel/*/*/*/gapic_generator_php/bazel-out/*/testlogs/* + path: ~/.cache/bazel/*/*/*/*/bazel-out/*/testlogs/* retention-days: 5 diff --git a/BUILD.bazel b/BUILD.bazel index f551edcf3..c479c9f29 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -11,3 +11,14 @@ # 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. + +exports_files(["composer.json"]) + +filegroup( + name = "srcs", + srcs = glob([ + "src/**", + "generated/**", + ]) + ["composer.json"], + visibility = ["//visibility:public"], +) diff --git a/rules_php_gapic/php.bzl b/rules_php_gapic/php.bzl index 19c50e54e..47eb2aa6a 100644 --- a/rules_php_gapic/php.bzl +++ b/rules_php_gapic/php.bzl @@ -16,25 +16,28 @@ def _php_binary_impl(ctx): run_name = "{}_run.sh".format(ctx.attr.name) out_dir = ctx.actions.declare_directory("out") out_run_sh = ctx.actions.declare_file(run_name) - entry_point_relative = ctx.file.entry_point.path[len(ctx.attr.entry_point.label.workspace_root):].strip("/") + ws_root = ctx.attr.entry_point.label.workspace_root + entry_point_relative = ctx.file.entry_point.path[len(ws_root):].strip("/") # I don't understand why this is required: entry_point_relative = entry_point_relative[len("rules_php_gapic/"):] # PHP files must be copied, as the PHP __DIR__ constant is incorrect if the src file is symlinked. - # Ideally this would cp with everything being symlinks except php files. - # However that's difficult, so copy every thing; using tar as this allows excluding of directories. + # Copy vendor/ from the composer install repo and source files from the workspace so that + # changes to src/ invalidate the Bazel action cache. cmd = """ DEST="$(pwd)/{out_dir_path}/install" mkdir "$DEST" -cd '{install_path}' -tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json | (cd "$DEST" && tar xf -) +(cd '{install_path}' && tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json) | (cd "$DEST" && tar xf -) +rm -rf "$DEST/src" "$DEST/generated" +(cd '{ws_root}' && tar cf - --dereference src/ generated/ composer.json) | (cd "$DEST" && tar xf -) """.format( install_path = ctx.file.php_composer_install.path, out_dir_path = out_dir.path, + ws_root = ws_root if ws_root else ".", ) ctx.actions.run_shell( - inputs = [ctx.file.php_composer_install], + inputs = [ctx.file.php_composer_install] + ctx.files.srcs, outputs = [out_dir], command = cmd, ) @@ -82,6 +85,7 @@ php_binary = rule( attrs = { "php": attr.label(default = Label("@php_micro//:php"), allow_single_file = True, executable = True, cfg = "host"), "php_composer_install": attr.label(allow_single_file = True), + "srcs": attr.label_list(default = [Label("@gapic_generator_php//:srcs")], allow_files = True), "entry_point": attr.label(allow_single_file = True), "working_directory_flag_name": attr.string(), }, diff --git a/rules_php_gapic/php_repo.bzl b/rules_php_gapic/php_repo.bzl index bf745696c..882836be6 100644 --- a/rules_php_gapic/php_repo.bzl +++ b/rules_php_gapic/php_repo.bzl @@ -124,6 +124,7 @@ def _find_ws_root(path): fail("Cannot find workspace root.") def _php_composer_install_impl(ctx): + ctx.read(ctx.attr.composer_json) ws_path = _find_ws_root(ctx.path(ctx.attr.composer_json).dirname) composer_json_relative = str(ctx.path(ctx.attr.composer_json))[len(str(ws_path)):] # Copy entire source workspace into the restored repo, then run `composer install`. From c598c8dbac92774e0fda0a86e9fae9c62b3a7933 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 7 Oct 2026 20:03:13 +0000 Subject: [PATCH 2/5] chore: migrate integration golden tests from Bazel to PHPUnit --- .github/workflows/bazel_example.yml | 91 --- .github/workflows/phpunit.yml | 2 +- BUILD.bazel | 11 - DEVELOPMENT.md | 69 +- composer.json | 6 +- googleapis | 2 +- phpunit.xml.dist | 4 + rules_php_gapic/php.bzl | 16 +- rules_php_gapic/php_repo.bzl | 1 - rules_php_test/integration_test.bzl | 150 ----- tests/Integration/BUILD.bazel | 611 ------------------ tests/Integration/GoldenUpdateMain.php | 78 +++ tests/Integration/IntegrationTest.php | 147 +++++ tests/Integration/goldens/asset/BUILD.bazel | 10 - .../goldens/compute_small/BUILD.bazel | 10 - .../Integration/goldens/container/BUILD.bazel | 10 - .../Integration/goldens/dataproc/BUILD.bazel | 10 - .../Integration/goldens/functions/BUILD.bazel | 10 - tests/Integration/goldens/iam/BUILD.bazel | 10 - tests/Integration/goldens/kms/BUILD.bazel | 10 - tests/Integration/goldens/logging/BUILD.bazel | 10 - tests/Integration/goldens/redis/BUILD.bazel | 10 - tests/Integration/goldens/retail/BUILD.bazel | 10 - .../goldens/securitycenter/BUILD.bazel | 10 - tests/Integration/goldens/spanner/BUILD.bazel | 10 - tests/Integration/goldens/speech/BUILD.bazel | 10 - tests/Integration/goldens/talent/BUILD.bazel | 10 - .../goldens/videointelligence/BUILD.bazel | 10 - tests/Tools/GeneratorUtils.php | 40 ++ tests/Tools/ProtoLoader.php | 18 +- tests/Unit/ProtoTests/UnitGoldenUpdater.php | 5 + tests/scripts/run_bazel_tests.sh | 27 - tests/scripts/run_bazel_updates.sh | 37 -- 33 files changed, 317 insertions(+), 1148 deletions(-) delete mode 100644 .github/workflows/bazel_example.yml delete mode 100644 rules_php_test/integration_test.bzl delete mode 100644 tests/Integration/BUILD.bazel create mode 100644 tests/Integration/GoldenUpdateMain.php create mode 100644 tests/Integration/IntegrationTest.php delete mode 100644 tests/Integration/goldens/asset/BUILD.bazel delete mode 100644 tests/Integration/goldens/compute_small/BUILD.bazel delete mode 100644 tests/Integration/goldens/container/BUILD.bazel delete mode 100644 tests/Integration/goldens/dataproc/BUILD.bazel delete mode 100644 tests/Integration/goldens/functions/BUILD.bazel delete mode 100644 tests/Integration/goldens/iam/BUILD.bazel delete mode 100644 tests/Integration/goldens/kms/BUILD.bazel delete mode 100644 tests/Integration/goldens/logging/BUILD.bazel delete mode 100644 tests/Integration/goldens/redis/BUILD.bazel delete mode 100644 tests/Integration/goldens/retail/BUILD.bazel delete mode 100644 tests/Integration/goldens/securitycenter/BUILD.bazel delete mode 100644 tests/Integration/goldens/spanner/BUILD.bazel delete mode 100644 tests/Integration/goldens/speech/BUILD.bazel delete mode 100644 tests/Integration/goldens/talent/BUILD.bazel delete mode 100644 tests/Integration/goldens/videointelligence/BUILD.bazel delete mode 100755 tests/scripts/run_bazel_tests.sh delete mode 100755 tests/scripts/run_bazel_updates.sh diff --git a/.github/workflows/bazel_example.yml b/.github/workflows/bazel_example.yml deleted file mode 100644 index f3e5a0b1c..000000000 --- a/.github/workflows/bazel_example.yml +++ /dev/null @@ -1,91 +0,0 @@ -permissions: - contents: read - -name: Bazel Build - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - runs-on: ubuntu-24.04 - container: gcr.io/gapic-images/googleapis@sha256:10f630423413f9138bd68c71f87c4734b9eeaba040675162c2a0b38410b0effc - - steps: - - name: Checkout code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - submodules: 'recursive' - persist-credentials: false - - - name: Bazel File Cache Setup - id: cache-bazel - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 - with: - path: ~/.cache/bazel - key: ${{ runner.os }}-bazel-20210105-${{ secrets.CACHE_VERSION }} - - - name: Bazel Cache Not Found - if: steps.cache-bazel.outputs.cache-hit != 'true' - run: | - echo "No cache found." - - name: Bazel Cache Found - if: steps.cache-bazel.outputs.cache-hit == 'true' - run: | - echo -n "Cache found. Cache size: " - du -sh ~/.cache/bazel - echo "If the cache seems broken, update the CACHE_VERSION secret in" - echo "https://github.com/googleapis/gapic-generator-php/settings/secrets/actions" - echo "(use any random string, any GUID will work)" - echo "and it will start over with a clean cache." - echo "The old one will disappear after 7 days." - - - name: Show bazel version - run: | - bazel --version - - #- name: Build example package; all targets - # run: | - # cd bazel_example; - # bazel build ... - - #- name: Extract Bazel package output - # run: | - # cd bazel_example; - # tar -xf ./bazel-bin/example_php_pkg.tar.gz - - ## grep returns 1 if no matches are found; and 0 if >0 matches are found. - #- name: Verify grpc_service_config.json was honoured - # run: | - # grep '"timeout_millis": 942000' ./bazel_example/example_php_pkg/src/resources/example_client_config.json -# - #- name: Verify gapic.yaml was honoured - # run: | - # grep "'initialPollDelayMillis' => '42042'" ./bazel_example/example_php_pkg/src/resources/example_descriptor_config.php - - - name: Integration Tests - run: | - bazel --batch test tests/Integration:asset \ - tests/Integration:compute_small \ - tests/Integration:container \ - tests/Integration:dataproc \ - tests/Integration:functions \ - tests/Integration:kms \ - tests/Integration:iam \ - tests/Integration:logging \ - tests/Integration:redis \ - tests/Integration:retail \ - tests/Integration:speech \ - tests/Integration:securitycenter \ - tests/Integration:talent \ - tests/Integration:videointelligence --noshow_progress --cache_test_results=no --test_output=errors - - - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 - if: ${{ failure() }} - with: - name: test-artifacts - path: ~/.cache/bazel/*/*/*/*/bazel-out/*/testlogs/* - retention-days: 5 diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 10da5a93f..3ad433a53 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -31,4 +31,4 @@ jobs: composer dump-autoload; - name: Run tests - run: USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit + run: USE_TOOLS_PROTOC=true ./vendor/bin/phpunit diff --git a/BUILD.bazel b/BUILD.bazel index c479c9f29..f551edcf3 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -11,14 +11,3 @@ # 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. - -exports_files(["composer.json"]) - -filegroup( - name = "srcs", - srcs = glob([ - "src/**", - "generated/**", - ]) + ["composer.json"], - visibility = ["//visibility:public"], -) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index e4c06f36b..d61ba95b3 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -64,52 +64,29 @@ We'll be using **PHP 7.4** for the setup. ## Running tests -- Unit tests +- All tests (unit and integration) ``` - ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit + ./vendor/bin/phpunit ``` If you do not have `protoc` installed, run with `USE_TOOLS_PROTOC=true`. ``` - USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit ``` This uses the Linux-only `protoc` binary checked into the repository. If you run into an error: `Error: Call to undefined function Google\Protobuf\Internal\bccomp()`, that is because the [BC Math](https://www.php.net/manual/en/book.bc.php) extension is not always included by default (see tracking bug here: https://github.com/protocolbuffers/protobuf/issues/4465). You can get around this by installing BC Math with the command `sudo apt install php-bcmath`. -- Bazel integration tests. +- Running a specific test suite or integration case: - - Running: - - ``` - bazel test tests/Integration:asset - ``` - - - Running all tests: - - ``` - bash tests/scripts/run_bazel_tests.sh - ``` - - _Note: Running `bazel` commands may require removing the `composer.lock` and - `vendor/` directory._ - - - Debugging in `googleapis`: - - In [`googleapis/WORKSPACE`](https://github.com/googleapis/googleapis/blob/86fa44cc5ee2136e87c312f153113d4dd8e9c4de/WORKSPACE#L397-L401), - replace the `http_archive` downloading the generator with a - `local_repository` target pointing to the locally modified version of the - generator: - - ``` - local_repository( - name = "gapic_generator_php", - path = "/absolute/path/to/local/generator", - ) - ``` + ``` + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Unit Tests" + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Integration Tests" + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Integration Tests" --filter asset + ``` ## Updating tests @@ -118,7 +95,7 @@ You will need to update the golden test files if you change something in the gen - Updating unit test goldens: ``` - php tests/Unit/ProtoTests/GoldenUpdateMain.php + USE_TOOLS_PROTOC=true php tests/Unit/ProtoTests/GoldenUpdateMain.php ``` Then follow the prompts for which tests to update. @@ -128,41 +105,25 @@ You will need to update the golden test files if you change something in the gen - Updating integration test goldens: ``` - bash tests/scripts/run_bazel_updates.sh --expunge + USE_TOOLS_PROTOC=true php tests/Integration/GoldenUpdateMain.php ``` - Integration tests can be updated individually as well: + Integration tests can be updated individually by passing a filter argument: ``` - bazel run tests/Integration:asset_update + USE_TOOLS_PROTOC=true php tests/Integration/GoldenUpdateMain.php asset ``` - __NOTE__: If a new integration test case is added, make sure to add it the list in [run_bazel_tests.sh](tests/scripts/run_bazel_tests.sh) and [run_bazel_updates.sh](tests/scripts/run_bazel_updates.sh). + __NOTE__: If a new integration test case is added, make sure to add it to `TESTS` in [IntegrationTest.php](tests/Integration/IntegrationTest.php). - Update all goldens (unit and integration) Run the composer script `update-all-tests` to update all goldens at once: ``` - composer update-all-tests + USE_TOOLS_PROTOC=true composer update-all-tests ``` -## Rotating the bazel cache key - -The GitHub Actions that run the `bazel`-based integration tests hold a cache of -the build in order to speed up testing pull requests that do not impact -generated surface. If proposing a change that modifies the integration test -golden files, one must also rotate the cache key using the -[`gh` CLI](https://cli.github.com/). Use the following command before opening -your pull request: - -``` -uuidgen | gh secret set CACHE_VERSION -r https://github.com/googleapis/gapic-generator-php -``` - -If you don't have the proper permissions to rotate the cache key, request that -the reviewers do so and rerun the Action checks. - ## Updating the `googleapis` submodule To update the `googleapis` submodule, change into the directory and pull: diff --git a/composer.json b/composer.json index 86dbdc72f..eb6c24f95 100644 --- a/composer.json +++ b/composer.json @@ -49,12 +49,16 @@ "scripts": { "update-all-tests": [ "Google\\Generator\\Tests\\Unit\\ProtoTests\\GoldenUpdateMain::updateAll", - "bash tests/scripts/run_bazel_updates.sh --expunge" + "Google\\Generator\\Tests\\Integration\\GoldenUpdateMain::updateAll" ] }, "config": { "platform": { "php": "8.2" + }, + "allow-plugins": { + "php-http/discovery": false, + "tbachert/spi": false } } } diff --git a/googleapis b/googleapis index d931df43c..9841522f9 160000 --- a/googleapis +++ b/googleapis @@ -1 +1 @@ -Subproject commit d931df43c4686be708ddfee74ee3be64571af0a2 +Subproject commit 9841522f92c6542aad0049d98721cba04f541f29 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index cd920d048..3abf16029 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,6 +15,10 @@ ./tests/Unit + + ./tests/Integration + ./tests/Integration/goldens + diff --git a/rules_php_gapic/php.bzl b/rules_php_gapic/php.bzl index 47eb2aa6a..19c50e54e 100644 --- a/rules_php_gapic/php.bzl +++ b/rules_php_gapic/php.bzl @@ -16,28 +16,25 @@ def _php_binary_impl(ctx): run_name = "{}_run.sh".format(ctx.attr.name) out_dir = ctx.actions.declare_directory("out") out_run_sh = ctx.actions.declare_file(run_name) - ws_root = ctx.attr.entry_point.label.workspace_root - entry_point_relative = ctx.file.entry_point.path[len(ws_root):].strip("/") + entry_point_relative = ctx.file.entry_point.path[len(ctx.attr.entry_point.label.workspace_root):].strip("/") # I don't understand why this is required: entry_point_relative = entry_point_relative[len("rules_php_gapic/"):] # PHP files must be copied, as the PHP __DIR__ constant is incorrect if the src file is symlinked. - # Copy vendor/ from the composer install repo and source files from the workspace so that - # changes to src/ invalidate the Bazel action cache. + # Ideally this would cp with everything being symlinks except php files. + # However that's difficult, so copy every thing; using tar as this allows excluding of directories. cmd = """ DEST="$(pwd)/{out_dir_path}/install" mkdir "$DEST" -(cd '{install_path}' && tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json) | (cd "$DEST" && tar xf -) -rm -rf "$DEST/src" "$DEST/generated" -(cd '{ws_root}' && tar cf - --dereference src/ generated/ composer.json) | (cd "$DEST" && tar xf -) +cd '{install_path}' +tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json | (cd "$DEST" && tar xf -) """.format( install_path = ctx.file.php_composer_install.path, out_dir_path = out_dir.path, - ws_root = ws_root if ws_root else ".", ) ctx.actions.run_shell( - inputs = [ctx.file.php_composer_install] + ctx.files.srcs, + inputs = [ctx.file.php_composer_install], outputs = [out_dir], command = cmd, ) @@ -85,7 +82,6 @@ php_binary = rule( attrs = { "php": attr.label(default = Label("@php_micro//:php"), allow_single_file = True, executable = True, cfg = "host"), "php_composer_install": attr.label(allow_single_file = True), - "srcs": attr.label_list(default = [Label("@gapic_generator_php//:srcs")], allow_files = True), "entry_point": attr.label(allow_single_file = True), "working_directory_flag_name": attr.string(), }, diff --git a/rules_php_gapic/php_repo.bzl b/rules_php_gapic/php_repo.bzl index 882836be6..bf745696c 100644 --- a/rules_php_gapic/php_repo.bzl +++ b/rules_php_gapic/php_repo.bzl @@ -124,7 +124,6 @@ def _find_ws_root(path): fail("Cannot find workspace root.") def _php_composer_install_impl(ctx): - ctx.read(ctx.attr.composer_json) ws_path = _find_ws_root(ctx.path(ctx.attr.composer_json).dirname) composer_json_relative = str(ctx.path(ctx.attr.composer_json))[len(str(ws_path)):] # Copy entire source workspace into the restored repo, then run `composer install`. diff --git a/rules_php_test/integration_test.bzl b/rules_php_test/integration_test.bzl deleted file mode 100644 index 92b462014..000000000 --- a/rules_php_test/integration_test.bzl +++ /dev/null @@ -1,150 +0,0 @@ -def _php_diff_integration_goldens_impl(ctx): - # Extract the Java source files from the generated 3 srcjars from API bazel target, - # and put them in the temporary folder `codegen_tmp`. - # Compare the `codegen_tmp` with the goldens folder (e.g tests/Integration/goldens/asset) - # and save the differences in output file `diff_output.txt`. - - diff_output = ctx.outputs.diff_output - check_diff_script = ctx.outputs.check_diff_script - gapic_library = ctx.attr.gapic_library - srcs = ctx.files.srcs - api_name = ctx.attr.name - - script = """ - mkdir codegen_tmp - unzip {input_srcs} -d codegen_tmp - diff -r codegen_tmp/ tests/Integration/goldens/{api_name}/ > {diff_output} - exit 0 # Avoid a build failure. - """.format( - diff_output = diff_output.path, - input_srcs = gapic_library[DefaultInfo].files.to_list()[0].path, - api_name = api_name, - ) - ctx.actions.run_shell( - inputs = srcs + [ - gapic_library[DefaultInfo].files.to_list()[0], - ], - outputs = [diff_output], - command = script, - ) - - # Check the generated diff_output file, if it is empty, that means there is no difference - # between generated source code and goldens files, test should pass. If it is not empty, then - # test will fail by exiting 1. - - check_diff_script_content = """ - # This will not print diff_output to the console unless `--test_output=all` option - # is enabled, it only emits the comparison results to the test.log. - # We could not copy the diff_output.txt to the test.log ($XML_OUTPUT_FILE) because that - # file is not existing at the moment. It is generated once test is finished. - cat $PWD/tests/Integration/{api_name}_diff_output.txt - if [ -s $PWD/tests/Integration/{api_name}_diff_output.txt ] - then - exit 1 - fi - """.format( - api_name = api_name, - ) - - ctx.actions.write( - output = check_diff_script, - content = check_diff_script_content, - ) - runfiles = ctx.runfiles(files = [ctx.outputs.diff_output]) - return [DefaultInfo(executable = check_diff_script, runfiles = runfiles)] - -php_diff_integration_goldens_test = rule( - attrs = { - "gapic_library": attr.label(), - "srcs": attr.label_list( - allow_files = True, - mandatory = True, - ), - }, - outputs = { - "diff_output": "%{name}_diff_output.txt", - "check_diff_script": "%{name}_check_diff_script.sh", - }, - implementation = _php_diff_integration_goldens_impl, - test = True, -) - -def php_integration_test(name, target, data): - # php_gapic_library generates only one srcjar. - php_diff_integration_goldens_test( - name = name, - gapic_library = target, - srcs = data, - ) - -def _php_overwrite_golden_impl(ctx): - # Extract source files from the srcjar generated from php_gapic_library into - # a temporary folder (codegen_tmp) and zip into goldens_output_zip. - # Overwrite the goldens dir (e.g tests/Integration/goldens/asset) with newly generated code. - gapic_library = ctx.attr.gapic_library - srcs = ctx.files.srcs - - # Convert the name of bazel rules e.g. `redis_update` to `redis` - # because we will need to overwrite the goldens files in `redis` folder. - api_name = "_".join(ctx.attr.name.split("_")[:-1]) - goldens_output_zip = ctx.outputs.goldens_output_zip - - script = """ - mkdir codegen_tmp - unzip {input_srcs} -d codegen_tmp - cd codegen_tmp - zip -r ../{goldens_output_zip} . - """.format( - goldens_output_zip = goldens_output_zip.path, - input_srcs = gapic_library[DefaultInfo].files.to_list()[0].path, - ) - - ctx.actions.run_shell( - inputs = srcs + [ - gapic_library[DefaultInfo].files.to_list()[0], - ], - outputs = [goldens_output_zip], - command = script, - ) - - # Overwrite the goldens. - golden_update_script_content = """ - cd ${{BUILD_WORKSPACE_DIRECTORY}} - # Filename pattern-based removal is needed to preserve the BUILD.bazel file. - find tests/Integration/goldens/{api_name}/ -name \\*.txt -type f -delete - find tests/Integration/goldens/{api_name}/ -name \\*.php -type f -delete - find tests/Integration/goldens/{api_name}/ -name \\*.json -type f -delete - unzip -ao {goldens_output_zip} -d tests/Integration/goldens/{api_name} - """.format( - goldens_output_zip = goldens_output_zip.path, - api_name = api_name, - ) - ctx.actions.write( - output = ctx.outputs.golden_update_script, - content = golden_update_script_content, - is_executable = True, - ) - return [DefaultInfo(executable = ctx.outputs.golden_update_script)] - -php_overwrite_golden = rule( - attrs = { - "gapic_library": attr.label(), - "srcs": attr.label_list( - allow_files = True, - mandatory = True, - ), - }, - outputs = { - "goldens_output_zip": "%{name}.zip", - "golden_update_script": "%{name}.sh", - }, - executable = True, - implementation = _php_overwrite_golden_impl, -) - -def php_golden_update(name, target, data): - php_overwrite_golden( - name = name, - gapic_library = target, - srcs = data, - ) diff --git a/tests/Integration/BUILD.bazel b/tests/Integration/BUILD.bazel deleted file mode 100644 index 2bf381f02..000000000 --- a/tests/Integration/BUILD.bazel +++ /dev/null @@ -1,611 +0,0 @@ -load( - "@gapic_generator_php//rules_php_gapic:php_gapic.bzl", - "php_gapic_library", - "php_grpc_library", - "php_proto_library", -) -load( - "@gapic_generator_php//rules_php_gapic:php_gapic_pkg.bzl", - "php_gapic_assembly_pkg", -) -load("@rules_gapic//:gapic.bzl", "proto_library_with_info") -load("//:rules_php_test/integration_test.bzl", "php_golden_update", "php_integration_test") -load("@rules_proto//proto:defs.bzl", "proto_library") - -#################################################### -# Integration Test Rules -#################################################### -INTEGRATION_TEST_LIBRARIES = [ - "asset", # Basic case. - "compute_small", # REGAPIC. - "container", # RPCs with more than one routing header. - "dataproc", # RPCs with additional_bindings in the HTTP annotation. - "functions", # RPCs with HTTP variables that fall into the edge case. - "kms", # Mixins. - "iam", # Standalone service that's in the mixin allowlist. - "logging", # Singleton resource names. - "redis", # sample_code field in gapic.yaml. - "retail", # ALpha. - "spanner", # Emulator support. - "speech", # sample_code field in gapic.yaml. - "securitycenter", # Exercises pathTemplateMap. - "talent", # Beta; path template and duplicate name template properties. - "videointelligence", # sample_code field in gapic.yaml. -] - -[php_integration_test( - name = lib_name, - data = ["//tests/Integration/goldens/%s:goldens_files" % lib_name], - target = "%s_php_gapic" % lib_name, -) for lib_name in INTEGRATION_TEST_LIBRARIES] - -[php_golden_update( - name = "%s_update" % lib_name, - data = ["//tests/Integration/goldens/%s:goldens_files" % lib_name], - target = "%s_php_gapic" % lib_name, -) for lib_name in INTEGRATION_TEST_LIBRARIES] - -#################################################### -# API Library Rules -#################################################### -# proto_library, grpc_library, and gapic_library rule redefinitions will eventually go away -# once more APIs in googleapis have been migrated to the microgenerator. - -# Asset API - basic case. -php_proto_library( - name = "asset_php_proto", - deps = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], -) - -php_grpc_library( - name = "asset_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], - deps = [":asset_php_proto"], -) - -php_gapic_library( - name = "asset_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/asset/v1:cloudasset_grpc_service_config.json", - rest_numeric_enums = True, - deps = [ - ":asset_php_grpc", - ":asset_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-asset-v1-php", - deps = [ - ":asset_php_gapic", - ":asset_php_grpc", - ":asset_php_proto", - ], -) - -# GCE REGAPIC. -proto_library( - name = "compute_small_proto", - srcs = [ - "apis/compute_small/v1/compute_small.proto", - ], - deps = [ - "@com_google_googleapis//google/api:annotations_proto", - "@com_google_googleapis//google/api:client_proto", - "@com_google_googleapis//google/api:field_behavior_proto", - "@com_google_googleapis//google/api:resource_proto", - "@com_google_googleapis//google/longrunning:operations_proto", - "@com_google_googleapis//google/cloud:extended_operations_proto", - "@com_google_protobuf//:descriptor_proto", - ], -) - -proto_library_with_info( - name = "compute_small_proto_with_info", - deps = [ - ":compute_small_proto", - "@com_google_googleapis//google/cloud:common_resources_proto", - ], -) - -php_proto_library( - name = "compute_small_php_proto", - deps = [":compute_small_proto"], -) - -php_grpc_library( - name = "compute_small_php_grpc", - srcs = [":compute_small_proto"], - deps = [":compute_small_php_proto"], -) - -php_gapic_library( - name = "compute_small_php_gapic", - srcs = [":compute_small_proto_with_info"], - service_yaml = "apis/compute_small/v1/compute_small_v1.yaml", - transport = "rest", - deps = [ - ":compute_small_php_grpc", - ":compute_small_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-compute-small-v1-php", - deps = [ - ":compute_small_php_gapic", - ":compute_small_php_grpc", - ":compute_small_php_proto", - ], -) - -# Container - RPCs with more than one routing header. -php_proto_library( - name = "container_php_proto", - deps = ["@com_google_googleapis//google/container/v1:container_proto"], -) - -php_grpc_library( - name = "container_php_grpc", - srcs = ["@com_google_googleapis//google/container/v1:container_proto"], - deps = [":container_php_proto"], -) - -php_gapic_library( - name = "container_php_gapic", - srcs = ["@com_google_googleapis//google/container/v1:container_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/container/v1:container_grpc_service_config.json", - deps = [ - ":container_php_grpc", - ":container_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-container-v1-php", - deps = [ - ":container_php_gapic", - ":container_php_grpc", - ":container_php_proto", - ], -) - -# Dataproc - RPCs with additional_bindings in the HTTP annotations. -php_proto_library( - name = "dataproc_php_proto", - deps = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto"], -) - -php_grpc_library( - name = "dataproc_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto"], - deps = [":dataproc_php_proto"], -) - -php_gapic_library( - name = "dataproc_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto_with_info"], - gapic_yaml = "apis/dataproc/v1/dataproc_gapic.yaml", - grpc_service_config = "@com_google_googleapis//google/cloud/dataproc/v1:dataproc_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/dataproc/v1:dataproc_v1.yaml", - deps = [ - ":dataproc_php_grpc", - ":dataproc_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-dataproc-v1-php", - deps = [ - ":dataproc_php_gapic", - ":dataproc_php_grpc", - ":dataproc_php_proto", - ], -) - -# Functions. -php_proto_library( - name = "functions_php_proto", - deps = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto"], -) - -php_grpc_library( - name = "functions_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto"], - deps = [":functions_php_proto"], -) - -php_gapic_library( - name = "functions_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/functions/v1:functions_grpc_service_config.json", - deps = [ - ":functions_php_grpc", - ":functions_php_proto", - ], -) - -# Open Source Packages -php_gapic_assembly_pkg( - name = "google-cloud-functions-v1-php", - deps = [ - ":functions_php_gapic", - ":functions_php_grpc", - ":functions_php_proto", - ], -) - -# Logging - singleton resource names. -php_proto_library( - name = "logging_php_proto", - deps = ["@com_google_googleapis//google/logging/v2:logging_proto"], -) - -php_grpc_library( - name = "logging_php_grpc", - srcs = ["@com_google_googleapis//google/logging/v2:logging_proto"], - deps = [":logging_php_proto"], -) - -php_gapic_library( - name = "logging_php_gapic", - srcs = ["@com_google_googleapis//google/logging/v2:logging_proto_with_info"], - # For batching. - gapic_yaml = "@com_google_googleapis//google/logging/v2:logging_gapic.yaml", - grpc_service_config = "@com_google_googleapis//google/logging/v2:logging_grpc_service_config.json", - deps = [ - ":logging_php_grpc", - ":logging_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-logging-v1-php", - deps = [ - ":logging_php_gapic", - ":logging_php_grpc", - ":logging_php_proto", - ], -) - -# Securitycenter. -php_proto_library( - name = "securitycenter_php_proto", - deps = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto"], -) - -php_grpc_library( - name = "securitycenter_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto"], - deps = [":securitycenter_php_proto"], -) - -php_gapic_library( - name = "securitycenter_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_v1.yaml", - deps = [ - ":securitycenter_php_grpc", - ":securitycenter_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-securitycenter-v1beta1-php", - deps = [ - ":securitycenter_php_gapic", - ":securitycenter_php_grpc", - ":securitycenter_php_proto", - ], -) - -# Speech - sample_code. -php_proto_library( - name = "speech_php_proto", - deps = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto"], -) - -php_grpc_library( - name = "speech_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto"], - deps = [":speech_php_proto"], -) - -php_gapic_library( - name = "speech_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/speech/v1:speech_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/speech/v1:speech_v1.yaml", - deps = [ - ":speech_php_grpc", - ":speech_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-speech-v1-php", - deps = [ - ":speech_php_gapic", - ":speech_php_grpc", - ":speech_php_proto", - ], -) - -# Redis - sample code. -php_proto_library( - name = "redis_php_proto", - deps = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto"], -) - -php_grpc_library( - name = "redis_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto"], - deps = [":redis_php_proto"], -) - -php_gapic_library( - name = "redis_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto_with_info"], - gapic_yaml = "apis/redis/v1/redis_gapic.yaml", - grpc_service_config = "@com_google_googleapis//google/cloud/redis/v1:redis_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/redis/v1:redis_v1.yaml", - transport = "grpc", - deps = [ - ":redis_php_grpc", - ":redis_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-redis-v1-php", - deps = [ - ":redis_php_gapic", - ":redis_php_grpc", - ":redis_php_proto", - ], -) - -# Retail - Alpha. -php_proto_library( - name = "retail_php_proto", - deps = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto"], -) - -php_grpc_library( - name = "retail_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto"], - deps = [":retail_php_proto"], -) - -php_gapic_library( - name = "retail_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/retail/v2alpha:retail_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/retail/v2alpha:retail_v2alpha.yaml", - deps = [ - ":retail_php_grpc", - ":retail_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-retail-v2alpha-php", - deps = [ - ":retail_php_gapic", - ":retail_php_grpc", - ":retail_php_proto", - ], -) - -# Video intelligence - sample code. -php_proto_library( - name = "videointelligence_php_proto", - deps = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto"], -) - -php_grpc_library( - name = "videointelligence_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto"], - deps = [":videointelligence_php_proto"], -) - -php_gapic_library( - name = "videointelligence_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto_with_info"], - gapic_yaml = "@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_gapic.yaml", - service_yaml = "apis/videointelligence/v1/videointelligence_v1.yaml", - deps = [ - ":videointelligence_php_grpc", - ":videointelligence_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-videointelligence-v1-php", - deps = [ - ":videointelligence_php_gapic", - ":videointelligence_php_grpc", - ":videointelligence_php_proto", - ], -) - -# KMS - mixins. -proto_library( - name = "kms_proto", - srcs = [ - "apis/kms/v1/resources.proto", - "apis/kms/v1/service.proto", - ], - deps = [ - "@com_google_googleapis//google/api:annotations_proto", - "@com_google_googleapis//google/api:client_proto", - "@com_google_googleapis//google/api:field_behavior_proto", - "@com_google_googleapis//google/api:resource_proto", - "@com_google_googleapis//google/cloud/location:location_proto", - "@com_google_googleapis//google/iam/v1:iam_policy_proto", - "@com_google_googleapis//google/iam/v1:policy_proto", - "@com_google_protobuf//:duration_proto", - "@com_google_protobuf//:field_mask_proto", - "@com_google_protobuf//:struct_proto", - "@com_google_protobuf//:timestamp_proto", - "@com_google_protobuf//:wrappers_proto", - ], -) - -proto_library_with_info( - name = "kms_proto_with_info", - deps = [ - ":kms_proto", - "@com_google_googleapis//google/cloud:common_resources_proto", - "@com_google_googleapis//google/cloud/location:location_proto", - "@com_google_googleapis//google/iam/v1:iam_policy_proto", - "@com_google_googleapis//google/iam/v1:policy_proto", - ], -) - -php_proto_library( - name = "kms_php_proto", - deps = [":kms_proto"], -) - -php_grpc_library( - name = "kms_php_grpc", - srcs = [":kms_proto"], - deps = [":kms_php_proto"], -) - -php_gapic_library( - name = "kms_php_gapic", - srcs = [":kms_proto_with_info"], - grpc_service_config = "apis/kms/v1/cloudkms_grpc_service_config.json", - # For the IAM mixin. - service_yaml = "apis/kms/v1/cloudkms_test_mixins_v1.yaml", - deps = [ - ":kms_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-kms-v1-php", - deps = [ - ":kms_php_gapic", - ":kms_php_grpc", - ":kms_php_proto", - ], -) - -# IAM - standalone mixed-in proto. -php_proto_library( - name = "iam_php_proto", - deps = [ - "@com_google_googleapis//google/iam/v1:iam_policy_proto", - "@com_google_googleapis//google/iam/v1:options_proto", - "@com_google_googleapis//google/iam/v1:policy_proto", - ], -) - -php_grpc_library( - name = "iam_php_grpc", - srcs = ["@com_google_googleapis//google/iam/v1:iam_policy_proto"], - deps = [":iam_php_proto"], -) - -php_gapic_library( - name = "iam_php_gapic", - srcs = ["@com_google_googleapis//google/iam/v1:iam_proto_with_info"], - gapic_yaml = "apis/iam/v1/iam_gapic.yaml", - service_yaml = "apis/iam/v1/iam_api.yaml", - deps = [ - ":iam_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-iam-v1-php", - deps = [ - ":iam_php_gapic", - ":iam_php_grpc", - ":iam_php_proto", - ], -) - -# Talent. -php_proto_library( - name = "talent_php_proto", - deps = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto"], -) - -php_grpc_library( - name = "talent_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto"], - deps = [":talent_php_proto"], -) - -php_gapic_library( - name = "talent_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/talent/v4beta1:talent_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/talent/v4beta1:jobs_v4beta1.yaml", - deps = [ - ":talent_php_grpc", - ":talent_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-talent-v4beta1-php", - deps = [ - ":talent_php_gapic", - ":talent_php_grpc", - ":talent_php_proto", - ], -) - -proto_library( - name = "compliance_proto", - srcs = [ - ":compliance.proto", - ], - deps = [ - "@com_google_googleapis//google/api:annotations_proto", - "@com_google_googleapis//google/api:client_proto", - ], -) - -php_proto_library( - name = "compliance_php_proto", - deps = [":compliance_proto"], -) - -# Spanner - Emulator support. -php_proto_library( - name = "spanner_php_proto", - deps = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto"], -) - -php_grpc_library( - name = "spanner_php_grpc", - srcs = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto"], - deps = [":spanner_php_proto"], -) - -php_gapic_library( - name = "spanner_php_gapic", - srcs = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto_with_info"], - service_yaml = "@com_google_googleapis//google/spanner/admin/database/v1:spanner.yaml", - rest_numeric_enums = True, - deps = [ - ":spanner_php_grpc", - ":spanner_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-spanner-admin-database-v1-php", - deps = [ - ":spanner_php_gapic", - ":spanner_php_grpc", - ":spanner_php_proto", - ], -) diff --git a/tests/Integration/GoldenUpdateMain.php b/tests/Integration/GoldenUpdateMain.php new file mode 100644 index 000000000..f29344010 --- /dev/null +++ b/tests/Integration/GoldenUpdateMain.php @@ -0,0 +1,78 @@ + sprintf("%d: '%s'", $idx + 1, $name), + $names, + array_keys($names) + )); + + while ($selection < 0 || $selection > count($names)) { + print("============ Integration tests ==========\n$optionString\n\nSelect golden to update (0 for all): "); + fscanf(STDIN, "%d\n", $selection); + } + + if ($selection !== 0) { + self::updateGolden($names[$selection - 1]); + } else { + foreach ($names as $name) { + self::updateGolden($name); + print("\n"); + } + } + return 0; + } + + private static function updateGolden(string $name): void + { + print("Updating integration goldens for {$name}\n"); + $codeIterator = GeneratorUtils::generateIntegration(IntegrationTest::TESTS[$name]); + UnitGoldenUpdater::writeGoldens($codeIterator, __DIR__ . '/goldens/' . $name); + print("\n"); + } +} + +if (isset($argv) && realpath($argv[0]) === __FILE__) { + $selection = $argv[1] ?? -1; + GoldenUpdateMain::update($selection); +} diff --git a/tests/Integration/IntegrationTest.php b/tests/Integration/IntegrationTest.php new file mode 100644 index 000000000..82ee895bc --- /dev/null +++ b/tests/Integration/IntegrationTest.php @@ -0,0 +1,147 @@ + [ + 'protoDir' => 'googleapis/google/cloud/asset/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/asset/v1/cloudasset_grpc_service_config.json', + 'numericEnums' => true, + ], + 'compute_small' => [ + 'protoDir' => 'tests/Integration/apis/compute_small/v1', + 'serviceYaml' => 'tests/Integration/apis/compute_small/v1/compute_small_v1.yaml', + 'transport' => 'rest', + ], + 'container' => [ + 'protoDir' => 'googleapis/google/container/v1', + 'grpcServiceConfig' => 'googleapis/google/container/v1/container_grpc_service_config.json', + ], + 'dataproc' => [ + 'protoDir' => 'googleapis/google/cloud/dataproc/v1', + 'gapicYaml' => 'tests/Integration/apis/dataproc/v1/dataproc_gapic.yaml', + 'grpcServiceConfig' => 'googleapis/google/cloud/dataproc/v1/dataproc_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/dataproc/v1/dataproc_v1.yaml', + ], + 'functions' => [ + 'protoDir' => 'googleapis/google/cloud/functions/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/functions/v1/functions_grpc_service_config.json', + ], + 'kms' => [ + 'protoDir' => 'tests/Integration/apis/kms/v1', + 'grpcServiceConfig' => 'tests/Integration/apis/kms/v1/cloudkms_grpc_service_config.json', + 'serviceYaml' => 'tests/Integration/apis/kms/v1/cloudkms_test_mixins_v1.yaml', + ], + 'iam' => [ + 'protoDir' => 'googleapis/google/iam/v1', + 'gapicYaml' => 'tests/Integration/apis/iam/v1/iam_gapic.yaml', + 'serviceYaml' => 'tests/Integration/apis/iam/v1/iam_api.yaml', + ], + 'logging' => [ + 'protoDir' => 'googleapis/google/logging/v2', + 'gapicYaml' => 'googleapis/google/logging/v2/logging_gapic.yaml', + 'grpcServiceConfig' => 'googleapis/google/logging/v2/logging_grpc_service_config.json', + ], + 'redis' => [ + 'protoDir' => 'googleapis/google/cloud/redis/v1', + 'gapicYaml' => 'tests/Integration/apis/redis/v1/redis_gapic.yaml', + 'grpcServiceConfig' => 'googleapis/google/cloud/redis/v1/redis_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/redis/v1/redis_v1.yaml', + 'transport' => 'grpc', + ], + 'retail' => [ + 'protoDir' => 'googleapis/google/cloud/retail/v2alpha', + 'grpcServiceConfig' => 'googleapis/google/cloud/retail/v2alpha/retail_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/retail/v2alpha/retail_v2alpha.yaml', + ], + 'spanner' => [ + 'protoDir' => 'googleapis/google/spanner/admin/database/v1', + 'serviceYaml' => 'googleapis/google/spanner/admin/database/v1/spanner.yaml', + 'numericEnums' => true, + ], + 'speech' => [ + 'protoDir' => 'googleapis/google/cloud/speech/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/speech/v1/speech_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/speech/v1/speech_v1.yaml', + ], + 'securitycenter' => [ + 'protoDir' => 'googleapis/google/cloud/securitycenter/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/securitycenter/v1/securitycenter_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/securitycenter/v1/securitycenter_v1.yaml', + ], + 'talent' => [ + 'protoDir' => 'googleapis/google/cloud/talent/v4beta1', + 'grpcServiceConfig' => 'googleapis/google/cloud/talent/v4beta1/talent_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/talent/v4beta1/jobs_v4beta1.yaml', + ], + 'videointelligence' => [ + 'protoDir' => 'googleapis/google/cloud/videointelligence/v1', + 'gapicYaml' => 'googleapis/google/cloud/videointelligence/v1/videointelligence_gapic.yaml', + 'serviceYaml' => 'tests/Integration/apis/videointelligence/v1/videointelligence_v1.yaml', + ], + ]; + + public function provideIntegrationTests(): array + { + $cases = []; + foreach (array_keys(self::TESTS) as $name) { + $cases[$name] = [$name]; + } + return $cases; + } + + /** + * @dataProvider provideIntegrationTests + */ + public function testIntegration(string $name): void + { + $codeIterator = GeneratorUtils::generateIntegration(self::TESTS[$name]); + $goldenDir = __DIR__ . '/goldens/' . $name . '/'; + $files = iterator_to_array( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( + $goldenDir, + FilesystemIterator::SKIP_DOTS + ) + ) + ); + + foreach ($codeIterator as [$relativeFilename, $code]) { + $filename = $goldenDir . $relativeFilename; + $this->assertTrue(file_exists($filename), "Expected code file missing: '{$filename}'"); + $expectedCode = file_get_contents($filename); + $this->assertEquals($expectedCode, $code, str_replace(__DIR__ . '/', '', $filename)); + unset($files[$filename]); + } + + $this->assertEmpty( + $files, + 'The following expected files were not generated: ' . + print_r(array_keys($files), true) + ); + } +} diff --git a/tests/Integration/goldens/asset/BUILD.bazel b/tests/Integration/goldens/asset/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/asset/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/compute_small/BUILD.bazel b/tests/Integration/goldens/compute_small/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/compute_small/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/container/BUILD.bazel b/tests/Integration/goldens/container/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/container/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/dataproc/BUILD.bazel b/tests/Integration/goldens/dataproc/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/dataproc/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/functions/BUILD.bazel b/tests/Integration/goldens/functions/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/functions/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/iam/BUILD.bazel b/tests/Integration/goldens/iam/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/iam/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/kms/BUILD.bazel b/tests/Integration/goldens/kms/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/kms/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/logging/BUILD.bazel b/tests/Integration/goldens/logging/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/logging/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/redis/BUILD.bazel b/tests/Integration/goldens/redis/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/redis/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/retail/BUILD.bazel b/tests/Integration/goldens/retail/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/retail/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/securitycenter/BUILD.bazel b/tests/Integration/goldens/securitycenter/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/securitycenter/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/spanner/BUILD.bazel b/tests/Integration/goldens/spanner/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/spanner/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/speech/BUILD.bazel b/tests/Integration/goldens/speech/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/speech/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/talent/BUILD.bazel b/tests/Integration/goldens/talent/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/talent/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/videointelligence/BUILD.bazel b/tests/Integration/goldens/videointelligence/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/videointelligence/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Tools/GeneratorUtils.php b/tests/Tools/GeneratorUtils.php index fa85e3b29..bcd4aa59e 100644 --- a/tests/Tools/GeneratorUtils.php +++ b/tests/Tools/GeneratorUtils.php @@ -19,6 +19,8 @@ namespace Google\Generator\Tests\Tools; use Google\Generator\CodeGenerator; +use Google\Generator\Collections\Vector; +use Google\Protobuf\Internal\FileDescriptorSet; class GeneratorUtils { @@ -66,4 +68,42 @@ public static function generateFromProto( ); return $codeIterator; } + + /** + * Runs the generator for an integration test configuration and returns the produced sources. + * + * @param array $config Integration test configuration. + * + * @return array[] [0] (string) is relative path; [1] (string) is file content. + */ + public static function generateIntegration(array $config): array + { + $protos = glob($config['protoDir'] . '/*.proto'); + $extraProtos = [ + 'googleapis/google/cloud/common_resources.proto', + 'googleapis/google/cloud/location/locations.proto', + 'googleapis/google/iam/v1/iam_policy.proto', + 'googleapis/google/iam/v1/policy.proto', + 'googleapis/google/iam/v1/options.proto', + ]; + $allProtos = array_values(array_unique(array_merge($protos, $extraProtos))); + $filesToGenerate = array_map(fn ($p) => preg_replace('#^googleapis/#', '', $p), $allProtos); + $descBytes = ProtoLoader::loadDescriptorBytesFromPaths($allProtos); + $descSet = new FileDescriptorSet(); + $descSet->mergeFromString($descBytes); + $fileDescs = Vector::new($descSet->getFile()); + + return CodeGenerator::generate( + $fileDescs, + Vector::new($filesToGenerate), + $config['transport'] ?? 'grpc+rest', + true, + isset($config['grpcServiceConfig']) ? file_get_contents($config['grpcServiceConfig']) : null, + isset($config['gapicYaml']) ? file_get_contents($config['gapicYaml']) : null, + isset($config['serviceYaml']) ? file_get_contents($config['serviceYaml']) : null, + $config['numericEnums'] ?? false, + 2026, // Avoid updating tests all the time. + true, + ); + } } diff --git a/tests/Tools/ProtoLoader.php b/tests/Tools/ProtoLoader.php index fdd2284a5..ce68ea1b8 100644 --- a/tests/Tools/ProtoLoader.php +++ b/tests/Tools/ProtoLoader.php @@ -33,9 +33,21 @@ class ProtoLoader * @return string */ public static function loadDescriptorBytes(string $protoPath): string + { + return static::loadDescriptorBytesFromPaths(["tests/Unit/{$protoPath}"]); + } + + /** + * Load descriptor set bytes from the specified proto paths relative to the repo root directory. + * + * @param string[] $protoPaths The proto paths relative to the repo root directory. + * + * @return string + */ + public static function loadDescriptorBytesFromPaths(array $protoPaths): string { // Set up required file locations and create tmp output file for protoc invocation. - // Assumes test are executed from within the repo root directory. + // Assumes tests are executed from within the repo root directory. $cwd = getcwd(); $protoc = "protoc"; $useToolsProtoc = getenv("USE_TOOLS_PROTOC"); @@ -44,12 +56,12 @@ public static function loadDescriptorBytes(string $protoPath): string } $descRes = tmpfile(); $descFilename = stream_get_meta_data($descRes)['uri']; - $input = "{$cwd}/tests/Unit/{$protoPath}"; + $inputs = implode(' ', array_map(fn ($path) => escapeshellarg("{$cwd}/{$path}"), $protoPaths)); // Invoke protoc to build the descriptor of the test proto. $protobuf = "{$cwd}/protobuf/src/"; $googleapis = "{$cwd}/googleapis/"; $protocCmdLine = "{$protoc} --include_imports --include_source_info -o {$descFilename} " . - "-I {$googleapis} -I {$protobuf} -I {$cwd} {$input} 2>&1"; + "-I {$googleapis} -I {$protobuf} -I {$cwd} {$inputs} 2>&1"; $output = []; $result = -1; exec($protocCmdLine, $output, $result); diff --git a/tests/Unit/ProtoTests/UnitGoldenUpdater.php b/tests/Unit/ProtoTests/UnitGoldenUpdater.php index 5d4cce2de..48fc75aa7 100644 --- a/tests/Unit/ProtoTests/UnitGoldenUpdater.php +++ b/tests/Unit/ProtoTests/UnitGoldenUpdater.php @@ -35,6 +35,11 @@ public function update( $generateSnippets, ); $outputPath = __DIR__ . '/' . dirname($protoPath) . '/out'; + static::writeGoldens($codeIterator, $outputPath); + } + + public static function writeGoldens(iterable $codeIterator, string $outputPath): void + { // Delete everything from the directory. if (is_dir($outputPath)) { $fileSysObjects = scandir($outputPath); diff --git a/tests/scripts/run_bazel_tests.sh b/tests/scripts/run_bazel_tests.sh deleted file mode 100755 index 3e9805c34..000000000 --- a/tests/scripts/run_bazel_tests.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# Usage: ./run_bazel_tests.sh - -# This runs the bazel test commands, ex: -# bazel test //tests/Integration:asset && \ -# bazel test //tests/Integration:compute_small -# etc - -echo "Running bazel tests" - -BAZELISK_CMD="bazelisk" - -$BAZELISK_CMD test //tests/Integration:asset && \ -$BAZELISK_CMD test //tests/Integration:compute_small && \ -$BAZELISK_CMD test //tests/Integration:container && \ -$BAZELISK_CMD test //tests/Integration:dataproc && \ -$BAZELISK_CMD test //tests/Integration:functions && \ -$BAZELISK_CMD test //tests/Integration:kms && \ -$BAZELISK_CMD test //tests/Integration:iam && \ -$BAZELISK_CMD test //tests/Integration:logging && \ -$BAZELISK_CMD test //tests/Integration:redis && \ -$BAZELISK_CMD test //tests/Integration:retail && \ -$BAZELISK_CMD test //tests/Integration:speech && \ -$BAZELISK_CMD test //tests/Integration:securitycenter && \ -$BAZELISK_CMD test //tests/Integration:talent && \ -$BAZELISK_CMD test //tests/Integration:videointelligence diff --git a/tests/scripts/run_bazel_updates.sh b/tests/scripts/run_bazel_updates.sh deleted file mode 100755 index 2014a8273..000000000 --- a/tests/scripts/run_bazel_updates.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -# Usage: ./run_bazel_updates.sh [--expunge] - -# This runs the bazel update commands, ex: -# bazel run //tests/Integration:asset_update && \ -# bazel run //tests/Integration:compute_small_update -# etc -# -# `bazel clean --expunge` is ran before the commands if the --expunge -# argument is passed - -if [ "$1" == "--expunge" ]; -then - echo "Running bazel clean --expunge" - bazelisk clean --expunge -fi - -echo "Running bazel update scripts" - -BAZEL_CMD="bazelisk" - -$BAZEL_CMD run //tests/Integration:asset_update && \ -$BAZEL_CMD run //tests/Integration:compute_small_update && \ -$BAZEL_CMD run //tests/Integration:container_update && \ -$BAZEL_CMD run //tests/Integration:dataproc_update && \ -$BAZEL_CMD run //tests/Integration:functions_update && \ -$BAZEL_CMD run //tests/Integration:kms_update && \ -$BAZEL_CMD run //tests/Integration:iam_update && \ -$BAZEL_CMD run //tests/Integration:logging_update && \ -$BAZEL_CMD run //tests/Integration:redis_update && \ -$BAZEL_CMD run //tests/Integration:retail_update && \ -$BAZEL_CMD run //tests/Integration:spanner_update && \ -$BAZEL_CMD run //tests/Integration:speech_update && \ -$BAZEL_CMD run //tests/Integration:securitycenter_update && \ -$BAZEL_CMD run //tests/Integration:talent_update && \ -$BAZEL_CMD run //tests/Integration:videointelligence_update From 1c3a7768b9af343175ba92dce3cf18c6159c3136 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 7 Oct 2026 22:02:05 +0000 Subject: [PATCH 3/5] Revert "chore: migrate integration golden tests from Bazel to PHPUnit" This reverts commit c598c8dbac92774e0fda0a86e9fae9c62b3a7933. --- .github/workflows/bazel_example.yml | 91 +++ .github/workflows/phpunit.yml | 2 +- BUILD.bazel | 11 + DEVELOPMENT.md | 69 +- composer.json | 6 +- googleapis | 2 +- phpunit.xml.dist | 4 - rules_php_gapic/php.bzl | 16 +- rules_php_gapic/php_repo.bzl | 1 + rules_php_test/integration_test.bzl | 150 +++++ tests/Integration/BUILD.bazel | 611 ++++++++++++++++++ tests/Integration/GoldenUpdateMain.php | 78 --- tests/Integration/IntegrationTest.php | 147 ----- tests/Integration/goldens/asset/BUILD.bazel | 10 + .../goldens/compute_small/BUILD.bazel | 10 + .../Integration/goldens/container/BUILD.bazel | 10 + .../Integration/goldens/dataproc/BUILD.bazel | 10 + .../Integration/goldens/functions/BUILD.bazel | 10 + tests/Integration/goldens/iam/BUILD.bazel | 10 + tests/Integration/goldens/kms/BUILD.bazel | 10 + tests/Integration/goldens/logging/BUILD.bazel | 10 + tests/Integration/goldens/redis/BUILD.bazel | 10 + tests/Integration/goldens/retail/BUILD.bazel | 10 + .../goldens/securitycenter/BUILD.bazel | 10 + tests/Integration/goldens/spanner/BUILD.bazel | 10 + tests/Integration/goldens/speech/BUILD.bazel | 10 + tests/Integration/goldens/talent/BUILD.bazel | 10 + .../goldens/videointelligence/BUILD.bazel | 10 + tests/Tools/GeneratorUtils.php | 40 -- tests/Tools/ProtoLoader.php | 18 +- tests/Unit/ProtoTests/UnitGoldenUpdater.php | 5 - tests/scripts/run_bazel_tests.sh | 27 + tests/scripts/run_bazel_updates.sh | 37 ++ 33 files changed, 1148 insertions(+), 317 deletions(-) create mode 100644 .github/workflows/bazel_example.yml create mode 100644 rules_php_test/integration_test.bzl create mode 100644 tests/Integration/BUILD.bazel delete mode 100644 tests/Integration/GoldenUpdateMain.php delete mode 100644 tests/Integration/IntegrationTest.php create mode 100644 tests/Integration/goldens/asset/BUILD.bazel create mode 100644 tests/Integration/goldens/compute_small/BUILD.bazel create mode 100644 tests/Integration/goldens/container/BUILD.bazel create mode 100644 tests/Integration/goldens/dataproc/BUILD.bazel create mode 100644 tests/Integration/goldens/functions/BUILD.bazel create mode 100644 tests/Integration/goldens/iam/BUILD.bazel create mode 100644 tests/Integration/goldens/kms/BUILD.bazel create mode 100644 tests/Integration/goldens/logging/BUILD.bazel create mode 100644 tests/Integration/goldens/redis/BUILD.bazel create mode 100644 tests/Integration/goldens/retail/BUILD.bazel create mode 100644 tests/Integration/goldens/securitycenter/BUILD.bazel create mode 100644 tests/Integration/goldens/spanner/BUILD.bazel create mode 100644 tests/Integration/goldens/speech/BUILD.bazel create mode 100644 tests/Integration/goldens/talent/BUILD.bazel create mode 100644 tests/Integration/goldens/videointelligence/BUILD.bazel create mode 100755 tests/scripts/run_bazel_tests.sh create mode 100755 tests/scripts/run_bazel_updates.sh diff --git a/.github/workflows/bazel_example.yml b/.github/workflows/bazel_example.yml new file mode 100644 index 000000000..f3e5a0b1c --- /dev/null +++ b/.github/workflows/bazel_example.yml @@ -0,0 +1,91 @@ +permissions: + contents: read + +name: Bazel Build + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-24.04 + container: gcr.io/gapic-images/googleapis@sha256:10f630423413f9138bd68c71f87c4734b9eeaba040675162c2a0b38410b0effc + + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + submodules: 'recursive' + persist-credentials: false + + - name: Bazel File Cache Setup + id: cache-bazel + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 + with: + path: ~/.cache/bazel + key: ${{ runner.os }}-bazel-20210105-${{ secrets.CACHE_VERSION }} + + - name: Bazel Cache Not Found + if: steps.cache-bazel.outputs.cache-hit != 'true' + run: | + echo "No cache found." + - name: Bazel Cache Found + if: steps.cache-bazel.outputs.cache-hit == 'true' + run: | + echo -n "Cache found. Cache size: " + du -sh ~/.cache/bazel + echo "If the cache seems broken, update the CACHE_VERSION secret in" + echo "https://github.com/googleapis/gapic-generator-php/settings/secrets/actions" + echo "(use any random string, any GUID will work)" + echo "and it will start over with a clean cache." + echo "The old one will disappear after 7 days." + + - name: Show bazel version + run: | + bazel --version + + #- name: Build example package; all targets + # run: | + # cd bazel_example; + # bazel build ... + + #- name: Extract Bazel package output + # run: | + # cd bazel_example; + # tar -xf ./bazel-bin/example_php_pkg.tar.gz + + ## grep returns 1 if no matches are found; and 0 if >0 matches are found. + #- name: Verify grpc_service_config.json was honoured + # run: | + # grep '"timeout_millis": 942000' ./bazel_example/example_php_pkg/src/resources/example_client_config.json +# + #- name: Verify gapic.yaml was honoured + # run: | + # grep "'initialPollDelayMillis' => '42042'" ./bazel_example/example_php_pkg/src/resources/example_descriptor_config.php + + - name: Integration Tests + run: | + bazel --batch test tests/Integration:asset \ + tests/Integration:compute_small \ + tests/Integration:container \ + tests/Integration:dataproc \ + tests/Integration:functions \ + tests/Integration:kms \ + tests/Integration:iam \ + tests/Integration:logging \ + tests/Integration:redis \ + tests/Integration:retail \ + tests/Integration:speech \ + tests/Integration:securitycenter \ + tests/Integration:talent \ + tests/Integration:videointelligence --noshow_progress --cache_test_results=no --test_output=errors + + - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + if: ${{ failure() }} + with: + name: test-artifacts + path: ~/.cache/bazel/*/*/*/*/bazel-out/*/testlogs/* + retention-days: 5 diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 3ad433a53..10da5a93f 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -31,4 +31,4 @@ jobs: composer dump-autoload; - name: Run tests - run: USE_TOOLS_PROTOC=true ./vendor/bin/phpunit + run: USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit diff --git a/BUILD.bazel b/BUILD.bazel index f551edcf3..c479c9f29 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -11,3 +11,14 @@ # 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. + +exports_files(["composer.json"]) + +filegroup( + name = "srcs", + srcs = glob([ + "src/**", + "generated/**", + ]) + ["composer.json"], + visibility = ["//visibility:public"], +) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index d61ba95b3..e4c06f36b 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -64,29 +64,52 @@ We'll be using **PHP 7.4** for the setup. ## Running tests -- All tests (unit and integration) +- Unit tests ``` - ./vendor/bin/phpunit + ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit ``` If you do not have `protoc` installed, run with `USE_TOOLS_PROTOC=true`. ``` - USE_TOOLS_PROTOC=true ./vendor/bin/phpunit + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit ``` This uses the Linux-only `protoc` binary checked into the repository. If you run into an error: `Error: Call to undefined function Google\Protobuf\Internal\bccomp()`, that is because the [BC Math](https://www.php.net/manual/en/book.bc.php) extension is not always included by default (see tracking bug here: https://github.com/protocolbuffers/protobuf/issues/4465). You can get around this by installing BC Math with the command `sudo apt install php-bcmath`. -- Running a specific test suite or integration case: +- Bazel integration tests. - ``` - USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Unit Tests" - USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Integration Tests" - USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Integration Tests" --filter asset - ``` + - Running: + + ``` + bazel test tests/Integration:asset + ``` + + - Running all tests: + + ``` + bash tests/scripts/run_bazel_tests.sh + ``` + + _Note: Running `bazel` commands may require removing the `composer.lock` and + `vendor/` directory._ + + - Debugging in `googleapis`: + + In [`googleapis/WORKSPACE`](https://github.com/googleapis/googleapis/blob/86fa44cc5ee2136e87c312f153113d4dd8e9c4de/WORKSPACE#L397-L401), + replace the `http_archive` downloading the generator with a + `local_repository` target pointing to the locally modified version of the + generator: + + ``` + local_repository( + name = "gapic_generator_php", + path = "/absolute/path/to/local/generator", + ) + ``` ## Updating tests @@ -95,7 +118,7 @@ You will need to update the golden test files if you change something in the gen - Updating unit test goldens: ``` - USE_TOOLS_PROTOC=true php tests/Unit/ProtoTests/GoldenUpdateMain.php + php tests/Unit/ProtoTests/GoldenUpdateMain.php ``` Then follow the prompts for which tests to update. @@ -105,25 +128,41 @@ You will need to update the golden test files if you change something in the gen - Updating integration test goldens: ``` - USE_TOOLS_PROTOC=true php tests/Integration/GoldenUpdateMain.php + bash tests/scripts/run_bazel_updates.sh --expunge ``` - Integration tests can be updated individually by passing a filter argument: + Integration tests can be updated individually as well: ``` - USE_TOOLS_PROTOC=true php tests/Integration/GoldenUpdateMain.php asset + bazel run tests/Integration:asset_update ``` - __NOTE__: If a new integration test case is added, make sure to add it to `TESTS` in [IntegrationTest.php](tests/Integration/IntegrationTest.php). + __NOTE__: If a new integration test case is added, make sure to add it the list in [run_bazel_tests.sh](tests/scripts/run_bazel_tests.sh) and [run_bazel_updates.sh](tests/scripts/run_bazel_updates.sh). - Update all goldens (unit and integration) Run the composer script `update-all-tests` to update all goldens at once: ``` - USE_TOOLS_PROTOC=true composer update-all-tests + composer update-all-tests ``` +## Rotating the bazel cache key + +The GitHub Actions that run the `bazel`-based integration tests hold a cache of +the build in order to speed up testing pull requests that do not impact +generated surface. If proposing a change that modifies the integration test +golden files, one must also rotate the cache key using the +[`gh` CLI](https://cli.github.com/). Use the following command before opening +your pull request: + +``` +uuidgen | gh secret set CACHE_VERSION -r https://github.com/googleapis/gapic-generator-php +``` + +If you don't have the proper permissions to rotate the cache key, request that +the reviewers do so and rerun the Action checks. + ## Updating the `googleapis` submodule To update the `googleapis` submodule, change into the directory and pull: diff --git a/composer.json b/composer.json index eb6c24f95..86dbdc72f 100644 --- a/composer.json +++ b/composer.json @@ -49,16 +49,12 @@ "scripts": { "update-all-tests": [ "Google\\Generator\\Tests\\Unit\\ProtoTests\\GoldenUpdateMain::updateAll", - "Google\\Generator\\Tests\\Integration\\GoldenUpdateMain::updateAll" + "bash tests/scripts/run_bazel_updates.sh --expunge" ] }, "config": { "platform": { "php": "8.2" - }, - "allow-plugins": { - "php-http/discovery": false, - "tbachert/spi": false } } } diff --git a/googleapis b/googleapis index 9841522f9..d931df43c 160000 --- a/googleapis +++ b/googleapis @@ -1 +1 @@ -Subproject commit 9841522f92c6542aad0049d98721cba04f541f29 +Subproject commit d931df43c4686be708ddfee74ee3be64571af0a2 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 3abf16029..cd920d048 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,10 +15,6 @@ ./tests/Unit - - ./tests/Integration - ./tests/Integration/goldens - diff --git a/rules_php_gapic/php.bzl b/rules_php_gapic/php.bzl index 19c50e54e..47eb2aa6a 100644 --- a/rules_php_gapic/php.bzl +++ b/rules_php_gapic/php.bzl @@ -16,25 +16,28 @@ def _php_binary_impl(ctx): run_name = "{}_run.sh".format(ctx.attr.name) out_dir = ctx.actions.declare_directory("out") out_run_sh = ctx.actions.declare_file(run_name) - entry_point_relative = ctx.file.entry_point.path[len(ctx.attr.entry_point.label.workspace_root):].strip("/") + ws_root = ctx.attr.entry_point.label.workspace_root + entry_point_relative = ctx.file.entry_point.path[len(ws_root):].strip("/") # I don't understand why this is required: entry_point_relative = entry_point_relative[len("rules_php_gapic/"):] # PHP files must be copied, as the PHP __DIR__ constant is incorrect if the src file is symlinked. - # Ideally this would cp with everything being symlinks except php files. - # However that's difficult, so copy every thing; using tar as this allows excluding of directories. + # Copy vendor/ from the composer install repo and source files from the workspace so that + # changes to src/ invalidate the Bazel action cache. cmd = """ DEST="$(pwd)/{out_dir_path}/install" mkdir "$DEST" -cd '{install_path}' -tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json | (cd "$DEST" && tar xf -) +(cd '{install_path}' && tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json) | (cd "$DEST" && tar xf -) +rm -rf "$DEST/src" "$DEST/generated" +(cd '{ws_root}' && tar cf - --dereference src/ generated/ composer.json) | (cd "$DEST" && tar xf -) """.format( install_path = ctx.file.php_composer_install.path, out_dir_path = out_dir.path, + ws_root = ws_root if ws_root else ".", ) ctx.actions.run_shell( - inputs = [ctx.file.php_composer_install], + inputs = [ctx.file.php_composer_install] + ctx.files.srcs, outputs = [out_dir], command = cmd, ) @@ -82,6 +85,7 @@ php_binary = rule( attrs = { "php": attr.label(default = Label("@php_micro//:php"), allow_single_file = True, executable = True, cfg = "host"), "php_composer_install": attr.label(allow_single_file = True), + "srcs": attr.label_list(default = [Label("@gapic_generator_php//:srcs")], allow_files = True), "entry_point": attr.label(allow_single_file = True), "working_directory_flag_name": attr.string(), }, diff --git a/rules_php_gapic/php_repo.bzl b/rules_php_gapic/php_repo.bzl index bf745696c..882836be6 100644 --- a/rules_php_gapic/php_repo.bzl +++ b/rules_php_gapic/php_repo.bzl @@ -124,6 +124,7 @@ def _find_ws_root(path): fail("Cannot find workspace root.") def _php_composer_install_impl(ctx): + ctx.read(ctx.attr.composer_json) ws_path = _find_ws_root(ctx.path(ctx.attr.composer_json).dirname) composer_json_relative = str(ctx.path(ctx.attr.composer_json))[len(str(ws_path)):] # Copy entire source workspace into the restored repo, then run `composer install`. diff --git a/rules_php_test/integration_test.bzl b/rules_php_test/integration_test.bzl new file mode 100644 index 000000000..92b462014 --- /dev/null +++ b/rules_php_test/integration_test.bzl @@ -0,0 +1,150 @@ +def _php_diff_integration_goldens_impl(ctx): + # Extract the Java source files from the generated 3 srcjars from API bazel target, + # and put them in the temporary folder `codegen_tmp`. + # Compare the `codegen_tmp` with the goldens folder (e.g tests/Integration/goldens/asset) + # and save the differences in output file `diff_output.txt`. + + diff_output = ctx.outputs.diff_output + check_diff_script = ctx.outputs.check_diff_script + gapic_library = ctx.attr.gapic_library + srcs = ctx.files.srcs + api_name = ctx.attr.name + + script = """ + mkdir codegen_tmp + unzip {input_srcs} -d codegen_tmp + diff -r codegen_tmp/ tests/Integration/goldens/{api_name}/ > {diff_output} + exit 0 # Avoid a build failure. + """.format( + diff_output = diff_output.path, + input_srcs = gapic_library[DefaultInfo].files.to_list()[0].path, + api_name = api_name, + ) + ctx.actions.run_shell( + inputs = srcs + [ + gapic_library[DefaultInfo].files.to_list()[0], + ], + outputs = [diff_output], + command = script, + ) + + # Check the generated diff_output file, if it is empty, that means there is no difference + # between generated source code and goldens files, test should pass. If it is not empty, then + # test will fail by exiting 1. + + check_diff_script_content = """ + # This will not print diff_output to the console unless `--test_output=all` option + # is enabled, it only emits the comparison results to the test.log. + # We could not copy the diff_output.txt to the test.log ($XML_OUTPUT_FILE) because that + # file is not existing at the moment. It is generated once test is finished. + cat $PWD/tests/Integration/{api_name}_diff_output.txt + if [ -s $PWD/tests/Integration/{api_name}_diff_output.txt ] + then + exit 1 + fi + """.format( + api_name = api_name, + ) + + ctx.actions.write( + output = check_diff_script, + content = check_diff_script_content, + ) + runfiles = ctx.runfiles(files = [ctx.outputs.diff_output]) + return [DefaultInfo(executable = check_diff_script, runfiles = runfiles)] + +php_diff_integration_goldens_test = rule( + attrs = { + "gapic_library": attr.label(), + "srcs": attr.label_list( + allow_files = True, + mandatory = True, + ), + }, + outputs = { + "diff_output": "%{name}_diff_output.txt", + "check_diff_script": "%{name}_check_diff_script.sh", + }, + implementation = _php_diff_integration_goldens_impl, + test = True, +) + +def php_integration_test(name, target, data): + # php_gapic_library generates only one srcjar. + php_diff_integration_goldens_test( + name = name, + gapic_library = target, + srcs = data, + ) + +def _php_overwrite_golden_impl(ctx): + # Extract source files from the srcjar generated from php_gapic_library into + # a temporary folder (codegen_tmp) and zip into goldens_output_zip. + # Overwrite the goldens dir (e.g tests/Integration/goldens/asset) with newly generated code. + gapic_library = ctx.attr.gapic_library + srcs = ctx.files.srcs + + # Convert the name of bazel rules e.g. `redis_update` to `redis` + # because we will need to overwrite the goldens files in `redis` folder. + api_name = "_".join(ctx.attr.name.split("_")[:-1]) + goldens_output_zip = ctx.outputs.goldens_output_zip + + script = """ + mkdir codegen_tmp + unzip {input_srcs} -d codegen_tmp + cd codegen_tmp + zip -r ../{goldens_output_zip} . + """.format( + goldens_output_zip = goldens_output_zip.path, + input_srcs = gapic_library[DefaultInfo].files.to_list()[0].path, + ) + + ctx.actions.run_shell( + inputs = srcs + [ + gapic_library[DefaultInfo].files.to_list()[0], + ], + outputs = [goldens_output_zip], + command = script, + ) + + # Overwrite the goldens. + golden_update_script_content = """ + cd ${{BUILD_WORKSPACE_DIRECTORY}} + # Filename pattern-based removal is needed to preserve the BUILD.bazel file. + find tests/Integration/goldens/{api_name}/ -name \\*.txt -type f -delete + find tests/Integration/goldens/{api_name}/ -name \\*.php -type f -delete + find tests/Integration/goldens/{api_name}/ -name \\*.json -type f -delete + unzip -ao {goldens_output_zip} -d tests/Integration/goldens/{api_name} + """.format( + goldens_output_zip = goldens_output_zip.path, + api_name = api_name, + ) + ctx.actions.write( + output = ctx.outputs.golden_update_script, + content = golden_update_script_content, + is_executable = True, + ) + return [DefaultInfo(executable = ctx.outputs.golden_update_script)] + +php_overwrite_golden = rule( + attrs = { + "gapic_library": attr.label(), + "srcs": attr.label_list( + allow_files = True, + mandatory = True, + ), + }, + outputs = { + "goldens_output_zip": "%{name}.zip", + "golden_update_script": "%{name}.sh", + }, + executable = True, + implementation = _php_overwrite_golden_impl, +) + +def php_golden_update(name, target, data): + php_overwrite_golden( + name = name, + gapic_library = target, + srcs = data, + ) diff --git a/tests/Integration/BUILD.bazel b/tests/Integration/BUILD.bazel new file mode 100644 index 000000000..2bf381f02 --- /dev/null +++ b/tests/Integration/BUILD.bazel @@ -0,0 +1,611 @@ +load( + "@gapic_generator_php//rules_php_gapic:php_gapic.bzl", + "php_gapic_library", + "php_grpc_library", + "php_proto_library", +) +load( + "@gapic_generator_php//rules_php_gapic:php_gapic_pkg.bzl", + "php_gapic_assembly_pkg", +) +load("@rules_gapic//:gapic.bzl", "proto_library_with_info") +load("//:rules_php_test/integration_test.bzl", "php_golden_update", "php_integration_test") +load("@rules_proto//proto:defs.bzl", "proto_library") + +#################################################### +# Integration Test Rules +#################################################### +INTEGRATION_TEST_LIBRARIES = [ + "asset", # Basic case. + "compute_small", # REGAPIC. + "container", # RPCs with more than one routing header. + "dataproc", # RPCs with additional_bindings in the HTTP annotation. + "functions", # RPCs with HTTP variables that fall into the edge case. + "kms", # Mixins. + "iam", # Standalone service that's in the mixin allowlist. + "logging", # Singleton resource names. + "redis", # sample_code field in gapic.yaml. + "retail", # ALpha. + "spanner", # Emulator support. + "speech", # sample_code field in gapic.yaml. + "securitycenter", # Exercises pathTemplateMap. + "talent", # Beta; path template and duplicate name template properties. + "videointelligence", # sample_code field in gapic.yaml. +] + +[php_integration_test( + name = lib_name, + data = ["//tests/Integration/goldens/%s:goldens_files" % lib_name], + target = "%s_php_gapic" % lib_name, +) for lib_name in INTEGRATION_TEST_LIBRARIES] + +[php_golden_update( + name = "%s_update" % lib_name, + data = ["//tests/Integration/goldens/%s:goldens_files" % lib_name], + target = "%s_php_gapic" % lib_name, +) for lib_name in INTEGRATION_TEST_LIBRARIES] + +#################################################### +# API Library Rules +#################################################### +# proto_library, grpc_library, and gapic_library rule redefinitions will eventually go away +# once more APIs in googleapis have been migrated to the microgenerator. + +# Asset API - basic case. +php_proto_library( + name = "asset_php_proto", + deps = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], +) + +php_grpc_library( + name = "asset_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], + deps = [":asset_php_proto"], +) + +php_gapic_library( + name = "asset_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/cloud/asset/v1:cloudasset_grpc_service_config.json", + rest_numeric_enums = True, + deps = [ + ":asset_php_grpc", + ":asset_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-asset-v1-php", + deps = [ + ":asset_php_gapic", + ":asset_php_grpc", + ":asset_php_proto", + ], +) + +# GCE REGAPIC. +proto_library( + name = "compute_small_proto", + srcs = [ + "apis/compute_small/v1/compute_small.proto", + ], + deps = [ + "@com_google_googleapis//google/api:annotations_proto", + "@com_google_googleapis//google/api:client_proto", + "@com_google_googleapis//google/api:field_behavior_proto", + "@com_google_googleapis//google/api:resource_proto", + "@com_google_googleapis//google/longrunning:operations_proto", + "@com_google_googleapis//google/cloud:extended_operations_proto", + "@com_google_protobuf//:descriptor_proto", + ], +) + +proto_library_with_info( + name = "compute_small_proto_with_info", + deps = [ + ":compute_small_proto", + "@com_google_googleapis//google/cloud:common_resources_proto", + ], +) + +php_proto_library( + name = "compute_small_php_proto", + deps = [":compute_small_proto"], +) + +php_grpc_library( + name = "compute_small_php_grpc", + srcs = [":compute_small_proto"], + deps = [":compute_small_php_proto"], +) + +php_gapic_library( + name = "compute_small_php_gapic", + srcs = [":compute_small_proto_with_info"], + service_yaml = "apis/compute_small/v1/compute_small_v1.yaml", + transport = "rest", + deps = [ + ":compute_small_php_grpc", + ":compute_small_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-compute-small-v1-php", + deps = [ + ":compute_small_php_gapic", + ":compute_small_php_grpc", + ":compute_small_php_proto", + ], +) + +# Container - RPCs with more than one routing header. +php_proto_library( + name = "container_php_proto", + deps = ["@com_google_googleapis//google/container/v1:container_proto"], +) + +php_grpc_library( + name = "container_php_grpc", + srcs = ["@com_google_googleapis//google/container/v1:container_proto"], + deps = [":container_php_proto"], +) + +php_gapic_library( + name = "container_php_gapic", + srcs = ["@com_google_googleapis//google/container/v1:container_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/container/v1:container_grpc_service_config.json", + deps = [ + ":container_php_grpc", + ":container_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-container-v1-php", + deps = [ + ":container_php_gapic", + ":container_php_grpc", + ":container_php_proto", + ], +) + +# Dataproc - RPCs with additional_bindings in the HTTP annotations. +php_proto_library( + name = "dataproc_php_proto", + deps = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto"], +) + +php_grpc_library( + name = "dataproc_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto"], + deps = [":dataproc_php_proto"], +) + +php_gapic_library( + name = "dataproc_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto_with_info"], + gapic_yaml = "apis/dataproc/v1/dataproc_gapic.yaml", + grpc_service_config = "@com_google_googleapis//google/cloud/dataproc/v1:dataproc_grpc_service_config.json", + service_yaml = "@com_google_googleapis//google/cloud/dataproc/v1:dataproc_v1.yaml", + deps = [ + ":dataproc_php_grpc", + ":dataproc_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-dataproc-v1-php", + deps = [ + ":dataproc_php_gapic", + ":dataproc_php_grpc", + ":dataproc_php_proto", + ], +) + +# Functions. +php_proto_library( + name = "functions_php_proto", + deps = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto"], +) + +php_grpc_library( + name = "functions_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto"], + deps = [":functions_php_proto"], +) + +php_gapic_library( + name = "functions_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/cloud/functions/v1:functions_grpc_service_config.json", + deps = [ + ":functions_php_grpc", + ":functions_php_proto", + ], +) + +# Open Source Packages +php_gapic_assembly_pkg( + name = "google-cloud-functions-v1-php", + deps = [ + ":functions_php_gapic", + ":functions_php_grpc", + ":functions_php_proto", + ], +) + +# Logging - singleton resource names. +php_proto_library( + name = "logging_php_proto", + deps = ["@com_google_googleapis//google/logging/v2:logging_proto"], +) + +php_grpc_library( + name = "logging_php_grpc", + srcs = ["@com_google_googleapis//google/logging/v2:logging_proto"], + deps = [":logging_php_proto"], +) + +php_gapic_library( + name = "logging_php_gapic", + srcs = ["@com_google_googleapis//google/logging/v2:logging_proto_with_info"], + # For batching. + gapic_yaml = "@com_google_googleapis//google/logging/v2:logging_gapic.yaml", + grpc_service_config = "@com_google_googleapis//google/logging/v2:logging_grpc_service_config.json", + deps = [ + ":logging_php_grpc", + ":logging_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-logging-v1-php", + deps = [ + ":logging_php_gapic", + ":logging_php_grpc", + ":logging_php_proto", + ], +) + +# Securitycenter. +php_proto_library( + name = "securitycenter_php_proto", + deps = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto"], +) + +php_grpc_library( + name = "securitycenter_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto"], + deps = [":securitycenter_php_proto"], +) + +php_gapic_library( + name = "securitycenter_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_grpc_service_config.json", + service_yaml = "@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_v1.yaml", + deps = [ + ":securitycenter_php_grpc", + ":securitycenter_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-securitycenter-v1beta1-php", + deps = [ + ":securitycenter_php_gapic", + ":securitycenter_php_grpc", + ":securitycenter_php_proto", + ], +) + +# Speech - sample_code. +php_proto_library( + name = "speech_php_proto", + deps = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto"], +) + +php_grpc_library( + name = "speech_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto"], + deps = [":speech_php_proto"], +) + +php_gapic_library( + name = "speech_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/cloud/speech/v1:speech_grpc_service_config.json", + service_yaml = "@com_google_googleapis//google/cloud/speech/v1:speech_v1.yaml", + deps = [ + ":speech_php_grpc", + ":speech_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-speech-v1-php", + deps = [ + ":speech_php_gapic", + ":speech_php_grpc", + ":speech_php_proto", + ], +) + +# Redis - sample code. +php_proto_library( + name = "redis_php_proto", + deps = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto"], +) + +php_grpc_library( + name = "redis_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto"], + deps = [":redis_php_proto"], +) + +php_gapic_library( + name = "redis_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto_with_info"], + gapic_yaml = "apis/redis/v1/redis_gapic.yaml", + grpc_service_config = "@com_google_googleapis//google/cloud/redis/v1:redis_grpc_service_config.json", + service_yaml = "@com_google_googleapis//google/cloud/redis/v1:redis_v1.yaml", + transport = "grpc", + deps = [ + ":redis_php_grpc", + ":redis_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-redis-v1-php", + deps = [ + ":redis_php_gapic", + ":redis_php_grpc", + ":redis_php_proto", + ], +) + +# Retail - Alpha. +php_proto_library( + name = "retail_php_proto", + deps = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto"], +) + +php_grpc_library( + name = "retail_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto"], + deps = [":retail_php_proto"], +) + +php_gapic_library( + name = "retail_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/cloud/retail/v2alpha:retail_grpc_service_config.json", + service_yaml = "@com_google_googleapis//google/cloud/retail/v2alpha:retail_v2alpha.yaml", + deps = [ + ":retail_php_grpc", + ":retail_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-retail-v2alpha-php", + deps = [ + ":retail_php_gapic", + ":retail_php_grpc", + ":retail_php_proto", + ], +) + +# Video intelligence - sample code. +php_proto_library( + name = "videointelligence_php_proto", + deps = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto"], +) + +php_grpc_library( + name = "videointelligence_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto"], + deps = [":videointelligence_php_proto"], +) + +php_gapic_library( + name = "videointelligence_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto_with_info"], + gapic_yaml = "@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_gapic.yaml", + service_yaml = "apis/videointelligence/v1/videointelligence_v1.yaml", + deps = [ + ":videointelligence_php_grpc", + ":videointelligence_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-videointelligence-v1-php", + deps = [ + ":videointelligence_php_gapic", + ":videointelligence_php_grpc", + ":videointelligence_php_proto", + ], +) + +# KMS - mixins. +proto_library( + name = "kms_proto", + srcs = [ + "apis/kms/v1/resources.proto", + "apis/kms/v1/service.proto", + ], + deps = [ + "@com_google_googleapis//google/api:annotations_proto", + "@com_google_googleapis//google/api:client_proto", + "@com_google_googleapis//google/api:field_behavior_proto", + "@com_google_googleapis//google/api:resource_proto", + "@com_google_googleapis//google/cloud/location:location_proto", + "@com_google_googleapis//google/iam/v1:iam_policy_proto", + "@com_google_googleapis//google/iam/v1:policy_proto", + "@com_google_protobuf//:duration_proto", + "@com_google_protobuf//:field_mask_proto", + "@com_google_protobuf//:struct_proto", + "@com_google_protobuf//:timestamp_proto", + "@com_google_protobuf//:wrappers_proto", + ], +) + +proto_library_with_info( + name = "kms_proto_with_info", + deps = [ + ":kms_proto", + "@com_google_googleapis//google/cloud:common_resources_proto", + "@com_google_googleapis//google/cloud/location:location_proto", + "@com_google_googleapis//google/iam/v1:iam_policy_proto", + "@com_google_googleapis//google/iam/v1:policy_proto", + ], +) + +php_proto_library( + name = "kms_php_proto", + deps = [":kms_proto"], +) + +php_grpc_library( + name = "kms_php_grpc", + srcs = [":kms_proto"], + deps = [":kms_php_proto"], +) + +php_gapic_library( + name = "kms_php_gapic", + srcs = [":kms_proto_with_info"], + grpc_service_config = "apis/kms/v1/cloudkms_grpc_service_config.json", + # For the IAM mixin. + service_yaml = "apis/kms/v1/cloudkms_test_mixins_v1.yaml", + deps = [ + ":kms_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-kms-v1-php", + deps = [ + ":kms_php_gapic", + ":kms_php_grpc", + ":kms_php_proto", + ], +) + +# IAM - standalone mixed-in proto. +php_proto_library( + name = "iam_php_proto", + deps = [ + "@com_google_googleapis//google/iam/v1:iam_policy_proto", + "@com_google_googleapis//google/iam/v1:options_proto", + "@com_google_googleapis//google/iam/v1:policy_proto", + ], +) + +php_grpc_library( + name = "iam_php_grpc", + srcs = ["@com_google_googleapis//google/iam/v1:iam_policy_proto"], + deps = [":iam_php_proto"], +) + +php_gapic_library( + name = "iam_php_gapic", + srcs = ["@com_google_googleapis//google/iam/v1:iam_proto_with_info"], + gapic_yaml = "apis/iam/v1/iam_gapic.yaml", + service_yaml = "apis/iam/v1/iam_api.yaml", + deps = [ + ":iam_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-iam-v1-php", + deps = [ + ":iam_php_gapic", + ":iam_php_grpc", + ":iam_php_proto", + ], +) + +# Talent. +php_proto_library( + name = "talent_php_proto", + deps = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto"], +) + +php_grpc_library( + name = "talent_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto"], + deps = [":talent_php_proto"], +) + +php_gapic_library( + name = "talent_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/cloud/talent/v4beta1:talent_grpc_service_config.json", + service_yaml = "@com_google_googleapis//google/cloud/talent/v4beta1:jobs_v4beta1.yaml", + deps = [ + ":talent_php_grpc", + ":talent_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-talent-v4beta1-php", + deps = [ + ":talent_php_gapic", + ":talent_php_grpc", + ":talent_php_proto", + ], +) + +proto_library( + name = "compliance_proto", + srcs = [ + ":compliance.proto", + ], + deps = [ + "@com_google_googleapis//google/api:annotations_proto", + "@com_google_googleapis//google/api:client_proto", + ], +) + +php_proto_library( + name = "compliance_php_proto", + deps = [":compliance_proto"], +) + +# Spanner - Emulator support. +php_proto_library( + name = "spanner_php_proto", + deps = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto"], +) + +php_grpc_library( + name = "spanner_php_grpc", + srcs = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto"], + deps = [":spanner_php_proto"], +) + +php_gapic_library( + name = "spanner_php_gapic", + srcs = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto_with_info"], + service_yaml = "@com_google_googleapis//google/spanner/admin/database/v1:spanner.yaml", + rest_numeric_enums = True, + deps = [ + ":spanner_php_grpc", + ":spanner_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-spanner-admin-database-v1-php", + deps = [ + ":spanner_php_gapic", + ":spanner_php_grpc", + ":spanner_php_proto", + ], +) diff --git a/tests/Integration/GoldenUpdateMain.php b/tests/Integration/GoldenUpdateMain.php deleted file mode 100644 index f29344010..000000000 --- a/tests/Integration/GoldenUpdateMain.php +++ /dev/null @@ -1,78 +0,0 @@ - sprintf("%d: '%s'", $idx + 1, $name), - $names, - array_keys($names) - )); - - while ($selection < 0 || $selection > count($names)) { - print("============ Integration tests ==========\n$optionString\n\nSelect golden to update (0 for all): "); - fscanf(STDIN, "%d\n", $selection); - } - - if ($selection !== 0) { - self::updateGolden($names[$selection - 1]); - } else { - foreach ($names as $name) { - self::updateGolden($name); - print("\n"); - } - } - return 0; - } - - private static function updateGolden(string $name): void - { - print("Updating integration goldens for {$name}\n"); - $codeIterator = GeneratorUtils::generateIntegration(IntegrationTest::TESTS[$name]); - UnitGoldenUpdater::writeGoldens($codeIterator, __DIR__ . '/goldens/' . $name); - print("\n"); - } -} - -if (isset($argv) && realpath($argv[0]) === __FILE__) { - $selection = $argv[1] ?? -1; - GoldenUpdateMain::update($selection); -} diff --git a/tests/Integration/IntegrationTest.php b/tests/Integration/IntegrationTest.php deleted file mode 100644 index 82ee895bc..000000000 --- a/tests/Integration/IntegrationTest.php +++ /dev/null @@ -1,147 +0,0 @@ - [ - 'protoDir' => 'googleapis/google/cloud/asset/v1', - 'grpcServiceConfig' => 'googleapis/google/cloud/asset/v1/cloudasset_grpc_service_config.json', - 'numericEnums' => true, - ], - 'compute_small' => [ - 'protoDir' => 'tests/Integration/apis/compute_small/v1', - 'serviceYaml' => 'tests/Integration/apis/compute_small/v1/compute_small_v1.yaml', - 'transport' => 'rest', - ], - 'container' => [ - 'protoDir' => 'googleapis/google/container/v1', - 'grpcServiceConfig' => 'googleapis/google/container/v1/container_grpc_service_config.json', - ], - 'dataproc' => [ - 'protoDir' => 'googleapis/google/cloud/dataproc/v1', - 'gapicYaml' => 'tests/Integration/apis/dataproc/v1/dataproc_gapic.yaml', - 'grpcServiceConfig' => 'googleapis/google/cloud/dataproc/v1/dataproc_grpc_service_config.json', - 'serviceYaml' => 'googleapis/google/cloud/dataproc/v1/dataproc_v1.yaml', - ], - 'functions' => [ - 'protoDir' => 'googleapis/google/cloud/functions/v1', - 'grpcServiceConfig' => 'googleapis/google/cloud/functions/v1/functions_grpc_service_config.json', - ], - 'kms' => [ - 'protoDir' => 'tests/Integration/apis/kms/v1', - 'grpcServiceConfig' => 'tests/Integration/apis/kms/v1/cloudkms_grpc_service_config.json', - 'serviceYaml' => 'tests/Integration/apis/kms/v1/cloudkms_test_mixins_v1.yaml', - ], - 'iam' => [ - 'protoDir' => 'googleapis/google/iam/v1', - 'gapicYaml' => 'tests/Integration/apis/iam/v1/iam_gapic.yaml', - 'serviceYaml' => 'tests/Integration/apis/iam/v1/iam_api.yaml', - ], - 'logging' => [ - 'protoDir' => 'googleapis/google/logging/v2', - 'gapicYaml' => 'googleapis/google/logging/v2/logging_gapic.yaml', - 'grpcServiceConfig' => 'googleapis/google/logging/v2/logging_grpc_service_config.json', - ], - 'redis' => [ - 'protoDir' => 'googleapis/google/cloud/redis/v1', - 'gapicYaml' => 'tests/Integration/apis/redis/v1/redis_gapic.yaml', - 'grpcServiceConfig' => 'googleapis/google/cloud/redis/v1/redis_grpc_service_config.json', - 'serviceYaml' => 'googleapis/google/cloud/redis/v1/redis_v1.yaml', - 'transport' => 'grpc', - ], - 'retail' => [ - 'protoDir' => 'googleapis/google/cloud/retail/v2alpha', - 'grpcServiceConfig' => 'googleapis/google/cloud/retail/v2alpha/retail_grpc_service_config.json', - 'serviceYaml' => 'googleapis/google/cloud/retail/v2alpha/retail_v2alpha.yaml', - ], - 'spanner' => [ - 'protoDir' => 'googleapis/google/spanner/admin/database/v1', - 'serviceYaml' => 'googleapis/google/spanner/admin/database/v1/spanner.yaml', - 'numericEnums' => true, - ], - 'speech' => [ - 'protoDir' => 'googleapis/google/cloud/speech/v1', - 'grpcServiceConfig' => 'googleapis/google/cloud/speech/v1/speech_grpc_service_config.json', - 'serviceYaml' => 'googleapis/google/cloud/speech/v1/speech_v1.yaml', - ], - 'securitycenter' => [ - 'protoDir' => 'googleapis/google/cloud/securitycenter/v1', - 'grpcServiceConfig' => 'googleapis/google/cloud/securitycenter/v1/securitycenter_grpc_service_config.json', - 'serviceYaml' => 'googleapis/google/cloud/securitycenter/v1/securitycenter_v1.yaml', - ], - 'talent' => [ - 'protoDir' => 'googleapis/google/cloud/talent/v4beta1', - 'grpcServiceConfig' => 'googleapis/google/cloud/talent/v4beta1/talent_grpc_service_config.json', - 'serviceYaml' => 'googleapis/google/cloud/talent/v4beta1/jobs_v4beta1.yaml', - ], - 'videointelligence' => [ - 'protoDir' => 'googleapis/google/cloud/videointelligence/v1', - 'gapicYaml' => 'googleapis/google/cloud/videointelligence/v1/videointelligence_gapic.yaml', - 'serviceYaml' => 'tests/Integration/apis/videointelligence/v1/videointelligence_v1.yaml', - ], - ]; - - public function provideIntegrationTests(): array - { - $cases = []; - foreach (array_keys(self::TESTS) as $name) { - $cases[$name] = [$name]; - } - return $cases; - } - - /** - * @dataProvider provideIntegrationTests - */ - public function testIntegration(string $name): void - { - $codeIterator = GeneratorUtils::generateIntegration(self::TESTS[$name]); - $goldenDir = __DIR__ . '/goldens/' . $name . '/'; - $files = iterator_to_array( - new RecursiveIteratorIterator( - new RecursiveDirectoryIterator( - $goldenDir, - FilesystemIterator::SKIP_DOTS - ) - ) - ); - - foreach ($codeIterator as [$relativeFilename, $code]) { - $filename = $goldenDir . $relativeFilename; - $this->assertTrue(file_exists($filename), "Expected code file missing: '{$filename}'"); - $expectedCode = file_get_contents($filename); - $this->assertEquals($expectedCode, $code, str_replace(__DIR__ . '/', '', $filename)); - unset($files[$filename]); - } - - $this->assertEmpty( - $files, - 'The following expected files were not generated: ' . - print_r(array_keys($files), true) - ); - } -} diff --git a/tests/Integration/goldens/asset/BUILD.bazel b/tests/Integration/goldens/asset/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/asset/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/compute_small/BUILD.bazel b/tests/Integration/goldens/compute_small/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/compute_small/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/container/BUILD.bazel b/tests/Integration/goldens/container/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/container/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/dataproc/BUILD.bazel b/tests/Integration/goldens/dataproc/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/dataproc/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/functions/BUILD.bazel b/tests/Integration/goldens/functions/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/functions/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/iam/BUILD.bazel b/tests/Integration/goldens/iam/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/iam/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/kms/BUILD.bazel b/tests/Integration/goldens/kms/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/kms/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/logging/BUILD.bazel b/tests/Integration/goldens/logging/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/logging/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/redis/BUILD.bazel b/tests/Integration/goldens/redis/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/redis/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/retail/BUILD.bazel b/tests/Integration/goldens/retail/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/retail/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/securitycenter/BUILD.bazel b/tests/Integration/goldens/securitycenter/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/securitycenter/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/spanner/BUILD.bazel b/tests/Integration/goldens/spanner/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/spanner/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/speech/BUILD.bazel b/tests/Integration/goldens/speech/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/speech/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/talent/BUILD.bazel b/tests/Integration/goldens/talent/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/talent/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Integration/goldens/videointelligence/BUILD.bazel b/tests/Integration/goldens/videointelligence/BUILD.bazel new file mode 100644 index 000000000..8ed15f6af --- /dev/null +++ b/tests/Integration/goldens/videointelligence/BUILD.bazel @@ -0,0 +1,10 @@ +package(default_visibility = ["//visibility:public"]) + +filegroup( + name = "goldens_files", + srcs = glob([ + "*/**/*.php", + "*/**/*.json", + "*/**/*.build.txt", + ]), +) diff --git a/tests/Tools/GeneratorUtils.php b/tests/Tools/GeneratorUtils.php index bcd4aa59e..fa85e3b29 100644 --- a/tests/Tools/GeneratorUtils.php +++ b/tests/Tools/GeneratorUtils.php @@ -19,8 +19,6 @@ namespace Google\Generator\Tests\Tools; use Google\Generator\CodeGenerator; -use Google\Generator\Collections\Vector; -use Google\Protobuf\Internal\FileDescriptorSet; class GeneratorUtils { @@ -68,42 +66,4 @@ public static function generateFromProto( ); return $codeIterator; } - - /** - * Runs the generator for an integration test configuration and returns the produced sources. - * - * @param array $config Integration test configuration. - * - * @return array[] [0] (string) is relative path; [1] (string) is file content. - */ - public static function generateIntegration(array $config): array - { - $protos = glob($config['protoDir'] . '/*.proto'); - $extraProtos = [ - 'googleapis/google/cloud/common_resources.proto', - 'googleapis/google/cloud/location/locations.proto', - 'googleapis/google/iam/v1/iam_policy.proto', - 'googleapis/google/iam/v1/policy.proto', - 'googleapis/google/iam/v1/options.proto', - ]; - $allProtos = array_values(array_unique(array_merge($protos, $extraProtos))); - $filesToGenerate = array_map(fn ($p) => preg_replace('#^googleapis/#', '', $p), $allProtos); - $descBytes = ProtoLoader::loadDescriptorBytesFromPaths($allProtos); - $descSet = new FileDescriptorSet(); - $descSet->mergeFromString($descBytes); - $fileDescs = Vector::new($descSet->getFile()); - - return CodeGenerator::generate( - $fileDescs, - Vector::new($filesToGenerate), - $config['transport'] ?? 'grpc+rest', - true, - isset($config['grpcServiceConfig']) ? file_get_contents($config['grpcServiceConfig']) : null, - isset($config['gapicYaml']) ? file_get_contents($config['gapicYaml']) : null, - isset($config['serviceYaml']) ? file_get_contents($config['serviceYaml']) : null, - $config['numericEnums'] ?? false, - 2026, // Avoid updating tests all the time. - true, - ); - } } diff --git a/tests/Tools/ProtoLoader.php b/tests/Tools/ProtoLoader.php index ce68ea1b8..fdd2284a5 100644 --- a/tests/Tools/ProtoLoader.php +++ b/tests/Tools/ProtoLoader.php @@ -33,21 +33,9 @@ class ProtoLoader * @return string */ public static function loadDescriptorBytes(string $protoPath): string - { - return static::loadDescriptorBytesFromPaths(["tests/Unit/{$protoPath}"]); - } - - /** - * Load descriptor set bytes from the specified proto paths relative to the repo root directory. - * - * @param string[] $protoPaths The proto paths relative to the repo root directory. - * - * @return string - */ - public static function loadDescriptorBytesFromPaths(array $protoPaths): string { // Set up required file locations and create tmp output file for protoc invocation. - // Assumes tests are executed from within the repo root directory. + // Assumes test are executed from within the repo root directory. $cwd = getcwd(); $protoc = "protoc"; $useToolsProtoc = getenv("USE_TOOLS_PROTOC"); @@ -56,12 +44,12 @@ public static function loadDescriptorBytesFromPaths(array $protoPaths): string } $descRes = tmpfile(); $descFilename = stream_get_meta_data($descRes)['uri']; - $inputs = implode(' ', array_map(fn ($path) => escapeshellarg("{$cwd}/{$path}"), $protoPaths)); + $input = "{$cwd}/tests/Unit/{$protoPath}"; // Invoke protoc to build the descriptor of the test proto. $protobuf = "{$cwd}/protobuf/src/"; $googleapis = "{$cwd}/googleapis/"; $protocCmdLine = "{$protoc} --include_imports --include_source_info -o {$descFilename} " . - "-I {$googleapis} -I {$protobuf} -I {$cwd} {$inputs} 2>&1"; + "-I {$googleapis} -I {$protobuf} -I {$cwd} {$input} 2>&1"; $output = []; $result = -1; exec($protocCmdLine, $output, $result); diff --git a/tests/Unit/ProtoTests/UnitGoldenUpdater.php b/tests/Unit/ProtoTests/UnitGoldenUpdater.php index 48fc75aa7..5d4cce2de 100644 --- a/tests/Unit/ProtoTests/UnitGoldenUpdater.php +++ b/tests/Unit/ProtoTests/UnitGoldenUpdater.php @@ -35,11 +35,6 @@ public function update( $generateSnippets, ); $outputPath = __DIR__ . '/' . dirname($protoPath) . '/out'; - static::writeGoldens($codeIterator, $outputPath); - } - - public static function writeGoldens(iterable $codeIterator, string $outputPath): void - { // Delete everything from the directory. if (is_dir($outputPath)) { $fileSysObjects = scandir($outputPath); diff --git a/tests/scripts/run_bazel_tests.sh b/tests/scripts/run_bazel_tests.sh new file mode 100755 index 000000000..3e9805c34 --- /dev/null +++ b/tests/scripts/run_bazel_tests.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# Usage: ./run_bazel_tests.sh + +# This runs the bazel test commands, ex: +# bazel test //tests/Integration:asset && \ +# bazel test //tests/Integration:compute_small +# etc + +echo "Running bazel tests" + +BAZELISK_CMD="bazelisk" + +$BAZELISK_CMD test //tests/Integration:asset && \ +$BAZELISK_CMD test //tests/Integration:compute_small && \ +$BAZELISK_CMD test //tests/Integration:container && \ +$BAZELISK_CMD test //tests/Integration:dataproc && \ +$BAZELISK_CMD test //tests/Integration:functions && \ +$BAZELISK_CMD test //tests/Integration:kms && \ +$BAZELISK_CMD test //tests/Integration:iam && \ +$BAZELISK_CMD test //tests/Integration:logging && \ +$BAZELISK_CMD test //tests/Integration:redis && \ +$BAZELISK_CMD test //tests/Integration:retail && \ +$BAZELISK_CMD test //tests/Integration:speech && \ +$BAZELISK_CMD test //tests/Integration:securitycenter && \ +$BAZELISK_CMD test //tests/Integration:talent && \ +$BAZELISK_CMD test //tests/Integration:videointelligence diff --git a/tests/scripts/run_bazel_updates.sh b/tests/scripts/run_bazel_updates.sh new file mode 100755 index 000000000..2014a8273 --- /dev/null +++ b/tests/scripts/run_bazel_updates.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Usage: ./run_bazel_updates.sh [--expunge] + +# This runs the bazel update commands, ex: +# bazel run //tests/Integration:asset_update && \ +# bazel run //tests/Integration:compute_small_update +# etc +# +# `bazel clean --expunge` is ran before the commands if the --expunge +# argument is passed + +if [ "$1" == "--expunge" ]; +then + echo "Running bazel clean --expunge" + bazelisk clean --expunge +fi + +echo "Running bazel update scripts" + +BAZEL_CMD="bazelisk" + +$BAZEL_CMD run //tests/Integration:asset_update && \ +$BAZEL_CMD run //tests/Integration:compute_small_update && \ +$BAZEL_CMD run //tests/Integration:container_update && \ +$BAZEL_CMD run //tests/Integration:dataproc_update && \ +$BAZEL_CMD run //tests/Integration:functions_update && \ +$BAZEL_CMD run //tests/Integration:kms_update && \ +$BAZEL_CMD run //tests/Integration:iam_update && \ +$BAZEL_CMD run //tests/Integration:logging_update && \ +$BAZEL_CMD run //tests/Integration:redis_update && \ +$BAZEL_CMD run //tests/Integration:retail_update && \ +$BAZEL_CMD run //tests/Integration:spanner_update && \ +$BAZEL_CMD run //tests/Integration:speech_update && \ +$BAZEL_CMD run //tests/Integration:securitycenter_update && \ +$BAZEL_CMD run //tests/Integration:talent_update && \ +$BAZEL_CMD run //tests/Integration:videointelligence_update From 3bf79a650210cacbf207659f5f8fe2fd19fdb606 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 7 Oct 2026 22:07:29 +0000 Subject: [PATCH 4/5] Reapply "chore: migrate integration golden tests from Bazel to PHPUnit" This reverts commit 1c3a7768b9af343175ba92dce3cf18c6159c3136. --- .github/workflows/bazel_example.yml | 91 --- .github/workflows/phpunit.yml | 2 +- BUILD.bazel | 11 - DEVELOPMENT.md | 69 +- composer.json | 6 +- googleapis | 2 +- phpunit.xml.dist | 4 + rules_php_gapic/php.bzl | 16 +- rules_php_gapic/php_repo.bzl | 1 - rules_php_test/integration_test.bzl | 150 ----- tests/Integration/BUILD.bazel | 611 ------------------ tests/Integration/GoldenUpdateMain.php | 78 +++ tests/Integration/IntegrationTest.php | 147 +++++ tests/Integration/goldens/asset/BUILD.bazel | 10 - .../goldens/compute_small/BUILD.bazel | 10 - .../Integration/goldens/container/BUILD.bazel | 10 - .../Integration/goldens/dataproc/BUILD.bazel | 10 - .../Integration/goldens/functions/BUILD.bazel | 10 - tests/Integration/goldens/iam/BUILD.bazel | 10 - tests/Integration/goldens/kms/BUILD.bazel | 10 - tests/Integration/goldens/logging/BUILD.bazel | 10 - tests/Integration/goldens/redis/BUILD.bazel | 10 - tests/Integration/goldens/retail/BUILD.bazel | 10 - .../goldens/securitycenter/BUILD.bazel | 10 - tests/Integration/goldens/spanner/BUILD.bazel | 10 - tests/Integration/goldens/speech/BUILD.bazel | 10 - tests/Integration/goldens/talent/BUILD.bazel | 10 - .../goldens/videointelligence/BUILD.bazel | 10 - tests/Tools/GeneratorUtils.php | 40 ++ tests/Tools/ProtoLoader.php | 18 +- tests/Unit/ProtoTests/UnitGoldenUpdater.php | 5 + tests/scripts/run_bazel_tests.sh | 27 - tests/scripts/run_bazel_updates.sh | 37 -- 33 files changed, 317 insertions(+), 1148 deletions(-) delete mode 100644 .github/workflows/bazel_example.yml delete mode 100644 rules_php_test/integration_test.bzl delete mode 100644 tests/Integration/BUILD.bazel create mode 100644 tests/Integration/GoldenUpdateMain.php create mode 100644 tests/Integration/IntegrationTest.php delete mode 100644 tests/Integration/goldens/asset/BUILD.bazel delete mode 100644 tests/Integration/goldens/compute_small/BUILD.bazel delete mode 100644 tests/Integration/goldens/container/BUILD.bazel delete mode 100644 tests/Integration/goldens/dataproc/BUILD.bazel delete mode 100644 tests/Integration/goldens/functions/BUILD.bazel delete mode 100644 tests/Integration/goldens/iam/BUILD.bazel delete mode 100644 tests/Integration/goldens/kms/BUILD.bazel delete mode 100644 tests/Integration/goldens/logging/BUILD.bazel delete mode 100644 tests/Integration/goldens/redis/BUILD.bazel delete mode 100644 tests/Integration/goldens/retail/BUILD.bazel delete mode 100644 tests/Integration/goldens/securitycenter/BUILD.bazel delete mode 100644 tests/Integration/goldens/spanner/BUILD.bazel delete mode 100644 tests/Integration/goldens/speech/BUILD.bazel delete mode 100644 tests/Integration/goldens/talent/BUILD.bazel delete mode 100644 tests/Integration/goldens/videointelligence/BUILD.bazel delete mode 100755 tests/scripts/run_bazel_tests.sh delete mode 100755 tests/scripts/run_bazel_updates.sh diff --git a/.github/workflows/bazel_example.yml b/.github/workflows/bazel_example.yml deleted file mode 100644 index f3e5a0b1c..000000000 --- a/.github/workflows/bazel_example.yml +++ /dev/null @@ -1,91 +0,0 @@ -permissions: - contents: read - -name: Bazel Build - -on: - push: - branches: [ main ] - pull_request: - branches: [ main ] - -jobs: - build: - runs-on: ubuntu-24.04 - container: gcr.io/gapic-images/googleapis@sha256:10f630423413f9138bd68c71f87c4734b9eeaba040675162c2a0b38410b0effc - - steps: - - name: Checkout code - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - submodules: 'recursive' - persist-credentials: false - - - name: Bazel File Cache Setup - id: cache-bazel - uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6 - with: - path: ~/.cache/bazel - key: ${{ runner.os }}-bazel-20210105-${{ secrets.CACHE_VERSION }} - - - name: Bazel Cache Not Found - if: steps.cache-bazel.outputs.cache-hit != 'true' - run: | - echo "No cache found." - - name: Bazel Cache Found - if: steps.cache-bazel.outputs.cache-hit == 'true' - run: | - echo -n "Cache found. Cache size: " - du -sh ~/.cache/bazel - echo "If the cache seems broken, update the CACHE_VERSION secret in" - echo "https://github.com/googleapis/gapic-generator-php/settings/secrets/actions" - echo "(use any random string, any GUID will work)" - echo "and it will start over with a clean cache." - echo "The old one will disappear after 7 days." - - - name: Show bazel version - run: | - bazel --version - - #- name: Build example package; all targets - # run: | - # cd bazel_example; - # bazel build ... - - #- name: Extract Bazel package output - # run: | - # cd bazel_example; - # tar -xf ./bazel-bin/example_php_pkg.tar.gz - - ## grep returns 1 if no matches are found; and 0 if >0 matches are found. - #- name: Verify grpc_service_config.json was honoured - # run: | - # grep '"timeout_millis": 942000' ./bazel_example/example_php_pkg/src/resources/example_client_config.json -# - #- name: Verify gapic.yaml was honoured - # run: | - # grep "'initialPollDelayMillis' => '42042'" ./bazel_example/example_php_pkg/src/resources/example_descriptor_config.php - - - name: Integration Tests - run: | - bazel --batch test tests/Integration:asset \ - tests/Integration:compute_small \ - tests/Integration:container \ - tests/Integration:dataproc \ - tests/Integration:functions \ - tests/Integration:kms \ - tests/Integration:iam \ - tests/Integration:logging \ - tests/Integration:redis \ - tests/Integration:retail \ - tests/Integration:speech \ - tests/Integration:securitycenter \ - tests/Integration:talent \ - tests/Integration:videointelligence --noshow_progress --cache_test_results=no --test_output=errors - - - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 - if: ${{ failure() }} - with: - name: test-artifacts - path: ~/.cache/bazel/*/*/*/*/bazel-out/*/testlogs/* - retention-days: 5 diff --git a/.github/workflows/phpunit.yml b/.github/workflows/phpunit.yml index 10da5a93f..3ad433a53 100644 --- a/.github/workflows/phpunit.yml +++ b/.github/workflows/phpunit.yml @@ -31,4 +31,4 @@ jobs: composer dump-autoload; - name: Run tests - run: USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit + run: USE_TOOLS_PROTOC=true ./vendor/bin/phpunit diff --git a/BUILD.bazel b/BUILD.bazel index c479c9f29..f551edcf3 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -11,14 +11,3 @@ # 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. - -exports_files(["composer.json"]) - -filegroup( - name = "srcs", - srcs = glob([ - "src/**", - "generated/**", - ]) + ["composer.json"], - visibility = ["//visibility:public"], -) diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index e4c06f36b..d61ba95b3 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -64,52 +64,29 @@ We'll be using **PHP 7.4** for the setup. ## Running tests -- Unit tests +- All tests (unit and integration) ``` - ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit + ./vendor/bin/phpunit ``` If you do not have `protoc` installed, run with `USE_TOOLS_PROTOC=true`. ``` - USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --bootstrap tests/Unit/autoload.php tests/Unit + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit ``` This uses the Linux-only `protoc` binary checked into the repository. If you run into an error: `Error: Call to undefined function Google\Protobuf\Internal\bccomp()`, that is because the [BC Math](https://www.php.net/manual/en/book.bc.php) extension is not always included by default (see tracking bug here: https://github.com/protocolbuffers/protobuf/issues/4465). You can get around this by installing BC Math with the command `sudo apt install php-bcmath`. -- Bazel integration tests. +- Running a specific test suite or integration case: - - Running: - - ``` - bazel test tests/Integration:asset - ``` - - - Running all tests: - - ``` - bash tests/scripts/run_bazel_tests.sh - ``` - - _Note: Running `bazel` commands may require removing the `composer.lock` and - `vendor/` directory._ - - - Debugging in `googleapis`: - - In [`googleapis/WORKSPACE`](https://github.com/googleapis/googleapis/blob/86fa44cc5ee2136e87c312f153113d4dd8e9c4de/WORKSPACE#L397-L401), - replace the `http_archive` downloading the generator with a - `local_repository` target pointing to the locally modified version of the - generator: - - ``` - local_repository( - name = "gapic_generator_php", - path = "/absolute/path/to/local/generator", - ) - ``` + ``` + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Unit Tests" + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Integration Tests" + USE_TOOLS_PROTOC=true ./vendor/bin/phpunit --testsuite "Integration Tests" --filter asset + ``` ## Updating tests @@ -118,7 +95,7 @@ You will need to update the golden test files if you change something in the gen - Updating unit test goldens: ``` - php tests/Unit/ProtoTests/GoldenUpdateMain.php + USE_TOOLS_PROTOC=true php tests/Unit/ProtoTests/GoldenUpdateMain.php ``` Then follow the prompts for which tests to update. @@ -128,41 +105,25 @@ You will need to update the golden test files if you change something in the gen - Updating integration test goldens: ``` - bash tests/scripts/run_bazel_updates.sh --expunge + USE_TOOLS_PROTOC=true php tests/Integration/GoldenUpdateMain.php ``` - Integration tests can be updated individually as well: + Integration tests can be updated individually by passing a filter argument: ``` - bazel run tests/Integration:asset_update + USE_TOOLS_PROTOC=true php tests/Integration/GoldenUpdateMain.php asset ``` - __NOTE__: If a new integration test case is added, make sure to add it the list in [run_bazel_tests.sh](tests/scripts/run_bazel_tests.sh) and [run_bazel_updates.sh](tests/scripts/run_bazel_updates.sh). + __NOTE__: If a new integration test case is added, make sure to add it to `TESTS` in [IntegrationTest.php](tests/Integration/IntegrationTest.php). - Update all goldens (unit and integration) Run the composer script `update-all-tests` to update all goldens at once: ``` - composer update-all-tests + USE_TOOLS_PROTOC=true composer update-all-tests ``` -## Rotating the bazel cache key - -The GitHub Actions that run the `bazel`-based integration tests hold a cache of -the build in order to speed up testing pull requests that do not impact -generated surface. If proposing a change that modifies the integration test -golden files, one must also rotate the cache key using the -[`gh` CLI](https://cli.github.com/). Use the following command before opening -your pull request: - -``` -uuidgen | gh secret set CACHE_VERSION -r https://github.com/googleapis/gapic-generator-php -``` - -If you don't have the proper permissions to rotate the cache key, request that -the reviewers do so and rerun the Action checks. - ## Updating the `googleapis` submodule To update the `googleapis` submodule, change into the directory and pull: diff --git a/composer.json b/composer.json index 86dbdc72f..eb6c24f95 100644 --- a/composer.json +++ b/composer.json @@ -49,12 +49,16 @@ "scripts": { "update-all-tests": [ "Google\\Generator\\Tests\\Unit\\ProtoTests\\GoldenUpdateMain::updateAll", - "bash tests/scripts/run_bazel_updates.sh --expunge" + "Google\\Generator\\Tests\\Integration\\GoldenUpdateMain::updateAll" ] }, "config": { "platform": { "php": "8.2" + }, + "allow-plugins": { + "php-http/discovery": false, + "tbachert/spi": false } } } diff --git a/googleapis b/googleapis index d931df43c..9841522f9 160000 --- a/googleapis +++ b/googleapis @@ -1 +1 @@ -Subproject commit d931df43c4686be708ddfee74ee3be64571af0a2 +Subproject commit 9841522f92c6542aad0049d98721cba04f541f29 diff --git a/phpunit.xml.dist b/phpunit.xml.dist index cd920d048..3abf16029 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -15,6 +15,10 @@ ./tests/Unit + + ./tests/Integration + ./tests/Integration/goldens + diff --git a/rules_php_gapic/php.bzl b/rules_php_gapic/php.bzl index 47eb2aa6a..19c50e54e 100644 --- a/rules_php_gapic/php.bzl +++ b/rules_php_gapic/php.bzl @@ -16,28 +16,25 @@ def _php_binary_impl(ctx): run_name = "{}_run.sh".format(ctx.attr.name) out_dir = ctx.actions.declare_directory("out") out_run_sh = ctx.actions.declare_file(run_name) - ws_root = ctx.attr.entry_point.label.workspace_root - entry_point_relative = ctx.file.entry_point.path[len(ws_root):].strip("/") + entry_point_relative = ctx.file.entry_point.path[len(ctx.attr.entry_point.label.workspace_root):].strip("/") # I don't understand why this is required: entry_point_relative = entry_point_relative[len("rules_php_gapic/"):] # PHP files must be copied, as the PHP __DIR__ constant is incorrect if the src file is symlinked. - # Copy vendor/ from the composer install repo and source files from the workspace so that - # changes to src/ invalidate the Bazel action cache. + # Ideally this would cp with everything being symlinks except php files. + # However that's difficult, so copy every thing; using tar as this allows excluding of directories. cmd = """ DEST="$(pwd)/{out_dir_path}/install" mkdir "$DEST" -(cd '{install_path}' && tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json) | (cd "$DEST" && tar xf -) -rm -rf "$DEST/src" "$DEST/generated" -(cd '{ws_root}' && tar cf - --dereference src/ generated/ composer.json) | (cd "$DEST" && tar xf -) +cd '{install_path}' +tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json | (cd "$DEST" && tar xf -) """.format( install_path = ctx.file.php_composer_install.path, out_dir_path = out_dir.path, - ws_root = ws_root if ws_root else ".", ) ctx.actions.run_shell( - inputs = [ctx.file.php_composer_install] + ctx.files.srcs, + inputs = [ctx.file.php_composer_install], outputs = [out_dir], command = cmd, ) @@ -85,7 +82,6 @@ php_binary = rule( attrs = { "php": attr.label(default = Label("@php_micro//:php"), allow_single_file = True, executable = True, cfg = "host"), "php_composer_install": attr.label(allow_single_file = True), - "srcs": attr.label_list(default = [Label("@gapic_generator_php//:srcs")], allow_files = True), "entry_point": attr.label(allow_single_file = True), "working_directory_flag_name": attr.string(), }, diff --git a/rules_php_gapic/php_repo.bzl b/rules_php_gapic/php_repo.bzl index 882836be6..bf745696c 100644 --- a/rules_php_gapic/php_repo.bzl +++ b/rules_php_gapic/php_repo.bzl @@ -124,7 +124,6 @@ def _find_ws_root(path): fail("Cannot find workspace root.") def _php_composer_install_impl(ctx): - ctx.read(ctx.attr.composer_json) ws_path = _find_ws_root(ctx.path(ctx.attr.composer_json).dirname) composer_json_relative = str(ctx.path(ctx.attr.composer_json))[len(str(ws_path)):] # Copy entire source workspace into the restored repo, then run `composer install`. diff --git a/rules_php_test/integration_test.bzl b/rules_php_test/integration_test.bzl deleted file mode 100644 index 92b462014..000000000 --- a/rules_php_test/integration_test.bzl +++ /dev/null @@ -1,150 +0,0 @@ -def _php_diff_integration_goldens_impl(ctx): - # Extract the Java source files from the generated 3 srcjars from API bazel target, - # and put them in the temporary folder `codegen_tmp`. - # Compare the `codegen_tmp` with the goldens folder (e.g tests/Integration/goldens/asset) - # and save the differences in output file `diff_output.txt`. - - diff_output = ctx.outputs.diff_output - check_diff_script = ctx.outputs.check_diff_script - gapic_library = ctx.attr.gapic_library - srcs = ctx.files.srcs - api_name = ctx.attr.name - - script = """ - mkdir codegen_tmp - unzip {input_srcs} -d codegen_tmp - diff -r codegen_tmp/ tests/Integration/goldens/{api_name}/ > {diff_output} - exit 0 # Avoid a build failure. - """.format( - diff_output = diff_output.path, - input_srcs = gapic_library[DefaultInfo].files.to_list()[0].path, - api_name = api_name, - ) - ctx.actions.run_shell( - inputs = srcs + [ - gapic_library[DefaultInfo].files.to_list()[0], - ], - outputs = [diff_output], - command = script, - ) - - # Check the generated diff_output file, if it is empty, that means there is no difference - # between generated source code and goldens files, test should pass. If it is not empty, then - # test will fail by exiting 1. - - check_diff_script_content = """ - # This will not print diff_output to the console unless `--test_output=all` option - # is enabled, it only emits the comparison results to the test.log. - # We could not copy the diff_output.txt to the test.log ($XML_OUTPUT_FILE) because that - # file is not existing at the moment. It is generated once test is finished. - cat $PWD/tests/Integration/{api_name}_diff_output.txt - if [ -s $PWD/tests/Integration/{api_name}_diff_output.txt ] - then - exit 1 - fi - """.format( - api_name = api_name, - ) - - ctx.actions.write( - output = check_diff_script, - content = check_diff_script_content, - ) - runfiles = ctx.runfiles(files = [ctx.outputs.diff_output]) - return [DefaultInfo(executable = check_diff_script, runfiles = runfiles)] - -php_diff_integration_goldens_test = rule( - attrs = { - "gapic_library": attr.label(), - "srcs": attr.label_list( - allow_files = True, - mandatory = True, - ), - }, - outputs = { - "diff_output": "%{name}_diff_output.txt", - "check_diff_script": "%{name}_check_diff_script.sh", - }, - implementation = _php_diff_integration_goldens_impl, - test = True, -) - -def php_integration_test(name, target, data): - # php_gapic_library generates only one srcjar. - php_diff_integration_goldens_test( - name = name, - gapic_library = target, - srcs = data, - ) - -def _php_overwrite_golden_impl(ctx): - # Extract source files from the srcjar generated from php_gapic_library into - # a temporary folder (codegen_tmp) and zip into goldens_output_zip. - # Overwrite the goldens dir (e.g tests/Integration/goldens/asset) with newly generated code. - gapic_library = ctx.attr.gapic_library - srcs = ctx.files.srcs - - # Convert the name of bazel rules e.g. `redis_update` to `redis` - # because we will need to overwrite the goldens files in `redis` folder. - api_name = "_".join(ctx.attr.name.split("_")[:-1]) - goldens_output_zip = ctx.outputs.goldens_output_zip - - script = """ - mkdir codegen_tmp - unzip {input_srcs} -d codegen_tmp - cd codegen_tmp - zip -r ../{goldens_output_zip} . - """.format( - goldens_output_zip = goldens_output_zip.path, - input_srcs = gapic_library[DefaultInfo].files.to_list()[0].path, - ) - - ctx.actions.run_shell( - inputs = srcs + [ - gapic_library[DefaultInfo].files.to_list()[0], - ], - outputs = [goldens_output_zip], - command = script, - ) - - # Overwrite the goldens. - golden_update_script_content = """ - cd ${{BUILD_WORKSPACE_DIRECTORY}} - # Filename pattern-based removal is needed to preserve the BUILD.bazel file. - find tests/Integration/goldens/{api_name}/ -name \\*.txt -type f -delete - find tests/Integration/goldens/{api_name}/ -name \\*.php -type f -delete - find tests/Integration/goldens/{api_name}/ -name \\*.json -type f -delete - unzip -ao {goldens_output_zip} -d tests/Integration/goldens/{api_name} - """.format( - goldens_output_zip = goldens_output_zip.path, - api_name = api_name, - ) - ctx.actions.write( - output = ctx.outputs.golden_update_script, - content = golden_update_script_content, - is_executable = True, - ) - return [DefaultInfo(executable = ctx.outputs.golden_update_script)] - -php_overwrite_golden = rule( - attrs = { - "gapic_library": attr.label(), - "srcs": attr.label_list( - allow_files = True, - mandatory = True, - ), - }, - outputs = { - "goldens_output_zip": "%{name}.zip", - "golden_update_script": "%{name}.sh", - }, - executable = True, - implementation = _php_overwrite_golden_impl, -) - -def php_golden_update(name, target, data): - php_overwrite_golden( - name = name, - gapic_library = target, - srcs = data, - ) diff --git a/tests/Integration/BUILD.bazel b/tests/Integration/BUILD.bazel deleted file mode 100644 index 2bf381f02..000000000 --- a/tests/Integration/BUILD.bazel +++ /dev/null @@ -1,611 +0,0 @@ -load( - "@gapic_generator_php//rules_php_gapic:php_gapic.bzl", - "php_gapic_library", - "php_grpc_library", - "php_proto_library", -) -load( - "@gapic_generator_php//rules_php_gapic:php_gapic_pkg.bzl", - "php_gapic_assembly_pkg", -) -load("@rules_gapic//:gapic.bzl", "proto_library_with_info") -load("//:rules_php_test/integration_test.bzl", "php_golden_update", "php_integration_test") -load("@rules_proto//proto:defs.bzl", "proto_library") - -#################################################### -# Integration Test Rules -#################################################### -INTEGRATION_TEST_LIBRARIES = [ - "asset", # Basic case. - "compute_small", # REGAPIC. - "container", # RPCs with more than one routing header. - "dataproc", # RPCs with additional_bindings in the HTTP annotation. - "functions", # RPCs with HTTP variables that fall into the edge case. - "kms", # Mixins. - "iam", # Standalone service that's in the mixin allowlist. - "logging", # Singleton resource names. - "redis", # sample_code field in gapic.yaml. - "retail", # ALpha. - "spanner", # Emulator support. - "speech", # sample_code field in gapic.yaml. - "securitycenter", # Exercises pathTemplateMap. - "talent", # Beta; path template and duplicate name template properties. - "videointelligence", # sample_code field in gapic.yaml. -] - -[php_integration_test( - name = lib_name, - data = ["//tests/Integration/goldens/%s:goldens_files" % lib_name], - target = "%s_php_gapic" % lib_name, -) for lib_name in INTEGRATION_TEST_LIBRARIES] - -[php_golden_update( - name = "%s_update" % lib_name, - data = ["//tests/Integration/goldens/%s:goldens_files" % lib_name], - target = "%s_php_gapic" % lib_name, -) for lib_name in INTEGRATION_TEST_LIBRARIES] - -#################################################### -# API Library Rules -#################################################### -# proto_library, grpc_library, and gapic_library rule redefinitions will eventually go away -# once more APIs in googleapis have been migrated to the microgenerator. - -# Asset API - basic case. -php_proto_library( - name = "asset_php_proto", - deps = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], -) - -php_grpc_library( - name = "asset_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], - deps = [":asset_php_proto"], -) - -php_gapic_library( - name = "asset_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/asset/v1:cloudasset_grpc_service_config.json", - rest_numeric_enums = True, - deps = [ - ":asset_php_grpc", - ":asset_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-asset-v1-php", - deps = [ - ":asset_php_gapic", - ":asset_php_grpc", - ":asset_php_proto", - ], -) - -# GCE REGAPIC. -proto_library( - name = "compute_small_proto", - srcs = [ - "apis/compute_small/v1/compute_small.proto", - ], - deps = [ - "@com_google_googleapis//google/api:annotations_proto", - "@com_google_googleapis//google/api:client_proto", - "@com_google_googleapis//google/api:field_behavior_proto", - "@com_google_googleapis//google/api:resource_proto", - "@com_google_googleapis//google/longrunning:operations_proto", - "@com_google_googleapis//google/cloud:extended_operations_proto", - "@com_google_protobuf//:descriptor_proto", - ], -) - -proto_library_with_info( - name = "compute_small_proto_with_info", - deps = [ - ":compute_small_proto", - "@com_google_googleapis//google/cloud:common_resources_proto", - ], -) - -php_proto_library( - name = "compute_small_php_proto", - deps = [":compute_small_proto"], -) - -php_grpc_library( - name = "compute_small_php_grpc", - srcs = [":compute_small_proto"], - deps = [":compute_small_php_proto"], -) - -php_gapic_library( - name = "compute_small_php_gapic", - srcs = [":compute_small_proto_with_info"], - service_yaml = "apis/compute_small/v1/compute_small_v1.yaml", - transport = "rest", - deps = [ - ":compute_small_php_grpc", - ":compute_small_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-compute-small-v1-php", - deps = [ - ":compute_small_php_gapic", - ":compute_small_php_grpc", - ":compute_small_php_proto", - ], -) - -# Container - RPCs with more than one routing header. -php_proto_library( - name = "container_php_proto", - deps = ["@com_google_googleapis//google/container/v1:container_proto"], -) - -php_grpc_library( - name = "container_php_grpc", - srcs = ["@com_google_googleapis//google/container/v1:container_proto"], - deps = [":container_php_proto"], -) - -php_gapic_library( - name = "container_php_gapic", - srcs = ["@com_google_googleapis//google/container/v1:container_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/container/v1:container_grpc_service_config.json", - deps = [ - ":container_php_grpc", - ":container_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-container-v1-php", - deps = [ - ":container_php_gapic", - ":container_php_grpc", - ":container_php_proto", - ], -) - -# Dataproc - RPCs with additional_bindings in the HTTP annotations. -php_proto_library( - name = "dataproc_php_proto", - deps = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto"], -) - -php_grpc_library( - name = "dataproc_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto"], - deps = [":dataproc_php_proto"], -) - -php_gapic_library( - name = "dataproc_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/dataproc/v1:dataproc_proto_with_info"], - gapic_yaml = "apis/dataproc/v1/dataproc_gapic.yaml", - grpc_service_config = "@com_google_googleapis//google/cloud/dataproc/v1:dataproc_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/dataproc/v1:dataproc_v1.yaml", - deps = [ - ":dataproc_php_grpc", - ":dataproc_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-dataproc-v1-php", - deps = [ - ":dataproc_php_gapic", - ":dataproc_php_grpc", - ":dataproc_php_proto", - ], -) - -# Functions. -php_proto_library( - name = "functions_php_proto", - deps = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto"], -) - -php_grpc_library( - name = "functions_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto"], - deps = [":functions_php_proto"], -) - -php_gapic_library( - name = "functions_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/functions/v1:functions_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/functions/v1:functions_grpc_service_config.json", - deps = [ - ":functions_php_grpc", - ":functions_php_proto", - ], -) - -# Open Source Packages -php_gapic_assembly_pkg( - name = "google-cloud-functions-v1-php", - deps = [ - ":functions_php_gapic", - ":functions_php_grpc", - ":functions_php_proto", - ], -) - -# Logging - singleton resource names. -php_proto_library( - name = "logging_php_proto", - deps = ["@com_google_googleapis//google/logging/v2:logging_proto"], -) - -php_grpc_library( - name = "logging_php_grpc", - srcs = ["@com_google_googleapis//google/logging/v2:logging_proto"], - deps = [":logging_php_proto"], -) - -php_gapic_library( - name = "logging_php_gapic", - srcs = ["@com_google_googleapis//google/logging/v2:logging_proto_with_info"], - # For batching. - gapic_yaml = "@com_google_googleapis//google/logging/v2:logging_gapic.yaml", - grpc_service_config = "@com_google_googleapis//google/logging/v2:logging_grpc_service_config.json", - deps = [ - ":logging_php_grpc", - ":logging_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-logging-v1-php", - deps = [ - ":logging_php_gapic", - ":logging_php_grpc", - ":logging_php_proto", - ], -) - -# Securitycenter. -php_proto_library( - name = "securitycenter_php_proto", - deps = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto"], -) - -php_grpc_library( - name = "securitycenter_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto"], - deps = [":securitycenter_php_proto"], -) - -php_gapic_library( - name = "securitycenter_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/securitycenter/v1:securitycenter_v1.yaml", - deps = [ - ":securitycenter_php_grpc", - ":securitycenter_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-securitycenter-v1beta1-php", - deps = [ - ":securitycenter_php_gapic", - ":securitycenter_php_grpc", - ":securitycenter_php_proto", - ], -) - -# Speech - sample_code. -php_proto_library( - name = "speech_php_proto", - deps = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto"], -) - -php_grpc_library( - name = "speech_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto"], - deps = [":speech_php_proto"], -) - -php_gapic_library( - name = "speech_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/speech/v1:speech_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/speech/v1:speech_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/speech/v1:speech_v1.yaml", - deps = [ - ":speech_php_grpc", - ":speech_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-speech-v1-php", - deps = [ - ":speech_php_gapic", - ":speech_php_grpc", - ":speech_php_proto", - ], -) - -# Redis - sample code. -php_proto_library( - name = "redis_php_proto", - deps = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto"], -) - -php_grpc_library( - name = "redis_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto"], - deps = [":redis_php_proto"], -) - -php_gapic_library( - name = "redis_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/redis/v1:redis_proto_with_info"], - gapic_yaml = "apis/redis/v1/redis_gapic.yaml", - grpc_service_config = "@com_google_googleapis//google/cloud/redis/v1:redis_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/redis/v1:redis_v1.yaml", - transport = "grpc", - deps = [ - ":redis_php_grpc", - ":redis_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-redis-v1-php", - deps = [ - ":redis_php_gapic", - ":redis_php_grpc", - ":redis_php_proto", - ], -) - -# Retail - Alpha. -php_proto_library( - name = "retail_php_proto", - deps = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto"], -) - -php_grpc_library( - name = "retail_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto"], - deps = [":retail_php_proto"], -) - -php_gapic_library( - name = "retail_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/retail/v2alpha:retail_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/retail/v2alpha:retail_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/retail/v2alpha:retail_v2alpha.yaml", - deps = [ - ":retail_php_grpc", - ":retail_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-retail-v2alpha-php", - deps = [ - ":retail_php_gapic", - ":retail_php_grpc", - ":retail_php_proto", - ], -) - -# Video intelligence - sample code. -php_proto_library( - name = "videointelligence_php_proto", - deps = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto"], -) - -php_grpc_library( - name = "videointelligence_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto"], - deps = [":videointelligence_php_proto"], -) - -php_gapic_library( - name = "videointelligence_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_proto_with_info"], - gapic_yaml = "@com_google_googleapis//google/cloud/videointelligence/v1:videointelligence_gapic.yaml", - service_yaml = "apis/videointelligence/v1/videointelligence_v1.yaml", - deps = [ - ":videointelligence_php_grpc", - ":videointelligence_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-videointelligence-v1-php", - deps = [ - ":videointelligence_php_gapic", - ":videointelligence_php_grpc", - ":videointelligence_php_proto", - ], -) - -# KMS - mixins. -proto_library( - name = "kms_proto", - srcs = [ - "apis/kms/v1/resources.proto", - "apis/kms/v1/service.proto", - ], - deps = [ - "@com_google_googleapis//google/api:annotations_proto", - "@com_google_googleapis//google/api:client_proto", - "@com_google_googleapis//google/api:field_behavior_proto", - "@com_google_googleapis//google/api:resource_proto", - "@com_google_googleapis//google/cloud/location:location_proto", - "@com_google_googleapis//google/iam/v1:iam_policy_proto", - "@com_google_googleapis//google/iam/v1:policy_proto", - "@com_google_protobuf//:duration_proto", - "@com_google_protobuf//:field_mask_proto", - "@com_google_protobuf//:struct_proto", - "@com_google_protobuf//:timestamp_proto", - "@com_google_protobuf//:wrappers_proto", - ], -) - -proto_library_with_info( - name = "kms_proto_with_info", - deps = [ - ":kms_proto", - "@com_google_googleapis//google/cloud:common_resources_proto", - "@com_google_googleapis//google/cloud/location:location_proto", - "@com_google_googleapis//google/iam/v1:iam_policy_proto", - "@com_google_googleapis//google/iam/v1:policy_proto", - ], -) - -php_proto_library( - name = "kms_php_proto", - deps = [":kms_proto"], -) - -php_grpc_library( - name = "kms_php_grpc", - srcs = [":kms_proto"], - deps = [":kms_php_proto"], -) - -php_gapic_library( - name = "kms_php_gapic", - srcs = [":kms_proto_with_info"], - grpc_service_config = "apis/kms/v1/cloudkms_grpc_service_config.json", - # For the IAM mixin. - service_yaml = "apis/kms/v1/cloudkms_test_mixins_v1.yaml", - deps = [ - ":kms_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-kms-v1-php", - deps = [ - ":kms_php_gapic", - ":kms_php_grpc", - ":kms_php_proto", - ], -) - -# IAM - standalone mixed-in proto. -php_proto_library( - name = "iam_php_proto", - deps = [ - "@com_google_googleapis//google/iam/v1:iam_policy_proto", - "@com_google_googleapis//google/iam/v1:options_proto", - "@com_google_googleapis//google/iam/v1:policy_proto", - ], -) - -php_grpc_library( - name = "iam_php_grpc", - srcs = ["@com_google_googleapis//google/iam/v1:iam_policy_proto"], - deps = [":iam_php_proto"], -) - -php_gapic_library( - name = "iam_php_gapic", - srcs = ["@com_google_googleapis//google/iam/v1:iam_proto_with_info"], - gapic_yaml = "apis/iam/v1/iam_gapic.yaml", - service_yaml = "apis/iam/v1/iam_api.yaml", - deps = [ - ":iam_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-iam-v1-php", - deps = [ - ":iam_php_gapic", - ":iam_php_grpc", - ":iam_php_proto", - ], -) - -# Talent. -php_proto_library( - name = "talent_php_proto", - deps = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto"], -) - -php_grpc_library( - name = "talent_php_grpc", - srcs = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto"], - deps = [":talent_php_proto"], -) - -php_gapic_library( - name = "talent_php_gapic", - srcs = ["@com_google_googleapis//google/cloud/talent/v4beta1:talent_proto_with_info"], - grpc_service_config = "@com_google_googleapis//google/cloud/talent/v4beta1:talent_grpc_service_config.json", - service_yaml = "@com_google_googleapis//google/cloud/talent/v4beta1:jobs_v4beta1.yaml", - deps = [ - ":talent_php_grpc", - ":talent_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-cloud-talent-v4beta1-php", - deps = [ - ":talent_php_gapic", - ":talent_php_grpc", - ":talent_php_proto", - ], -) - -proto_library( - name = "compliance_proto", - srcs = [ - ":compliance.proto", - ], - deps = [ - "@com_google_googleapis//google/api:annotations_proto", - "@com_google_googleapis//google/api:client_proto", - ], -) - -php_proto_library( - name = "compliance_php_proto", - deps = [":compliance_proto"], -) - -# Spanner - Emulator support. -php_proto_library( - name = "spanner_php_proto", - deps = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto"], -) - -php_grpc_library( - name = "spanner_php_grpc", - srcs = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto"], - deps = [":spanner_php_proto"], -) - -php_gapic_library( - name = "spanner_php_gapic", - srcs = ["@com_google_googleapis//google/spanner/admin/database/v1:database_proto_with_info"], - service_yaml = "@com_google_googleapis//google/spanner/admin/database/v1:spanner.yaml", - rest_numeric_enums = True, - deps = [ - ":spanner_php_grpc", - ":spanner_php_proto", - ], -) - -php_gapic_assembly_pkg( - name = "google-spanner-admin-database-v1-php", - deps = [ - ":spanner_php_gapic", - ":spanner_php_grpc", - ":spanner_php_proto", - ], -) diff --git a/tests/Integration/GoldenUpdateMain.php b/tests/Integration/GoldenUpdateMain.php new file mode 100644 index 000000000..f29344010 --- /dev/null +++ b/tests/Integration/GoldenUpdateMain.php @@ -0,0 +1,78 @@ + sprintf("%d: '%s'", $idx + 1, $name), + $names, + array_keys($names) + )); + + while ($selection < 0 || $selection > count($names)) { + print("============ Integration tests ==========\n$optionString\n\nSelect golden to update (0 for all): "); + fscanf(STDIN, "%d\n", $selection); + } + + if ($selection !== 0) { + self::updateGolden($names[$selection - 1]); + } else { + foreach ($names as $name) { + self::updateGolden($name); + print("\n"); + } + } + return 0; + } + + private static function updateGolden(string $name): void + { + print("Updating integration goldens for {$name}\n"); + $codeIterator = GeneratorUtils::generateIntegration(IntegrationTest::TESTS[$name]); + UnitGoldenUpdater::writeGoldens($codeIterator, __DIR__ . '/goldens/' . $name); + print("\n"); + } +} + +if (isset($argv) && realpath($argv[0]) === __FILE__) { + $selection = $argv[1] ?? -1; + GoldenUpdateMain::update($selection); +} diff --git a/tests/Integration/IntegrationTest.php b/tests/Integration/IntegrationTest.php new file mode 100644 index 000000000..82ee895bc --- /dev/null +++ b/tests/Integration/IntegrationTest.php @@ -0,0 +1,147 @@ + [ + 'protoDir' => 'googleapis/google/cloud/asset/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/asset/v1/cloudasset_grpc_service_config.json', + 'numericEnums' => true, + ], + 'compute_small' => [ + 'protoDir' => 'tests/Integration/apis/compute_small/v1', + 'serviceYaml' => 'tests/Integration/apis/compute_small/v1/compute_small_v1.yaml', + 'transport' => 'rest', + ], + 'container' => [ + 'protoDir' => 'googleapis/google/container/v1', + 'grpcServiceConfig' => 'googleapis/google/container/v1/container_grpc_service_config.json', + ], + 'dataproc' => [ + 'protoDir' => 'googleapis/google/cloud/dataproc/v1', + 'gapicYaml' => 'tests/Integration/apis/dataproc/v1/dataproc_gapic.yaml', + 'grpcServiceConfig' => 'googleapis/google/cloud/dataproc/v1/dataproc_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/dataproc/v1/dataproc_v1.yaml', + ], + 'functions' => [ + 'protoDir' => 'googleapis/google/cloud/functions/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/functions/v1/functions_grpc_service_config.json', + ], + 'kms' => [ + 'protoDir' => 'tests/Integration/apis/kms/v1', + 'grpcServiceConfig' => 'tests/Integration/apis/kms/v1/cloudkms_grpc_service_config.json', + 'serviceYaml' => 'tests/Integration/apis/kms/v1/cloudkms_test_mixins_v1.yaml', + ], + 'iam' => [ + 'protoDir' => 'googleapis/google/iam/v1', + 'gapicYaml' => 'tests/Integration/apis/iam/v1/iam_gapic.yaml', + 'serviceYaml' => 'tests/Integration/apis/iam/v1/iam_api.yaml', + ], + 'logging' => [ + 'protoDir' => 'googleapis/google/logging/v2', + 'gapicYaml' => 'googleapis/google/logging/v2/logging_gapic.yaml', + 'grpcServiceConfig' => 'googleapis/google/logging/v2/logging_grpc_service_config.json', + ], + 'redis' => [ + 'protoDir' => 'googleapis/google/cloud/redis/v1', + 'gapicYaml' => 'tests/Integration/apis/redis/v1/redis_gapic.yaml', + 'grpcServiceConfig' => 'googleapis/google/cloud/redis/v1/redis_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/redis/v1/redis_v1.yaml', + 'transport' => 'grpc', + ], + 'retail' => [ + 'protoDir' => 'googleapis/google/cloud/retail/v2alpha', + 'grpcServiceConfig' => 'googleapis/google/cloud/retail/v2alpha/retail_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/retail/v2alpha/retail_v2alpha.yaml', + ], + 'spanner' => [ + 'protoDir' => 'googleapis/google/spanner/admin/database/v1', + 'serviceYaml' => 'googleapis/google/spanner/admin/database/v1/spanner.yaml', + 'numericEnums' => true, + ], + 'speech' => [ + 'protoDir' => 'googleapis/google/cloud/speech/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/speech/v1/speech_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/speech/v1/speech_v1.yaml', + ], + 'securitycenter' => [ + 'protoDir' => 'googleapis/google/cloud/securitycenter/v1', + 'grpcServiceConfig' => 'googleapis/google/cloud/securitycenter/v1/securitycenter_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/securitycenter/v1/securitycenter_v1.yaml', + ], + 'talent' => [ + 'protoDir' => 'googleapis/google/cloud/talent/v4beta1', + 'grpcServiceConfig' => 'googleapis/google/cloud/talent/v4beta1/talent_grpc_service_config.json', + 'serviceYaml' => 'googleapis/google/cloud/talent/v4beta1/jobs_v4beta1.yaml', + ], + 'videointelligence' => [ + 'protoDir' => 'googleapis/google/cloud/videointelligence/v1', + 'gapicYaml' => 'googleapis/google/cloud/videointelligence/v1/videointelligence_gapic.yaml', + 'serviceYaml' => 'tests/Integration/apis/videointelligence/v1/videointelligence_v1.yaml', + ], + ]; + + public function provideIntegrationTests(): array + { + $cases = []; + foreach (array_keys(self::TESTS) as $name) { + $cases[$name] = [$name]; + } + return $cases; + } + + /** + * @dataProvider provideIntegrationTests + */ + public function testIntegration(string $name): void + { + $codeIterator = GeneratorUtils::generateIntegration(self::TESTS[$name]); + $goldenDir = __DIR__ . '/goldens/' . $name . '/'; + $files = iterator_to_array( + new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( + $goldenDir, + FilesystemIterator::SKIP_DOTS + ) + ) + ); + + foreach ($codeIterator as [$relativeFilename, $code]) { + $filename = $goldenDir . $relativeFilename; + $this->assertTrue(file_exists($filename), "Expected code file missing: '{$filename}'"); + $expectedCode = file_get_contents($filename); + $this->assertEquals($expectedCode, $code, str_replace(__DIR__ . '/', '', $filename)); + unset($files[$filename]); + } + + $this->assertEmpty( + $files, + 'The following expected files were not generated: ' . + print_r(array_keys($files), true) + ); + } +} diff --git a/tests/Integration/goldens/asset/BUILD.bazel b/tests/Integration/goldens/asset/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/asset/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/compute_small/BUILD.bazel b/tests/Integration/goldens/compute_small/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/compute_small/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/container/BUILD.bazel b/tests/Integration/goldens/container/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/container/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/dataproc/BUILD.bazel b/tests/Integration/goldens/dataproc/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/dataproc/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/functions/BUILD.bazel b/tests/Integration/goldens/functions/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/functions/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/iam/BUILD.bazel b/tests/Integration/goldens/iam/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/iam/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/kms/BUILD.bazel b/tests/Integration/goldens/kms/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/kms/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/logging/BUILD.bazel b/tests/Integration/goldens/logging/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/logging/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/redis/BUILD.bazel b/tests/Integration/goldens/redis/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/redis/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/retail/BUILD.bazel b/tests/Integration/goldens/retail/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/retail/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/securitycenter/BUILD.bazel b/tests/Integration/goldens/securitycenter/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/securitycenter/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/spanner/BUILD.bazel b/tests/Integration/goldens/spanner/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/spanner/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/speech/BUILD.bazel b/tests/Integration/goldens/speech/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/speech/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/talent/BUILD.bazel b/tests/Integration/goldens/talent/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/talent/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Integration/goldens/videointelligence/BUILD.bazel b/tests/Integration/goldens/videointelligence/BUILD.bazel deleted file mode 100644 index 8ed15f6af..000000000 --- a/tests/Integration/goldens/videointelligence/BUILD.bazel +++ /dev/null @@ -1,10 +0,0 @@ -package(default_visibility = ["//visibility:public"]) - -filegroup( - name = "goldens_files", - srcs = glob([ - "*/**/*.php", - "*/**/*.json", - "*/**/*.build.txt", - ]), -) diff --git a/tests/Tools/GeneratorUtils.php b/tests/Tools/GeneratorUtils.php index fa85e3b29..bcd4aa59e 100644 --- a/tests/Tools/GeneratorUtils.php +++ b/tests/Tools/GeneratorUtils.php @@ -19,6 +19,8 @@ namespace Google\Generator\Tests\Tools; use Google\Generator\CodeGenerator; +use Google\Generator\Collections\Vector; +use Google\Protobuf\Internal\FileDescriptorSet; class GeneratorUtils { @@ -66,4 +68,42 @@ public static function generateFromProto( ); return $codeIterator; } + + /** + * Runs the generator for an integration test configuration and returns the produced sources. + * + * @param array $config Integration test configuration. + * + * @return array[] [0] (string) is relative path; [1] (string) is file content. + */ + public static function generateIntegration(array $config): array + { + $protos = glob($config['protoDir'] . '/*.proto'); + $extraProtos = [ + 'googleapis/google/cloud/common_resources.proto', + 'googleapis/google/cloud/location/locations.proto', + 'googleapis/google/iam/v1/iam_policy.proto', + 'googleapis/google/iam/v1/policy.proto', + 'googleapis/google/iam/v1/options.proto', + ]; + $allProtos = array_values(array_unique(array_merge($protos, $extraProtos))); + $filesToGenerate = array_map(fn ($p) => preg_replace('#^googleapis/#', '', $p), $allProtos); + $descBytes = ProtoLoader::loadDescriptorBytesFromPaths($allProtos); + $descSet = new FileDescriptorSet(); + $descSet->mergeFromString($descBytes); + $fileDescs = Vector::new($descSet->getFile()); + + return CodeGenerator::generate( + $fileDescs, + Vector::new($filesToGenerate), + $config['transport'] ?? 'grpc+rest', + true, + isset($config['grpcServiceConfig']) ? file_get_contents($config['grpcServiceConfig']) : null, + isset($config['gapicYaml']) ? file_get_contents($config['gapicYaml']) : null, + isset($config['serviceYaml']) ? file_get_contents($config['serviceYaml']) : null, + $config['numericEnums'] ?? false, + 2026, // Avoid updating tests all the time. + true, + ); + } } diff --git a/tests/Tools/ProtoLoader.php b/tests/Tools/ProtoLoader.php index fdd2284a5..ce68ea1b8 100644 --- a/tests/Tools/ProtoLoader.php +++ b/tests/Tools/ProtoLoader.php @@ -33,9 +33,21 @@ class ProtoLoader * @return string */ public static function loadDescriptorBytes(string $protoPath): string + { + return static::loadDescriptorBytesFromPaths(["tests/Unit/{$protoPath}"]); + } + + /** + * Load descriptor set bytes from the specified proto paths relative to the repo root directory. + * + * @param string[] $protoPaths The proto paths relative to the repo root directory. + * + * @return string + */ + public static function loadDescriptorBytesFromPaths(array $protoPaths): string { // Set up required file locations and create tmp output file for protoc invocation. - // Assumes test are executed from within the repo root directory. + // Assumes tests are executed from within the repo root directory. $cwd = getcwd(); $protoc = "protoc"; $useToolsProtoc = getenv("USE_TOOLS_PROTOC"); @@ -44,12 +56,12 @@ public static function loadDescriptorBytes(string $protoPath): string } $descRes = tmpfile(); $descFilename = stream_get_meta_data($descRes)['uri']; - $input = "{$cwd}/tests/Unit/{$protoPath}"; + $inputs = implode(' ', array_map(fn ($path) => escapeshellarg("{$cwd}/{$path}"), $protoPaths)); // Invoke protoc to build the descriptor of the test proto. $protobuf = "{$cwd}/protobuf/src/"; $googleapis = "{$cwd}/googleapis/"; $protocCmdLine = "{$protoc} --include_imports --include_source_info -o {$descFilename} " . - "-I {$googleapis} -I {$protobuf} -I {$cwd} {$input} 2>&1"; + "-I {$googleapis} -I {$protobuf} -I {$cwd} {$inputs} 2>&1"; $output = []; $result = -1; exec($protocCmdLine, $output, $result); diff --git a/tests/Unit/ProtoTests/UnitGoldenUpdater.php b/tests/Unit/ProtoTests/UnitGoldenUpdater.php index 5d4cce2de..48fc75aa7 100644 --- a/tests/Unit/ProtoTests/UnitGoldenUpdater.php +++ b/tests/Unit/ProtoTests/UnitGoldenUpdater.php @@ -35,6 +35,11 @@ public function update( $generateSnippets, ); $outputPath = __DIR__ . '/' . dirname($protoPath) . '/out'; + static::writeGoldens($codeIterator, $outputPath); + } + + public static function writeGoldens(iterable $codeIterator, string $outputPath): void + { // Delete everything from the directory. if (is_dir($outputPath)) { $fileSysObjects = scandir($outputPath); diff --git a/tests/scripts/run_bazel_tests.sh b/tests/scripts/run_bazel_tests.sh deleted file mode 100755 index 3e9805c34..000000000 --- a/tests/scripts/run_bazel_tests.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -# Usage: ./run_bazel_tests.sh - -# This runs the bazel test commands, ex: -# bazel test //tests/Integration:asset && \ -# bazel test //tests/Integration:compute_small -# etc - -echo "Running bazel tests" - -BAZELISK_CMD="bazelisk" - -$BAZELISK_CMD test //tests/Integration:asset && \ -$BAZELISK_CMD test //tests/Integration:compute_small && \ -$BAZELISK_CMD test //tests/Integration:container && \ -$BAZELISK_CMD test //tests/Integration:dataproc && \ -$BAZELISK_CMD test //tests/Integration:functions && \ -$BAZELISK_CMD test //tests/Integration:kms && \ -$BAZELISK_CMD test //tests/Integration:iam && \ -$BAZELISK_CMD test //tests/Integration:logging && \ -$BAZELISK_CMD test //tests/Integration:redis && \ -$BAZELISK_CMD test //tests/Integration:retail && \ -$BAZELISK_CMD test //tests/Integration:speech && \ -$BAZELISK_CMD test //tests/Integration:securitycenter && \ -$BAZELISK_CMD test //tests/Integration:talent && \ -$BAZELISK_CMD test //tests/Integration:videointelligence diff --git a/tests/scripts/run_bazel_updates.sh b/tests/scripts/run_bazel_updates.sh deleted file mode 100755 index 2014a8273..000000000 --- a/tests/scripts/run_bazel_updates.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash - -# Usage: ./run_bazel_updates.sh [--expunge] - -# This runs the bazel update commands, ex: -# bazel run //tests/Integration:asset_update && \ -# bazel run //tests/Integration:compute_small_update -# etc -# -# `bazel clean --expunge` is ran before the commands if the --expunge -# argument is passed - -if [ "$1" == "--expunge" ]; -then - echo "Running bazel clean --expunge" - bazelisk clean --expunge -fi - -echo "Running bazel update scripts" - -BAZEL_CMD="bazelisk" - -$BAZEL_CMD run //tests/Integration:asset_update && \ -$BAZEL_CMD run //tests/Integration:compute_small_update && \ -$BAZEL_CMD run //tests/Integration:container_update && \ -$BAZEL_CMD run //tests/Integration:dataproc_update && \ -$BAZEL_CMD run //tests/Integration:functions_update && \ -$BAZEL_CMD run //tests/Integration:kms_update && \ -$BAZEL_CMD run //tests/Integration:iam_update && \ -$BAZEL_CMD run //tests/Integration:logging_update && \ -$BAZEL_CMD run //tests/Integration:redis_update && \ -$BAZEL_CMD run //tests/Integration:retail_update && \ -$BAZEL_CMD run //tests/Integration:spanner_update && \ -$BAZEL_CMD run //tests/Integration:speech_update && \ -$BAZEL_CMD run //tests/Integration:securitycenter_update && \ -$BAZEL_CMD run //tests/Integration:talent_update && \ -$BAZEL_CMD run //tests/Integration:videointelligence_update From 5491d313d2795554adea9878b93573066e4cccd9 Mon Sep 17 00:00:00 2001 From: Brent Shaffer Date: Wed, 7 Oct 2026 22:09:53 +0000 Subject: [PATCH 5/5] chore: keep single-target Bazel smoke test alongside PHPUnit integration tests --- .github/workflows/bazel_example.yml | 37 ++++++++++++++ BUILD.bazel | 11 ++++ rules_php_gapic/php.bzl | 16 +++--- rules_php_gapic/php_repo.bzl | 1 + rules_php_test/integration_test.bzl | 78 +++++++++++++++++++++++++++++ tests/Integration/BUILD.bazel | 52 +++++++++++++++++++ 6 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/bazel_example.yml create mode 100644 rules_php_test/integration_test.bzl create mode 100644 tests/Integration/BUILD.bazel diff --git a/.github/workflows/bazel_example.yml b/.github/workflows/bazel_example.yml new file mode 100644 index 000000000..035fb5dea --- /dev/null +++ b/.github/workflows/bazel_example.yml @@ -0,0 +1,37 @@ +permissions: + contents: read + +name: Bazel Build + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + build: + runs-on: ubuntu-24.04 + container: gcr.io/gapic-images/googleapis@sha256:10f630423413f9138bd68c71f87c4734b9eeaba040675162c2a0b38410b0effc + + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + submodules: 'recursive' + persist-credentials: false + + - name: Show bazel version + run: | + bazel --version + + - name: Bazel Smoke Test + run: | + bazel --batch test tests/Integration:asset --noshow_progress --cache_test_results=no --test_output=errors + + - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + if: ${{ failure() }} + with: + name: test-artifacts + path: ~/.cache/bazel/*/*/*/*/bazel-out/*/testlogs/* + retention-days: 5 diff --git a/BUILD.bazel b/BUILD.bazel index f551edcf3..c479c9f29 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -11,3 +11,14 @@ # 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. + +exports_files(["composer.json"]) + +filegroup( + name = "srcs", + srcs = glob([ + "src/**", + "generated/**", + ]) + ["composer.json"], + visibility = ["//visibility:public"], +) diff --git a/rules_php_gapic/php.bzl b/rules_php_gapic/php.bzl index 19c50e54e..47eb2aa6a 100644 --- a/rules_php_gapic/php.bzl +++ b/rules_php_gapic/php.bzl @@ -16,25 +16,28 @@ def _php_binary_impl(ctx): run_name = "{}_run.sh".format(ctx.attr.name) out_dir = ctx.actions.declare_directory("out") out_run_sh = ctx.actions.declare_file(run_name) - entry_point_relative = ctx.file.entry_point.path[len(ctx.attr.entry_point.label.workspace_root):].strip("/") + ws_root = ctx.attr.entry_point.label.workspace_root + entry_point_relative = ctx.file.entry_point.path[len(ws_root):].strip("/") # I don't understand why this is required: entry_point_relative = entry_point_relative[len("rules_php_gapic/"):] # PHP files must be copied, as the PHP __DIR__ constant is incorrect if the src file is symlinked. - # Ideally this would cp with everything being symlinks except php files. - # However that's difficult, so copy every thing; using tar as this allows excluding of directories. + # Copy vendor/ from the composer install repo and source files from the workspace so that + # changes to src/ invalidate the Bazel action cache. cmd = """ DEST="$(pwd)/{out_dir_path}/install" mkdir "$DEST" -cd '{install_path}' -tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json | (cd "$DEST" && tar xf -) +(cd '{install_path}' && tar cf - --dereference src/ generated/ googleapis/ tools/ vendor/ composer.json) | (cd "$DEST" && tar xf -) +rm -rf "$DEST/src" "$DEST/generated" +(cd '{ws_root}' && tar cf - --dereference src/ generated/ composer.json) | (cd "$DEST" && tar xf -) """.format( install_path = ctx.file.php_composer_install.path, out_dir_path = out_dir.path, + ws_root = ws_root if ws_root else ".", ) ctx.actions.run_shell( - inputs = [ctx.file.php_composer_install], + inputs = [ctx.file.php_composer_install] + ctx.files.srcs, outputs = [out_dir], command = cmd, ) @@ -82,6 +85,7 @@ php_binary = rule( attrs = { "php": attr.label(default = Label("@php_micro//:php"), allow_single_file = True, executable = True, cfg = "host"), "php_composer_install": attr.label(allow_single_file = True), + "srcs": attr.label_list(default = [Label("@gapic_generator_php//:srcs")], allow_files = True), "entry_point": attr.label(allow_single_file = True), "working_directory_flag_name": attr.string(), }, diff --git a/rules_php_gapic/php_repo.bzl b/rules_php_gapic/php_repo.bzl index bf745696c..882836be6 100644 --- a/rules_php_gapic/php_repo.bzl +++ b/rules_php_gapic/php_repo.bzl @@ -124,6 +124,7 @@ def _find_ws_root(path): fail("Cannot find workspace root.") def _php_composer_install_impl(ctx): + ctx.read(ctx.attr.composer_json) ws_path = _find_ws_root(ctx.path(ctx.attr.composer_json).dirname) composer_json_relative = str(ctx.path(ctx.attr.composer_json))[len(str(ws_path)):] # Copy entire source workspace into the restored repo, then run `composer install`. diff --git a/rules_php_test/integration_test.bzl b/rules_php_test/integration_test.bzl new file mode 100644 index 000000000..bc69e03c3 --- /dev/null +++ b/rules_php_test/integration_test.bzl @@ -0,0 +1,78 @@ +def _php_diff_integration_goldens_impl(ctx): + # Extract the source files from the generated srcjar from API bazel target, + # and put them in the temporary folder `codegen_tmp`. + # Compare the `codegen_tmp` with the goldens folder (e.g tests/Integration/goldens/asset) + # and save the differences in output file `diff_output.txt`. + + diff_output = ctx.outputs.diff_output + check_diff_script = ctx.outputs.check_diff_script + gapic_library = ctx.attr.gapic_library + srcs = ctx.files.srcs + api_name = ctx.attr.name + + script = """ + mkdir codegen_tmp + unzip {input_srcs} -d codegen_tmp + diff -r codegen_tmp/ tests/Integration/goldens/{api_name}/ > {diff_output} + exit 0 # Avoid a build failure. + """.format( + diff_output = diff_output.path, + input_srcs = gapic_library[DefaultInfo].files.to_list()[0].path, + api_name = api_name, + ) + ctx.actions.run_shell( + inputs = srcs + [ + gapic_library[DefaultInfo].files.to_list()[0], + ], + outputs = [diff_output], + command = script, + ) + + # Check the generated diff_output file, if it is empty, that means there is no difference + # between generated source code and goldens files, test should pass. If it is not empty, then + # test will fail by exiting 1. + + check_diff_script_content = """ + # This will not print diff_output to the console unless `--test_output=all` option + # is enabled, it only emits the comparison results to the test.log. + # We could not copy the diff_output.txt to the test.log ($XML_OUTPUT_FILE) because that + # file is not existing at the moment. It is generated once test is finished. + cat $PWD/tests/Integration/{api_name}_diff_output.txt + if [ -s $PWD/tests/Integration/{api_name}_diff_output.txt ] + then + exit 1 + fi + """.format( + api_name = api_name, + ) + + ctx.actions.write( + output = check_diff_script, + content = check_diff_script_content, + ) + runfiles = ctx.runfiles(files = [ctx.outputs.diff_output]) + return [DefaultInfo(executable = check_diff_script, runfiles = runfiles)] + +php_diff_integration_goldens_test = rule( + attrs = { + "gapic_library": attr.label(), + "srcs": attr.label_list( + allow_files = True, + mandatory = True, + ), + }, + outputs = { + "diff_output": "%{name}_diff_output.txt", + "check_diff_script": "%{name}_check_diff_script.sh", + }, + implementation = _php_diff_integration_goldens_impl, + test = True, +) + +def php_integration_test(name, target, data): + # php_gapic_library generates only one srcjar. + php_diff_integration_goldens_test( + name = name, + gapic_library = target, + srcs = data, + ) diff --git a/tests/Integration/BUILD.bazel b/tests/Integration/BUILD.bazel new file mode 100644 index 000000000..677c7aa90 --- /dev/null +++ b/tests/Integration/BUILD.bazel @@ -0,0 +1,52 @@ +load( + "@gapic_generator_php//rules_php_gapic:php_gapic.bzl", + "php_gapic_library", + "php_grpc_library", + "php_proto_library", +) +load( + "@gapic_generator_php//rules_php_gapic:php_gapic_pkg.bzl", + "php_gapic_assembly_pkg", +) +load("//:rules_php_test/integration_test.bzl", "php_integration_test") + +php_integration_test( + name = "asset", + data = glob([ + "goldens/asset/**/*.txt", + "goldens/asset/**/*.php", + "goldens/asset/**/*.json", + ]), + target = "asset_php_gapic", +) + +php_proto_library( + name = "asset_php_proto", + deps = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], +) + +php_grpc_library( + name = "asset_php_grpc", + srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto"], + deps = [":asset_php_proto"], +) + +php_gapic_library( + name = "asset_php_gapic", + srcs = ["@com_google_googleapis//google/cloud/asset/v1:asset_proto_with_info"], + grpc_service_config = "@com_google_googleapis//google/cloud/asset/v1:cloudasset_grpc_service_config.json", + rest_numeric_enums = True, + deps = [ + ":asset_php_grpc", + ":asset_php_proto", + ], +) + +php_gapic_assembly_pkg( + name = "google-cloud-asset-v1-php", + deps = [ + ":asset_php_gapic", + ":asset_php_grpc", + ":asset_php_proto", + ], +)