From 08f60ece4f9092cc41b6b206801e2df7ff84bc6e Mon Sep 17 00:00:00 2001 From: Conor Schaefer Date: Wed, 15 May 2024 16:52:40 -0700 Subject: [PATCH] test(pd): add integration test for grpc reflection Refs #4392. We want to ensure that server reflection remains working, despite changes to the tonic dependencies (#4400) and proto compiling logic #4422. While the most effective test is exercising all these protos regularly, we currently lack solid coverage, so this superficial integration test is a sanity-check to save time versus building locally and inspecting the output manually. --- Cargo.lock | 2 + crates/bin/pd/Cargo.toml | 2 + crates/bin/pd/tests/network_integration.rs | 46 ++++++++++++++++++++++ deployments/scripts/smoke-test.sh | 6 +++ 4 files changed, 56 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 530bb8f031..496d30b8b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4526,6 +4526,7 @@ version = "0.75.0" dependencies = [ "anyhow", "ark-ff", + "assert_cmd", "async-stream", "async-trait", "axum", @@ -4581,6 +4582,7 @@ dependencies = [ "penumbra-transaction", "pin-project", "pin-project-lite", + "predicates 2.1.5", "prost", "prost-types", "rand 0.8.5", diff --git a/crates/bin/pd/Cargo.toml b/crates/bin/pd/Cargo.toml index e3a6e1c080..8272bbc1c0 100644 --- a/crates/bin/pd/Cargo.toml +++ b/crates/bin/pd/Cargo.toml @@ -128,3 +128,5 @@ penumbra-proof-params = { workspace = true, features = [ "bundled-proving-keys", "download-proving-keys", ], default-features = true } +assert_cmd = { workspace = true } +predicates = "2.1" diff --git a/crates/bin/pd/tests/network_integration.rs b/crates/bin/pd/tests/network_integration.rs index 17585ee39d..904845f5bf 100644 --- a/crates/bin/pd/tests/network_integration.rs +++ b/crates/bin/pd/tests/network_integration.rs @@ -4,7 +4,10 @@ //! headers in all contexts. Does NOT evaluate application logic; see the //! integration tests for pcli/pclientd for that. +use assert_cmd::Command; use http::StatusCode; +use predicates::prelude::*; +use url::Url; #[ignore] #[tokio::test] @@ -39,3 +42,46 @@ async fn check_minifront_http_ok() -> anyhow::Result<()> { assert_eq!(r.status(), StatusCode::OK); Ok(()) } + +#[ignore] +#[tokio::test] +/// Validate that gRPC server reflection is enabled and working, by calling out +/// to `grpcurl` and verifying that it can view methods. See GH4392 for context. +async fn check_grpc_server_reflection() -> anyhow::Result<()> { + let pd_url: Url = std::env::var("PENUMBRA_NODE_PD_URL") + .unwrap_or("http://localhost:8080".to_string()) + .parse() + .unwrap(); + let pd_hostname = format!("{}:{}", pd_url.host().unwrap(), pd_url.port().unwrap()); + let mut args = Vec::::new(); + if pd_url.scheme() == "http" { + args.push("-plaintext".to_owned()); + } + args.push(pd_hostname); + // grpcurl takes `list` as a command, to inspect the server reflection API. + args.push("list".to_owned()); + + // Permit override of the fullpath to the `grpcurl` binary, in case we want + // to test multiple versions in CI. + let grpcurl_path = std::env::var("GRPCURL_PATH").unwrap_or("grpcurl".to_string()); + let std_cmd = std::process::Command::new(grpcurl_path); + let mut cmd = Command::from_std(std_cmd); + cmd.args(args); + + // Here we hardcode a few specific checks, to verify they're present. + // This ensures reflection is ostensibly working, and doesn't assume + // that the FILE_DESCRIPTOR tonic-build logic is wired up. + let methods = vec![ + "penumbra.core.app.v1.QueryService", + // "grpc.reflection.v1alpha.ServerReflection", + "grpc.reflection.v1.ServerReflection", + "ibc.core.channel.v1.Query", + ]; + for m in methods { + cmd.assert().stdout(predicate::str::contains(m)); + } + cmd.assert() + .stdout(predicate::str::contains("ibc.core.channel.v1.Query")); + // TODO: import the method names from the FILE_DESCRIPTOR export from the proto crate. + Ok(()) +} diff --git a/deployments/scripts/smoke-test.sh b/deployments/scripts/smoke-test.sh index 728332e91b..8fc78dbe61 100755 --- a/deployments/scripts/smoke-test.sh +++ b/deployments/scripts/smoke-test.sh @@ -23,6 +23,12 @@ if ! hash process-compose > /dev/null 2>&1 ; then exit 1 fi +if ! hash grpcurl > /dev/null 2>&1 ; then + >&2 echo "ERROR: grpcurl not found in PATH" + >&2 echo "Install it via https://github.com/fullstorydev/grpcurl/" + exit 1 +fi + # Check for interactive terminal session, enable TUI if yes. if [[ -t 1 ]] ; then use_tui="true"