Browse Source

Add more plugin integration tests (#46)

Motivation:

The SwiftPM build plugin doesn't currently handle proto files with the
same name even if they come from different packages. This happens
because the build system cannot handle object files with the same name.
This change adds such a test while tidying up some of the plugin test
code.

Modifications:

- Divide up test resources in sources, config, and proto directories.
- Have one function per test
- Document each test with the expected structure
- Add another test but don't run it. (It fails.)

Result:

More tests. The issue will be fixed in a separate change.
George Barnett 11 months ago
parent
commit
e426ad8924

+ 0 - 0
IntegrationTests/PluginTests/Resources/import-directory-1-grpc-swift-proto-generator-config.json → IntegrationTests/PluginTests/Resources/Config/import-directory-1-grpc-swift-proto-generator-config.json


+ 0 - 0
IntegrationTests/PluginTests/Resources/internal-grpc-swift-proto-generator-config.json → IntegrationTests/PluginTests/Resources/Config/internal-grpc-swift-proto-generator-config.json


+ 0 - 0
IntegrationTests/PluginTests/Resources/public-grpc-swift-proto-generator-config.json → IntegrationTests/PluginTests/Resources/Config/public-grpc-swift-proto-generator-config.json


+ 0 - 0
IntegrationTests/PluginTests/Resources/Foo/foo-messages.proto → IntegrationTests/PluginTests/Resources/Protos/Foo/foo-messages.proto


+ 0 - 0
IntegrationTests/PluginTests/Resources/Foo/foo-service.proto → IntegrationTests/PluginTests/Resources/Protos/Foo/foo-service.proto


+ 0 - 0
IntegrationTests/PluginTests/Resources/HelloWorld/HelloWorld.proto → IntegrationTests/PluginTests/Resources/Protos/HelloWorld/HelloWorld.proto


+ 0 - 0
IntegrationTests/PluginTests/Resources/HelloWorld/Messages.proto → IntegrationTests/PluginTests/Resources/Protos/HelloWorld/Messages.proto


+ 0 - 0
IntegrationTests/PluginTests/Resources/HelloWorld/Service.proto → IntegrationTests/PluginTests/Resources/Protos/HelloWorld/Service.proto


+ 9 - 0
IntegrationTests/PluginTests/Resources/Protos/noop/noop.proto

@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+import "google/protobuf/empty.proto";
+
+package noop;
+
+service NoOpService {
+  rpc NoOp(google.protobuf.Empty) returns (google.protobuf.Empty);
+}

+ 9 - 0
IntegrationTests/PluginTests/Resources/Protos/noop2/noop.proto

@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+import "google/protobuf/empty.proto";
+
+package noop2;
+
+service NoOpService {
+  rpc NoOp(google.protobuf.Empty) returns (google.protobuf.Empty);
+}

+ 0 - 0
IntegrationTests/PluginTests/Resources/FooHelloWorldAdopter.swift → IntegrationTests/PluginTests/Resources/Sources/FooHelloWorldAdopter.swift


+ 0 - 0
IntegrationTests/PluginTests/Resources/HelloWorldAdopter.swift → IntegrationTests/PluginTests/Resources/Sources/HelloWorldAdopter.swift


+ 43 - 0
IntegrationTests/PluginTests/Resources/Sources/NoOp.swift

@@ -0,0 +1,43 @@
+/*
+ * Copyright 2025, gRPC Authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import GRPCCore
+import GRPCProtobuf
+import SwiftProtobuf
+
+@main
+struct PluginAdopter {
+  static func main() async throws {
+  }
+}
+
+struct NoOp: Noop_NoOpService.SimpleServiceProtocol {
+  func noOp(
+    request: Google_Protobuf_Empty,
+    context: ServerContext
+  ) async throws -> Google_Protobuf_Empty {
+    return Google_Protobuf_Empty()
+  }
+}
+
+struct NoOp2: Noop2_NoOpService.SimpleServiceProtocol {
+  func noOp(
+    request: Google_Protobuf_Empty,
+    context: ServerContext
+  ) async throws -> Google_Protobuf_Empty {
+    return Google_Protobuf_Empty()
+  }
+}

+ 0 - 1
IntegrationTests/PluginTests/Resources/Package.swift → IntegrationTests/PluginTests/Resources/Sources/Package.swift

@@ -28,7 +28,6 @@ let package = Package(
   ],
   dependencies: [
     // Dependency on grpc-swift-protobuf to be added by setup-plugin-tests.sh script
-
     .package(
       url: "https://github.com/grpc/grpc-swift.git",
       from: "2.0.0"

+ 172 - 59
dev/setup-plugin-tests.sh

@@ -24,73 +24,186 @@ output_directory="${PLUGIN_TESTS_OUTPUT_DIRECTORY:=$(mktemp -d)}"
 here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
 grpc_swift_protobuf_directory="$(readlink -f "${here}/..")"
 resources_directory="$(readlink -f "${grpc_swift_protobuf_directory}/IntegrationTests/PluginTests/Resources")"
+config="${resources_directory}/Config"
+sources="${resources_directory}/Sources"
+protos="${resources_directory}/Protos"
 scratch_directory="$(mktemp -d)"
+package_manifest="${scratch_directory}/Package.swift"
 
 echo "Output directory: $output_directory"
 echo "grpc-swift-protobuf directory: $grpc_swift_protobuf_directory"
 
 # modify Package.swift
-cp "${resources_directory}/Package.swift" "${scratch_directory}/"
-cat >> "${scratch_directory}/Package.swift" <<- EOM
+cp "${resources_directory}/Sources/Package.swift" "${scratch_directory}/"
+cat >> "${package_manifest}" <<- EOM
 package.dependencies.append(
   .package(path: "$grpc_swift_protobuf_directory")
 )
 EOM
 
-# test_01_top_level_config_file
-test_01_output_directory="${output_directory}/test_01_top_level_config_file"
-mkdir -p "${test_01_output_directory}/Sources/Protos"
-cp "${scratch_directory}/Package.swift" "${test_01_output_directory}/"
-cp "${resources_directory}/HelloWorldAdopter.swift" "${test_01_output_directory}/Sources/adopter.swift"
-cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_01_output_directory}/Sources/Protos"
-cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_01_output_directory}/Sources/grpc-swift-proto-generator-config.json"
-
-# test_02_peer_config_file
-test_02_output_directory="${output_directory}/test_02_peer_config_file"
-mkdir -p "${test_02_output_directory}/Sources/Protos"
-cp "${scratch_directory}/Package.swift" "${test_02_output_directory}/"
-cp "${resources_directory}/HelloWorldAdopter.swift" "${test_02_output_directory}/Sources/adopter.swift"
-cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_02_output_directory}/Sources/Protos/"
-cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_02_output_directory}/Sources/Protos/grpc-swift-proto-generator-config.json"
-
-# test_03_separate_service_message_protos
-test_03_output_directory="${output_directory}/test_03_separate_service_message_protos"
-mkdir -p "${test_03_output_directory}/Sources/Protos"
-cp "${scratch_directory}/Package.swift" "${test_03_output_directory}/"
-cp "${resources_directory}/HelloWorldAdopter.swift" "${test_03_output_directory}/Sources/adopter.swift"
-cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_03_output_directory}/Sources/Protos/grpc-swift-proto-generator-config.json"
-cp "${resources_directory}/HelloWorld/Service.proto"  "${test_03_output_directory}/Sources/Protos/"
-cp "${resources_directory}/HelloWorld/Messages.proto"  "${test_03_output_directory}/Sources/Protos/"
-
-# test_04_cross_directory_imports
-test_04_output_directory="${output_directory}/test_04_cross_directory_imports"
-mkdir -p "${test_04_output_directory}/Sources/Protos/directory_1"
-mkdir -p "${test_04_output_directory}/Sources/Protos/directory_2"
-cp "${scratch_directory}/Package.swift" "${test_04_output_directory}/"
-cp "${resources_directory}/HelloWorldAdopter.swift" "${test_04_output_directory}/Sources/adopter.swift"
-cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_04_output_directory}/Sources/Protos/directory_1/grpc-swift-proto-generator-config.json"
-cp "${resources_directory}/import-directory-1-grpc-swift-proto-generator-config.json" "${test_04_output_directory}/Sources/Protos/directory_2/grpc-swift-proto-generator-config.json"
-cp "${resources_directory}/HelloWorld/Service.proto" "${test_04_output_directory}/Sources/Protos/directory_2/"
-cp "${resources_directory}/HelloWorld/Messages.proto" "${test_04_output_directory}/Sources/Protos/directory_1/"
-
-# test_05_two_definitions
-test_05_output_directory="${output_directory}/test_05_two_definitions"
-mkdir -p "${test_05_output_directory}/Sources/Protos/HelloWorld"
-mkdir -p "${test_05_output_directory}/Sources/Protos/Foo"
-cp "${scratch_directory}/Package.swift" "${test_05_output_directory}/"
-cp "${resources_directory}/FooHelloWorldAdopter.swift" "${test_05_output_directory}/Sources/adopter.swift"
-cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_05_output_directory}/Sources/Protos/HelloWorld/"
-cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_05_output_directory}/Sources/Protos/grpc-swift-proto-generator-config.json"
-cp "${resources_directory}/Foo/foo-messages.proto" "${test_05_output_directory}/Sources/Protos/Foo/"
-cp "${resources_directory}/Foo/foo-service.proto" "${test_05_output_directory}/Sources/Protos/Foo/"
-
-# test_06_nested_definitions
-test_06_output_directory="${output_directory}/test_06_nested_definitions"
-mkdir -p "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/Foo"
-cp "${scratch_directory}/Package.swift" "${test_06_output_directory}/"
-cp "${resources_directory}/FooHelloWorldAdopter.swift" "${test_06_output_directory}/Sources/adopter.swift"
-cp "${resources_directory}/HelloWorld/HelloWorld.proto" "${test_06_output_directory}/Sources/Protos/HelloWorld/"
-cp "${resources_directory}/internal-grpc-swift-proto-generator-config.json" "${test_06_output_directory}/Sources/Protos/HelloWorld/grpc-swift-proto-generator-config.json"
-cp "${resources_directory}/public-grpc-swift-proto-generator-config.json" "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/grpc-swift-proto-generator-config.json"
-cp "${resources_directory}/Foo/foo-messages.proto" "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/Foo/"
-cp "${resources_directory}/Foo/foo-service.proto" "${test_06_output_directory}/Sources/Protos/HelloWorld/FooDefinitions/Foo/"
+function test_dir_name {
+  # $FUNCNAME is a stack of function names. The 0th element is the name of this
+  # function, so the 1st element is the calling function.
+  echo "${output_directory}/${FUNCNAME[1]}"
+}
+
+function test_01_top_level_config_file {
+  # .
+  # ├── Package.swift
+  # └── Sources
+  #     ├── HelloWorldAdopter.swift
+  #     ├── Protos
+  #     │   └── HelloWorld.proto
+  #     └── grpc-swift-proto-generator-config.json
+
+  local -r test_dir=$(test_dir_name)
+  mkdir -p "${test_dir}/Sources/Protos"
+  cp "${package_manifest}" "${test_dir}/"
+  cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/"
+  cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos"
+  cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/grpc-swift-proto-generator-config.json"
+}
+
+function test_02_peer_config_file {
+  # .
+  # ├── Package.swift
+  # └── Sources
+  #     ├── HelloWorldAdopter.swift
+  #     └── Protos
+  #         ├── HelloWorld.proto
+  #         └── grpc-swift-proto-generator-config.json
+
+  local -r test_dir=$(test_dir_name)
+  mkdir -p "${test_dir}/Sources/Protos"
+  cp "${package_manifest}" "${test_dir}/"
+  cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/"
+  cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos/"
+  cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json"
+}
+
+function test_03_separate_service_message_protos {
+  # .
+  # ├── Package.swift
+  # └── Sources
+  #     ├── HelloWorldAdopter.swift
+  #     └── Protos
+  #         ├── Messages.proto
+  #         ├── Service.proto
+  #         └── grpc-swift-proto-generator-config.json
+
+  local -r test_dir=$(test_dir_name)
+  mkdir -p "${test_dir}/Sources/Protos"
+  cp "${package_manifest}" "${test_dir}/"
+  cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/"
+  cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json"
+  cp "${protos}/HelloWorld/Service.proto"  "${test_dir}/Sources/Protos/"
+  cp "${protos}/HelloWorld/Messages.proto"  "${test_dir}/Sources/Protos/"
+}
+
+function test_04_cross_directory_imports {
+  # .
+  # ├── Package.swift
+  # └── Sources
+  #     ├── HelloWorldAdopter.swift
+  #     └── Protos
+  #         ├── directory_1
+  #         │   ├── Messages.proto
+  #         │   └── grpc-swift-proto-generator-config.json
+  #         └── directory_2
+  #             ├── Service.proto
+  #             └── grpc-swift-proto-generator-config.json
+
+  local -r test_dir=$(test_dir_name)
+  mkdir -p "${test_dir}/Sources/Protos/directory_1"
+  mkdir -p "${test_dir}/Sources/Protos/directory_2"
+
+  cp "${package_manifest}" "${test_dir}/"
+  cp "${sources}/HelloWorldAdopter.swift" "${test_dir}/Sources/"
+  cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/directory_1/grpc-swift-proto-generator-config.json"
+  cp "${config}/import-directory-1-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/directory_2/grpc-swift-proto-generator-config.json"
+  cp "${protos}/HelloWorld/Service.proto" "${test_dir}/Sources/Protos/directory_2/"
+  cp "${protos}/HelloWorld/Messages.proto" "${test_dir}/Sources/Protos/directory_1/"
+}
+
+function test_05_two_definitions {
+  # .
+  # ├── Package.swift
+  # └── Sources
+  #     ├── FooHelloWorldAdopter.swift
+  #     └── Protos
+  #         ├── Foo
+  #         │   ├── foo-messages.proto
+  #         │   └── foo-service.proto
+  #         ├── HelloWorld
+  #         │   └── HelloWorld.proto
+  #         └── grpc-swift-proto-generator-config.json
+
+  local -r test_dir=$(test_dir_name)
+  mkdir -p "${test_dir}/Sources/Protos/HelloWorld"
+  mkdir -p "${test_dir}/Sources/Protos/Foo"
+
+  cp "${package_manifest}" "${test_dir}/"
+  cp "${sources}/FooHelloWorldAdopter.swift" "${test_dir}/Sources/"
+  cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos/HelloWorld/"
+  cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json"
+  cp "${protos}/Foo/foo-messages.proto" "${test_dir}/Sources/Protos/Foo/"
+  cp "${protos}/Foo/foo-service.proto" "${test_dir}/Sources/Protos/Foo/"
+}
+
+function test_06_nested_definitions {
+  # .
+  # ├── Package.swift
+  # └── Sources
+  #     ├── FooHelloWorldAdopter.swift
+  #     └── Protos
+  #         └── HelloWorld
+  #             ├── FooDefinitions
+  #             │   ├── Foo
+  #             │   │   ├── foo-messages.proto
+  #             │   │   └── foo-service.proto
+  #             │   └── grpc-swift-proto-generator-config.json
+  #             ├── HelloWorld.proto
+  #             └── grpc-swift-proto-generator-config.json
+
+  local -r test_dir=$(test_dir_name)
+  mkdir -p "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/Foo"
+  cp "${package_manifest}" "${test_dir}/"
+  cp "${sources}/FooHelloWorldAdopter.swift" "${test_dir}/Sources/"
+  cp "${protos}/HelloWorld/HelloWorld.proto" "${test_dir}/Sources/Protos/HelloWorld/"
+  cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/HelloWorld/grpc-swift-proto-generator-config.json"
+  cp "${config}/public-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/grpc-swift-proto-generator-config.json"
+  cp "${protos}/Foo/foo-messages.proto" "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/Foo/"
+  cp "${protos}/Foo/foo-service.proto" "${test_dir}/Sources/Protos/HelloWorld/FooDefinitions/Foo/"
+}
+
+function test_07_duplicated_proto_file_name {
+  # .
+  # ├── Package.swift
+  # └── Sources
+  #     ├── NoOp.swift
+  #     └── Protos
+  #         ├── grpc-swift-proto-generator-config.json
+  #         ├── noop
+  #         │   └── noop.proto
+  #         └── noop2
+  #             └── noop.proto
+
+  local -r test_dir=$(test_dir_name)
+  mkdir -p "${test_dir}/Sources/Protos"
+
+  cp "${package_manifest}" "${test_dir}/"
+  mkdir -p "${test_dir}/Sources/Protos"
+  cp -rp "${protos}/noop" "${test_dir}/Sources/Protos"
+  cp -rp "${protos}/noop2" "${test_dir}/Sources/Protos"
+  cp "${sources}/NoOp.swift" "${test_dir}/Sources"
+  cp "${config}/internal-grpc-swift-proto-generator-config.json" "${test_dir}/Sources/Protos/grpc-swift-proto-generator-config.json"
+}
+
+test_01_top_level_config_file
+test_02_peer_config_file
+test_03_separate_service_message_protos
+test_04_cross_directory_imports
+test_05_two_definitions
+test_06_nested_definitions
+# Expected to fail:
+# test_07_duplicated_proto_file_name