115 Commits

Author SHA1 Message Date
Gustavo Passini
400fa5f2d3 Update Dockerfile to use Go v1.21 (#455) 2024-04-10 11:33:24 -04:00
goodfirm
0e13e85e65 chore: fix some typos in comments (#454)
Signed-off-by: goodfirm <fanyishang@yeah.net>
2024-04-10 09:51:09 -04:00
Joshua Humphries
07361b21ea Use latest protoreflect to fix some bugs (#453)
* update to latest jhump/protoreflect

* be lenient when possible if server cannot furnish all dependencies

* move linting back to go 1.21 instead of latest go 1.22

* make staticcheck happy
2024-04-09 17:50:10 -04:00
Gustavo Passini
8e76884d21 Brand name update (#452) 2024-04-09 16:19:28 -04:00
dependabot[bot]
805ce40c63 Bump github.com/golang/protobuf from 1.5.3 to 1.5.4 (#448)
Bumps [github.com/golang/protobuf](https://github.com/golang/protobuf) from 1.5.3 to 1.5.4.
- [Release notes](https://github.com/golang/protobuf/releases)
- [Commits](https://github.com/golang/protobuf/compare/v1.5.3...v1.5.4)

---
updated-dependencies:
- dependency-name: github.com/golang/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-11 08:31:42 -04:00
Albin Parou
93ea011b36 goreleaser: bump version & add nfmp support (#440) 2024-02-26 09:09:32 -05:00
Paul Chesnais
5592211a41 Enable xDS credentials (#424)
* Enable xDS credentials

This change should be relatively straightforward. It is a noop outside of the
context of xDS (as demonstrated by the fact that the tests all pass), but it
enables xDS-provided certificates (i.e. the ones that would be
provided/specified in GRPC_XDS_BOOTSTRAP). See proposal
[A29](https://github.com/grpc/proposal/blob/master/A29-xds-tls-security.md#go)
for additional detail.

* Only enable xds credentials if the target is an xDS target

* Update after merge
2024-02-12 13:49:16 -05:00
dependabot[bot]
184c8f70b5 Bump github.com/jhump/protoreflect from 1.15.5 to 1.15.6 (#446)
Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.15.5 to 1.15.6.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.15.5...v1.15.6)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-07 12:30:33 -05:00
Kristopher Wuollett
149a93e0ec Use localhost for default unix domain socket authority (#445) 2024-01-30 11:38:15 -05:00
dependabot[bot]
252b57fd45 Bump github.com/jhump/protoreflect from 1.15.4 to 1.15.5 (#443)
Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.15.4 to 1.15.5.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.15.4...v1.15.5)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-29 13:38:20 -05:00
KaibutsuX
24b80dfed8 Added initial support for -t flag to show timings (#428)
* Added initial support for -t flag to show timings

Shows very basic timing data for the Dial stage (TLS setup and
BlockingDial) and InvokeRPC method as well as the total time.

* Made timing data part of the very verbose functionality

* cleanup

* fix

---------

Co-authored-by: Scott Blum <dragonsinth@gmail.com>
2024-01-23 19:04:51 -05:00
Michael Diamond
334e3f56de Expand the documentation of -max-time to clarify this sets the RPC timeout (#435)
Notably, this adds the words "timeout" and "deadline" to this help text which is helpful for discovering this flag.
2024-01-09 11:39:10 -05:00
dependabot[bot]
f4157743ed Bump github.com/jhump/protoreflect from 1.15.3 to 1.15.4 (#436)
Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-01-08 16:59:50 -05:00
dependabot[bot]
79fb35f680 Bump google.golang.org/protobuf from 1.31.0 to 1.32.0 (#437)
* Bump google.golang.org/protobuf from 1.31.0 to 1.32.0

Bumps google.golang.org/protobuf from 1.31.0 to 1.32.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* go mod tidy?

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scott Blum <dragonsinth@gmail.com>
2023-12-26 09:20:30 -05:00
Scott Blum
7ccaf0a21f indent: rip out old go 1.9 support 2023-11-22 08:54:31 -05:00
ns-yuhanl
6093b09afa Bump golang.google.org/grpc to v1.57.1 (#427)
* Bump golang.google.org/grpc to v1.57.1

	See https://github.com/advisories/GHSA-m425-mq94-257g

* Revert "Bump golang.google.org/grpc to v1.57.1"

This reverts commit 385868b36b.

* Bump golang.google.org/grpc to v1.57.1
2023-10-26 12:39:52 -04:00
Gustavo Passini
70c215f7e2 Update Tarball URL used by Homebrew (#421) 2023-10-24 15:33:15 -04:00
Gustavo Passini
28c0ee28f0 Disable CGO for improved compatibility across distros (#420)
* Disable CGO for improved compatibility across distros

* Enabled CGO in tests for the race detector
2023-10-24 11:53:47 -04:00
dependabot[bot]
bc2944de97 Bump golang.org/x/net from 0.9.0 to 0.17.0 (#419)
* Bump golang.org/x/net from 0.9.0 to 0.17.0

Bumps [golang.org/x/net](https://github.com/golang/net) from 0.9.0 to 0.17.0.
- [Commits](https://github.com/golang/net/compare/v0.9.0...v0.17.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

* manual go.sum

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scott Blum <dragonsinth@gmail.com>
2023-10-12 14:45:27 +00:00
Michael Primeaux
7a845ca5e9 SIGSEGV: panic: runtime error: invalid memory address or nil pointer dereference in protoreflect (#416)
* SIGSEGV: panic: runtime error: invalid memory address

- Executed the updatedeps make target
- protoreflect upgraded to v1.15.3, which addresses this panic.

* Reverted. Only updated protoreflect.
2023-10-03 16:42:07 -04:00
Jonathan Beaulieu
c17f0782f7 Added alts credential option (#341)
* Added alts credential option

Added flag that sets up ALTS credentials to connect to gRPC services using Application Layer Transport Security.

Reference: https://grpc.io/docs/languages/go/alts/
Fixes: #333

* Added ALTS client options as cmd arguments.

* Update target service accounts docs

Co-authored-by: Joshua Humphries <2035234+jhump@users.noreply.github.com>

* Applied feedback

* Small fix: removed indirection on usetls

---------

Co-authored-by: Joshua Humphries <2035234+jhump@users.noreply.github.com>
2023-09-25 13:57:49 -04:00
Scott Blum
42f63028d4 Update go.mod, goreleaser for v1.8.8 (#413)
* Update go.mod, goreleaser for v1.8.8

* move ci check to go 1.20

* debug

* ci diff
2023-09-22 16:21:54 -04:00
Valters Jansons
743e60a4c9 Run tests on Go 1.21 (#408)
* Run tests on Go 1.21

For the most part, there are no breaking changes.

However, the expired certificate is now showing "expired certificate"
although previously it showed a simpler "bad certificate" which was
hard-coded into the TLS settings test scenario.

* Simplify condition for certificate error

Instead of two `expired certificate` and `bad certificate` comparisons, we can just check for `certificate` in error output. This satisfies us when checking there is something wrong with the certificate.

Co-authored-by: Scott Blum <dragonsinth@gmail.com>

---------

Co-authored-by: Scott Blum <dragonsinth@gmail.com>
2023-08-31 12:14:34 -04:00
Valters Jansons
b7a5d3bba8 Update protoreflect v1.15.2 and grpc v1.57.0 (#406)
The proposal already exists by Dependabot, but the version bump pulls
in `grpc.reflection.v1.ServerReflection` resulting in minor test change
being required.

Transient dependency `github.com/bufbuild/protocompile` is now added,
and requires at least Go 1.18. This PR includes the version removal.
2023-08-31 12:14:03 -04:00
Valters Jansons
2a29c1e64b Use grpc.reflection.v1.ServerReflection (#407)
The proper `v1` gRPC reflection has been around for a bit.
The "client auto" mechanism still supports falling back to `v1alpha`.
Not many support the `v1`, but we should default to it when possible.
2023-08-31 12:13:33 -04:00
dependabot[bot]
9a59bed1d2 Bump google.golang.org/protobuf from 1.30.0 to 1.31.0 (#401)
Bumps google.golang.org/protobuf from 1.30.0 to 1.31.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-26 12:05:13 -04:00
dependabot[bot]
ae7dadff19 Bump google.golang.org/grpc from 1.55.0 to 1.56.1 (#400)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.55.0 to 1.56.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.55.0...v1.56.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-06-26 11:38:28 -04:00
Sophy Cao
3961a33e7f Fix issues with error details (#379)
Co-authored-by: Erik Engberg <ejohansson@spotify.com>
2023-06-22 12:58:51 -04:00
Joshua Humphries
d5b8e4d4ce fix nil-dereference panic (#395) 2023-05-12 12:50:32 -04:00
dependabot[bot]
0efcfa65f2 Bump google.golang.org/grpc from 1.54.0 to 1.55.0 (#390)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.54.0 to 1.55.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.54.0...v1.55.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-05-09 20:08:41 -04:00
Joshua Humphries
fae58803d9 Add "checkgenerate" make target to CI (#385) 2023-04-18 12:09:16 -04:00
dependabot[bot]
1fda47eb90 Bump google.golang.org/grpc from 1.53.0 to 1.54.0 (#383)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.53.0 to 1.54.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.53.0...v1.54.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-27 10:01:15 -04:00
dependabot[bot]
031cd3d1e7 Bump google.golang.org/protobuf from 1.29.1 to 1.30.0 (#378)
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.29.1 to 1.30.0.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.29.1...v1.30.0)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-20 09:58:32 -04:00
dependabot[bot]
a5037bdf4a Bump google.golang.org/protobuf from 1.29.0 to 1.29.1 (#376)
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.29.0 to 1.29.1.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.29.0...v1.29.1)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-14 23:11:32 +00:00
dependabot[bot]
4775fb574b Bump google.golang.org/protobuf from 1.28.1 to 1.29.0 (#375)
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.28.1 to 1.29.0.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.28.1...v1.29.0)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-13 09:12:47 -04:00
dependabot[bot]
b96cb4ddd0 Bump github.com/golang/protobuf from 1.5.2 to 1.5.3 (#374)
Bumps [github.com/golang/protobuf](https://github.com/golang/protobuf) from 1.5.2 to 1.5.3.
- [Release notes](https://github.com/golang/protobuf/releases)
- [Commits](https://github.com/golang/protobuf/compare/v1.5.2...v1.5.3)

---
updated-dependencies:
- dependency-name: github.com/golang/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-13 09:11:31 -04:00
dependabot[bot]
006918123d Bump google.golang.org/grpc from 1.52.3 to 1.53.0 (#370)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.52.3 to 1.53.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.52.3...v1.53.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-13 17:08:49 -05:00
codesee-maps[bot]
66a2405833 Install the CodeSee workflow. Learn more at https://docs.codesee.io (#368)
Co-authored-by: codesee-maps[bot] <86324825+codesee-maps[bot]@users.noreply.github.com>
2023-02-07 15:24:26 -05:00
dependabot[bot]
dfd889a44b Bump google.golang.org/grpc from 1.51.0 to 1.52.3 (#365)
* Bump google.golang.org/grpc from 1.51.0 to 1.52.3

Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.51.0 to 1.52.3.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.51.0...v1.52.3)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* update test assertion for latest version of grpc-go (#366)

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Joshua Humphries <2035234+jhump@users.noreply.github.com>
2023-01-30 20:35:03 -05:00
dependabot[bot]
a3a5bcd8ab Bump github.com/jhump/protoreflect from 1.14.0 to 1.14.1 (#361)
Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.14.0 to 1.14.1.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.14.0...v1.14.1)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-16 09:15:25 -05:00
dependabot[bot]
61a9c00d87 Bump google.golang.org/grpc from 1.50.1 to 1.51.0 (#348)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.50.1 to 1.51.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.50.1...v1.51.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-22 11:01:49 -05:00
cui fliter
85f1cbf7ad fix funcname in comment (#346)
Signed-off-by: cui fliter <imcusg@gmail.com>

Signed-off-by: cui fliter <imcusg@gmail.com>
2022-11-09 07:59:56 -05:00
dependabot[bot]
dd2f60135c Bump github.com/jhump/protoreflect from 1.13.0 to 1.14.0 (#343)
* Bump github.com/jhump/protoreflect from 1.13.0 to 1.14.0

Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.13.0 to 1.14.0.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.13.0...v1.14.0)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix ci

* what can we even build on?

* stop testing old things

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scott Blum <dragonsinth@gmail.com>
2022-11-01 10:26:55 -04:00
dependabot[bot]
81c624c41f Bump google.golang.org/grpc from 1.50.0 to 1.50.1 (#338)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.50.0 to 1.50.1.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.50.0...v1.50.1)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-17 12:49:30 -04:00
dependabot[bot]
3826617999 Bump google.golang.org/grpc from 1.49.0 to 1.50.0 (#336)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.49.0 to 1.50.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.49.0...v1.50.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-10 12:31:11 -04:00
dependabot[bot]
8d60b618ac Bump github.com/jhump/protoreflect from 1.12.0 to 1.13.0 (#335)
Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.12.0 to 1.13.0.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.12.0...v1.13.0)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-09-19 11:26:42 -04:00
dependabot[bot]
47b842a805 Bump google.golang.org/grpc from 1.48.0 to 1.49.0 (#330)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.48.0 to 1.49.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.48.0...v1.49.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-29 09:36:26 -04:00
Scott Blum
898bdad041 fixup release process (#328) 2022-08-10 14:25:13 -04:00
dependabot[bot]
25c896aa59 Bump google.golang.org/protobuf from 1.28.0 to 1.28.1 (#327)
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.28.0 to 1.28.1.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.28.0...v1.28.1)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-08 12:26:59 -04:00
Scott Blum
0d0992e6a2 Add go 1.18 support; set Dockerfile to go 1.18 (#325) 2022-07-25 11:54:27 -04:00
Ben Redmond-Benham
8093376ece build alpine base image (#311) 2022-07-20 14:58:00 -04:00
cui fliter
fec466efa6 fix some typos (#314)
Signed-off-by: cuishuang <imcusg@gmail.com>
2022-07-20 14:57:53 -04:00
dependabot[bot]
7f919e6459 Bump google.golang.org/grpc from 1.47.0 to 1.48.0 (#324)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.47.0 to 1.48.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.47.0...v1.48.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-07-18 13:22:36 -04:00
ghatwala
0df5c93e8d Adding power(ppc64le) arch support (#296)
Needing power(ppc64le) arch based "grpcurl" binaries here https://docs.openshift.com/container-platform/4.9/operators/admin/olm-restricted-networks.html
1. Adding power support for releases and docker images(multi-arch).

signed-off-by : Amit Ghatwal <ghatwala@us.ibm.com>
2022-06-27 11:10:08 -04:00
Lyubomir Gardev
353e0953cb Enable support for Unix sockets for Windows by enabling -unix flag for Windows builds. (#317) 2022-06-20 09:37:33 -04:00
dependabot[bot]
c9ac3da95f Bump google.golang.org/grpc from 1.46.2 to 1.47.0 (#315)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.46.2 to 1.47.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.46.2...v1.47.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-06 08:08:43 -04:00
dependabot[bot]
ea24a77215 Bump github.com/jhump/protoreflect from 1.10.3 to 1.12.0 (#294)
Bumps [github.com/jhump/protoreflect](https://github.com/jhump/protoreflect) from 1.10.3 to 1.12.0.
- [Release notes](https://github.com/jhump/protoreflect/releases)
- [Commits](https://github.com/jhump/protoreflect/compare/v1.10.3...v1.12.0)

---
updated-dependencies:
- dependency-name: github.com/jhump/protoreflect
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-02 16:18:22 -04:00
dependabot[bot]
c3fbeaff64 Bump google.golang.org/grpc from 1.44.0 to 1.46.2 (#310)
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.44.0 to 1.46.2.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.44.0...v1.46.2)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Scott Blum <dragonsinth@gmail.com>
2022-06-02 16:10:40 -04:00
dependabot[bot]
7860209a53 Bump google.golang.org/protobuf from 1.27.1 to 1.28.0 (#298)
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.27.1 to 1.28.0.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.27.1...v1.28.0)

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-02 15:56:21 -04:00
Joshua Humphries
b953ea196a use newer goreleaser (#293) 2022-02-15 20:31:31 -05:00
Joshua Humphries
683a7fb09c Restore support for linux/s390x for the next release. (#292)
This reverts commit 8ee6c9423b.
2022-02-15 19:03:59 -05:00
dependabot[bot]
8bb6eeb0d0 Bump google.golang.org/protobuf from 1.26.0 to 1.27.1 (#288)
Bumps [google.golang.org/protobuf](https://github.com/protocolbuffers/protobuf-go) from 1.26.0 to 1.27.1.
- [Release notes](https://github.com/protocolbuffers/protobuf-go/releases)
- [Changelog](https://github.com/protocolbuffers/protobuf-go/blob/master/release.bash)
- [Commits](https://github.com/protocolbuffers/protobuf-go/compare/v1.26.0...v1.27.1)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 14:27:46 -05:00
Joshua Humphries
805e231182 bump protoreflect again, to 1.10.3 (#290) 2022-02-08 16:49:23 -05:00
Joshua Humphries
aa5998a119 no longer supporting go 1.14 (#289) 2022-02-07 12:03:53 -05:00
Jeff Widman
b34b13bab3 Bump grpc lib and fix deprecations (#286)
* Bump google.golang.org/grpc from 1.37.0 to 1.44.0

Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.37.0 to 1.44.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.37.0...v1.44.0)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-05 10:28:05 -05:00
Jeff Widman
b890db745f Bump protobuf lib and fix deprecation warnings (#285)
* Bump github.com/golang/protobuf from 1.4.2 to 1.5.2

Bumps [github.com/golang/protobuf](https://github.com/golang/protobuf) from 1.4.2 to 1.5.2.
- [Release notes](https://github.com/golang/protobuf/releases)
- [Commits](https://github.com/golang/protobuf/compare/v1.4.2...v1.5.2)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
---

* Also pulls along update of golang.google.org/protobuf to v1.26
* Fix deprecation warnings about `ptypes` package
2022-02-04 17:19:52 -05:00
Vladyslav Shalamai
57a2cd1a09 bump github.com/jhump/protoreflect from v1.10.1 to v1.10.2 (#284) 2022-02-04 10:15:18 -05:00
wwuck
ae7473c7a7 add dependabot configuration (#267) 2022-01-12 09:57:41 -05:00
Joshua Humphries
b3f576068c update golang.org/x/text to v0.3.7 (#275) 2022-01-10 15:18:54 -05:00
Joshua Humphries
8ee6c9423b can't build s390x docker images; skip for now (#265) 2021-10-07 16:37:41 -04:00
Joshua Humphries
4b65b3ee55 fix release script: 'docker buildx create' step needs to be re-runnable without error (#264) 2021-10-07 16:10:47 -04:00
Jeffrey Duce
9ac7e3a34d set value of creds instead of creating new variable (#263) 2021-10-07 15:49:59 -04:00
Joshua Humphries
76bbedeed0 invoking client-streaming RPC can panic (#262) 2021-10-07 14:55:12 -04:00
Joshua Humphries
b9d2d8cfa8 cleanup deps; pin versions of tools using 'go install' instead of in go.mod; tidy up go.sum (#260)
Addresses two depend-a-bot security warnings for libraries previously references in go.sum.
2021-10-06 20:58:00 -04:00
Bjarne Sievers
30b8cd1531 Add info about docker pitfalls to README (#258) 2021-10-06 15:25:18 -04:00
Joshua Humphries
a8f79c8751 use latest protoreflect (#259) 2021-10-06 09:39:01 -04:00
Joshua Humphries
bf9b13d6c5 update install from source directions to work with Go 1.16 2021-09-23 10:37:13 -04:00
Joshua Humphries
c3bde04cc1 use circleci instead of travis (#256) 2021-09-23 09:20:48 -04:00
Namrata Bhave
2e9ba5024e Build multiarch docker images for release: amd, s390x, arm (#251) 2021-09-23 07:55:01 -04:00
Igor
127194b205 Support SSLKEYLOGFILE environment variable for key logging (#245) 2021-09-20 11:53:44 -04:00
Namrata Bhave
cd242fe1ed build release binaries for linux/s390x (#248) 2021-08-18 08:53:40 -04:00
Sunil Thorat
59a32e5eb0 Upgrade to using golang 1.15 to build (#240) 2021-07-14 10:24:01 -04:00
Joshua Humphries
7e1cd16164 use newer protoreflect, v1.9.0 (#242) 2021-07-13 11:53:16 -04:00
Joshua Humphries
de25c89822 allow callers of BlockingDial to override grpc.FailOnNonTempDialError dial option (#241) 2021-07-12 15:27:33 -04:00
Joshua Humphries
f1d396c31e freshen README, point to 3rd party packages for install (#229) 2021-05-04 12:03:54 -04:00
Josh Humphries
1986364acd make go.sum authoritative 2021-04-30 17:15:18 -04:00
Erik Johansson
bdf97bc934 Bump grpc-go to 1.37.0 (#230)
Pulls in support for XDS v3
2021-04-29 10:48:41 -04:00
Z. Liu
2f55ac63a4 release binaries for arm64 (#220) 2021-04-02 08:06:16 -04:00
Joshua Humphries
8d7770a962 use latest version of protoreflect (#212) 2021-02-22 17:32:40 -05:00
Leonhard Markert
1f34448998 Help text for "-H" option: remove duplicated word (#207) 2021-02-01 10:31:49 -05:00
Josh Humphries
06a970022e darwin/386... 🤦 2021-01-05 12:42:15 -05:00
Josh Humphries
db90ec1160 go 1.15 no longer supports darwin/386; ignore any IDE config folder 2021-01-05 12:39:34 -05:00
Mikhail Katychev
9da71fbe53 when -format-error option is used, format service reflection errors, too (#188) 2020-09-30 13:24:46 -04:00
Guilherme Salazar
9846afccbc feat: add support for user-agent header (#182) 2020-09-04 11:31:28 -04:00
Joshua Humphries
ba5f667e13 fix latest CI breakages by forking code from grpc-go's interop/testing
Also moves testing package to internal/testing
2020-08-31 14:44:59 -04:00
Joshua Humphries
54ffdcacda fix typo 2020-08-24 13:58:09 -04:00
Joshua Humphries
ceef817807 make use of -plaintext flag more clear in examples 2020-08-24 13:56:57 -04:00
Sergei Vorobev
e544b9e66f Print size of the message in very verbose mode (#181)
Adds -vv flag for "very verbose".
Includes estimated message size when enabled. The size is an estimate because it is the canonical size for the proto message, but not necessarily its actual on-the-wire size.
2020-08-14 11:02:42 -04:00
Joshua Humphries
41a6ac0479 no more support for go 1.11 without modules (#180) 2020-07-31 12:26:31 -04:00
Joshua Humphries
f37ec641c5 make release work... (#179) 2020-07-30 22:10:03 -04:00
Adam Babik
8e51c5e2d3 cmd/grpcurl: add -allow-unknown-fields option (#147) 2020-07-23 10:54:06 -04:00
Joshua Humphries
8376c2f7bb update go get line in README
Go tool needs to also gets dependencies for sub-packages
2020-07-20 12:46:55 -04:00
Joshua Humphries
0162fa9726 go.mod and Makefile tweaks; move import of xds package to cmd/grpcurl (#170) 2020-07-14 12:20:32 -04:00
Erik Johansson
b8c67b7a4e Bump grpc-go to 1.30.0 (#168)
* Bump grpc-go to 1.30.0
* Import new xds package instead of experimental

Co-authored-by: Erik Johansson <ejohansson@spotify.com>
2020-07-13 13:16:48 -04:00
Joshua Humphries
ff114930fd update travis badge and link 2020-07-09 20:53:23 -04:00
Joshua Humphries
5ad5edb29c pin goreleaser in go.mod; fix config file so latest version accepts it; allow using go modules in 'make release' (#161) 2020-06-01 18:56:18 -04:00
Joshua Humphries
44547153b3 unpin Go point release and alpine version in Dockerfile (#162) 2020-05-15 11:40:32 -04:00
Joshua Humphries
2108c8f0b3 use go 1.13 to build docker image (#160) 2020-05-15 08:21:08 -04:00
Mikhail Katychev
36008aa111 Add -format-error option (#155) 2020-05-14 20:40:13 -04:00
Joshua Humphries
50833f1b21 upgrade deps; remove go 1.14 from go.mod (#158) 2020-05-14 20:00:04 -04:00
Joshua Humphries
939766fb42 Go tip does not like using string(i) where i untyped int (#159) 2020-05-14 19:38:08 -04:00
Joshua Humphries
b58182a88d get travis CI green again (#157)
* fix test to work w/ newer grpc repo; run 'make ci' to have it update go.mod and go.sum, trying to repro ci failure locally
* vet w/ go 1.13; use normal go proxy instead of direct in CI
2020-05-12 13:06:14 -04:00
Serge Bazanski
8e2cf9b3c2 fix crash when emitting empty messages in text format (#153) 2020-04-23 16:20:45 -04:00
Alexander Chiu
36f9e53dfd Allow extra descriptor sources in reflection mode (#146)
Allows descriptors or proto files to be supplied that are used as an additional descriptor source when server reflection is used. This is needed to resolve message types embedded in an Any message, that the server has no knowledge of, as well as extensions that the server has no knowledge of.
2020-04-20 15:42:11 -04:00
Joshua Humphries
bfbbed1d42 vet with modules (#150)
fixes CI failures caused by newer version of dependency introducing new deprecations that cause staticcheck violations
2020-04-16 15:27:01 -04:00
78 changed files with 6092 additions and 3357 deletions

49
.circleci/config.yml Normal file
View File

@@ -0,0 +1,49 @@
shared_configs:
simple_job_steps: &simple_job_steps
- checkout
- run:
name: Run tests
command: |
make test
# Use the latest 2.1 version of CircleCI pipeline process engine. See: https://circleci.com/docs/2.0/configuration-reference
version: 2.1
jobs:
build-1-19:
working_directory: ~/repo
docker:
- image: cimg/go:1.19
steps: *simple_job_steps
build-1-20:
working_directory: ~/repo
docker:
- image: cimg/go:1.20
steps: *simple_job_steps
build-1-21:
working_directory: ~/repo
docker:
- image: cimg/go:1.21
steps:
- checkout
- run:
name: Run tests and linters
command: |
make ci
# TODO: Need updates to some static analyzer tools to support 1.22. After those
# are updated, move the full linting from 1.21 to this latest release.
build-1-22:
working_directory: ~/repo
docker:
- image: cimg/go:1.22
steps: *simple_job_steps
workflows:
pr-build-test:
jobs:
- build-1-19
- build-1-20
- build-1-21
- build-1-22

7
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "gomod"
directory: "/"
# Check for updates once a week
schedule:
interval: "weekly"

View File

@@ -0,0 +1,22 @@
# This workflow was added by CodeSee. Learn more at https://codesee.io/
# This is v2.0 of this workflow file
on:
push:
branches:
- master
pull_request_target:
types: [opened, synchronize, reopened]
name: CodeSee
permissions: read-all
jobs:
codesee:
runs-on: ubuntu-latest
continue-on-error: true
name: Analyze the repo with CodeSee
steps:
- uses: Codesee-io/codesee-action@v2
with:
codesee-token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}

2
.gitignore vendored
View File

@@ -1,2 +1,4 @@
dist/ dist/
.idea/
VERSION VERSION
.tmp/

View File

@@ -8,17 +8,47 @@ builds:
goarch: goarch:
- amd64 - amd64
- 386 - 386
- arm64
- s390x
- ppc64le
ignore:
- goos: darwin
goarch: 386
- goos: windows
goarch: arm64
- goos: darwin
goarch: s390x
- goos: windows
goarch: s390x
- goos: darwin
goarch: ppc64le
- goos: windows
goarch: ppc64le
ldflags: ldflags:
- -s -w -X main.version=v{{.Version}} - -s -w -X main.version=v{{.Version}}
archive: archives:
format: tar.gz - format: tar.gz
format_overrides: name_template: >-
- goos: windows {{ .Binary }}_{{ .Version }}_
format: zip {{- if eq .Os "darwin" }}osx{{ else }}{{ .Os }}{{ end }}_
replacements: {{- if eq .Arch "amd64" }}x86_64
amd64: x86_64 {{- else if eq .Arch "386" }}x86_32
386: x86_32 {{- else }}{{ .Arch }}{{ end }}
darwin: osx {{- with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}
files: format_overrides:
- LICENSE - goos: windows
format: zip
files:
- LICENSE
nfpms:
- vendor: Fullstory
homepage: https://github.com/fullstorydev/grpcurl/
maintainer: Engineering at Fullstory <fixme@fixme>
description: 'Like cURL, but for gRPC: Command-line tool for interacting with gRPC servers'
license: MIT
id: nfpms
formats:
- deb
- rpm

View File

@@ -1,31 +0,0 @@
language: go
sudo: false
matrix:
include:
# TODO: update the version used to vet to Go 1.13
- go: 1.11.x
env:
- GO111MODULE=off
- VET=1
- go: 1.11.x
env: GO111MODULE=on
- go: 1.12.x
env: GO111MODULE=off
- go: 1.12.x
env: GO111MODULE=on
- go: 1.13.x
env:
- GO111MODULE=on
- GOPROXY=direct
- go: 1.14.x
env:
- GO111MODULE=on
- GOPROXY=direct
- go: tip
env:
- GO111MODULE=on
- GOPROXY=direct
script:
- if [[ "$VET" = 1 ]]; then make ci; else make deps test; fi

View File

@@ -1,10 +1,6 @@
FROM golang:1.11.10-alpine as builder FROM golang:1.21-alpine as builder
MAINTAINER FullStory Engineering MAINTAINER Fullstory Engineering
# currently, a module build requires gcc (so Go tool can build
# module-aware versions of std library; it ships only w/ the
# non-module versions)
RUN apk update && apk add --no-cache ca-certificates git gcc g++ libc-dev
# create non-privileged group and user # create non-privileged group and user
RUN addgroup -S grpcurl && adduser -S grpcurl -G grpcurl RUN addgroup -S grpcurl && adduser -S grpcurl -G grpcurl
@@ -15,13 +11,20 @@ COPY cmd /tmp/fullstorydev/grpcurl/cmd
# and build a completely static binary (so we can use # and build a completely static binary (so we can use
# scratch as basis for the final image) # scratch as basis for the final image)
ENV CGO_ENABLED=0 ENV CGO_ENABLED=0
ENV GOOS=linux
ENV GOARCH=amd64
ENV GO111MODULE=on ENV GO111MODULE=on
RUN go build -o /grpcurl \ RUN go build -o /grpcurl \
-ldflags "-w -extldflags \"-static\" -X \"main.version=$(cat VERSION)\"" \ -ldflags "-w -extldflags \"-static\" -X \"main.version=$(cat VERSION)\"" \
./cmd/grpcurl ./cmd/grpcurl
FROM alpine:3 as alpine
WORKDIR /
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /grpcurl /bin/grpcurl
USER grpcurl
ENTRYPOINT ["/bin/grpcurl"]
# New FROM so we have a nice'n'tiny image # New FROM so we have a nice'n'tiny image
FROM scratch FROM scratch
WORKDIR / WORKDIR /

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2017 FullStory, Inc Copyright (c) 2017 Fullstory, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -1,20 +1,29 @@
dev_build_version=$(shell git describe --tags --always --dirty) dev_build_version=$(shell git describe --tags --always --dirty)
export PATH := $(shell pwd)/.tmp/protoc/bin:$(PATH)
export PROTOC_VERSION := 22.0
# Disable CGO for improved compatibility across distros
export CGO_ENABLED=0
# TODO: run golint and errcheck, but only to catch *new* violations and # TODO: run golint and errcheck, but only to catch *new* violations and
# decide whether to change code or not (e.g. we need to be able to whitelist # decide whether to change code or not (e.g. we need to be able to whitelist
# violations already in the code). They can be useful to catch errors, but # violations already in the code). They can be useful to catch errors, but
# they are just too noisy to be a requirement for a CI -- we don't even *want* # they are just too noisy to be a requirement for a CI -- we don't even *want*
# to fix some of the things they consider to be violations. # to fix some of the things they consider to be violations.
.PHONY: ci .PHONY: ci
ci: deps checkgofmt vet staticcheck ineffassign predeclared test ci: deps checkgofmt checkgenerate vet staticcheck ineffassign predeclared test
.PHONY: deps .PHONY: deps
deps: deps:
go get -d -v -t ./... go get -d -v -t ./...
go mod tidy
.PHONY: updatedeps .PHONY: updatedeps
updatedeps: updatedeps:
go get -d -v -t -u -f ./... go get -d -v -t -u -f ./...
go mod tidy
.PHONY: install .PHONY: install
install: install:
@@ -22,8 +31,8 @@ install:
.PHONY: release .PHONY: release
release: release:
@GO111MODULE=off go get github.com/goreleaser/goreleaser @go install github.com/goreleaser/goreleaser@v1.21.0
goreleaser --rm-dist goreleaser release --clean
.PHONY: docker .PHONY: docker
docker: docker:
@@ -31,6 +40,20 @@ docker:
docker build -t fullstorydev/grpcurl:$(dev_build_version) . docker build -t fullstorydev/grpcurl:$(dev_build_version) .
@rm VERSION @rm VERSION
.PHONY: generate
generate: .tmp/protoc/bin/protoc
@go install google.golang.org/protobuf/cmd/protoc-gen-go@a709e31e5d12
@go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1.0
go generate ./...
.PHONY: checkgenerate
checkgenerate: generate
git status --porcelain
@if [ -n "$$(git status --porcelain)" ]; then \
git diff; \
exit 1; \
fi
.PHONY: checkgofmt .PHONY: checkgofmt
checkgofmt: checkgofmt:
gofmt -s -l . gofmt -s -l .
@@ -42,41 +65,38 @@ checkgofmt:
vet: vet:
go vet ./... go vet ./...
# TODO: remove the ignored check; need it for now because it
# is complaining about a deprecated comment added to grpc,
# but it's not yet released. Once the new (non-deprecated)
# API is included in a release, we can move to that new
# version and fix the call site to no longer use deprecated
# method.
# This all works fine with Go modules, but without modules,
# CI is just getting latest master for dependencies like grpc.
.PHONY: staticcheck .PHONY: staticcheck
staticcheck: staticcheck:
@go get honnef.co/go/tools/cmd/staticcheck @go install honnef.co/go/tools/cmd/staticcheck@v0.4.3
staticcheck ./... staticcheck ./...
.PHONY: ineffassign .PHONY: ineffassign
ineffassign: ineffassign:
@go get github.com/gordonklaus/ineffassign @go install github.com/gordonklaus/ineffassign@7953dde2c7bf
ineffassign . ineffassign .
.PHONY: predeclared .PHONY: predeclared
predeclared: predeclared:
@go get github.com/nishanths/predeclared @go install github.com/nishanths/predeclared@5f2f810c9ae6
predeclared . predeclared ./...
# Intentionally omitted from CI, but target here for ad-hoc reports. # Intentionally omitted from CI, but target here for ad-hoc reports.
.PHONY: golint .PHONY: golint
golint: golint:
@go get golang.org/x/lint/golint @go install golang.org/x/lint/golint@v0.0.0-20210508222113-6edffad5e616
golint -min_confidence 0.9 -set_exit_status ./... golint -min_confidence 0.9 -set_exit_status ./...
# Intentionally omitted from CI, but target here for ad-hoc reports. # Intentionally omitted from CI, but target here for ad-hoc reports.
.PHONY: errcheck .PHONY: errcheck
errcheck: errcheck:
@go get github.com/kisielk/errcheck @go install github.com/kisielk/errcheck@v1.2.0
errcheck ./... errcheck ./...
.PHONY: test .PHONY: test
test: test:
go test -race ./... # The race detector requires CGO: https://github.com/golang/go/issues/6508
CGO_ENABLED=1 go test -race ./...
.tmp/protoc/bin/protoc: ./Makefile ./download_protoc.sh
./download_protoc.sh

View File

@@ -1,5 +1,5 @@
# gRPCurl # gRPCurl
[![Build Status](https://travis-ci.org/fullstorydev/grpcurl.svg?branch=master)](https://travis-ci.org/fullstorydev/grpcurl/branches) [![Build Status](https://circleci.com/gh/fullstorydev/grpcurl/tree/master.svg?style=svg)](https://circleci.com/gh/fullstorydev/grpcurl/tree/master)
[![Go Report Card](https://goreportcard.com/badge/github.com/fullstorydev/grpcurl)](https://goreportcard.com/report/github.com/fullstorydev/grpcurl) [![Go Report Card](https://goreportcard.com/badge/github.com/fullstorydev/grpcurl)](https://goreportcard.com/report/github.com/fullstorydev/grpcurl)
`grpcurl` is a command-line tool that lets you interact with gRPC servers. It's `grpcurl` is a command-line tool that lets you interact with gRPC servers. It's
@@ -14,7 +14,7 @@ This program accepts messages using JSON encoding, which is much more friendly f
humans and scripts. humans and scripts.
With this tool you can also browse the schema for gRPC services, either by querying With this tool you can also browse the schema for gRPC services, either by querying
a server that supports [server reflection](https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto), a server that supports [server reflection](https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1/reflection.proto),
by reading proto source files, or by loading in compiled "protoset" files (files that contain by reading proto source files, or by loading in compiled "protoset" files (files that contain
encoded file [descriptor protos](https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto)). encoded file [descriptor protos](https://github.com/google/protobuf/blob/master/src/google/protobuf/descriptor.proto)).
In fact, the way the tool transforms JSON request data into a binary encoded protobuf In fact, the way the tool transforms JSON request data into a binary encoded protobuf
@@ -35,9 +35,9 @@ See also the [`grpcurl` talk at GopherCon 2018](https://www.youtube.com/watch?v=
operate bi-directional streaming methods interactively by running `grpcurl` from an operate bi-directional streaming methods interactively by running `grpcurl` from an
interactive terminal and using stdin as the request body! interactive terminal and using stdin as the request body!
`grpcurl` supports both plain-text and TLS servers and has numerous options for TLS `grpcurl` supports both secure/TLS servers _and_ plain-text servers (i.e. no TLS) and has
configuration. It also supports mutual TLS, where the client is required to present a numerous options for TLS configuration. It also supports mutual TLS, where the client is
client certificate. required to present a client certificate.
As mentioned above, `grpcurl` works seamlessly if the server supports the reflection As mentioned above, `grpcurl` works seamlessly if the server supports the reflection
service. If not, you can supply the `.proto` source files or you can supply protoset service. If not, you can supply the `.proto` source files or you can supply protoset
@@ -49,32 +49,57 @@ files (containing compiled descriptors, produced by `protoc`) to `grpcurl`.
Download the binary from the [releases](https://github.com/fullstorydev/grpcurl/releases) page. Download the binary from the [releases](https://github.com/fullstorydev/grpcurl/releases) page.
### Homebrew (macOS)
On macOS, `grpcurl` is available via Homebrew: On macOS, `grpcurl` is available via Homebrew:
```shell ```shell
brew install grpcurl brew install grpcurl
``` ```
### From Source ### Docker
You can use the `go` tool to install `grpcurl`:
For platforms that support Docker, you can download an image that lets you run `grpcurl`:
```shell ```shell
go get github.com/fullstorydev/grpcurl # Download image
go install github.com/fullstorydev/grpcurl/cmd/grpcurl docker pull fullstorydev/grpcurl:latest
# Run the tool
docker run fullstorydev/grpcurl api.grpc.me:443 list
```
Note that there are some pitfalls when using docker:
- If you need to interact with a server listening on the host's loopback network, you must specify the host as `host.docker.internal` instead of `localhost` (for Mac or Windows) _OR_ have the container use the host network with `-network="host"` (Linux only).
- If you need to provide proto source files or descriptor sets, you must mount the folder containing the files as a volume (`-v $(pwd):/protos`) and adjust the import paths to container paths accordingly.
- If you want to provide the request message via stdin, using the `-d @` option, you need to use the `-i` flag on the docker command.
### Other Packages
There are numerous other ways to install `grpcurl`, thanks to support from third parties that
have created recipes/packages for it. These include other ways to install `grpcurl` on a variety
of environments, including Windows and myriad Linux distributions.
You can see more details and the full list of other packages for `grpcurl` at _repology.org_:
https://repology.org/project/grpcurl/information
### From Source
If you already have the [Go SDK](https://golang.org/doc/install) installed, you can use the `go`
tool to install `grpcurl`:
```shell
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
``` ```
This installs the command into the `bin` sub-folder of wherever your `$GOPATH` This installs the command into the `bin` sub-folder of wherever your `$GOPATH`
environment variable points. If this directory is already in your `$PATH`, then environment variable points. (If you have no `GOPATH` environment variable set,
you should be good to go. the default install location is `$HOME/go/bin`). If this directory is already in
your `$PATH`, then you should be good to go.
If you have already pulled down this repo to a location that is not in your If you have already pulled down this repo to a location that is not in your
`$GOPATH` and want to build from the sources, you can `cd` into the repo and then `$GOPATH` and want to build from the sources, you can `cd` into the repo and then
run `make install`. run `make install`.
If you encounter compile errors, you could have out-dated versions of `grpcurl`'s If you encounter compile errors and are using a version of the Go SDK older than 1.13,
dependencies. You can update the dependencies by running `make updatedeps`. You can you could have out-dated versions of `grpcurl`'s dependencies. You can update the
also use [`vgo`](https://github.com/golang/vgo) to install, which will use the right dependencies by running `make updatedeps`. Or, if you are using Go 1.11 or 1.12, you
versions of dependencies. Or, if you are using Go 1.11, you can add `GO111MODULE=on` can add `GO111MODULE=on` as a prefix to the commands above, which will also build using
as a prefix to the commands above, which will also build using the right versions of the right versions of dependencies (vs. whatever you may already have in your `GOPATH`).
dependencies (vs. whatever you may already in your `GOPATH`).
## Usage ## Usage
The usage doc for the tool explains the numerous options: The usage doc for the tool explains the numerous options:
@@ -91,6 +116,9 @@ that requires no client certs and supports server reflection is the simplest thi
do with `grpcurl`. This minimal invocation sends an empty request body: do with `grpcurl`. This minimal invocation sends an empty request body:
```shell ```shell
grpcurl grpc.server.com:443 my.custom.server.Service/Method grpcurl grpc.server.com:443 my.custom.server.Service/Method
# no TLS
grpcurl -plaintext grpc.server.com:80 my.custom.server.Service/Method
``` ```
To send a non-empty request, use the `-d` argument. Note that all arguments must come To send a non-empty request, use the `-d` argument. Note that all arguments must come
@@ -164,7 +192,7 @@ are needed to use them.
### Server Reflection ### Server Reflection
Without any additional command-line flags, `grpcurl` will try to use [server reflection](https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1alpha/reflection.proto). Without any additional command-line flags, `grpcurl` will try to use [server reflection](https://github.com/grpc/grpc/blob/master/src/proto/grpc/reflection/v1/reflection.proto).
Examples for how to set up server reflection can be found [here](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md#known-implementations). Examples for how to set up server reflection can be found [here](https://github.com/grpc/grpc/blob/master/doc/server-reflection.md#known-implementations).

View File

@@ -1,9 +0,0 @@
// +build go1.10
package main
func indent() string {
// In Go 1.10 and up, the flag package automatically
// adds the right indentation.
return ""
}

View File

@@ -1,9 +0,0 @@
// +build !go1.10
package main
func indent() string {
// In Go 1.9 and older, we need to add indentation
// after newlines in the flag doc strings.
return " \t"
}

View File

@@ -4,31 +4,43 @@
package main package main
import ( import (
"context"
"flag" "flag"
"fmt" "fmt"
"io" "io"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"strings" "strings"
"time" "time"
"github.com/fullstorydev/grpcurl"
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/grpcreflect" "github.com/jhump/protoreflect/grpcreflect"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/alts"
"google.golang.org/grpc/keepalive" "google.golang.org/grpc/keepalive"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/descriptorpb"
// Register gzip compressor so compressed responses will work: // Register gzip compressor so compressed responses will work
_ "google.golang.org/grpc/encoding/gzip" _ "google.golang.org/grpc/encoding/gzip"
// Register xds so xds and xds-experimental resolver schemes work
_ "google.golang.org/grpc/xds"
"github.com/fullstorydev/grpcurl"
) )
var version = "dev build <no version set>" // To avoid confusion between program error codes and the gRPC response
// status codes 'Cancelled' and 'Unknown', 1 and 2 respectively,
// the response status codes emitted use an offset of 64
const statusCodeOffset = 64
const noVersion = "dev build <no version set>"
var version = noVersion
var ( var (
exit = os.Exit exit = os.Exit
@@ -41,11 +53,14 @@ var (
Print usage instructions and exit.`)) Print usage instructions and exit.`))
printVersion = flags.Bool("version", false, prettify(` printVersion = flags.Bool("version", false, prettify(`
Print version.`)) Print version.`))
plaintext = flags.Bool("plaintext", false, prettify(` plaintext = flags.Bool("plaintext", false, prettify(`
Use plain-text HTTP/2 when connecting to server (no TLS).`)) Use plain-text HTTP/2 when connecting to server (no TLS).`))
insecure = flags.Bool("insecure", false, prettify(` insecure = flags.Bool("insecure", false, prettify(`
Skip server certificate and domain verification. (NOT SECURE!) Not Skip server certificate and domain verification. (NOT SECURE!) Not
valid with -plaintext option.`)) valid with -plaintext option.`))
// TLS Options
cacert = flags.String("cacert", "", prettify(` cacert = flags.String("cacert", "", prettify(`
File containing trusted root certificates for verifying the server. File containing trusted root certificates for verifying the server.
Ignored if -insecure is specified.`)) Ignored if -insecure is specified.`))
@@ -55,6 +70,13 @@ var (
key = flags.String("key", "", prettify(` key = flags.String("key", "", prettify(`
File containing client private key, to present to the server. Not valid File containing client private key, to present to the server. Not valid
with -plaintext option. Must also provide -cert option.`)) with -plaintext option. Must also provide -cert option.`))
// ALTS Options
usealts = flags.Bool("alts", false, prettify(`
Use Application Layer Transport Security (ALTS) when connecting to server.`))
altsHandshakerServiceAddress = flags.String("alts-handshaker-service", "", prettify(`If set, this server will be used to do the ATLS handshaking.`))
altsTargetServiceAccounts multiString
protoset multiString protoset multiString
protoFiles multiString protoFiles multiString
importPaths multiString importPaths multiString
@@ -75,7 +97,12 @@ var (
value of the ":authority" pseudo-header in the HTTP/2 protocol. When TLS value of the ":authority" pseudo-header in the HTTP/2 protocol. When TLS
is used, this will also be used as the server name when verifying the is used, this will also be used as the server name when verifying the
server's certificate. It defaults to the address that is provided in the server's certificate. It defaults to the address that is provided in the
positional arguments.`)) positional arguments, or 'localhost' in the case of a unix domain
socket.`))
userAgent = flags.String("user-agent", "", prettify(`
If set, the specified value will be added to the User-Agent header set
by the grpc-go library.
`))
data = flags.String("d", "", prettify(` data = flags.String("d", "", prettify(`
Data for request contents. If the value is '@' then the request contents Data for request contents. If the value is '@' then the request contents
are read from stdin. For calls that accept a stream of requests, the are read from stdin. For calls that accept a stream of requests, the
@@ -91,18 +118,27 @@ var (
ASCII character: 0x1E. The stream should not end in a record separator. ASCII character: 0x1E. The stream should not end in a record separator.
If it does, it will be interpreted as a final, blank message after the If it does, it will be interpreted as a final, blank message after the
separator.`)) separator.`))
allowUnknownFields = flags.Bool("allow-unknown-fields", false, prettify(`
When true, the request contents, if 'json' format is used, allows
unknown fields to be present. They will be ignored when parsing
the request.`))
connectTimeout = flags.Float64("connect-timeout", 0, prettify(` connectTimeout = flags.Float64("connect-timeout", 0, prettify(`
The maximum time, in seconds, to wait for connection to be established. The maximum time, in seconds, to wait for connection to be established.
Defaults to 10 seconds.`)) Defaults to 10 seconds.`))
formatError = flags.Bool("format-error", false, prettify(`
When a non-zero status is returned, format the response using the
value set by the -format flag .`))
keepaliveTime = flags.Float64("keepalive-time", 0, prettify(` keepaliveTime = flags.Float64("keepalive-time", 0, prettify(`
If present, the maximum idle time in seconds, after which a keepalive If present, the maximum idle time in seconds, after which a keepalive
probe is sent. If the connection remains idle and no keepalive response probe is sent. If the connection remains idle and no keepalive response
is received for this same period then the connection is closed and the is received for this same period then the connection is closed and the
operation fails.`)) operation fails.`))
maxTime = flags.Float64("max-time", 0, prettify(` maxTime = flags.Float64("max-time", 0, prettify(`
The maximum total time the operation can take, in seconds. This is The maximum total time the operation can take, in seconds. This sets a
useful for preventing batch jobs that use grpcurl from hanging due to timeout on the gRPC context, allowing both client and server to give up
slow or bad network links or due to incorrect stream method usage.`)) after the deadline has past. This is useful for preventing batch jobs
that use grpcurl from hanging due to slow or bad network links or due
to incorrect stream method usage.`))
maxMsgSz = flags.Int("max-msg-sz", 0, prettify(` maxMsgSz = flags.Int("max-msg-sz", 0, prettify(`
The maximum encoded size of a response message, in bytes, that grpcurl The maximum encoded size of a response message, in bytes, that grpcurl
will accept. If not specified, defaults to 4,194,304 (4 megabytes).`)) will accept. If not specified, defaults to 4,194,304 (4 megabytes).`))
@@ -119,6 +155,8 @@ var (
When describing messages, show a template of input data.`)) When describing messages, show a template of input data.`))
verbose = flags.Bool("v", false, prettify(` verbose = flags.Bool("v", false, prettify(`
Enable verbose output.`)) Enable verbose output.`))
veryVerbose = flags.Bool("vv", false, prettify(`
Enable very verbose output (includes timing data).`))
serverName = flags.String("servername", "", prettify(` serverName = flags.String("servername", "", prettify(`
Override server name when validating TLS certificate. This flag is Override server name when validating TLS certificate. This flag is
ignored if -plaintext or -insecure is used. ignored if -plaintext or -insecure is used.
@@ -126,13 +164,14 @@ var (
an error to use both -authority and -servername (though this will be an error to use both -authority and -servername (though this will be
permitted if they are both set to the same value, to increase backwards permitted if they are both set to the same value, to increase backwards
compatibility with earlier releases that allowed both to be set).`)) compatibility with earlier releases that allowed both to be set).`))
reflection = optionalBoolFlag{val: true}
) )
func init() { func init() {
flags.Var(&addlHeaders, "H", prettify(` flags.Var(&addlHeaders, "H", prettify(`
Additional headers in 'name: value' format. May specify more than one Additional headers in 'name: value' format. May specify more than one
via multiple flags. These headers will also be included in reflection via multiple flags. These headers will also be included in reflection
requests requests to a server.`)) requests to a server.`))
flags.Var(&rpcHeaders, "rpc-header", prettify(` flags.Var(&rpcHeaders, "rpc-header", prettify(`
Additional RPC headers in 'name: value' format. May specify more than Additional RPC headers in 'name: value' format. May specify more than
one via multiple flags. These headers will *only* be used when invoking one via multiple flags. These headers will *only* be used when invoking
@@ -168,6 +207,20 @@ func init() {
order given. If no import paths are given, all files (including all order given. If no import paths are given, all files (including all
imports) must be provided as -proto flags, and grpcurl will attempt to imports) must be provided as -proto flags, and grpcurl will attempt to
resolve all import statements from the set of file names given.`)) resolve all import statements from the set of file names given.`))
flags.Var(&reflection, "use-reflection", prettify(`
When true, server reflection will be used to determine the RPC schema.
Defaults to true unless a -proto or -protoset option is provided. If
-use-reflection is used in combination with a -proto or -protoset flag,
the provided descriptor sources will be used in addition to server
reflection to resolve messages and extensions.`))
flags.Var(&altsTargetServiceAccounts, "alts-target-service-account", prettify(`
The full email address of the service account that the server is
expected to be using when ALTS is used. You can specify this option
multiple times to indicate multiple allowed service accounts. If the
server authenticates with a service account that is not one of the
expected accounts, the RPC will not be issued. If no such arguments are
provided, no check will be performed, and the RPC will be issued
regardless of the server's service account.`))
} }
type multiString []string type multiString []string
@@ -181,6 +234,75 @@ func (s *multiString) Set(value string) error {
return nil return nil
} }
// Uses a file source as a fallback for resolving symbols and extensions, but
// only uses the reflection source for listing services
type compositeSource struct {
reflection grpcurl.DescriptorSource
file grpcurl.DescriptorSource
}
func (cs compositeSource) ListServices() ([]string, error) {
return cs.reflection.ListServices()
}
func (cs compositeSource) FindSymbol(fullyQualifiedName string) (desc.Descriptor, error) {
d, err := cs.reflection.FindSymbol(fullyQualifiedName)
if err == nil {
return d, nil
}
return cs.file.FindSymbol(fullyQualifiedName)
}
func (cs compositeSource) AllExtensionsForType(typeName string) ([]*desc.FieldDescriptor, error) {
exts, err := cs.reflection.AllExtensionsForType(typeName)
if err != nil {
// On error fall back to file source
return cs.file.AllExtensionsForType(typeName)
}
// Track the tag numbers from the reflection source
tags := make(map[int32]bool)
for _, ext := range exts {
tags[ext.GetNumber()] = true
}
fileExts, err := cs.file.AllExtensionsForType(typeName)
if err != nil {
return exts, nil
}
for _, ext := range fileExts {
// Prioritize extensions found via reflection
if !tags[ext.GetNumber()] {
exts = append(exts, ext)
}
}
return exts, nil
}
type timingData struct {
Title string
Start time.Time
Value time.Duration
Parent *timingData
Sub []*timingData
}
func (d *timingData) Child(title string) *timingData {
if d == nil {
return nil
}
child := &timingData{Title: title, Start: time.Now()}
d.Sub = append(d.Sub, child)
return child
}
func (d *timingData) Done() {
if d == nil {
return
}
if d.Value == 0 {
d.Value = time.Since(d.Start)
}
}
func main() { func main() {
flags.Usage = usage flags.Usage = usage
flags.Parse(os.Args[1:]) flags.Parse(os.Args[1:])
@@ -193,6 +315,9 @@ func main() {
os.Exit(0) os.Exit(0)
} }
// default behavior is to use tls
usetls := !*plaintext && !*usealts
// Do extra validation on arguments and figure out what user asked us to do. // Do extra validation on arguments and figure out what user asked us to do.
if *connectTimeout < 0 { if *connectTimeout < 0 {
fail(nil, "The -connect-timeout argument must not be negative.") fail(nil, "The -connect-timeout argument must not be negative.")
@@ -206,20 +331,29 @@ func main() {
if *maxMsgSz < 0 { if *maxMsgSz < 0 {
fail(nil, "The -max-msg-sz argument must not be negative.") fail(nil, "The -max-msg-sz argument must not be negative.")
} }
if *plaintext && *insecure { if *plaintext && *usealts {
fail(nil, "The -plaintext and -insecure arguments are mutually exclusive.") fail(nil, "The -plaintext and -alts arguments are mutually exclusive.")
} }
if *plaintext && *cert != "" { if *insecure && !usetls {
fail(nil, "The -plaintext and -cert arguments are mutually exclusive.") fail(nil, "The -insecure argument can only be used with TLS.")
} }
if *plaintext && *key != "" { if *cert != "" && !usetls {
fail(nil, "The -plaintext and -key arguments are mutually exclusive.") fail(nil, "The -cert argument can only be used with TLS.")
}
if *key != "" && !usetls {
fail(nil, "The -key argument can only be used with TLS.")
} }
if (*key == "") != (*cert == "") { if (*key == "") != (*cert == "") {
fail(nil, "The -cert and -key arguments must be used together and both be present.") fail(nil, "The -cert and -key arguments must be used together and both be present.")
} }
if *altsHandshakerServiceAddress != "" && !*usealts {
fail(nil, "The -alts-handshaker-service argument must be used with the -alts argument.")
}
if len(altsTargetServiceAccounts) > 0 && !*usealts {
fail(nil, "The -alts-target-service-account argument must be used with the -alts argument.")
}
if *format != "json" && *format != "text" { if *format != "json" && *format != "text" {
fail(nil, "The -format option must be 'json' or 'text.") fail(nil, "The -format option must be 'json' or 'text'.")
} }
if *emitDefaults && *format != "json" { if *emitDefaults && *format != "json" {
warn("The -emit-defaults is only used when using json format.") warn("The -emit-defaults is only used when using json format.")
@@ -250,6 +384,22 @@ func main() {
invoke = true invoke = true
} }
verbosityLevel := 0
if *verbose {
verbosityLevel = 1
}
var rootTiming *timingData
if *veryVerbose {
verbosityLevel = 2
rootTiming = &timingData{Title: "Timing Data", Start: time.Now()}
defer func() {
rootTiming.Done()
dumpTiming(rootTiming, 0)
}()
}
var symbol string var symbol string
if invoke { if invoke {
if len(args) == 0 { if len(args) == 0 {
@@ -288,14 +438,26 @@ func main() {
if len(importPaths) > 0 && len(protoFiles) == 0 { if len(importPaths) > 0 && len(protoFiles) == 0 {
warn("The -import-path argument is not used unless -proto files are used.") warn("The -import-path argument is not used unless -proto files are used.")
} }
if !reflection.val && len(protoset) == 0 && len(protoFiles) == 0 {
fail(nil, "No protoset files or proto files specified and -use-reflection set to false.")
}
// Protoset or protofiles provided and -use-reflection unset
if !reflection.set && (len(protoset) > 0 || len(protoFiles) > 0) {
reflection.val = false
}
ctx := context.Background() ctx := context.Background()
if *maxTime > 0 { if *maxTime > 0 {
timeout := time.Duration(*maxTime * float64(time.Second)) timeout := time.Duration(*maxTime * float64(time.Second))
ctx, _ = context.WithTimeout(ctx, timeout) var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, timeout)
defer cancel()
} }
dial := func() *grpc.ClientConn { dial := func() *grpc.ClientConn {
dialTiming := rootTiming.Child("Dial")
defer dialTiming.Done()
dialTime := 10 * time.Second dialTime := 10 * time.Second
if *connectTimeout > 0 { if *connectTimeout > 0 {
dialTime = time.Duration(*connectTimeout * float64(time.Second)) dialTime = time.Duration(*connectTimeout * float64(time.Second))
@@ -313,13 +475,46 @@ func main() {
if *maxMsgSz > 0 { if *maxMsgSz > 0 {
opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(*maxMsgSz))) opts = append(opts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(*maxMsgSz)))
} }
var creds credentials.TransportCredentials network := "tcp"
if !*plaintext { if isUnixSocket != nil && isUnixSocket() {
var err error network = "unix"
creds, err = grpcurl.ClientTransportCredentials(*insecure, *cacert, *cert, *key) if *authority == "" {
if err != nil { *authority = "localhost"
fail(err, "Failed to configure transport credentials")
} }
}
var creds credentials.TransportCredentials
if *plaintext {
if *authority != "" {
opts = append(opts, grpc.WithAuthority(*authority))
}
} else if *usealts {
clientOptions := alts.DefaultClientOptions()
if len(altsTargetServiceAccounts) > 0 {
clientOptions.TargetServiceAccounts = altsTargetServiceAccounts
}
if *altsHandshakerServiceAddress != "" {
clientOptions.HandshakerServiceAddress = *altsHandshakerServiceAddress
}
creds = alts.NewClientCreds(clientOptions)
} else if usetls {
tlsTiming := dialTiming.Child("TLS Setup")
defer tlsTiming.Done()
tlsConf, err := grpcurl.ClientTLSConfig(*insecure, *cacert, *cert, *key)
if err != nil {
fail(err, "Failed to create TLS config")
}
sslKeylogFile := os.Getenv("SSLKEYLOGFILE")
if sslKeylogFile != "" {
w, err := os.OpenFile(sslKeylogFile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0600)
if err != nil {
fail(err, "Could not open SSLKEYLOGFILE %s", sslKeylogFile)
}
tlsConf.KeyLogWriter = w
}
creds = credentials.NewTLS(tlsConf)
// can use either -servername or -authority; but not both // can use either -servername or -authority; but not both
if *serverName != "" && *authority != "" { if *serverName != "" && *authority != "" {
@@ -335,23 +530,37 @@ func main() {
} }
if overrideName != "" { if overrideName != "" {
if err := creds.OverrideServerName(overrideName); err != nil { opts = append(opts, grpc.WithAuthority(overrideName))
fail(err, "Failed to override server name as %q", overrideName)
}
} }
} else if *authority != "" { tlsTiming.Done()
opts = append(opts, grpc.WithAuthority(*authority)) } else {
panic("Should have defaulted to use TLS.")
} }
network := "tcp"
if isUnixSocket != nil && isUnixSocket() { grpcurlUA := "grpcurl/" + version
network = "unix" if version == noVersion {
grpcurlUA = "grpcurl/dev-build (no version set)"
} }
if *userAgent != "" {
grpcurlUA = *userAgent + " " + grpcurlUA
}
opts = append(opts, grpc.WithUserAgent(grpcurlUA))
blockingDialTiming := dialTiming.Child("BlockingDial")
defer blockingDialTiming.Done()
cc, err := grpcurl.BlockingDial(ctx, network, target, creds, opts...) cc, err := grpcurl.BlockingDial(ctx, network, target, creds, opts...)
if err != nil { if err != nil {
fail(err, "Failed to dial target host %q", target) fail(err, "Failed to dial target host %q", target)
} }
return cc return cc
} }
printFormattedStatus := func(w io.Writer, stat *status.Status, formatter grpcurl.Formatter) {
formattedStatus, err := formatter(stat.Proto())
if err != nil {
fmt.Fprintf(w, "ERROR: %v", err.Error())
}
fmt.Fprint(w, formattedStatus)
}
if *expandHeaders { if *expandHeaders {
var err error var err error
@@ -372,24 +581,34 @@ func main() {
var cc *grpc.ClientConn var cc *grpc.ClientConn
var descSource grpcurl.DescriptorSource var descSource grpcurl.DescriptorSource
var refClient *grpcreflect.Client var refClient *grpcreflect.Client
var fileSource grpcurl.DescriptorSource
if len(protoset) > 0 { if len(protoset) > 0 {
var err error var err error
descSource, err = grpcurl.DescriptorSourceFromProtoSets(protoset...) fileSource, err = grpcurl.DescriptorSourceFromProtoSets(protoset...)
if err != nil { if err != nil {
fail(err, "Failed to process proto descriptor sets.") fail(err, "Failed to process proto descriptor sets.")
} }
} else if len(protoFiles) > 0 { } else if len(protoFiles) > 0 {
var err error var err error
descSource, err = grpcurl.DescriptorSourceFromProtoFiles(importPaths, protoFiles...) fileSource, err = grpcurl.DescriptorSourceFromProtoFiles(importPaths, protoFiles...)
if err != nil { if err != nil {
fail(err, "Failed to process proto source files.") fail(err, "Failed to process proto source files.")
} }
} else { }
if reflection.val {
md := grpcurl.MetadataFromHeaders(append(addlHeaders, reflHeaders...)) md := grpcurl.MetadataFromHeaders(append(addlHeaders, reflHeaders...))
refCtx := metadata.NewOutgoingContext(ctx, md) refCtx := metadata.NewOutgoingContext(ctx, md)
cc = dial() cc = dial()
refClient = grpcreflect.NewClient(refCtx, reflectpb.NewServerReflectionClient(cc)) refClient = grpcreflect.NewClientAuto(refCtx, cc)
descSource = grpcurl.DescriptorSourceFromServer(ctx, refClient) refClient.AllowMissingFileDescriptors()
reflSource := grpcurl.DescriptorSourceFromServer(ctx, refClient)
if fileSource != nil {
descSource = compositeSource{reflSource, fileSource}
} else {
descSource = reflSource
}
} else {
descSource = fileSource
} }
// arrange for the RPCs to be cleanly shutdown // arrange for the RPCs to be cleanly shutdown
@@ -487,7 +706,7 @@ func main() {
} else { } else {
// see if it's a group // see if it's a group
for _, f := range parent.GetFields() { for _, f := range parent.GetFields() {
if f.GetType() == descpb.FieldDescriptorProto_TYPE_GROUP && f.GetMessageType() == d { if f.GetType() == descriptorpb.FieldDescriptorProto_TYPE_GROUP && f.GetMessageType() == d {
// found it: describe the map field instead // found it: describe the map field instead
elementType = "the type of a group field" elementType = "the type of a group field"
dsc = f dsc = f
@@ -498,7 +717,7 @@ func main() {
} }
case *desc.FieldDescriptor: case *desc.FieldDescriptor:
elementType = "a field" elementType = "a field"
if d.GetType() == descpb.FieldDescriptorProto_TYPE_GROUP { if d.GetType() == descriptorpb.FieldDescriptorProto_TYPE_GROUP {
elementType = "a group field" elementType = "a group field"
} else if d.IsExtension() { } else if d.IsExtension() {
elementType = "an extension" elementType = "an extension"
@@ -529,7 +748,8 @@ func main() {
// for messages, also show a template in JSON, to make it easier to // for messages, also show a template in JSON, to make it easier to
// create a request to invoke an RPC // create a request to invoke an RPC
tmpl := grpcurl.MakeTemplate(dsc) tmpl := grpcurl.MakeTemplate(dsc)
_, formatter, err := grpcurl.RequestParserAndFormatterFor(grpcurl.Format(*format), descSource, true, false, nil) options := grpcurl.FormatOptions{EmitJSONDefaultFields: true}
_, formatter, err := grpcurl.RequestParserAndFormatter(grpcurl.Format(*format), descSource, nil, options)
if err != nil { if err != nil {
fail(err, "Failed to construct formatter for %q", *format) fail(err, "Failed to construct formatter for %q", *format)
} }
@@ -560,16 +780,31 @@ func main() {
// if not verbose output, then also include record delimiters // if not verbose output, then also include record delimiters
// between each message, so output could potentially be piped // between each message, so output could potentially be piped
// to another grpcurl process // to another grpcurl process
includeSeparators := !*verbose includeSeparators := verbosityLevel == 0
rf, formatter, err := grpcurl.RequestParserAndFormatterFor(grpcurl.Format(*format), descSource, *emitDefaults, includeSeparators, in) options := grpcurl.FormatOptions{
EmitJSONDefaultFields: *emitDefaults,
IncludeTextSeparator: includeSeparators,
AllowUnknownFields: *allowUnknownFields,
}
rf, formatter, err := grpcurl.RequestParserAndFormatter(grpcurl.Format(*format), descSource, in, options)
if err != nil { if err != nil {
fail(err, "Failed to construct request parser and formatter for %q", *format) fail(err, "Failed to construct request parser and formatter for %q", *format)
} }
h := grpcurl.NewDefaultEventHandler(os.Stdout, descSource, formatter, *verbose) h := &grpcurl.DefaultEventHandler{
Out: os.Stdout,
Formatter: formatter,
VerbosityLevel: verbosityLevel,
}
invokeTiming := rootTiming.Child("InvokeRPC")
err = grpcurl.InvokeRPC(ctx, descSource, cc, symbol, append(addlHeaders, rpcHeaders...), h, rf.Next) err = grpcurl.InvokeRPC(ctx, descSource, cc, symbol, append(addlHeaders, rpcHeaders...), h, rf.Next)
invokeTiming.Done()
if err != nil { if err != nil {
fail(err, "Error invoking method %q", symbol) if errStatus, ok := status.FromError(err); ok && *formatError {
h.Status = errStatus
} else {
fail(err, "Error invoking method %q", symbol)
}
} }
reqSuffix := "" reqSuffix := ""
respSuffix := "" respSuffix := ""
@@ -580,16 +815,31 @@ func main() {
if h.NumResponses != 1 { if h.NumResponses != 1 {
respSuffix = "s" respSuffix = "s"
} }
if *verbose { if verbosityLevel > 0 {
fmt.Printf("Sent %d request%s and received %d response%s\n", reqCount, reqSuffix, h.NumResponses, respSuffix) fmt.Printf("Sent %d request%s and received %d response%s\n", reqCount, reqSuffix, h.NumResponses, respSuffix)
} }
if h.Status.Code() != codes.OK { if h.Status.Code() != codes.OK {
grpcurl.PrintStatus(os.Stderr, h.Status, formatter) if *formatError {
exit(1) printFormattedStatus(os.Stderr, h.Status, formatter)
} else {
grpcurl.PrintStatus(os.Stderr, h.Status, formatter)
}
exit(statusCodeOffset + int(h.Status.Code()))
} }
} }
} }
func dumpTiming(td *timingData, lvl int) {
ind := ""
for x := 0; x < lvl; x++ {
ind += " "
}
fmt.Printf("%s%s: %s\n", ind, td.Title, td.Value)
for _, sd := range td.Sub {
dumpTiming(sd, lvl+1)
}
}
func usage() { func usage() {
fmt.Fprintf(os.Stderr, `Usage: fmt.Fprintf(os.Stderr, `Usage:
%s [flags] [address] [list|describe] [symbol] %s [flags] [address] [list|describe] [symbol]
@@ -637,7 +887,7 @@ func prettify(docString string) string {
j++ j++
} }
return strings.Join(parts[:j], "\n"+indent()) return strings.Join(parts[:j], "\n")
} }
func warn(msg string, args ...interface{}) { func warn(msg string, args ...interface{}) {
@@ -672,3 +922,28 @@ func writeProtoset(descSource grpcurl.DescriptorSource, symbols ...string) error
defer f.Close() defer f.Close()
return grpcurl.WriteProtoset(f, descSource, symbols...) return grpcurl.WriteProtoset(f, descSource, symbols...)
} }
type optionalBoolFlag struct {
set, val bool
}
func (f *optionalBoolFlag) String() string {
if !f.set {
return "unset"
}
return strconv.FormatBool(f.val)
}
func (f *optionalBoolFlag) Set(s string) error {
v, err := strconv.ParseBool(s)
if err != nil {
return err
}
f.set = true
f.val = v
return nil
}
func (f *optionalBoolFlag) IsBoolFlag() bool {
return true
}

View File

@@ -1,4 +1,5 @@
// +build darwin dragonfly freebsd linux netbsd openbsd solaris //go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || windows
// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
package main package main

View File

@@ -1,21 +1,21 @@
package grpcurl package grpcurl
import ( import (
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"io/ioutil" "os"
"sync" "sync"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/desc/protoparse" "github.com/jhump/protoreflect/desc/protoparse"
"github.com/jhump/protoreflect/dynamic" "github.com/jhump/protoreflect/dynamic"
"github.com/jhump/protoreflect/grpcreflect" "github.com/jhump/protoreflect/grpcreflect"
"golang.org/x/net/context"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/descriptorpb"
) )
// ErrReflectionNotSupported is returned by DescriptorSource operations that // ErrReflectionNotSupported is returned by DescriptorSource operations that
@@ -39,13 +39,13 @@ type DescriptorSource interface {
// DescriptorSourceFromProtoSets creates a DescriptorSource that is backed by the named files, whose contents // DescriptorSourceFromProtoSets creates a DescriptorSource that is backed by the named files, whose contents
// are encoded FileDescriptorSet protos. // are encoded FileDescriptorSet protos.
func DescriptorSourceFromProtoSets(fileNames ...string) (DescriptorSource, error) { func DescriptorSourceFromProtoSets(fileNames ...string) (DescriptorSource, error) {
files := &descpb.FileDescriptorSet{} files := &descriptorpb.FileDescriptorSet{}
for _, fileName := range fileNames { for _, fileName := range fileNames {
b, err := ioutil.ReadFile(fileName) b, err := os.ReadFile(fileName)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not load protoset file %q: %v", fileName, err) return nil, fmt.Errorf("could not load protoset file %q: %v", fileName, err)
} }
var fs descpb.FileDescriptorSet var fs descriptorpb.FileDescriptorSet
err = proto.Unmarshal(b, &fs) err = proto.Unmarshal(b, &fs)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not parse contents of protoset file %q: %v", fileName, err) return nil, fmt.Errorf("could not parse contents of protoset file %q: %v", fileName, err)
@@ -76,8 +76,8 @@ func DescriptorSourceFromProtoFiles(importPaths []string, fileNames ...string) (
} }
// DescriptorSourceFromFileDescriptorSet creates a DescriptorSource that is backed by the FileDescriptorSet. // DescriptorSourceFromFileDescriptorSet creates a DescriptorSource that is backed by the FileDescriptorSet.
func DescriptorSourceFromFileDescriptorSet(files *descpb.FileDescriptorSet) (DescriptorSource, error) { func DescriptorSourceFromFileDescriptorSet(files *descriptorpb.FileDescriptorSet) (DescriptorSource, error) {
unresolved := map[string]*descpb.FileDescriptorProto{} unresolved := map[string]*descriptorpb.FileDescriptorProto{}
for _, fd := range files.File { for _, fd := range files.File {
unresolved[fd.GetName()] = fd unresolved[fd.GetName()] = fd
} }
@@ -91,7 +91,7 @@ func DescriptorSourceFromFileDescriptorSet(files *descpb.FileDescriptorSet) (Des
return &fileSource{files: resolved}, nil return &fileSource{files: resolved}, nil
} }
func resolveFileDescriptor(unresolved map[string]*descpb.FileDescriptorProto, resolved map[string]*desc.FileDescriptor, filename string) (*desc.FileDescriptor, error) { func resolveFileDescriptor(unresolved map[string]*descriptorpb.FileDescriptorProto, resolved map[string]*desc.FileDescriptor, filename string) (*desc.FileDescriptor, error) {
if r, ok := resolved[filename]; ok { if r, ok := resolved[filename]; ok {
return r, nil return r, nil
} }
@@ -275,12 +275,12 @@ func WriteProtoset(out io.Writer, descSource DescriptorSource, symbols ...string
// now expand that to include transitive dependencies in topologically sorted // now expand that to include transitive dependencies in topologically sorted
// order (such that file always appears after its dependencies) // order (such that file always appears after its dependencies)
expandedFiles := make(map[string]struct{}, len(fds)) expandedFiles := make(map[string]struct{}, len(fds))
allFilesSlice := make([]*descpb.FileDescriptorProto, 0, len(fds)) allFilesSlice := make([]*descriptorpb.FileDescriptorProto, 0, len(fds))
for _, filename := range filenames { for _, filename := range filenames {
allFilesSlice = addFilesToSet(allFilesSlice, expandedFiles, fds[filename]) allFilesSlice = addFilesToSet(allFilesSlice, expandedFiles, fds[filename])
} }
// now we can serialize to file // now we can serialize to file
b, err := proto.Marshal(&descpb.FileDescriptorSet{File: allFilesSlice}) b, err := proto.Marshal(&descriptorpb.FileDescriptorSet{File: allFilesSlice})
if err != nil { if err != nil {
return fmt.Errorf("failed to serialize file descriptor set: %v", err) return fmt.Errorf("failed to serialize file descriptor set: %v", err)
} }
@@ -290,7 +290,7 @@ func WriteProtoset(out io.Writer, descSource DescriptorSource, symbols ...string
return nil return nil
} }
func addFilesToSet(allFiles []*descpb.FileDescriptorProto, expanded map[string]struct{}, fd *desc.FileDescriptor) []*descpb.FileDescriptorProto { func addFilesToSet(allFiles []*descriptorpb.FileDescriptorProto, expanded map[string]struct{}, fd *desc.FileDescriptor) []*descriptorpb.FileDescriptorProto {
if _, ok := expanded[fd.GetName()]; ok { if _, ok := expanded[fd.GetName()]; ok {
// already seen this one // already seen this one
return allFiles return allFiles

View File

@@ -2,24 +2,24 @@ package grpcurl
import ( import (
"bytes" "bytes"
"io/ioutil" "os"
"testing" "testing"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/golang/protobuf/protoc-gen-go/descriptor" "google.golang.org/protobuf/types/descriptorpb"
) )
func TestWriteProtoset(t *testing.T) { func TestWriteProtoset(t *testing.T) {
exampleProtoset, err := loadProtoset("./testing/example.protoset") exampleProtoset, err := loadProtoset("./internal/testing/example.protoset")
if err != nil { if err != nil {
t.Fatalf("failed to load example.protoset: %v", err) t.Fatalf("failed to load example.protoset: %v", err)
} }
testProtoset, err := loadProtoset("./testing/test.protoset") testProtoset, err := loadProtoset("./internal/testing/test.protoset")
if err != nil { if err != nil {
t.Fatalf("failed to load test.protoset: %v", err) t.Fatalf("failed to load test.protoset: %v", err)
} }
mergedProtoset := &descriptor.FileDescriptorSet{ mergedProtoset := &descriptorpb.FileDescriptorSet{
File: append(exampleProtoset.File, testProtoset.File...), File: append(exampleProtoset.File, testProtoset.File...),
} }
@@ -29,29 +29,29 @@ func TestWriteProtoset(t *testing.T) {
} }
checkWriteProtoset(t, descSrc, exampleProtoset, "TestService") checkWriteProtoset(t, descSrc, exampleProtoset, "TestService")
checkWriteProtoset(t, descSrc, testProtoset, "grpc.testing.TestService") checkWriteProtoset(t, descSrc, testProtoset, "testing.TestService")
checkWriteProtoset(t, descSrc, mergedProtoset, "TestService", "grpc.testing.TestService") checkWriteProtoset(t, descSrc, mergedProtoset, "TestService", "testing.TestService")
} }
func loadProtoset(path string) (*descriptor.FileDescriptorSet, error) { func loadProtoset(path string) (*descriptorpb.FileDescriptorSet, error) {
b, err := ioutil.ReadFile(path) b, err := os.ReadFile(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var protoset descriptor.FileDescriptorSet var protoset descriptorpb.FileDescriptorSet
if err := proto.Unmarshal(b, &protoset); err != nil { if err := proto.Unmarshal(b, &protoset); err != nil {
return nil, err return nil, err
} }
return &protoset, nil return &protoset, nil
} }
func checkWriteProtoset(t *testing.T, descSrc DescriptorSource, protoset *descriptor.FileDescriptorSet, symbols ...string) { func checkWriteProtoset(t *testing.T, descSrc DescriptorSource, protoset *descriptorpb.FileDescriptorSet, symbols ...string) {
var buf bytes.Buffer var buf bytes.Buffer
if err := WriteProtoset(&buf, descSrc, symbols...); err != nil { if err := WriteProtoset(&buf, descSrc, symbols...); err != nil {
t.Fatalf("failed to write protoset: %v", err) t.Fatalf("failed to write protoset: %v", err)
} }
var result descriptor.FileDescriptorSet var result descriptorpb.FileDescriptorSet
if err := proto.Unmarshal(buf.Bytes(), &result); err != nil { if err := proto.Unmarshal(buf.Bytes(), &result); err != nil {
t.Fatalf("failed to unmarshal written protoset: %v", err) t.Fatalf("failed to unmarshal written protoset: %v", err)
} }

35
download_protoc.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/usr/bin/env bash
set -e
cd $(dirname $0)
if [[ -z "$PROTOC_VERSION" ]]; then
echo "Set PROTOC_VERSION env var to indicate the version to download" >&2
exit 1
fi
PROTOC_OS="$(uname -s)"
PROTOC_ARCH="$(uname -m)"
case "${PROTOC_OS}" in
Darwin) PROTOC_OS="osx" ;;
Linux) PROTOC_OS="linux" ;;
*)
echo "Invalid value for uname -s: ${PROTOC_OS}" >&2
exit 1
esac
# This is for macs with M1 chips. Precompiled binaries for osx/amd64 are not available for download, so for that case
# we download the x86_64 version instead. This will work as long as rosetta2 is installed.
if [ "$PROTOC_OS" = "osx" ] && [ "$PROTOC_ARCH" = "arm64" ]; then
PROTOC_ARCH="x86_64"
fi
PROTOC="${PWD}/.tmp/protoc/bin/protoc"
if [[ "$(${PROTOC} --version 2>/dev/null)" != "libprotoc 3.${PROTOC_VERSION}" ]]; then
rm -rf ./.tmp/protoc
mkdir -p .tmp/protoc
curl -L "https://github.com/google/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-${PROTOC_OS}-${PROTOC_ARCH}.zip" > .tmp/protoc/protoc.zip
pushd ./.tmp/protoc && unzip protoc.zip && popd
fi

169
format.go
View File

@@ -11,8 +11,8 @@ import (
"strings" "strings"
"sync" "sync"
"github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/dynamic" "github.com/jhump/protoreflect/dynamic"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
@@ -55,6 +55,15 @@ func NewJSONRequestParser(in io.Reader, resolver jsonpb.AnyResolver) RequestPars
} }
} }
// NewJSONRequestParserWithUnmarshaler is like NewJSONRequestParser but
// accepts a protobuf jsonpb.Unmarshaler instead of jsonpb.AnyResolver.
func NewJSONRequestParserWithUnmarshaler(in io.Reader, unmarshaler jsonpb.Unmarshaler) RequestParser {
return &jsonRequestParser{
dec: json.NewDecoder(in),
unmarshaler: unmarshaler,
}
}
func (f *jsonRequestParser) Next(m proto.Message) error { func (f *jsonRequestParser) Next(m proto.Message) error {
var msg json.RawMessage var msg json.RawMessage
if err := f.dec.Decode(&msg); err != nil { if err := f.dec.Decode(&msg); err != nil {
@@ -69,7 +78,7 @@ func (f *jsonRequestParser) NumRequests() int {
} }
const ( const (
textSeparatorChar = 0x1e textSeparatorChar = '\x1e'
) )
type textRequestParser struct { type textRequestParser struct {
@@ -127,10 +136,25 @@ type Formatter func(proto.Message) (string, error)
func NewJSONFormatter(emitDefaults bool, resolver jsonpb.AnyResolver) Formatter { func NewJSONFormatter(emitDefaults bool, resolver jsonpb.AnyResolver) Formatter {
marshaler := jsonpb.Marshaler{ marshaler := jsonpb.Marshaler{
EmitDefaults: emitDefaults, EmitDefaults: emitDefaults,
Indent: " ",
AnyResolver: resolver, AnyResolver: resolver,
} }
return marshaler.MarshalToString // Workaround for indentation issue in jsonpb with Any messages.
// Bug was originally fixed in https://github.com/golang/protobuf/pull/834
// but later re-introduced before the module was deprecated and frozen.
// If jsonpb is ever replaced with google.golang.org/protobuf/encoding/protojson
// this workaround will no longer be needed.
formatter := func(message proto.Message) (string, error) {
output, err := marshaler.MarshalToString(message)
if err != nil {
return "", err
}
var buf bytes.Buffer
if err := json.Indent(&buf, []byte(output), "", " "); err != nil {
return "", err
}
return buf.String(), nil
}
return formatter
} }
// NewTextFormatter returns a formatter that returns strings in the protobuf // NewTextFormatter returns a formatter that returns strings in the protobuf
@@ -179,7 +203,7 @@ func (tf *textFormatter) format(m proto.Message) (string, error) {
// no trailing newline needed // no trailing newline needed
str := buf.String() str := buf.String()
if str[len(str)-1] == '\n' { if len(str) > 0 && str[len(str)-1] == '\n' {
str = str[:len(str)-1] str = str[:len(str)-1]
} }
@@ -188,10 +212,20 @@ func (tf *textFormatter) format(m proto.Message) (string, error) {
return str, nil return str, nil
} }
// Format of request data. The allowed values are 'json' or 'text'.
type Format string type Format string
const ( const (
// FormatJSON specifies input data in JSON format. Multiple request values
// may be concatenated (messages with a JSON representation other than
// object must be separated by whitespace, such as a newline)
FormatJSON = Format("json") FormatJSON = Format("json")
// FormatText specifies input data must be in the protobuf text format.
// Multiple request values must be separated by the "record separator"
// ASCII character: 0x1E. The stream should not end in a record separator.
// If it does, it will be interpreted as a final, blank message after the
// separator.
FormatText = Format("text") FormatText = Format("text")
) )
@@ -255,11 +289,11 @@ func (r *anyResolver) Resolve(typeUrl string) (proto.Message, error) {
if !ok { if !ok {
return nil, fmt.Errorf("unknown message: %s", typeUrl) return nil, fmt.Errorf("unknown message: %s", typeUrl)
} }
// populate any extensions for this message, too // populate any extensions for this message, too (if there are any)
if exts, err := r.source.AllExtensionsForType(mname); err != nil { if exts, err := r.source.AllExtensionsForType(mname); err == nil {
return nil, err if err := r.er.AddExtension(exts...); err != nil {
} else if err := r.er.AddExtension(exts...); err != nil { return nil, err
return nil, err }
} }
if r.mf == nil { if r.mf == nil {
@@ -296,6 +330,7 @@ func (r anyResolverWithFallback) Resolve(typeUrl string) (proto.Message, error)
if slash := strings.LastIndex(mname, "/"); slash >= 0 { if slash := strings.LastIndex(mname, "/"); slash >= 0 {
mname = mname[slash+1:] mname = mname[slash+1:]
} }
//lint:ignore SA1019 new non-deprecated API requires other code changes; deferring...
mt := proto.MessageType(mname) mt := proto.MessageType(mname)
if mt != nil { if mt != nil {
return reflect.New(mt.Elem()).Interface().(proto.Message), nil return reflect.New(mt.Elem()).Interface().(proto.Message), nil
@@ -342,31 +377,70 @@ func (a *unknownAny) ProtoMessage() {
var _ proto.Message = (*unknownAny)(nil) var _ proto.Message = (*unknownAny)(nil)
// FormatOptions is a set of flags that are passed to a JSON or text formatter.
type FormatOptions struct {
// EmitJSONDefaultFields flag, when true, includes empty/default values in the output.
// FormatJSON only flag.
EmitJSONDefaultFields bool
// AllowUnknownFields is an option for the parser. When true,
// it accepts input which includes unknown fields. These unknown fields
// are skipped instead of returning an error.
// FormatJSON only flag.
AllowUnknownFields bool
// IncludeTextSeparator is true then, when invoked to format multiple messages,
// all messages after the first one will be prefixed with the
// ASCII 'Record Separator' character (0x1E).
// It might be useful when the output is piped to another grpcurl process.
// FormatText only flag.
IncludeTextSeparator bool
}
// RequestParserAndFormatter returns a request parser and formatter for the
// given format. The given descriptor source may be used for parsing message
// data (if needed by the format).
// It accepts a set of options. The field EmitJSONDefaultFields and IncludeTextSeparator
// are options for JSON and protobuf text formats, respectively. The AllowUnknownFields field
// is a JSON-only format flag.
// Requests will be parsed from the given in.
func RequestParserAndFormatter(format Format, descSource DescriptorSource, in io.Reader, opts FormatOptions) (RequestParser, Formatter, error) {
switch format {
case FormatJSON:
resolver := AnyResolverFromDescriptorSource(descSource)
unmarshaler := jsonpb.Unmarshaler{AnyResolver: resolver, AllowUnknownFields: opts.AllowUnknownFields}
return NewJSONRequestParserWithUnmarshaler(in, unmarshaler), NewJSONFormatter(opts.EmitJSONDefaultFields, anyResolverWithFallback{AnyResolver: resolver}), nil
case FormatText:
return NewTextRequestParser(in), NewTextFormatter(opts.IncludeTextSeparator), nil
default:
return nil, nil, fmt.Errorf("unknown format: %s", format)
}
}
// RequestParserAndFormatterFor returns a request parser and formatter for the // RequestParserAndFormatterFor returns a request parser and formatter for the
// given format. The given descriptor source may be used for parsing message // given format. The given descriptor source may be used for parsing message
// data (if needed by the format). The flags emitJSONDefaultFields and // data (if needed by the format). The flags emitJSONDefaultFields and
// includeTextSeparator are options for JSON and protobuf text formats, // includeTextSeparator are options for JSON and protobuf text formats,
// respectively. Requests will be parsed from the given in. // respectively. Requests will be parsed from the given in.
// This function is deprecated. Please use RequestParserAndFormatter instead.
// DEPRECATED
func RequestParserAndFormatterFor(format Format, descSource DescriptorSource, emitJSONDefaultFields, includeTextSeparator bool, in io.Reader) (RequestParser, Formatter, error) { func RequestParserAndFormatterFor(format Format, descSource DescriptorSource, emitJSONDefaultFields, includeTextSeparator bool, in io.Reader) (RequestParser, Formatter, error) {
switch format { return RequestParserAndFormatter(format, descSource, in, FormatOptions{
case FormatJSON: EmitJSONDefaultFields: emitJSONDefaultFields,
resolver := AnyResolverFromDescriptorSource(descSource) IncludeTextSeparator: includeTextSeparator,
return NewJSONRequestParser(in, resolver), NewJSONFormatter(emitJSONDefaultFields, anyResolverWithFallback{AnyResolver: resolver}), nil })
case FormatText:
return NewTextRequestParser(in), NewTextFormatter(includeTextSeparator), nil
default:
return nil, nil, fmt.Errorf("unknown format: %s", format)
}
} }
// DefaultEventHandler logs events to a writer. This is not thread-safe, but is // DefaultEventHandler logs events to a writer. This is not thread-safe, but is
// safe for use with InvokeRPC as long as NumResponses and Status are not read // safe for use with InvokeRPC as long as NumResponses and Status are not read
// until the call to InvokeRPC completes. // until the call to InvokeRPC completes.
type DefaultEventHandler struct { type DefaultEventHandler struct {
out io.Writer Out io.Writer
descSource DescriptorSource Formatter Formatter
formatter func(proto.Message) (string, error) // 0 = default
verbose bool // 1 = verbose
// 2 = very verbose
VerbosityLevel int
// NumResponses is the number of responses that have been received. // NumResponses is the number of responses that have been received.
NumResponses int NumResponses int
@@ -378,54 +452,65 @@ type DefaultEventHandler struct {
// NewDefaultEventHandler returns an InvocationEventHandler that logs events to // NewDefaultEventHandler returns an InvocationEventHandler that logs events to
// the given output. If verbose is true, all events are logged. Otherwise, only // the given output. If verbose is true, all events are logged. Otherwise, only
// response messages are logged. // response messages are logged.
//
// Deprecated: NewDefaultEventHandler exists for compatibility.
// It doesn't allow fine control over the `VerbosityLevel`
// and provides only 0 and 1 options (which corresponds to the `verbose` argument).
// Use DefaultEventHandler{} initializer directly.
func NewDefaultEventHandler(out io.Writer, descSource DescriptorSource, formatter Formatter, verbose bool) *DefaultEventHandler { func NewDefaultEventHandler(out io.Writer, descSource DescriptorSource, formatter Formatter, verbose bool) *DefaultEventHandler {
verbosityLevel := 0
if verbose {
verbosityLevel = 1
}
return &DefaultEventHandler{ return &DefaultEventHandler{
out: out, Out: out,
descSource: descSource, Formatter: formatter,
formatter: formatter, VerbosityLevel: verbosityLevel,
verbose: verbose,
} }
} }
var _ InvocationEventHandler = (*DefaultEventHandler)(nil) var _ InvocationEventHandler = (*DefaultEventHandler)(nil)
func (h *DefaultEventHandler) OnResolveMethod(md *desc.MethodDescriptor) { func (h *DefaultEventHandler) OnResolveMethod(md *desc.MethodDescriptor) {
if h.verbose { if h.VerbosityLevel > 0 {
txt, err := GetDescriptorText(md, h.descSource) txt, err := GetDescriptorText(md, nil)
if err == nil { if err == nil {
fmt.Fprintf(h.out, "\nResolved method descriptor:\n%s\n", txt) fmt.Fprintf(h.Out, "\nResolved method descriptor:\n%s\n", txt)
} }
} }
} }
func (h *DefaultEventHandler) OnSendHeaders(md metadata.MD) { func (h *DefaultEventHandler) OnSendHeaders(md metadata.MD) {
if h.verbose { if h.VerbosityLevel > 0 {
fmt.Fprintf(h.out, "\nRequest metadata to send:\n%s\n", MetadataToString(md)) fmt.Fprintf(h.Out, "\nRequest metadata to send:\n%s\n", MetadataToString(md))
} }
} }
func (h *DefaultEventHandler) OnReceiveHeaders(md metadata.MD) { func (h *DefaultEventHandler) OnReceiveHeaders(md metadata.MD) {
if h.verbose { if h.VerbosityLevel > 0 {
fmt.Fprintf(h.out, "\nResponse headers received:\n%s\n", MetadataToString(md)) fmt.Fprintf(h.Out, "\nResponse headers received:\n%s\n", MetadataToString(md))
} }
} }
func (h *DefaultEventHandler) OnReceiveResponse(resp proto.Message) { func (h *DefaultEventHandler) OnReceiveResponse(resp proto.Message) {
h.NumResponses++ h.NumResponses++
if h.verbose { if h.VerbosityLevel > 1 {
fmt.Fprint(h.out, "\nResponse contents:\n") fmt.Fprintf(h.Out, "\nEstimated response size: %d bytes\n", proto.Size(resp))
} }
if respStr, err := h.formatter(resp); err != nil { if h.VerbosityLevel > 0 {
fmt.Fprintf(h.out, "Failed to format response message %d: %v\n", h.NumResponses, err) fmt.Fprint(h.Out, "\nResponse contents:\n")
}
if respStr, err := h.Formatter(resp); err != nil {
fmt.Fprintf(h.Out, "Failed to format response message %d: %v\n", h.NumResponses, err)
} else { } else {
fmt.Fprintln(h.out, respStr) fmt.Fprintln(h.Out, respStr)
} }
} }
func (h *DefaultEventHandler) OnReceiveTrailers(stat *status.Status, md metadata.MD) { func (h *DefaultEventHandler) OnReceiveTrailers(stat *status.Status, md metadata.MD) {
h.Status = stat h.Status = stat
if h.verbose { if h.VerbosityLevel > 0 {
fmt.Fprintf(h.out, "\nResponse trailers received:\n%s\n", MetadataToString(md)) fmt.Fprintf(h.Out, "\nResponse trailers received:\n%s\n", MetadataToString(md))
} }
} }

View File

@@ -7,15 +7,15 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/golang/protobuf/ptypes/struct"
"github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"google.golang.org/protobuf/types/known/structpb"
) )
func TestRequestParser(t *testing.T) { func TestRequestParser(t *testing.T) {
source, err := DescriptorSourceFromProtoSets("testing/example.protoset") source, err := DescriptorSourceFromProtoSets("internal/testing/example.protoset")
if err != nil { if err != nil {
t.Fatalf("failed to create descriptor source: %v", err) t.Fatalf("failed to create descriptor source: %v", err)
} }
@@ -69,7 +69,7 @@ func TestRequestParser(t *testing.T) {
for i, tc := range testCases { for i, tc := range testCases {
name := fmt.Sprintf("#%d, %s, %d message(s)", i+1, tc.format, len(tc.expectedOutput)) name := fmt.Sprintf("#%d, %s, %d message(s)", i+1, tc.format, len(tc.expectedOutput))
rf, _, err := RequestParserAndFormatterFor(tc.format, source, false, false, strings.NewReader(tc.input)) rf, _, err := RequestParserAndFormatter(tc.format, source, strings.NewReader(tc.input), FormatOptions{})
if err != nil { if err != nil {
t.Errorf("Failed to create parser and formatter: %v", err) t.Errorf("Failed to create parser and formatter: %v", err)
continue continue
@@ -97,7 +97,7 @@ func TestRequestParser(t *testing.T) {
// Handler prints response data (and headers/trailers in verbose mode). // Handler prints response data (and headers/trailers in verbose mode).
// This verifies that we get the right output in both JSON and proto text modes. // This verifies that we get the right output in both JSON and proto text modes.
func TestHandler(t *testing.T) { func TestHandler(t *testing.T) {
source, err := DescriptorSourceFromProtoSets("testing/example.protoset") source, err := DescriptorSourceFromProtoSets("internal/testing/example.protoset")
if err != nil { if err != nil {
t.Fatalf("failed to create descriptor source: %v", err) t.Fatalf("failed to create descriptor source: %v", err)
} }
@@ -120,20 +120,26 @@ func TestHandler(t *testing.T) {
for _, format := range []Format{FormatJSON, FormatText} { for _, format := range []Format{FormatJSON, FormatText} {
for _, numMessages := range []int{1, 3} { for _, numMessages := range []int{1, 3} {
for _, verbose := range []bool{true, false} { for verbosityLevel := 0; verbosityLevel <= 2; verbosityLevel++ {
name := fmt.Sprintf("%s, %d message(s)", format, numMessages) name := fmt.Sprintf("%s, %d message(s)", format, numMessages)
if verbose { if verbosityLevel > 0 {
name += ", verbose" name += fmt.Sprintf(", verbosityLevel=%d", verbosityLevel)
} }
_, formatter, err := RequestParserAndFormatterFor(format, source, false, !verbose, nil) verbose := verbosityLevel > 0
_, formatter, err := RequestParserAndFormatter(format, source, nil, FormatOptions{IncludeTextSeparator: !verbose})
if err != nil { if err != nil {
t.Errorf("Failed to create parser and formatter: %v", err) t.Errorf("Failed to create parser and formatter: %v", err)
continue continue
} }
var buf bytes.Buffer var buf bytes.Buffer
h := NewDefaultEventHandler(&buf, source, formatter, verbose) h := &DefaultEventHandler{
Out: &buf,
Formatter: formatter,
VerbosityLevel: verbosityLevel,
}
h.OnResolveMethod(md) h.OnResolveMethod(md)
h.OnSendHeaders(reqHeaders) h.OnSendHeaders(reqHeaders)
@@ -148,6 +154,9 @@ func TestHandler(t *testing.T) {
expectedOutput += verbosePrefix expectedOutput += verbosePrefix
} }
for i := 0; i < numMessages; i++ { for i := 0; i < numMessages; i++ {
if verbosityLevel > 1 {
expectedOutput += verboseResponseSize
}
if verbose { if verbose {
expectedOutput += verboseResponseHeader expectedOutput += verboseResponseHeader
} }
@@ -226,6 +235,9 @@ Response trailers received:
a: 1 a: 1
b: 2 b: 2
c: 3 c: 3
`
verboseResponseSize = `
Estimated response size: 100 bytes
` `
verboseResponseHeader = ` verboseResponseHeader = `
Response contents: Response contents:

31
go.mod
View File

@@ -1,10 +1,31 @@
module github.com/fullstorydev/grpcurl module github.com/fullstorydev/grpcurl
go 1.14 go 1.19
require ( require (
github.com/golang/protobuf v1.3.5 github.com/golang/protobuf v1.5.4
github.com/jhump/protoreflect v1.5.0 github.com/jhump/protoreflect v1.16.0
golang.org/x/net v0.0.0-20190311183353-d8887717615a google.golang.org/grpc v1.61.0
google.golang.org/grpc v1.28.0 google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002
)
require (
cloud.google.com/go/compute v1.23.3 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/bufbuild/protocompile v0.10.0 // indirect
github.com/census-instrumentation/opencensus-proto v0.4.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe // indirect
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 // indirect
github.com/envoyproxy/go-control-plane v0.11.1 // indirect
github.com/envoyproxy/protoc-gen-validate v1.0.2 // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/oauth2 v0.14.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
) )

101
go.sum
View File

@@ -1,65 +1,118 @@
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk=
cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/bufbuild/protocompile v0.10.0 h1:+jW/wnLMLxaCEG8AX9lD0bQ5v9h1RUiMKOBOT5ll9dM=
github.com/bufbuild/protocompile v0.10.0/go.mod h1:G9qQIQo0xZ6Uyj6CMNz0saGmx2so+KONo8/KrELABiY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/census-instrumentation/opencensus-proto v0.4.1 h1:iKLQ0xPNFxR/2hzXZMrBo8f1j86j5WHzznCCQxV/b8g=
github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f h1:WBZRG4aNOuI15bLRrCgN8fCq8E5Xuty6jGbmSNEvSsU= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe h1:QQ3GSy+MqSHxm/d8nCtnAiZdYFd45cYZPs8vOOIYKfk=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20220112060539-c52dc94e7fbe/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101 h1:7To3pQ+pZo0i3dsWEbinPNFs5gPSBOsJtx3wTT94VBY=
github.com/cncf/xds/go v0.0.0-20231109132714-523115ebc101/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E= github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/envoyproxy/protoc-gen-validate v1.0.2 h1:QkIBuU5k+x7/QXPvPPnWXWlCdaBFApVqftFV6k087DA=
github.com/envoyproxy/protoc-gen-validate v1.0.2/go.mod h1:GpiZQP3dDbg4JouG/NNS7QWXpgx6x8QiMKdmN72jogE=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/jhump/protoreflect v1.5.0 h1:NgpVT+dX71c8hZnxHof2M7QDK7QtohIJ7DYycjnkyfc= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/jhump/protoreflect v1.5.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/jhump/protoreflect v1.16.0 h1:54fZg+49widqXYQ0b+usAFHbMkBGR4PpXrsHc8+TBDg=
github.com/jhump/protoreflect v1.16.0/go.mod h1:oYPd7nPvcBw/5wlDfm/AVmU9zH9BgqGCI469pGxfj/8=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.14.0 h1:P0Vrf/2538nmC0H+pEQ3MNFRRnVR7RlqyVw+bvm26z0=
golang.org/x/oauth2 v0.14.0/go.mod h1:lAtNWgaWfL4cm7j2OV8TxGi9Qb7ECORx8DktCY74OwM=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17 h1:wpZ8pe2x1Q3f2KyT5f8oP/fa9rHAKgFPr/HZdNuS+PQ=
google.golang.org/genproto v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:J7XzRzVy1+IPwWHZUzoD0IccYZIrXILAQpc+Qy9CMhY=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17 h1:JpwMPBpFN3uKhdaekDpiNlImDdkUAyiJ6ez/uxGaUSo=
google.golang.org/genproto/googleapis/api v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:0xJLfVdJqpAPl8tDg1ujOCGzx6LFLttXT5NhllGOXY4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4= google.golang.org/grpc v1.61.0 h1:TOvOcuXn30kRao+gfcvsebNEa5iZIiLkisYEkf7R7o0=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= google.golang.org/grpc v1.61.0/go.mod h1:VUbo7IFqmF1QtCAstipjG0GIoq49KvMe9+h1jFLBNJs=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002 h1:V7Da7qt0MkY3noVANIMVBk28nOnijADeOR3i5Hcvpj4=
google.golang.org/protobuf v1.33.1-0.20240408130810-98873a205002/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -8,31 +8,32 @@ package grpcurl
import ( import (
"bytes" "bytes"
"context"
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
descpb "github.com/golang/protobuf/protoc-gen-go/descriptor"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/empty"
"github.com/golang/protobuf/ptypes/struct"
"github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/desc/protoprint" "github.com/jhump/protoreflect/desc/protoprint"
"github.com/jhump/protoreflect/dynamic" "github.com/jhump/protoreflect/dynamic"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/insecure"
xdsCredentials "google.golang.org/grpc/credentials/xds"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
_ "google.golang.org/grpc/xds/experimental" protov2 "google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/descriptorpb"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/structpb"
) )
// ListServices uses the given descriptor source to return a sorted list of fully-qualified // ListServices uses the given descriptor source to return a sorted list of fully-qualified
@@ -328,7 +329,7 @@ func fetchAllExtensions(source DescriptorSource, ext *dynamic.ExtensionRegistry,
return nil return nil
} }
// fullConvertToDynamic attempts to convert the given message to a dynamic message as well // fullyConvertToDynamic attempts to convert the given message to a dynamic message as well
// as any nested messages it may contain as field values. If the given message factory has // as any nested messages it may contain as field values. If the given message factory has
// extensions registered that were not known when the given message was parsed, this effectively // extensions registered that were not known when the given message was parsed, this effectively
// allows re-parsing to identify those extensions. // allows re-parsing to identify those extensions.
@@ -406,8 +407,9 @@ func makeTemplate(md *desc.MessageDescriptor, path []*desc.MessageDescriptor) pr
case "google.protobuf.Any": case "google.protobuf.Any":
// empty type URL is not allowed by JSON representation // empty type URL is not allowed by JSON representation
// so we must give it a dummy type // so we must give it a dummy type
msg, _ := ptypes.MarshalAny(&empty.Empty{}) var anyVal anypb.Any
return msg _ = anypb.MarshalFrom(&anyVal, &emptypb.Empty{}, protov2.MarshalOptions{})
return &anyVal
case "google.protobuf.Value": case "google.protobuf.Value":
// unset kind is not allowed by JSON representation // unset kind is not allowed by JSON representation
// so we must give it something // so we must give it something
@@ -462,42 +464,42 @@ func makeTemplate(md *desc.MessageDescriptor, path []*desc.MessageDescriptor) pr
for _, fd := range dm.GetMessageDescriptor().GetFields() { for _, fd := range dm.GetMessageDescriptor().GetFields() {
if fd.IsRepeated() { if fd.IsRepeated() {
switch fd.GetType() { switch fd.GetType() {
case descpb.FieldDescriptorProto_TYPE_FIXED32, case descriptorpb.FieldDescriptorProto_TYPE_FIXED32,
descpb.FieldDescriptorProto_TYPE_UINT32: descriptorpb.FieldDescriptorProto_TYPE_UINT32:
dm.AddRepeatedField(fd, uint32(0)) dm.AddRepeatedField(fd, uint32(0))
case descpb.FieldDescriptorProto_TYPE_SFIXED32, case descriptorpb.FieldDescriptorProto_TYPE_SFIXED32,
descpb.FieldDescriptorProto_TYPE_SINT32, descriptorpb.FieldDescriptorProto_TYPE_SINT32,
descpb.FieldDescriptorProto_TYPE_INT32, descriptorpb.FieldDescriptorProto_TYPE_INT32,
descpb.FieldDescriptorProto_TYPE_ENUM: descriptorpb.FieldDescriptorProto_TYPE_ENUM:
dm.AddRepeatedField(fd, int32(0)) dm.AddRepeatedField(fd, int32(0))
case descpb.FieldDescriptorProto_TYPE_FIXED64, case descriptorpb.FieldDescriptorProto_TYPE_FIXED64,
descpb.FieldDescriptorProto_TYPE_UINT64: descriptorpb.FieldDescriptorProto_TYPE_UINT64:
dm.AddRepeatedField(fd, uint64(0)) dm.AddRepeatedField(fd, uint64(0))
case descpb.FieldDescriptorProto_TYPE_SFIXED64, case descriptorpb.FieldDescriptorProto_TYPE_SFIXED64,
descpb.FieldDescriptorProto_TYPE_SINT64, descriptorpb.FieldDescriptorProto_TYPE_SINT64,
descpb.FieldDescriptorProto_TYPE_INT64: descriptorpb.FieldDescriptorProto_TYPE_INT64:
dm.AddRepeatedField(fd, int64(0)) dm.AddRepeatedField(fd, int64(0))
case descpb.FieldDescriptorProto_TYPE_STRING: case descriptorpb.FieldDescriptorProto_TYPE_STRING:
dm.AddRepeatedField(fd, "") dm.AddRepeatedField(fd, "")
case descpb.FieldDescriptorProto_TYPE_BYTES: case descriptorpb.FieldDescriptorProto_TYPE_BYTES:
dm.AddRepeatedField(fd, []byte{}) dm.AddRepeatedField(fd, []byte{})
case descpb.FieldDescriptorProto_TYPE_BOOL: case descriptorpb.FieldDescriptorProto_TYPE_BOOL:
dm.AddRepeatedField(fd, false) dm.AddRepeatedField(fd, false)
case descpb.FieldDescriptorProto_TYPE_FLOAT: case descriptorpb.FieldDescriptorProto_TYPE_FLOAT:
dm.AddRepeatedField(fd, float32(0)) dm.AddRepeatedField(fd, float32(0))
case descpb.FieldDescriptorProto_TYPE_DOUBLE: case descriptorpb.FieldDescriptorProto_TYPE_DOUBLE:
dm.AddRepeatedField(fd, float64(0)) dm.AddRepeatedField(fd, float64(0))
case descpb.FieldDescriptorProto_TYPE_MESSAGE, case descriptorpb.FieldDescriptorProto_TYPE_MESSAGE,
descpb.FieldDescriptorProto_TYPE_GROUP: descriptorpb.FieldDescriptorProto_TYPE_GROUP:
dm.AddRepeatedField(fd, makeTemplate(fd.GetMessageType(), path)) dm.AddRepeatedField(fd, makeTemplate(fd.GetMessageType(), path))
} }
} else if fd.GetMessageType() != nil { } else if fd.GetMessageType() != nil {
@@ -507,11 +509,25 @@ func makeTemplate(md *desc.MessageDescriptor, path []*desc.MessageDescriptor) pr
return dm return dm
} }
// ClientTransportCredentials builds transport credentials for a gRPC client using the // ClientTransportCredentials is a helper function that constructs a TLS config with
// the given properties (see ClientTLSConfig) and then constructs and returns gRPC
// transport credentials using that config.
//
// Deprecated: Use grpcurl.ClientTLSConfig and credentials.NewTLS instead.
func ClientTransportCredentials(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string) (credentials.TransportCredentials, error) {
tlsConf, err := ClientTLSConfig(insecureSkipVerify, cacertFile, clientCertFile, clientKeyFile)
if err != nil {
return nil, err
}
return credentials.NewTLS(tlsConf), nil
}
// ClientTLSConfig builds transport-layer config for a gRPC client using the
// given properties. If cacertFile is blank, only standard trusted certs are used to // given properties. If cacertFile is blank, only standard trusted certs are used to
// verify the server certs. If clientCertFile is blank, the client will not use a client // verify the server certs. If clientCertFile is blank, the client will not use a client
// certificate. If clientCertFile is not blank then clientKeyFile must not be blank. // certificate. If clientCertFile is not blank then clientKeyFile must not be blank.
func ClientTransportCredentials(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string) (credentials.TransportCredentials, error) { func ClientTLSConfig(insecureSkipVerify bool, cacertFile, clientCertFile, clientKeyFile string) (*tls.Config, error) {
var tlsConf tls.Config var tlsConf tls.Config
if clientCertFile != "" { if clientCertFile != "" {
@@ -528,7 +544,7 @@ func ClientTransportCredentials(insecureSkipVerify bool, cacertFile, clientCertF
} else if cacertFile != "" { } else if cacertFile != "" {
// Create a certificate pool from the certificate authority // Create a certificate pool from the certificate authority
certPool := x509.NewCertPool() certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile(cacertFile) ca, err := os.ReadFile(cacertFile)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not read ca certificate: %v", err) return nil, fmt.Errorf("could not read ca certificate: %v", err)
} }
@@ -541,7 +557,7 @@ func ClientTransportCredentials(insecureSkipVerify bool, cacertFile, clientCertF
tlsConf.RootCAs = certPool tlsConf.RootCAs = certPool
} }
return credentials.NewTLS(&tlsConf), nil return &tlsConf, nil
} }
// ServerTransportCredentials builds transport credentials for a gRPC server using the // ServerTransportCredentials builds transport credentials for a gRPC server using the
@@ -565,7 +581,7 @@ func ServerTransportCredentials(cacertFile, serverCertFile, serverKeyFile string
if cacertFile != "" { if cacertFile != "" {
// Create a certificate pool from the certificate authority // Create a certificate pool from the certificate authority
certPool := x509.NewCertPool() certPool := x509.NewCertPool()
ca, err := ioutil.ReadFile(cacertFile) ca, err := os.ReadFile(cacertFile)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not read ca certificate: %v", err) return nil, fmt.Errorf("could not read ca certificate: %v", err)
} }
@@ -593,6 +609,21 @@ func ServerTransportCredentials(cacertFile, serverCertFile, serverKeyFile string
// and blocking until the returned connection is ready. If the given credentials are nil, the // and blocking until the returned connection is ready. If the given credentials are nil, the
// connection will be insecure (plain-text). // connection will be insecure (plain-text).
func BlockingDial(ctx context.Context, network, address string, creds credentials.TransportCredentials, opts ...grpc.DialOption) (*grpc.ClientConn, error) { func BlockingDial(ctx context.Context, network, address string, creds credentials.TransportCredentials, opts ...grpc.DialOption) (*grpc.ClientConn, error) {
if creds == nil {
creds = insecure.NewCredentials()
}
var err error
if strings.HasPrefix(address, "xds:///") {
// The xds:/// prefix is used to signal to the gRPC client to use an xDS server to resolve the
// target. The relevant credentials will be automatically pulled from the GRPC_XDS_BOOTSTRAP or
// GRPC_XDS_BOOTSTRAP_CONFIG env vars.
creds, err = xdsCredentials.NewClientCredentials(xdsCredentials.ClientOptions{FallbackCreds: creds})
if err != nil {
return nil, err
}
}
// grpc.Dial doesn't provide any information on permanent connection errors (like // grpc.Dial doesn't provide any information on permanent connection errors (like
// TLS handshake failures). So in order to provide good error messages, we need a // TLS handshake failures). So in order to provide good error messages, we need a
// custom dialer that can provide that info. That means we manage the TLS handshake. // custom dialer that can provide that info. That means we manage the TLS handshake.
@@ -608,20 +639,19 @@ func BlockingDial(ctx context.Context, network, address string, creds credential
// custom credentials and dialer will notify on error via the // custom credentials and dialer will notify on error via the
// writeResult function // writeResult function
if creds != nil { creds = &errSignalingCreds{
creds = &errSignalingCreds{ TransportCredentials: creds,
TransportCredentials: creds, writeResult: writeResult,
writeResult: writeResult,
}
} }
dialer := func(ctx context.Context, address string) (net.Conn, error) { dialer := func(ctx context.Context, address string) (net.Conn, error) {
// NB: We *could* handle the TLS handshake ourselves, in the custom // NB: We *could* handle the TLS handshake ourselves, in the custom
// dialer (instead of customizing both the dialer and the credentials). // dialer (instead of customizing both the dialer and the credentials).
// But that requires using WithInsecure dial option (so that the gRPC // But that requires using insecure.NewCredentials() dial transport
// library doesn't *also* try to do a handshake). And that would mean // option (so that the gRPC library doesn't *also* try to do a
// that the library would send the wrong ":scheme" metaheader to // handshake). And that would mean that the library would send the
// servers: it would send "http" instead of "https" because it is // wrong ":scheme" metaheader to servers: it would send "http" instead
// unaware that TLS is actually in use. // of "https" because it is unaware that TLS is actually in use.
conn, err := (&net.Dialer{}).DialContext(ctx, network, address) conn, err := (&net.Dialer{}).DialContext(ctx, network, address)
if err != nil { if err != nil {
writeResult(err) writeResult(err)
@@ -634,16 +664,13 @@ func BlockingDial(ctx context.Context, network, address string, creds credential
// know when we're done. So we run it in a goroutine and then use result // know when we're done. So we run it in a goroutine and then use result
// channel to either get the connection or fail-fast. // channel to either get the connection or fail-fast.
go func() { go func() {
opts = append(opts, // We put grpc.FailOnNonTempDialError *before* the explicitly provided
grpc.WithBlock(), // options so that it could be overridden.
grpc.FailOnNonTempDialError(true), opts = append([]grpc.DialOption{grpc.FailOnNonTempDialError(true)}, opts...)
grpc.WithContextDialer(dialer), // But we don't want caller to be able to override these two, so we put
) // them *after* the explicitly provided options.
if creds == nil { opts = append(opts, grpc.WithBlock(), grpc.WithContextDialer(dialer), grpc.WithTransportCredentials(creds))
opts = append(opts, grpc.WithInsecure())
} else {
opts = append(opts, grpc.WithTransportCredentials(creds))
}
conn, err := grpc.DialContext(ctx, address, opts...) conn, err := grpc.DialContext(ctx, address, opts...)
var res interface{} var res interface{}
if err != nil { if err != nil {

View File

@@ -1,6 +1,7 @@
package grpcurl_test package grpcurl_test
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
@@ -11,22 +12,20 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/grpcreflect" "github.com/jhump/protoreflect/grpcreflect"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/interop/grpc_testing" "google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
reflectpb "google.golang.org/grpc/reflection/grpc_reflection_v1alpha"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
. "github.com/fullstorydev/grpcurl" . "github.com/fullstorydev/grpcurl"
grpcurl_testing "github.com/fullstorydev/grpcurl/testing" grpcurl_testing "github.com/fullstorydev/grpcurl/internal/testing"
jsonpbtest "github.com/fullstorydev/grpcurl/testing/jsonpb_test_proto" jsonpbtest "github.com/fullstorydev/grpcurl/internal/testing/jsonpb_test_proto"
) )
var ( var (
@@ -52,18 +51,18 @@ type descSourceCase struct {
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
var err error var err error
sourceProtoset, err = DescriptorSourceFromProtoSets("testing/test.protoset") sourceProtoset, err = DescriptorSourceFromProtoSets("internal/testing/test.protoset")
if err != nil { if err != nil {
panic(err) panic(err)
} }
sourceProtoFiles, err = DescriptorSourceFromProtoFiles(nil, "testing/test.proto") sourceProtoFiles, err = DescriptorSourceFromProtoFiles([]string{"internal/testing"}, "test.proto")
if err != nil { if err != nil {
panic(err) panic(err)
} }
// Create a server that includes the reflection service // Create a server that includes the reflection service
svrReflect := grpc.NewServer() svrReflect := grpc.NewServer()
grpc_testing.RegisterTestServiceServer(svrReflect, grpcurl_testing.TestServer{}) grpcurl_testing.RegisterTestServiceServer(svrReflect, grpcurl_testing.TestServer{})
reflection.Register(svrReflect) reflection.Register(svrReflect)
var portReflect int var portReflect int
if l, err := net.Listen("tcp", "127.0.0.1:0"); err != nil { if l, err := net.Listen("tcp", "127.0.0.1:0"); err != nil {
@@ -78,18 +77,18 @@ func TestMain(m *testing.M) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
if ccReflect, err = grpc.DialContext(ctx, fmt.Sprintf("127.0.0.1:%d", portReflect), if ccReflect, err = grpc.DialContext(ctx, fmt.Sprintf("127.0.0.1:%d", portReflect),
grpc.WithInsecure(), grpc.WithBlock()); err != nil { grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()); err != nil {
panic(err) panic(err)
} }
defer ccReflect.Close() defer ccReflect.Close()
refClient := grpcreflect.NewClient(context.Background(), reflectpb.NewServerReflectionClient(ccReflect)) refClient := grpcreflect.NewClientAuto(context.Background(), ccReflect)
defer refClient.Reset() defer refClient.Reset()
sourceReflect = DescriptorSourceFromServer(context.Background(), refClient) sourceReflect = DescriptorSourceFromServer(context.Background(), refClient)
// Also create a server that does *not* include the reflection service // Also create a server that does *not* include the reflection service
svrProtoset := grpc.NewServer() svrProtoset := grpc.NewServer()
grpc_testing.RegisterTestServiceServer(svrProtoset, grpcurl_testing.TestServer{}) grpcurl_testing.RegisterTestServiceServer(svrProtoset, grpcurl_testing.TestServer{})
var portProtoset int var portProtoset int
if l, err := net.Listen("tcp", "127.0.0.1:0"); err != nil { if l, err := net.Listen("tcp", "127.0.0.1:0"); err != nil {
panic(err) panic(err)
@@ -103,7 +102,7 @@ func TestMain(m *testing.M) {
ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second) ctx, cancel = context.WithTimeout(context.Background(), 10*time.Second)
defer cancel() defer cancel()
if ccNoReflect, err = grpc.DialContext(ctx, fmt.Sprintf("127.0.0.1:%d", portProtoset), if ccNoReflect, err = grpc.DialContext(ctx, fmt.Sprintf("127.0.0.1:%d", portProtoset),
grpc.WithInsecure(), grpc.WithBlock()); err != nil { grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()); err != nil {
panic(err) panic(err)
} }
defer ccNoReflect.Close() defer ccNoReflect.Close()
@@ -118,7 +117,7 @@ func TestMain(m *testing.M) {
} }
func TestServerDoesNotSupportReflection(t *testing.T) { func TestServerDoesNotSupportReflection(t *testing.T) {
refClient := grpcreflect.NewClient(context.Background(), reflectpb.NewServerReflectionClient(ccNoReflect)) refClient := grpcreflect.NewClientAuto(context.Background(), ccNoReflect)
defer refClient.Reset() defer refClient.Reset()
refSource := DescriptorSourceFromServer(context.Background(), refClient) refSource := DescriptorSourceFromServer(context.Background(), refClient)
@@ -141,7 +140,7 @@ func TestServerDoesNotSupportReflection(t *testing.T) {
} }
func TestProtosetWithImports(t *testing.T) { func TestProtosetWithImports(t *testing.T) {
sourceProtoset, err := DescriptorSourceFromProtoSets("testing/example.protoset") sourceProtoset, err := DescriptorSourceFromProtoSets("internal/testing/example.protoset")
if err != nil { if err != nil {
t.Fatalf("failed to load protoset: %v", err) t.Fatalf("failed to load protoset: %v", err)
} }
@@ -178,11 +177,11 @@ func doTestListServices(t *testing.T, source DescriptorSource, includeReflection
var expected []string var expected []string
if includeReflection { if includeReflection {
// when using server reflection, we see the TestService as well as the ServerReflection service // when using server reflection, we see the TestService as well as the ServerReflection service
expected = []string{"grpc.reflection.v1alpha.ServerReflection", "grpc.testing.TestService"} expected = []string{"grpc.reflection.v1.ServerReflection", "grpc.reflection.v1alpha.ServerReflection", "testing.TestService"}
} else { } else {
// without reflection, we see all services defined in the same test.proto file, which is the // without reflection, we see all services defined in the same test.proto file, which is the
// TestService as well as UnimplementedService // TestService as well as UnimplementedService
expected = []string{"grpc.testing.TestService", "grpc.testing.UnimplementedService"} expected = []string{"testing.TestService", "testing.UnimplementedService"}
} }
if !reflect.DeepEqual(expected, names) { if !reflect.DeepEqual(expected, names) {
t.Errorf("ListServices returned wrong results: wanted %v, got %v", expected, names) t.Errorf("ListServices returned wrong results: wanted %v, got %v", expected, names)
@@ -198,17 +197,17 @@ func TestListMethods(t *testing.T) {
} }
func doTestListMethods(t *testing.T, source DescriptorSource, includeReflection bool) { func doTestListMethods(t *testing.T, source DescriptorSource, includeReflection bool) {
names, err := ListMethods(source, "grpc.testing.TestService") names, err := ListMethods(source, "testing.TestService")
if err != nil { if err != nil {
t.Fatalf("failed to list methods for TestService: %v", err) t.Fatalf("failed to list methods for TestService: %v", err)
} }
expected := []string{ expected := []string{
"grpc.testing.TestService.EmptyCall", "testing.TestService.EmptyCall",
"grpc.testing.TestService.FullDuplexCall", "testing.TestService.FullDuplexCall",
"grpc.testing.TestService.HalfDuplexCall", "testing.TestService.HalfDuplexCall",
"grpc.testing.TestService.StreamingInputCall", "testing.TestService.StreamingInputCall",
"grpc.testing.TestService.StreamingOutputCall", "testing.TestService.StreamingOutputCall",
"grpc.testing.TestService.UnaryCall", "testing.TestService.UnaryCall",
} }
if !reflect.DeepEqual(expected, names) { if !reflect.DeepEqual(expected, names) {
t.Errorf("ListMethods returned wrong results: wanted %v, got %v", expected, names) t.Errorf("ListMethods returned wrong results: wanted %v, got %v", expected, names)
@@ -216,19 +215,19 @@ func doTestListMethods(t *testing.T, source DescriptorSource, includeReflection
if includeReflection { if includeReflection {
// when using server reflection, we see the TestService as well as the ServerReflection service // when using server reflection, we see the TestService as well as the ServerReflection service
names, err = ListMethods(source, "grpc.reflection.v1alpha.ServerReflection") names, err = ListMethods(source, "grpc.reflection.v1.ServerReflection")
if err != nil { if err != nil {
t.Fatalf("failed to list methods for ServerReflection: %v", err) t.Fatalf("failed to list methods for ServerReflection: %v", err)
} }
expected = []string{"grpc.reflection.v1alpha.ServerReflection.ServerReflectionInfo"} expected = []string{"grpc.reflection.v1.ServerReflection.ServerReflectionInfo"}
} else { } else {
// without reflection, we see all services defined in the same test.proto file, which is the // without reflection, we see all services defined in the same test.proto file, which is the
// TestService as well as UnimplementedService // TestService as well as UnimplementedService
names, err = ListMethods(source, "grpc.testing.UnimplementedService") names, err = ListMethods(source, "testing.UnimplementedService")
if err != nil { if err != nil {
t.Fatalf("failed to list methods for ServerReflection: %v", err) t.Fatalf("failed to list methods for ServerReflection: %v", err)
} }
expected = []string{"grpc.testing.UnimplementedService.UnimplementedCall"} expected = []string{"testing.UnimplementedService.UnimplementedCall"}
} }
if !reflect.DeepEqual(expected, names) { if !reflect.DeepEqual(expected, names) {
t.Errorf("ListMethods returned wrong results: wanted %v, got %v", expected, names) t.Errorf("ListMethods returned wrong results: wanted %v, got %v", expected, names)
@@ -242,10 +241,10 @@ func doTestListMethods(t *testing.T, source DescriptorSource, includeReflection
} }
func TestGetAllFiles(t *testing.T) { func TestGetAllFiles(t *testing.T) {
expectedFiles := []string{"testing/test.proto"} expectedFiles := []string{"test.proto"}
// server reflection picks up filename from linked in Go package, expectedFilesWithReflection := []string{
// which indicates "grpc_testing/test.proto", not our local copy. "grpc/reflection/v1/reflection.proto", "grpc/reflection/v1alpha/reflection.proto", "test.proto",
expectedFilesWithReflection := []string{"grpc_reflection_v1alpha/reflection.proto", "grpc_testing/test.proto"} }
for _, ds := range descSources { for _, ds := range descSources {
t.Run(ds.name, func(t *testing.T) { t.Run(ds.name, func(t *testing.T) {
@@ -254,22 +253,26 @@ func TestGetAllFiles(t *testing.T) {
t.Fatalf("failed to get all files: %v", err) t.Fatalf("failed to get all files: %v", err)
} }
names := fileNames(files) names := fileNames(files)
expected := expectedFiles match := false
var expected []string
if ds.includeRefl { if ds.includeRefl {
expected = expectedFilesWithReflection expected = expectedFilesWithReflection
} else {
expected = expectedFiles
} }
if !reflect.DeepEqual(expected, names) { match = reflect.DeepEqual(expected, names)
if !match {
t.Errorf("GetAllFiles returned wrong results: wanted %v, got %v", expected, names) t.Errorf("GetAllFiles returned wrong results: wanted %v, got %v", expected, names)
} }
}) })
} }
// try cases with more complicated set of files // try cases with more complicated set of files
otherSourceProtoset, err := DescriptorSourceFromProtoSets("testing/test.protoset", "testing/example.protoset") otherSourceProtoset, err := DescriptorSourceFromProtoSets("internal/testing/test.protoset", "internal/testing/example.protoset")
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
otherSourceProtoFiles, err := DescriptorSourceFromProtoFiles(nil, "testing/test.proto", "testing/example.proto") otherSourceProtoFiles, err := DescriptorSourceFromProtoFiles([]string{"internal/testing"}, "test.proto", "example.proto")
if err != nil { if err != nil {
t.Fatal(err.Error()) t.Fatal(err.Error())
} }
@@ -278,13 +281,13 @@ func TestGetAllFiles(t *testing.T) {
{"proto[b]", otherSourceProtoFiles, false}, {"proto[b]", otherSourceProtoFiles, false},
} }
expectedFiles = []string{ expectedFiles = []string{
"example.proto",
"example2.proto",
"google/protobuf/any.proto", "google/protobuf/any.proto",
"google/protobuf/descriptor.proto", "google/protobuf/descriptor.proto",
"google/protobuf/empty.proto", "google/protobuf/empty.proto",
"google/protobuf/timestamp.proto", "google/protobuf/timestamp.proto",
"testing/example.proto", "test.proto",
"testing/example2.proto",
"testing/test.proto",
} }
for _, ds := range otherDescSources { for _, ds := range otherDescSources {
t.Run(ds.name, func(t *testing.T) { t.Run(ds.name, func(t *testing.T) {
@@ -389,7 +392,7 @@ func TestDescribe(t *testing.T) {
} }
func doTestDescribe(t *testing.T, source DescriptorSource) { func doTestDescribe(t *testing.T, source DescriptorSource) {
sym := "grpc.testing.TestService.EmptyCall" sym := "testing.TestService.EmptyCall"
dsc, err := source.FindSymbol(sym) dsc, err := source.FindSymbol(sym)
if err != nil { if err != nil {
t.Fatalf("failed to get descriptor for %q: %v", sym, err) t.Fatalf("failed to get descriptor for %q: %v", sym, err)
@@ -400,14 +403,14 @@ func doTestDescribe(t *testing.T, source DescriptorSource) {
txt := proto.MarshalTextString(dsc.AsProto()) txt := proto.MarshalTextString(dsc.AsProto())
expected := expected :=
`name: "EmptyCall" `name: "EmptyCall"
input_type: ".grpc.testing.Empty" input_type: ".testing.Empty"
output_type: ".grpc.testing.Empty" output_type: ".testing.Empty"
` `
if expected != txt { if expected != txt {
t.Errorf("descriptor mismatch: expected %s, got %s", expected, txt) t.Errorf("descriptor mismatch: expected %s, got %s", expected, txt)
} }
sym = "grpc.testing.StreamingOutputCallResponse" sym = "testing.StreamingOutputCallResponse"
dsc, err = source.FindSymbol(sym) dsc, err = source.FindSymbol(sym)
if err != nil { if err != nil {
t.Fatalf("failed to get descriptor for %q: %v", sym, err) t.Fatalf("failed to get descriptor for %q: %v", sym, err)
@@ -423,7 +426,7 @@ field: <
number: 1 number: 1
label: LABEL_OPTIONAL label: LABEL_OPTIONAL
type: TYPE_MESSAGE type: TYPE_MESSAGE
type_name: ".grpc.testing.Payload" type_name: ".testing.Payload"
json_name: "payload" json_name: "payload"
> >
` `
@@ -479,12 +482,12 @@ func TestUnary(t *testing.T) {
func doTestUnary(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) { func doTestUnary(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
// Success // Success
h := &handler{reqMessages: []string{payload1}} h := &handler{reqMessages: []string{payload1}}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/UnaryCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRpc(context.Background(), source, cc, "testing.TestService/UnaryCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
if h.check(t, "grpc.testing.TestService.UnaryCall", codes.OK, 1, 1) { if h.check(t, "testing.TestService.UnaryCall", codes.OK, 1, 1) {
if h.respMessages[0] != payload1 { if h.respMessages[0] != payload1 {
t.Errorf("unexpected response from RPC: expecting %s; got %s", payload1, h.respMessages[0]) t.Errorf("unexpected response from RPC: expecting %s; got %s", payload1, h.respMessages[0])
} }
@@ -492,12 +495,12 @@ func doTestUnary(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
// Failure // Failure
h = &handler{reqMessages: []string{payload1}} h = &handler{reqMessages: []string{payload1}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/UnaryCall", makeHeaders(codes.NotFound), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/UnaryCall", makeHeaders(codes.NotFound), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.UnaryCall", codes.NotFound, 1, 0) h.check(t, "testing.TestService.UnaryCall", codes.NotFound, 1, 0)
} }
func TestClientStream(t *testing.T) { func TestClientStream(t *testing.T) {
@@ -511,12 +514,12 @@ func TestClientStream(t *testing.T) {
func doTestClientStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) { func doTestClientStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
// Success // Success
h := &handler{reqMessages: []string{payload1, payload2, payload3}} h := &handler{reqMessages: []string{payload1, payload2, payload3}}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRpc(context.Background(), source, cc, "testing.TestService/StreamingInputCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
if h.check(t, "grpc.testing.TestService.StreamingInputCall", codes.OK, 3, 1) { if h.check(t, "testing.TestService.StreamingInputCall", codes.OK, 3, 1) {
expected := expected :=
`{ `{
"aggregatedPayloadSize": 61 "aggregatedPayloadSize": 61
@@ -528,21 +531,21 @@ func doTestClientStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: []string{payload1, payload2, payload3}} h = &handler{reqMessages: []string{payload1, payload2, payload3}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.InvalidArgument), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/StreamingInputCall", makeHeaders(codes.InvalidArgument), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.StreamingInputCall", codes.InvalidArgument, -3, 0) h.check(t, "testing.TestService.StreamingInputCall", codes.InvalidArgument, -3, 0)
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: []string{payload1, payload2, payload3}} h = &handler{reqMessages: []string{payload1, payload2, payload3}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingInputCall", makeHeaders(codes.Internal, true), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/StreamingInputCall", makeHeaders(codes.Internal, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.StreamingInputCall", codes.Internal, 3, 0) h.check(t, "testing.TestService.StreamingInputCall", codes.Internal, 3, 0)
} }
func TestServerStream(t *testing.T) { func TestServerStream(t *testing.T) {
@@ -554,9 +557,9 @@ func TestServerStream(t *testing.T) {
} }
func doTestServerStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) { func doTestServerStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
req := &grpc_testing.StreamingOutputCallRequest{ req := &grpcurl_testing.StreamingOutputCallRequest{
ResponseType: grpc_testing.PayloadType_COMPRESSABLE, ResponseType: grpcurl_testing.PayloadType_COMPRESSABLE,
ResponseParameters: []*grpc_testing.ResponseParameters{ ResponseParameters: []*grpcurl_testing.ResponseParameters{
{Size: 10}, {Size: 20}, {Size: 30}, {Size: 40}, {Size: 50}, {Size: 10}, {Size: 20}, {Size: 30}, {Size: 40}, {Size: 50},
}, },
} }
@@ -567,19 +570,19 @@ func doTestServerStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Success // Success
h := &handler{reqMessages: []string{payload}} h := &handler{reqMessages: []string{payload}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.OK), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/StreamingOutputCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
if h.check(t, "grpc.testing.TestService.StreamingOutputCall", codes.OK, 1, 5) { if h.check(t, "testing.TestService.StreamingOutputCall", codes.OK, 1, 5) {
resp := &grpc_testing.StreamingOutputCallResponse{} resp := &grpcurl_testing.StreamingOutputCallResponse{}
for i, msg := range h.respMessages { for i, msg := range h.respMessages {
if err := jsonpb.UnmarshalString(msg, resp); err != nil { if err := jsonpb.UnmarshalString(msg, resp); err != nil {
t.Errorf("failed to parse response %d: %v", i+1, err) t.Errorf("failed to parse response %d: %v", i+1, err)
} }
if resp.Payload.GetType() != grpc_testing.PayloadType_COMPRESSABLE { if resp.Payload.GetType() != grpcurl_testing.PayloadType_COMPRESSABLE {
t.Errorf("response %d has wrong payload type; expecting %v, got %v", i, grpc_testing.PayloadType_COMPRESSABLE, resp.Payload.Type) t.Errorf("response %d has wrong payload type; expecting %v, got %v", i, grpcurl_testing.PayloadType_COMPRESSABLE, resp.Payload.Type)
} }
if len(resp.Payload.Body) != (i+1)*10 { if len(resp.Payload.Body) != (i+1)*10 {
t.Errorf("response %d has wrong payload size; expecting %d, got %d", i, (i+1)*10, len(resp.Payload.Body)) t.Errorf("response %d has wrong payload size; expecting %d, got %d", i, (i+1)*10, len(resp.Payload.Body))
@@ -590,21 +593,21 @@ func doTestServerStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSour
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: []string{payload}} h = &handler{reqMessages: []string{payload}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.Aborted), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/StreamingOutputCall", makeHeaders(codes.Aborted), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.StreamingOutputCall", codes.Aborted, 1, 0) h.check(t, "testing.TestService.StreamingOutputCall", codes.Aborted, 1, 0)
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: []string{payload}} h = &handler{reqMessages: []string{payload}}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/StreamingOutputCall", makeHeaders(codes.AlreadyExists, true), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/StreamingOutputCall", makeHeaders(codes.AlreadyExists, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.StreamingOutputCall", codes.AlreadyExists, 1, 5) h.check(t, "testing.TestService.StreamingOutputCall", codes.AlreadyExists, 1, 5)
} }
func TestHalfDuplexStream(t *testing.T) { func TestHalfDuplexStream(t *testing.T) {
@@ -620,12 +623,12 @@ func doTestHalfDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Success // Success
h := &handler{reqMessages: reqs} h := &handler{reqMessages: reqs}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRpc(context.Background(), source, cc, "testing.TestService/HalfDuplexCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
if h.check(t, "grpc.testing.TestService.HalfDuplexCall", codes.OK, 3, 3) { if h.check(t, "testing.TestService.HalfDuplexCall", codes.OK, 3, 3) {
for i, resp := range h.respMessages { for i, resp := range h.respMessages {
if resp != reqs[i] { if resp != reqs[i] {
t.Errorf("unexpected response %d from RPC:\nexpecting %q\ngot %q", i, reqs[i], resp) t.Errorf("unexpected response %d from RPC:\nexpecting %q\ngot %q", i, reqs[i], resp)
@@ -635,21 +638,21 @@ func doTestHalfDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.Canceled), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/HalfDuplexCall", makeHeaders(codes.Canceled), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.HalfDuplexCall", codes.Canceled, -3, 0) h.check(t, "testing.TestService.HalfDuplexCall", codes.Canceled, -3, 0)
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/HalfDuplexCall", makeHeaders(codes.DataLoss, true), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/HalfDuplexCall", makeHeaders(codes.DataLoss, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.HalfDuplexCall", codes.DataLoss, 3, 3) h.check(t, "testing.TestService.HalfDuplexCall", codes.DataLoss, 3, 3)
} }
func TestFullDuplexStream(t *testing.T) { func TestFullDuplexStream(t *testing.T) {
@@ -662,11 +665,11 @@ func TestFullDuplexStream(t *testing.T) {
func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) { func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source DescriptorSource) {
reqs := make([]string, 3) reqs := make([]string, 3)
req := &grpc_testing.StreamingOutputCallRequest{ req := &grpcurl_testing.StreamingOutputCallRequest{
ResponseType: grpc_testing.PayloadType_RANDOM, ResponseType: grpcurl_testing.PayloadType_RANDOM,
} }
for i := range reqs { for i := range reqs {
req.ResponseParameters = append(req.ResponseParameters, &grpc_testing.ResponseParameters{Size: int32((i + 1) * 10)}) req.ResponseParameters = append(req.ResponseParameters, &grpcurl_testing.ResponseParameters{Size: int32((i + 1) * 10)})
payload, err := (&jsonpb.Marshaler{}).MarshalToString(req) payload, err := (&jsonpb.Marshaler{}).MarshalToString(req)
if err != nil { if err != nil {
t.Fatalf("failed to construct request %d: %v", i, err) t.Fatalf("failed to construct request %d: %v", i, err)
@@ -676,13 +679,13 @@ func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Success // Success
h := &handler{reqMessages: reqs} h := &handler{reqMessages: reqs}
err := InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.OK), h, h.getRequestData) err := InvokeRpc(context.Background(), source, cc, "testing.TestService/FullDuplexCall", makeHeaders(codes.OK), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
if h.check(t, "grpc.testing.TestService.FullDuplexCall", codes.OK, 3, 6) { if h.check(t, "testing.TestService.FullDuplexCall", codes.OK, 3, 6) {
resp := &grpc_testing.StreamingOutputCallResponse{} resp := &grpcurl_testing.StreamingOutputCallResponse{}
i := 0 i := 0
for j := 1; j < 3; j++ { for j := 1; j < 3; j++ {
// three requests // three requests
@@ -692,8 +695,8 @@ func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
if err := jsonpb.UnmarshalString(msg, resp); err != nil { if err := jsonpb.UnmarshalString(msg, resp); err != nil {
t.Errorf("failed to parse response %d: %v", i+1, err) t.Errorf("failed to parse response %d: %v", i+1, err)
} }
if resp.Payload.GetType() != grpc_testing.PayloadType_RANDOM { if resp.Payload.GetType() != grpcurl_testing.PayloadType_RANDOM {
t.Errorf("response %d has wrong payload type; expecting %v, got %v", i, grpc_testing.PayloadType_RANDOM, resp.Payload.Type) t.Errorf("response %d has wrong payload type; expecting %v, got %v", i, grpcurl_testing.PayloadType_RANDOM, resp.Payload.Type)
} }
if len(resp.Payload.Body) != (k+1)*10 { if len(resp.Payload.Body) != (k+1)*10 {
t.Errorf("response %d has wrong payload size; expecting %d, got %d", i, (k+1)*10, len(resp.Payload.Body)) t.Errorf("response %d has wrong payload size; expecting %d, got %d", i, (k+1)*10, len(resp.Payload.Body))
@@ -707,21 +710,21 @@ func doTestFullDuplexStream(t *testing.T, cc *grpc.ClientConn, source Descriptor
// Fail fast (server rejects as soon as possible) // Fail fast (server rejects as soon as possible)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.PermissionDenied), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/FullDuplexCall", makeHeaders(codes.PermissionDenied), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.FullDuplexCall", codes.PermissionDenied, -3, 0) h.check(t, "testing.TestService.FullDuplexCall", codes.PermissionDenied, -3, 0)
// Fail late (server waits until stream is complete to reject) // Fail late (server waits until stream is complete to reject)
h = &handler{reqMessages: reqs} h = &handler{reqMessages: reqs}
err = InvokeRpc(context.Background(), source, cc, "grpc.testing.TestService/FullDuplexCall", makeHeaders(codes.ResourceExhausted, true), h, h.getRequestData) err = InvokeRpc(context.Background(), source, cc, "testing.TestService/FullDuplexCall", makeHeaders(codes.ResourceExhausted, true), h, h.getRequestData)
if err != nil { if err != nil {
t.Fatalf("unexpected error during RPC: %v", err) t.Fatalf("unexpected error during RPC: %v", err)
} }
h.check(t, "grpc.testing.TestService.FullDuplexCall", codes.ResourceExhausted, 3, 6) h.check(t, "testing.TestService.FullDuplexCall", codes.ResourceExhausted, 3, 6)
} }
type handler struct { type handler struct {

View File

@@ -1,9 +1,9 @@
package main package main
import ( import (
"context"
"strings" "strings"
"golang.org/x/net/context"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
) )

View File

@@ -1,18 +1,18 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"time" "time"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
"golang.org/x/net/context"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
) )
// bankServer implements the Bank gRPC service. // bankServer implements the Bank gRPC service.
type bankServer struct { type bankServer struct {
UnimplementedBankServer
allAccounts *accounts allAccounts *accounts
} }
@@ -72,26 +72,29 @@ func (s *bankServer) GetTransactions(req *GetTransactionsRequest, stream Bank_Ge
var start, end time.Time var start, end time.Time
if req.Start != nil { if req.Start != nil {
start, err = ptypes.Timestamp(req.Start) err := req.Start.CheckValid()
if err != nil { if err != nil {
return err return err
} }
start = req.Start.AsTime()
} }
if req.End != nil { if req.End != nil {
end, err = ptypes.Timestamp(req.End) err := req.End.CheckValid()
if err != nil { if err != nil {
return err return err
} }
end = req.End.AsTime()
} else { } else {
end = time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.Local) end = time.Date(9999, 12, 31, 23, 59, 59, 999999999, time.Local)
} }
txns := acct.getTransactions() txns := acct.getTransactions()
for _, txn := range txns { for _, txn := range txns {
t, err := ptypes.Timestamp(txn.Date) err := txn.Date.CheckValid()
if err != nil { if err != nil {
return err return err
} }
t := txn.Date.AsTime()
if (t.After(start) || t.Equal(start)) && if (t.After(start) || t.Equal(start)) &&
(t.Before(end) || t.Equal(end)) { (t.Before(end) || t.Equal(end)) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
option go_package = "main"; option go_package = ".;main";
import "google/protobuf/empty.proto"; import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";

View File

@@ -0,0 +1,374 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package main
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
emptypb "google.golang.org/protobuf/types/known/emptypb"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// BankClient is the client API for Bank service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type BankClient interface {
// OpenAccount creates an account with the type and given initial deposit
// as its balance.
OpenAccount(ctx context.Context, in *OpenAccountRequest, opts ...grpc.CallOption) (*Account, error)
// CloseAccount closes the indicated account. An account can only be
// closed if its balance is zero.
CloseAccount(ctx context.Context, in *CloseAccountRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
// GetAccounts lists all accounts for the current customer.
GetAccounts(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetAccountsResponse, error)
// GetTransactions streams all transactions that match the given criteria.
// If the given start date is not specified, transactions since beginning
// of time are included. Similarly, if the given end date is not specified,
// transactions all the way to the presnet are included.
GetTransactions(ctx context.Context, in *GetTransactionsRequest, opts ...grpc.CallOption) (Bank_GetTransactionsClient, error)
// Deposit increases the balance of an account by depositing funds into it.
Deposit(ctx context.Context, in *DepositRequest, opts ...grpc.CallOption) (*BalanceResponse, error)
// Withdraw decreases the balance of an account by withdrawing funds from it.
Withdraw(ctx context.Context, in *WithdrawRequest, opts ...grpc.CallOption) (*BalanceResponse, error)
// Transfer moves money from one account to another. The source and destination
// accounts can be with this bank (e.g. "local" account numbers) or can be
// external accounts, identified by their ACH routing and account numbers.
Transfer(ctx context.Context, in *TransferRequest, opts ...grpc.CallOption) (*TransferResponse, error)
}
type bankClient struct {
cc grpc.ClientConnInterface
}
func NewBankClient(cc grpc.ClientConnInterface) BankClient {
return &bankClient{cc}
}
func (c *bankClient) OpenAccount(ctx context.Context, in *OpenAccountRequest, opts ...grpc.CallOption) (*Account, error) {
out := new(Account)
err := c.cc.Invoke(ctx, "/Bank/OpenAccount", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *bankClient) CloseAccount(ctx context.Context, in *CloseAccountRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, "/Bank/CloseAccount", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *bankClient) GetAccounts(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetAccountsResponse, error) {
out := new(GetAccountsResponse)
err := c.cc.Invoke(ctx, "/Bank/GetAccounts", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *bankClient) GetTransactions(ctx context.Context, in *GetTransactionsRequest, opts ...grpc.CallOption) (Bank_GetTransactionsClient, error) {
stream, err := c.cc.NewStream(ctx, &Bank_ServiceDesc.Streams[0], "/Bank/GetTransactions", opts...)
if err != nil {
return nil, err
}
x := &bankGetTransactionsClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type Bank_GetTransactionsClient interface {
Recv() (*Transaction, error)
grpc.ClientStream
}
type bankGetTransactionsClient struct {
grpc.ClientStream
}
func (x *bankGetTransactionsClient) Recv() (*Transaction, error) {
m := new(Transaction)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *bankClient) Deposit(ctx context.Context, in *DepositRequest, opts ...grpc.CallOption) (*BalanceResponse, error) {
out := new(BalanceResponse)
err := c.cc.Invoke(ctx, "/Bank/Deposit", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *bankClient) Withdraw(ctx context.Context, in *WithdrawRequest, opts ...grpc.CallOption) (*BalanceResponse, error) {
out := new(BalanceResponse)
err := c.cc.Invoke(ctx, "/Bank/Withdraw", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *bankClient) Transfer(ctx context.Context, in *TransferRequest, opts ...grpc.CallOption) (*TransferResponse, error) {
out := new(TransferResponse)
err := c.cc.Invoke(ctx, "/Bank/Transfer", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// BankServer is the server API for Bank service.
// All implementations must embed UnimplementedBankServer
// for forward compatibility
type BankServer interface {
// OpenAccount creates an account with the type and given initial deposit
// as its balance.
OpenAccount(context.Context, *OpenAccountRequest) (*Account, error)
// CloseAccount closes the indicated account. An account can only be
// closed if its balance is zero.
CloseAccount(context.Context, *CloseAccountRequest) (*emptypb.Empty, error)
// GetAccounts lists all accounts for the current customer.
GetAccounts(context.Context, *emptypb.Empty) (*GetAccountsResponse, error)
// GetTransactions streams all transactions that match the given criteria.
// If the given start date is not specified, transactions since beginning
// of time are included. Similarly, if the given end date is not specified,
// transactions all the way to the presnet are included.
GetTransactions(*GetTransactionsRequest, Bank_GetTransactionsServer) error
// Deposit increases the balance of an account by depositing funds into it.
Deposit(context.Context, *DepositRequest) (*BalanceResponse, error)
// Withdraw decreases the balance of an account by withdrawing funds from it.
Withdraw(context.Context, *WithdrawRequest) (*BalanceResponse, error)
// Transfer moves money from one account to another. The source and destination
// accounts can be with this bank (e.g. "local" account numbers) or can be
// external accounts, identified by their ACH routing and account numbers.
Transfer(context.Context, *TransferRequest) (*TransferResponse, error)
mustEmbedUnimplementedBankServer()
}
// UnimplementedBankServer must be embedded to have forward compatible implementations.
type UnimplementedBankServer struct {
}
func (UnimplementedBankServer) OpenAccount(context.Context, *OpenAccountRequest) (*Account, error) {
return nil, status.Errorf(codes.Unimplemented, "method OpenAccount not implemented")
}
func (UnimplementedBankServer) CloseAccount(context.Context, *CloseAccountRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method CloseAccount not implemented")
}
func (UnimplementedBankServer) GetAccounts(context.Context, *emptypb.Empty) (*GetAccountsResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetAccounts not implemented")
}
func (UnimplementedBankServer) GetTransactions(*GetTransactionsRequest, Bank_GetTransactionsServer) error {
return status.Errorf(codes.Unimplemented, "method GetTransactions not implemented")
}
func (UnimplementedBankServer) Deposit(context.Context, *DepositRequest) (*BalanceResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Deposit not implemented")
}
func (UnimplementedBankServer) Withdraw(context.Context, *WithdrawRequest) (*BalanceResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Withdraw not implemented")
}
func (UnimplementedBankServer) Transfer(context.Context, *TransferRequest) (*TransferResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Transfer not implemented")
}
func (UnimplementedBankServer) mustEmbedUnimplementedBankServer() {}
// UnsafeBankServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to BankServer will
// result in compilation errors.
type UnsafeBankServer interface {
mustEmbedUnimplementedBankServer()
}
func RegisterBankServer(s grpc.ServiceRegistrar, srv BankServer) {
s.RegisterService(&Bank_ServiceDesc, srv)
}
func _Bank_OpenAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(OpenAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BankServer).OpenAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Bank/OpenAccount",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BankServer).OpenAccount(ctx, req.(*OpenAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Bank_CloseAccount_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(CloseAccountRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BankServer).CloseAccount(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Bank/CloseAccount",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BankServer).CloseAccount(ctx, req.(*CloseAccountRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Bank_GetAccounts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BankServer).GetAccounts(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Bank/GetAccounts",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BankServer).GetAccounts(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _Bank_GetTransactions_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(GetTransactionsRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(BankServer).GetTransactions(m, &bankGetTransactionsServer{stream})
}
type Bank_GetTransactionsServer interface {
Send(*Transaction) error
grpc.ServerStream
}
type bankGetTransactionsServer struct {
grpc.ServerStream
}
func (x *bankGetTransactionsServer) Send(m *Transaction) error {
return x.ServerStream.SendMsg(m)
}
func _Bank_Deposit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(DepositRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BankServer).Deposit(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Bank/Deposit",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BankServer).Deposit(ctx, req.(*DepositRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Bank_Withdraw_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(WithdrawRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BankServer).Withdraw(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Bank/Withdraw",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BankServer).Withdraw(ctx, req.(*WithdrawRequest))
}
return interceptor(ctx, in, info, handler)
}
func _Bank_Transfer_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(TransferRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(BankServer).Transfer(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/Bank/Transfer",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(BankServer).Transfer(ctx, req.(*TransferRequest))
}
return interceptor(ctx, in, info, handler)
}
// Bank_ServiceDesc is the grpc.ServiceDesc for Bank service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Bank_ServiceDesc = grpc.ServiceDesc{
ServiceName: "Bank",
HandlerType: (*BankServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "OpenAccount",
Handler: _Bank_OpenAccount_Handler,
},
{
MethodName: "CloseAccount",
Handler: _Bank_CloseAccount_Handler,
},
{
MethodName: "GetAccounts",
Handler: _Bank_GetAccounts_Handler,
},
{
MethodName: "Deposit",
Handler: _Bank_Deposit_Handler,
},
{
MethodName: "Withdraw",
Handler: _Bank_Withdraw_Handler,
},
{
MethodName: "Transfer",
Handler: _Bank_Transfer_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "GetTransactions",
Handler: _Bank_GetTransactions_Handler,
ServerStreams: true,
},
},
Metadata: "bank.proto",
}

View File

@@ -1,20 +1,21 @@
package main package main
import ( import (
"context"
"fmt" "fmt"
"io" "io"
"sync" "sync"
"github.com/golang/protobuf/ptypes"
"golang.org/x/net/context"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/timestamppb"
) )
// chatServer implements the Support gRPC service, for providing // chatServer implements the Support gRPC service, for providing
// a capability to connect customers and support agents in real-time // a capability to connect customers and support agents in real-time
// chat. // chat.
type chatServer struct { type chatServer struct {
UnimplementedSupportServer
chatsBySession map[string]*session chatsBySession map[string]*session
chatsAwaitingAgent []string chatsAwaitingAgent []string
lastSession int32 lastSession int32
@@ -134,7 +135,7 @@ func (s *chatServer) ChatCustomer(stream Support_ChatCustomerServer) error {
} }
entry := &ChatEntry{ entry := &ChatEntry{
Date: ptypes.TimestampNow(), Date: timestamppb.Now(),
Entry: &ChatEntry_CustomerMsg{ Entry: &ChatEntry_CustomerMsg{
CustomerMsg: req.Msg, CustomerMsg: req.Msg,
}, },
@@ -279,7 +280,7 @@ func (s *chatServer) ChatAgent(stream Support_ChatAgentServer) error {
} }
entry := &ChatEntry{ entry := &ChatEntry{
Date: ptypes.TimestampNow(), Date: timestamppb.Now(),
Entry: &ChatEntry_AgentMsg{ Entry: &ChatEntry_AgentMsg{
AgentMsg: &AgentMessage{ AgentMsg: &AgentMessage{
AgentName: agent, AgentName: agent,

View File

@@ -1,14 +1,13 @@
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"sync" "sync"
"github.com/golang/protobuf/jsonpb"
"github.com/golang/protobuf/ptypes"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/timestamppb"
) )
// In-memory database that is periodically saved to a JSON file. // In-memory database that is periodically saved to a JSON file.
@@ -43,7 +42,7 @@ func (a *accounts) openAccount(customer string, accountType Account_Type, initia
acct.Transactions = append(acct.Transactions, &Transaction{ acct.Transactions = append(acct.Transactions, &Transaction{
AccountNumber: num, AccountNumber: num,
SeqNumber: 1, SeqNumber: 1,
Date: ptypes.TimestampNow(), Date: timestamppb.Now(),
AmountCents: initialBalanceCents, AmountCents: initialBalanceCents,
Desc: "initial deposit", Desc: "initial deposit",
}) })
@@ -130,7 +129,7 @@ func (a *account) newTransaction(amountCents int32, desc string) (newBalance int
a.BalanceCents = bal a.BalanceCents = bal
a.Transactions = append(a.Transactions, &Transaction{ a.Transactions = append(a.Transactions, &Transaction{
AccountNumber: a.AccountNumber, AccountNumber: a.AccountNumber,
Date: ptypes.TimestampNow(), Date: timestamppb.Now(),
AmountCents: amountCents, AmountCents: amountCents,
SeqNumber: uint64(len(a.Transactions) + 1), SeqNumber: uint64(len(a.Transactions) + 1),
Desc: desc, Desc: desc,
@@ -139,16 +138,11 @@ func (a *account) newTransaction(amountCents int32, desc string) (newBalance int
} }
func (t *Transaction) MarshalJSON() ([]byte, error) { func (t *Transaction) MarshalJSON() ([]byte, error) {
var jsm jsonpb.Marshaler return protojson.Marshal(t)
var buf bytes.Buffer
if err := jsm.Marshal(&buf, t); err != nil {
return nil, err
}
return buf.Bytes(), nil
} }
func (t *Transaction) UnmarshalJSON(b []byte) error { func (t *Transaction) UnmarshalJSON(b []byte) error {
return jsonpb.Unmarshal(bytes.NewReader(b), t) return protojson.Unmarshal(b, t)
} }
func (a *accounts) clone() *accounts { func (a *accounts) clone() *accounts {

View File

@@ -1,12 +1,12 @@
package main package main
//go:generate protoc --go_out=plugins=grpc:./ bank.proto support.proto //go:generate protoc --go_out=. --go-grpc_out=. bank.proto support.proto
import ( import (
"context"
"encoding/json" "encoding/json"
"flag" "flag"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os" "os"
"os/signal" "os/signal"
@@ -14,7 +14,6 @@ import (
"syscall" "syscall"
"time" "time"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/grpclog" "google.golang.org/grpc/grpclog"
"google.golang.org/grpc/peer" "google.golang.org/grpc/peer"
@@ -130,7 +129,7 @@ type svr struct {
} }
func (s *svr) load() error { func (s *svr) load() error {
accts, err := ioutil.ReadFile(s.datafile) accts, err := os.ReadFile(s.datafile)
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return err return err
} }
@@ -162,7 +161,7 @@ func (s *svr) flush() {
if b, err := json.Marshal(accounts); err != nil { if b, err := json.Marshal(accounts); err != nil {
grpclog.Errorf("failed to save data to %q", s.datafile) grpclog.Errorf("failed to save data to %q", s.datafile)
} else if err := ioutil.WriteFile(s.datafile, b, 0666); err != nil { } else if err := os.WriteFile(s.datafile, b, 0666); err != nil {
grpclog.Errorf("failed to save data to %q", s.datafile) grpclog.Errorf("failed to save data to %q", s.datafile)
} }
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
syntax = "proto3"; syntax = "proto3";
option go_package = "main"; option go_package = ".;main";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";

View File

@@ -0,0 +1,217 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package main
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// SupportClient is the client API for Support service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type SupportClient interface {
// ChatCustomer is used by a customer-facing app to send the customer's messages
// to a chat session. The customer is how initiates and terminates (via "hangup")
// a chat session. Only customers may invoke this method (e.g. requests must
// include customer auth credentials).
ChatCustomer(ctx context.Context, opts ...grpc.CallOption) (Support_ChatCustomerClient, error)
// ChatAgent is used by an agent-facing app to allow an agent to reply to a
// customer's messages in a chat session. The agent may accept a chat session,
// which defaults to the session awaiting an agent for the longest period of time
// (FIFO queue).
ChatAgent(ctx context.Context, opts ...grpc.CallOption) (Support_ChatAgentClient, error)
}
type supportClient struct {
cc grpc.ClientConnInterface
}
func NewSupportClient(cc grpc.ClientConnInterface) SupportClient {
return &supportClient{cc}
}
func (c *supportClient) ChatCustomer(ctx context.Context, opts ...grpc.CallOption) (Support_ChatCustomerClient, error) {
stream, err := c.cc.NewStream(ctx, &Support_ServiceDesc.Streams[0], "/Support/ChatCustomer", opts...)
if err != nil {
return nil, err
}
x := &supportChatCustomerClient{stream}
return x, nil
}
type Support_ChatCustomerClient interface {
Send(*ChatCustomerRequest) error
Recv() (*ChatCustomerResponse, error)
grpc.ClientStream
}
type supportChatCustomerClient struct {
grpc.ClientStream
}
func (x *supportChatCustomerClient) Send(m *ChatCustomerRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *supportChatCustomerClient) Recv() (*ChatCustomerResponse, error) {
m := new(ChatCustomerResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *supportClient) ChatAgent(ctx context.Context, opts ...grpc.CallOption) (Support_ChatAgentClient, error) {
stream, err := c.cc.NewStream(ctx, &Support_ServiceDesc.Streams[1], "/Support/ChatAgent", opts...)
if err != nil {
return nil, err
}
x := &supportChatAgentClient{stream}
return x, nil
}
type Support_ChatAgentClient interface {
Send(*ChatAgentRequest) error
Recv() (*ChatAgentResponse, error)
grpc.ClientStream
}
type supportChatAgentClient struct {
grpc.ClientStream
}
func (x *supportChatAgentClient) Send(m *ChatAgentRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *supportChatAgentClient) Recv() (*ChatAgentResponse, error) {
m := new(ChatAgentResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// SupportServer is the server API for Support service.
// All implementations must embed UnimplementedSupportServer
// for forward compatibility
type SupportServer interface {
// ChatCustomer is used by a customer-facing app to send the customer's messages
// to a chat session. The customer is how initiates and terminates (via "hangup")
// a chat session. Only customers may invoke this method (e.g. requests must
// include customer auth credentials).
ChatCustomer(Support_ChatCustomerServer) error
// ChatAgent is used by an agent-facing app to allow an agent to reply to a
// customer's messages in a chat session. The agent may accept a chat session,
// which defaults to the session awaiting an agent for the longest period of time
// (FIFO queue).
ChatAgent(Support_ChatAgentServer) error
mustEmbedUnimplementedSupportServer()
}
// UnimplementedSupportServer must be embedded to have forward compatible implementations.
type UnimplementedSupportServer struct {
}
func (UnimplementedSupportServer) ChatCustomer(Support_ChatCustomerServer) error {
return status.Errorf(codes.Unimplemented, "method ChatCustomer not implemented")
}
func (UnimplementedSupportServer) ChatAgent(Support_ChatAgentServer) error {
return status.Errorf(codes.Unimplemented, "method ChatAgent not implemented")
}
func (UnimplementedSupportServer) mustEmbedUnimplementedSupportServer() {}
// UnsafeSupportServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to SupportServer will
// result in compilation errors.
type UnsafeSupportServer interface {
mustEmbedUnimplementedSupportServer()
}
func RegisterSupportServer(s grpc.ServiceRegistrar, srv SupportServer) {
s.RegisterService(&Support_ServiceDesc, srv)
}
func _Support_ChatCustomer_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(SupportServer).ChatCustomer(&supportChatCustomerServer{stream})
}
type Support_ChatCustomerServer interface {
Send(*ChatCustomerResponse) error
Recv() (*ChatCustomerRequest, error)
grpc.ServerStream
}
type supportChatCustomerServer struct {
grpc.ServerStream
}
func (x *supportChatCustomerServer) Send(m *ChatCustomerResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *supportChatCustomerServer) Recv() (*ChatCustomerRequest, error) {
m := new(ChatCustomerRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func _Support_ChatAgent_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(SupportServer).ChatAgent(&supportChatAgentServer{stream})
}
type Support_ChatAgentServer interface {
Send(*ChatAgentResponse) error
Recv() (*ChatAgentRequest, error)
grpc.ServerStream
}
type supportChatAgentServer struct {
grpc.ServerStream
}
func (x *supportChatAgentServer) Send(m *ChatAgentResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *supportChatAgentServer) Recv() (*ChatAgentRequest, error) {
m := new(ChatAgentRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// Support_ServiceDesc is the grpc.ServiceDesc for Support service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var Support_ServiceDesc = grpc.ServiceDesc{
ServiceName: "Support",
HandlerType: (*SupportServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
{
StreamName: "ChatCustomer",
Handler: _Support_ChatCustomer_Handler,
ServerStreams: true,
ClientStreams: true,
},
{
StreamName: "ChatAgent",
Handler: _Support_ChatAgent_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "support.proto",
}

View File

@@ -2,6 +2,7 @@
package main package main
import ( import (
"context"
"flag" "flag"
"fmt" "fmt"
"net" "net"
@@ -9,17 +10,15 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/grpclog" "google.golang.org/grpc/grpclog"
"google.golang.org/grpc/interop/grpc_testing"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/fullstorydev/grpcurl" "github.com/fullstorydev/grpcurl"
grpcurl_testing "github.com/fullstorydev/grpcurl/testing" grpcurl_testing "github.com/fullstorydev/grpcurl/internal/testing"
) )
var ( var (
@@ -96,7 +95,7 @@ func main() {
svr := grpc.NewServer(opts...) svr := grpc.NewServer(opts...)
grpc_testing.RegisterTestServiceServer(svr, grpcurl_testing.TestServer{}) grpcurl_testing.RegisterTestServiceServer(svr, grpcurl_testing.TestServer{})
if !*noreflect { if !*noreflect {
reflection.Register(svr) reflection.Register(svr)
} }

View File

@@ -1,3 +1,4 @@
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
// +build darwin dragonfly freebsd linux netbsd openbsd solaris // +build darwin dragonfly freebsd linux netbsd openbsd solaris
package main package main

View File

@@ -3,7 +3,7 @@ syntax = "proto3";
import "google/protobuf/descriptor.proto"; import "google/protobuf/descriptor.proto";
import "google/protobuf/empty.proto"; import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto"; import "google/protobuf/timestamp.proto";
import "testing/example2.proto"; import "example2.proto";
message TestRequest { message TestRequest {
repeated string file_names = 1; repeated string file_names = 1;

View File

@@ -0,0 +1,344 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.25.0-devel
// protoc v3.14.0
// source: test_objects.proto
package jsonpb
import (
proto "github.com/golang/protobuf/proto"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
anypb "google.golang.org/protobuf/types/known/anypb"
durationpb "google.golang.org/protobuf/types/known/durationpb"
structpb "google.golang.org/protobuf/types/known/structpb"
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
wrapperspb "google.golang.org/protobuf/types/known/wrapperspb"
reflect "reflect"
sync "sync"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// This is a compile-time assertion that a sufficiently up-to-date version
// of the legacy proto package is being used.
const _ = proto.ProtoPackageIsVersion4
type KnownTypes struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
An *anypb.Any `protobuf:"bytes,14,opt,name=an" json:"an,omitempty"`
Dur *durationpb.Duration `protobuf:"bytes,1,opt,name=dur" json:"dur,omitempty"`
St *structpb.Struct `protobuf:"bytes,12,opt,name=st" json:"st,omitempty"`
Ts *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=ts" json:"ts,omitempty"`
Lv *structpb.ListValue `protobuf:"bytes,15,opt,name=lv" json:"lv,omitempty"`
Val *structpb.Value `protobuf:"bytes,16,opt,name=val" json:"val,omitempty"`
Dbl *wrapperspb.DoubleValue `protobuf:"bytes,3,opt,name=dbl" json:"dbl,omitempty"`
Flt *wrapperspb.FloatValue `protobuf:"bytes,4,opt,name=flt" json:"flt,omitempty"`
I64 *wrapperspb.Int64Value `protobuf:"bytes,5,opt,name=i64" json:"i64,omitempty"`
U64 *wrapperspb.UInt64Value `protobuf:"bytes,6,opt,name=u64" json:"u64,omitempty"`
I32 *wrapperspb.Int32Value `protobuf:"bytes,7,opt,name=i32" json:"i32,omitempty"`
U32 *wrapperspb.UInt32Value `protobuf:"bytes,8,opt,name=u32" json:"u32,omitempty"`
Bool *wrapperspb.BoolValue `protobuf:"bytes,9,opt,name=bool" json:"bool,omitempty"`
Str *wrapperspb.StringValue `protobuf:"bytes,10,opt,name=str" json:"str,omitempty"`
Bytes *wrapperspb.BytesValue `protobuf:"bytes,11,opt,name=bytes" json:"bytes,omitempty"`
}
func (x *KnownTypes) Reset() {
*x = KnownTypes{}
if protoimpl.UnsafeEnabled {
mi := &file_test_objects_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *KnownTypes) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*KnownTypes) ProtoMessage() {}
func (x *KnownTypes) ProtoReflect() protoreflect.Message {
mi := &file_test_objects_proto_msgTypes[0]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use KnownTypes.ProtoReflect.Descriptor instead.
func (*KnownTypes) Descriptor() ([]byte, []int) {
return file_test_objects_proto_rawDescGZIP(), []int{0}
}
func (x *KnownTypes) GetAn() *anypb.Any {
if x != nil {
return x.An
}
return nil
}
func (x *KnownTypes) GetDur() *durationpb.Duration {
if x != nil {
return x.Dur
}
return nil
}
func (x *KnownTypes) GetSt() *structpb.Struct {
if x != nil {
return x.St
}
return nil
}
func (x *KnownTypes) GetTs() *timestamppb.Timestamp {
if x != nil {
return x.Ts
}
return nil
}
func (x *KnownTypes) GetLv() *structpb.ListValue {
if x != nil {
return x.Lv
}
return nil
}
func (x *KnownTypes) GetVal() *structpb.Value {
if x != nil {
return x.Val
}
return nil
}
func (x *KnownTypes) GetDbl() *wrapperspb.DoubleValue {
if x != nil {
return x.Dbl
}
return nil
}
func (x *KnownTypes) GetFlt() *wrapperspb.FloatValue {
if x != nil {
return x.Flt
}
return nil
}
func (x *KnownTypes) GetI64() *wrapperspb.Int64Value {
if x != nil {
return x.I64
}
return nil
}
func (x *KnownTypes) GetU64() *wrapperspb.UInt64Value {
if x != nil {
return x.U64
}
return nil
}
func (x *KnownTypes) GetI32() *wrapperspb.Int32Value {
if x != nil {
return x.I32
}
return nil
}
func (x *KnownTypes) GetU32() *wrapperspb.UInt32Value {
if x != nil {
return x.U32
}
return nil
}
func (x *KnownTypes) GetBool() *wrapperspb.BoolValue {
if x != nil {
return x.Bool
}
return nil
}
func (x *KnownTypes) GetStr() *wrapperspb.StringValue {
if x != nil {
return x.Str
}
return nil
}
func (x *KnownTypes) GetBytes() *wrapperspb.BytesValue {
if x != nil {
return x.Bytes
}
return nil
}
var File_test_objects_proto protoreflect.FileDescriptor
var file_test_objects_proto_rawDesc = []byte{
0x0a, 0x12, 0x74, 0x65, 0x73, 0x74, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x62, 0x1a, 0x19, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e,
0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73,
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xba, 0x05, 0x0a, 0x0a, 0x4b, 0x6e, 0x6f, 0x77, 0x6e,
0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x24, 0x0a, 0x02, 0x61, 0x6e, 0x18, 0x0e, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x02, 0x61, 0x6e, 0x12, 0x2b, 0x0a, 0x03, 0x64,
0x75, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x52, 0x03, 0x64, 0x75, 0x72, 0x12, 0x27, 0x0a, 0x02, 0x73, 0x74, 0x18, 0x0c,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x52, 0x02, 0x73,
0x74, 0x12, 0x2a, 0x0a, 0x02, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x02, 0x74, 0x73, 0x12, 0x2a, 0x0a,
0x02, 0x6c, 0x76, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4c, 0x69, 0x73, 0x74,
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x02, 0x6c, 0x76, 0x12, 0x28, 0x0a, 0x03, 0x76, 0x61, 0x6c,
0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03,
0x76, 0x61, 0x6c, 0x12, 0x2e, 0x0a, 0x03, 0x64, 0x62, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x44, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03,
0x64, 0x62, 0x6c, 0x12, 0x2d, 0x0a, 0x03, 0x66, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x46, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x66,
0x6c, 0x74, 0x12, 0x2d, 0x0a, 0x03, 0x69, 0x36, 0x34, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x69, 0x36,
0x34, 0x12, 0x2e, 0x0a, 0x03, 0x75, 0x36, 0x34, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x55, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x75, 0x36,
0x34, 0x12, 0x2d, 0x0a, 0x03, 0x69, 0x33, 0x32, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x69, 0x33, 0x32,
0x12, 0x2e, 0x0a, 0x03, 0x75, 0x33, 0x32, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x55, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x75, 0x33, 0x32,
0x12, 0x2e, 0x0a, 0x04, 0x62, 0x6f, 0x6f, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x62, 0x6f, 0x6f, 0x6c,
0x12, 0x2e, 0x0a, 0x03, 0x73, 0x74, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x03, 0x73, 0x74, 0x72,
0x12, 0x31, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x62, 0x79,
0x74, 0x65, 0x73, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x3b, 0x6a, 0x73, 0x6f, 0x6e, 0x70, 0x62,
}
var (
file_test_objects_proto_rawDescOnce sync.Once
file_test_objects_proto_rawDescData = file_test_objects_proto_rawDesc
)
func file_test_objects_proto_rawDescGZIP() []byte {
file_test_objects_proto_rawDescOnce.Do(func() {
file_test_objects_proto_rawDescData = protoimpl.X.CompressGZIP(file_test_objects_proto_rawDescData)
})
return file_test_objects_proto_rawDescData
}
var file_test_objects_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_test_objects_proto_goTypes = []interface{}{
(*KnownTypes)(nil), // 0: jsonpb.KnownTypes
(*anypb.Any)(nil), // 1: google.protobuf.Any
(*durationpb.Duration)(nil), // 2: google.protobuf.Duration
(*structpb.Struct)(nil), // 3: google.protobuf.Struct
(*timestamppb.Timestamp)(nil), // 4: google.protobuf.Timestamp
(*structpb.ListValue)(nil), // 5: google.protobuf.ListValue
(*structpb.Value)(nil), // 6: google.protobuf.Value
(*wrapperspb.DoubleValue)(nil), // 7: google.protobuf.DoubleValue
(*wrapperspb.FloatValue)(nil), // 8: google.protobuf.FloatValue
(*wrapperspb.Int64Value)(nil), // 9: google.protobuf.Int64Value
(*wrapperspb.UInt64Value)(nil), // 10: google.protobuf.UInt64Value
(*wrapperspb.Int32Value)(nil), // 11: google.protobuf.Int32Value
(*wrapperspb.UInt32Value)(nil), // 12: google.protobuf.UInt32Value
(*wrapperspb.BoolValue)(nil), // 13: google.protobuf.BoolValue
(*wrapperspb.StringValue)(nil), // 14: google.protobuf.StringValue
(*wrapperspb.BytesValue)(nil), // 15: google.protobuf.BytesValue
}
var file_test_objects_proto_depIdxs = []int32{
1, // 0: jsonpb.KnownTypes.an:type_name -> google.protobuf.Any
2, // 1: jsonpb.KnownTypes.dur:type_name -> google.protobuf.Duration
3, // 2: jsonpb.KnownTypes.st:type_name -> google.protobuf.Struct
4, // 3: jsonpb.KnownTypes.ts:type_name -> google.protobuf.Timestamp
5, // 4: jsonpb.KnownTypes.lv:type_name -> google.protobuf.ListValue
6, // 5: jsonpb.KnownTypes.val:type_name -> google.protobuf.Value
7, // 6: jsonpb.KnownTypes.dbl:type_name -> google.protobuf.DoubleValue
8, // 7: jsonpb.KnownTypes.flt:type_name -> google.protobuf.FloatValue
9, // 8: jsonpb.KnownTypes.i64:type_name -> google.protobuf.Int64Value
10, // 9: jsonpb.KnownTypes.u64:type_name -> google.protobuf.UInt64Value
11, // 10: jsonpb.KnownTypes.i32:type_name -> google.protobuf.Int32Value
12, // 11: jsonpb.KnownTypes.u32:type_name -> google.protobuf.UInt32Value
13, // 12: jsonpb.KnownTypes.bool:type_name -> google.protobuf.BoolValue
14, // 13: jsonpb.KnownTypes.str:type_name -> google.protobuf.StringValue
15, // 14: jsonpb.KnownTypes.bytes:type_name -> google.protobuf.BytesValue
15, // [15:15] is the sub-list for method output_type
15, // [15:15] is the sub-list for method input_type
15, // [15:15] is the sub-list for extension type_name
15, // [15:15] is the sub-list for extension extendee
0, // [0:15] is the sub-list for field type_name
}
func init() { file_test_objects_proto_init() }
func file_test_objects_proto_init() {
if File_test_objects_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_test_objects_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*KnownTypes); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_test_objects_proto_rawDesc,
NumEnums: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_test_objects_proto_goTypes,
DependencyIndexes: file_test_objects_proto_depIdxs,
MessageInfos: file_test_objects_proto_msgTypes,
}.Build()
File_test_objects_proto = out.File
file_test_objects_proto_rawDesc = nil
file_test_objects_proto_goTypes = nil
file_test_objects_proto_depIdxs = nil
}

View File

@@ -0,0 +1,30 @@
syntax = "proto2";
import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
package jsonpb;
option go_package=".;jsonpb";
message KnownTypes {
optional google.protobuf.Any an = 14;
optional google.protobuf.Duration dur = 1;
optional google.protobuf.Struct st = 12;
optional google.protobuf.Timestamp ts = 2;
optional google.protobuf.ListValue lv = 15;
optional google.protobuf.Value val = 16;
optional google.protobuf.DoubleValue dbl = 3;
optional google.protobuf.FloatValue flt = 4;
optional google.protobuf.Int64Value i64 = 5;
optional google.protobuf.UInt64Value u64 = 6;
optional google.protobuf.Int32Value i32 = 7;
optional google.protobuf.UInt32Value u32 = 8;
optional google.protobuf.BoolValue bool = 9;
optional google.protobuf.StringValue str = 10;
optional google.protobuf.BytesValue bytes = 11;
}

1030
internal/testing/test.pb.go Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,9 @@
// of unary/streaming requests/responses. // of unary/streaming requests/responses.
syntax = "proto3"; syntax = "proto3";
package grpc.testing; package testing;
option go_package = ".;testing";
message Empty {} message Empty {}
@@ -172,5 +174,5 @@ service TestService {
// that case. // that case.
service UnimplementedService { service UnimplementedService {
// A call that no server should implement // A call that no server should implement
rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); rpc UnimplementedCall(Empty) returns (Empty);
} }

Binary file not shown.

View File

@@ -0,0 +1,523 @@
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
package testing
import (
context "context"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
)
// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
// Requires gRPC-Go v1.32.0 or later.
const _ = grpc.SupportPackageIsVersion7
// TestServiceClient is the client API for TestService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type TestServiceClient interface {
// One empty request followed by one empty response.
EmptyCall(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
// One request followed by one response.
// The server returns the client payload as-is.
UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error)
// One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes.
StreamingOutputCall(ctx context.Context, in *StreamingOutputCallRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error)
// A sequence of requests followed by one response (streamed upload).
// The server returns the aggregated size of client payload as the result.
StreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error)
// A sequence of requests with each request served by the server immediately.
// As one request could lead to multiple responses, this interface
// demonstrates the idea of full duplexing.
FullDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_FullDuplexCallClient, error)
// A sequence of requests followed by a sequence of responses.
// The server buffers all the client requests and then serves them in order. A
// stream of responses are returned to the client when the server starts with
// first request.
HalfDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_HalfDuplexCallClient, error)
}
type testServiceClient struct {
cc grpc.ClientConnInterface
}
func NewTestServiceClient(cc grpc.ClientConnInterface) TestServiceClient {
return &testServiceClient{cc}
}
func (c *testServiceClient) EmptyCall(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty)
err := c.cc.Invoke(ctx, "/testing.TestService/EmptyCall", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *testServiceClient) UnaryCall(ctx context.Context, in *SimpleRequest, opts ...grpc.CallOption) (*SimpleResponse, error) {
out := new(SimpleResponse)
err := c.cc.Invoke(ctx, "/testing.TestService/UnaryCall", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *testServiceClient) StreamingOutputCall(ctx context.Context, in *StreamingOutputCallRequest, opts ...grpc.CallOption) (TestService_StreamingOutputCallClient, error) {
stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[0], "/testing.TestService/StreamingOutputCall", opts...)
if err != nil {
return nil, err
}
x := &testServiceStreamingOutputCallClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
return x, nil
}
type TestService_StreamingOutputCallClient interface {
Recv() (*StreamingOutputCallResponse, error)
grpc.ClientStream
}
type testServiceStreamingOutputCallClient struct {
grpc.ClientStream
}
func (x *testServiceStreamingOutputCallClient) Recv() (*StreamingOutputCallResponse, error) {
m := new(StreamingOutputCallResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *testServiceClient) StreamingInputCall(ctx context.Context, opts ...grpc.CallOption) (TestService_StreamingInputCallClient, error) {
stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[1], "/testing.TestService/StreamingInputCall", opts...)
if err != nil {
return nil, err
}
x := &testServiceStreamingInputCallClient{stream}
return x, nil
}
type TestService_StreamingInputCallClient interface {
Send(*StreamingInputCallRequest) error
CloseAndRecv() (*StreamingInputCallResponse, error)
grpc.ClientStream
}
type testServiceStreamingInputCallClient struct {
grpc.ClientStream
}
func (x *testServiceStreamingInputCallClient) Send(m *StreamingInputCallRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *testServiceStreamingInputCallClient) CloseAndRecv() (*StreamingInputCallResponse, error) {
if err := x.ClientStream.CloseSend(); err != nil {
return nil, err
}
m := new(StreamingInputCallResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *testServiceClient) FullDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_FullDuplexCallClient, error) {
stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[2], "/testing.TestService/FullDuplexCall", opts...)
if err != nil {
return nil, err
}
x := &testServiceFullDuplexCallClient{stream}
return x, nil
}
type TestService_FullDuplexCallClient interface {
Send(*StreamingOutputCallRequest) error
Recv() (*StreamingOutputCallResponse, error)
grpc.ClientStream
}
type testServiceFullDuplexCallClient struct {
grpc.ClientStream
}
func (x *testServiceFullDuplexCallClient) Send(m *StreamingOutputCallRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *testServiceFullDuplexCallClient) Recv() (*StreamingOutputCallResponse, error) {
m := new(StreamingOutputCallResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func (c *testServiceClient) HalfDuplexCall(ctx context.Context, opts ...grpc.CallOption) (TestService_HalfDuplexCallClient, error) {
stream, err := c.cc.NewStream(ctx, &TestService_ServiceDesc.Streams[3], "/testing.TestService/HalfDuplexCall", opts...)
if err != nil {
return nil, err
}
x := &testServiceHalfDuplexCallClient{stream}
return x, nil
}
type TestService_HalfDuplexCallClient interface {
Send(*StreamingOutputCallRequest) error
Recv() (*StreamingOutputCallResponse, error)
grpc.ClientStream
}
type testServiceHalfDuplexCallClient struct {
grpc.ClientStream
}
func (x *testServiceHalfDuplexCallClient) Send(m *StreamingOutputCallRequest) error {
return x.ClientStream.SendMsg(m)
}
func (x *testServiceHalfDuplexCallClient) Recv() (*StreamingOutputCallResponse, error) {
m := new(StreamingOutputCallResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// TestServiceServer is the server API for TestService service.
// All implementations must embed UnimplementedTestServiceServer
// for forward compatibility
type TestServiceServer interface {
// One empty request followed by one empty response.
EmptyCall(context.Context, *Empty) (*Empty, error)
// One request followed by one response.
// The server returns the client payload as-is.
UnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error)
// One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes.
StreamingOutputCall(*StreamingOutputCallRequest, TestService_StreamingOutputCallServer) error
// A sequence of requests followed by one response (streamed upload).
// The server returns the aggregated size of client payload as the result.
StreamingInputCall(TestService_StreamingInputCallServer) error
// A sequence of requests with each request served by the server immediately.
// As one request could lead to multiple responses, this interface
// demonstrates the idea of full duplexing.
FullDuplexCall(TestService_FullDuplexCallServer) error
// A sequence of requests followed by a sequence of responses.
// The server buffers all the client requests and then serves them in order. A
// stream of responses are returned to the client when the server starts with
// first request.
HalfDuplexCall(TestService_HalfDuplexCallServer) error
mustEmbedUnimplementedTestServiceServer()
}
// UnimplementedTestServiceServer must be embedded to have forward compatible implementations.
type UnimplementedTestServiceServer struct {
}
func (UnimplementedTestServiceServer) EmptyCall(context.Context, *Empty) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method EmptyCall not implemented")
}
func (UnimplementedTestServiceServer) UnaryCall(context.Context, *SimpleRequest) (*SimpleResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method UnaryCall not implemented")
}
func (UnimplementedTestServiceServer) StreamingOutputCall(*StreamingOutputCallRequest, TestService_StreamingOutputCallServer) error {
return status.Errorf(codes.Unimplemented, "method StreamingOutputCall not implemented")
}
func (UnimplementedTestServiceServer) StreamingInputCall(TestService_StreamingInputCallServer) error {
return status.Errorf(codes.Unimplemented, "method StreamingInputCall not implemented")
}
func (UnimplementedTestServiceServer) FullDuplexCall(TestService_FullDuplexCallServer) error {
return status.Errorf(codes.Unimplemented, "method FullDuplexCall not implemented")
}
func (UnimplementedTestServiceServer) HalfDuplexCall(TestService_HalfDuplexCallServer) error {
return status.Errorf(codes.Unimplemented, "method HalfDuplexCall not implemented")
}
func (UnimplementedTestServiceServer) mustEmbedUnimplementedTestServiceServer() {}
// UnsafeTestServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to TestServiceServer will
// result in compilation errors.
type UnsafeTestServiceServer interface {
mustEmbedUnimplementedTestServiceServer()
}
func RegisterTestServiceServer(s grpc.ServiceRegistrar, srv TestServiceServer) {
s.RegisterService(&TestService_ServiceDesc, srv)
}
func _TestService_EmptyCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TestServiceServer).EmptyCall(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/testing.TestService/EmptyCall",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TestServiceServer).EmptyCall(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
func _TestService_UnaryCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(SimpleRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(TestServiceServer).UnaryCall(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/testing.TestService/UnaryCall",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(TestServiceServer).UnaryCall(ctx, req.(*SimpleRequest))
}
return interceptor(ctx, in, info, handler)
}
func _TestService_StreamingOutputCall_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(StreamingOutputCallRequest)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(TestServiceServer).StreamingOutputCall(m, &testServiceStreamingOutputCallServer{stream})
}
type TestService_StreamingOutputCallServer interface {
Send(*StreamingOutputCallResponse) error
grpc.ServerStream
}
type testServiceStreamingOutputCallServer struct {
grpc.ServerStream
}
func (x *testServiceStreamingOutputCallServer) Send(m *StreamingOutputCallResponse) error {
return x.ServerStream.SendMsg(m)
}
func _TestService_StreamingInputCall_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(TestServiceServer).StreamingInputCall(&testServiceStreamingInputCallServer{stream})
}
type TestService_StreamingInputCallServer interface {
SendAndClose(*StreamingInputCallResponse) error
Recv() (*StreamingInputCallRequest, error)
grpc.ServerStream
}
type testServiceStreamingInputCallServer struct {
grpc.ServerStream
}
func (x *testServiceStreamingInputCallServer) SendAndClose(m *StreamingInputCallResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *testServiceStreamingInputCallServer) Recv() (*StreamingInputCallRequest, error) {
m := new(StreamingInputCallRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func _TestService_FullDuplexCall_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(TestServiceServer).FullDuplexCall(&testServiceFullDuplexCallServer{stream})
}
type TestService_FullDuplexCallServer interface {
Send(*StreamingOutputCallResponse) error
Recv() (*StreamingOutputCallRequest, error)
grpc.ServerStream
}
type testServiceFullDuplexCallServer struct {
grpc.ServerStream
}
func (x *testServiceFullDuplexCallServer) Send(m *StreamingOutputCallResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *testServiceFullDuplexCallServer) Recv() (*StreamingOutputCallRequest, error) {
m := new(StreamingOutputCallRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
func _TestService_HalfDuplexCall_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(TestServiceServer).HalfDuplexCall(&testServiceHalfDuplexCallServer{stream})
}
type TestService_HalfDuplexCallServer interface {
Send(*StreamingOutputCallResponse) error
Recv() (*StreamingOutputCallRequest, error)
grpc.ServerStream
}
type testServiceHalfDuplexCallServer struct {
grpc.ServerStream
}
func (x *testServiceHalfDuplexCallServer) Send(m *StreamingOutputCallResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *testServiceHalfDuplexCallServer) Recv() (*StreamingOutputCallRequest, error) {
m := new(StreamingOutputCallRequest)
if err := x.ServerStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
}
// TestService_ServiceDesc is the grpc.ServiceDesc for TestService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var TestService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "testing.TestService",
HandlerType: (*TestServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "EmptyCall",
Handler: _TestService_EmptyCall_Handler,
},
{
MethodName: "UnaryCall",
Handler: _TestService_UnaryCall_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "StreamingOutputCall",
Handler: _TestService_StreamingOutputCall_Handler,
ServerStreams: true,
},
{
StreamName: "StreamingInputCall",
Handler: _TestService_StreamingInputCall_Handler,
ClientStreams: true,
},
{
StreamName: "FullDuplexCall",
Handler: _TestService_FullDuplexCall_Handler,
ServerStreams: true,
ClientStreams: true,
},
{
StreamName: "HalfDuplexCall",
Handler: _TestService_HalfDuplexCall_Handler,
ServerStreams: true,
ClientStreams: true,
},
},
Metadata: "test.proto",
}
// UnimplementedServiceClient is the client API for UnimplementedService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type UnimplementedServiceClient interface {
// A call that no server should implement
UnimplementedCall(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error)
}
type unimplementedServiceClient struct {
cc grpc.ClientConnInterface
}
func NewUnimplementedServiceClient(cc grpc.ClientConnInterface) UnimplementedServiceClient {
return &unimplementedServiceClient{cc}
}
func (c *unimplementedServiceClient) UnimplementedCall(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*Empty, error) {
out := new(Empty)
err := c.cc.Invoke(ctx, "/testing.UnimplementedService/UnimplementedCall", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// UnimplementedServiceServer is the server API for UnimplementedService service.
// All implementations must embed UnimplementedUnimplementedServiceServer
// for forward compatibility
type UnimplementedServiceServer interface {
// A call that no server should implement
UnimplementedCall(context.Context, *Empty) (*Empty, error)
mustEmbedUnimplementedUnimplementedServiceServer()
}
// UnimplementedUnimplementedServiceServer must be embedded to have forward compatible implementations.
type UnimplementedUnimplementedServiceServer struct {
}
func (UnimplementedUnimplementedServiceServer) UnimplementedCall(context.Context, *Empty) (*Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method UnimplementedCall not implemented")
}
func (UnimplementedUnimplementedServiceServer) mustEmbedUnimplementedUnimplementedServiceServer() {}
// UnsafeUnimplementedServiceServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to UnimplementedServiceServer will
// result in compilation errors.
type UnsafeUnimplementedServiceServer interface {
mustEmbedUnimplementedUnimplementedServiceServer()
}
func RegisterUnimplementedServiceServer(s grpc.ServiceRegistrar, srv UnimplementedServiceServer) {
s.RegisterService(&UnimplementedService_ServiceDesc, srv)
}
func _UnimplementedService_UnimplementedCall_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(UnimplementedServiceServer).UnimplementedCall(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/testing.UnimplementedService/UnimplementedCall",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(UnimplementedServiceServer).UnimplementedCall(ctx, req.(*Empty))
}
return interceptor(ctx, in, info, handler)
}
// UnimplementedService_ServiceDesc is the grpc.ServiceDesc for UnimplementedService service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var UnimplementedService_ServiceDesc = grpc.ServiceDesc{
ServiceName: "testing.UnimplementedService",
HandlerType: (*UnimplementedServiceServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "UnimplementedCall",
Handler: _UnimplementedService_UnimplementedCall_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "test.proto",
}

View File

@@ -1,14 +1,17 @@
package testing package testing
//go:generate protoc --go_out=. --go-grpc_out=. test.proto
//go:generate protoc --descriptor_set_out=./test.protoset test.proto
//go:generate protoc --descriptor_set_out=./example.protoset --include_imports example.proto
import ( import (
"context"
"io" "io"
"strconv" "strconv"
"time" "time"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/interop/grpc_testing"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
@@ -16,10 +19,12 @@ import (
) )
// TestServer implements the TestService interface defined in example.proto. // TestServer implements the TestService interface defined in example.proto.
type TestServer struct{} type TestServer struct {
UnimplementedTestServiceServer
}
// EmptyCall accepts one empty request and issues one empty response. // EmptyCall accepts one empty request and issues one empty response.
func (TestServer) EmptyCall(ctx context.Context, req *grpc_testing.Empty) (*grpc_testing.Empty, error) { func (TestServer) EmptyCall(ctx context.Context, req *Empty) (*Empty, error) {
headers, trailers, failEarly, failLate := processMetadata(ctx) headers, trailers, failEarly, failLate := processMetadata(ctx)
grpc.SetHeader(ctx, headers) grpc.SetHeader(ctx, headers)
grpc.SetTrailer(ctx, trailers) grpc.SetTrailer(ctx, trailers)
@@ -35,7 +40,7 @@ func (TestServer) EmptyCall(ctx context.Context, req *grpc_testing.Empty) (*grpc
// UnaryCall accepts one request and issues one response. The response includes // UnaryCall accepts one request and issues one response. The response includes
// the client's payload as-is. // the client's payload as-is.
func (TestServer) UnaryCall(ctx context.Context, req *grpc_testing.SimpleRequest) (*grpc_testing.SimpleResponse, error) { func (TestServer) UnaryCall(ctx context.Context, req *SimpleRequest) (*SimpleResponse, error) {
headers, trailers, failEarly, failLate := processMetadata(ctx) headers, trailers, failEarly, failLate := processMetadata(ctx)
grpc.SetHeader(ctx, headers) grpc.SetHeader(ctx, headers)
grpc.SetTrailer(ctx, trailers) grpc.SetTrailer(ctx, trailers)
@@ -46,7 +51,7 @@ func (TestServer) UnaryCall(ctx context.Context, req *grpc_testing.SimpleRequest
return nil, status.Error(failLate, "fail") return nil, status.Error(failLate, "fail")
} }
return &grpc_testing.SimpleResponse{ return &SimpleResponse{
Payload: req.Payload, Payload: req.Payload,
}, nil }, nil
} }
@@ -54,7 +59,7 @@ func (TestServer) UnaryCall(ctx context.Context, req *grpc_testing.SimpleRequest
// StreamingOutputCall accepts one request and issues a sequence of responses // StreamingOutputCall accepts one request and issues a sequence of responses
// (streamed download). The server returns the payload with client desired type // (streamed download). The server returns the payload with client desired type
// and sizes as specified in the request's ResponseParameters. // and sizes as specified in the request's ResponseParameters.
func (TestServer) StreamingOutputCall(req *grpc_testing.StreamingOutputCallRequest, str grpc_testing.TestService_StreamingOutputCallServer) error { func (TestServer) StreamingOutputCall(req *StreamingOutputCallRequest, str TestService_StreamingOutputCallServer) error {
headers, trailers, failEarly, failLate := processMetadata(str.Context()) headers, trailers, failEarly, failLate := processMetadata(str.Context())
str.SetHeader(headers) str.SetHeader(headers)
str.SetTrailer(trailers) str.SetTrailer(trailers)
@@ -62,7 +67,7 @@ func (TestServer) StreamingOutputCall(req *grpc_testing.StreamingOutputCallReque
return status.Error(failEarly, "fail") return status.Error(failEarly, "fail")
} }
rsp := &grpc_testing.StreamingOutputCallResponse{Payload: &grpc_testing.Payload{}} rsp := &StreamingOutputCallResponse{Payload: &Payload{}}
for _, param := range req.ResponseParameters { for _, param := range req.ResponseParameters {
if str.Context().Err() != nil { if str.Context().Err() != nil {
return str.Context().Err() return str.Context().Err()
@@ -92,7 +97,7 @@ func (TestServer) StreamingOutputCall(req *grpc_testing.StreamingOutputCallReque
// StreamingInputCall accepts a sequence of requests and issues one response // StreamingInputCall accepts a sequence of requests and issues one response
// (streamed upload). The server returns the aggregated size of client payloads // (streamed upload). The server returns the aggregated size of client payloads
// as the result. // as the result.
func (TestServer) StreamingInputCall(str grpc_testing.TestService_StreamingInputCallServer) error { func (TestServer) StreamingInputCall(str TestService_StreamingInputCallServer) error {
headers, trailers, failEarly, failLate := processMetadata(str.Context()) headers, trailers, failEarly, failLate := processMetadata(str.Context())
str.SetHeader(headers) str.SetHeader(headers)
str.SetTrailer(trailers) str.SetTrailer(trailers)
@@ -114,7 +119,7 @@ func (TestServer) StreamingInputCall(str grpc_testing.TestService_StreamingInput
sz += len(req.Payload.Body) sz += len(req.Payload.Body)
} }
} }
if err := str.SendAndClose(&grpc_testing.StreamingInputCallResponse{AggregatedPayloadSize: int32(sz)}); err != nil { if err := str.SendAndClose(&StreamingInputCallResponse{AggregatedPayloadSize: int32(sz)}); err != nil {
return err return err
} }
@@ -127,7 +132,7 @@ func (TestServer) StreamingInputCall(str grpc_testing.TestService_StreamingInput
// FullDuplexCall accepts a sequence of requests with each request served by the // FullDuplexCall accepts a sequence of requests with each request served by the
// server immediately. As one request could lead to multiple responses, this // server immediately. As one request could lead to multiple responses, this
// interface demonstrates the idea of full duplexing. // interface demonstrates the idea of full duplexing.
func (TestServer) FullDuplexCall(str grpc_testing.TestService_FullDuplexCallServer) error { func (TestServer) FullDuplexCall(str TestService_FullDuplexCallServer) error {
headers, trailers, failEarly, failLate := processMetadata(str.Context()) headers, trailers, failEarly, failLate := processMetadata(str.Context())
str.SetHeader(headers) str.SetHeader(headers)
str.SetTrailer(trailers) str.SetTrailer(trailers)
@@ -135,7 +140,7 @@ func (TestServer) FullDuplexCall(str grpc_testing.TestService_FullDuplexCallServ
return status.Error(failEarly, "fail") return status.Error(failEarly, "fail")
} }
rsp := &grpc_testing.StreamingOutputCallResponse{Payload: &grpc_testing.Payload{}} rsp := &StreamingOutputCallResponse{Payload: &Payload{}}
for { for {
if str.Context().Err() != nil { if str.Context().Err() != nil {
return str.Context().Err() return str.Context().Err()
@@ -170,7 +175,7 @@ func (TestServer) FullDuplexCall(str grpc_testing.TestService_FullDuplexCallServ
// responses. The server buffers all the client requests and then serves them // responses. The server buffers all the client requests and then serves them
// in order. A stream of responses is returned to the client once the client // in order. A stream of responses is returned to the client once the client
// half-closes the stream. // half-closes the stream.
func (TestServer) HalfDuplexCall(str grpc_testing.TestService_HalfDuplexCallServer) error { func (TestServer) HalfDuplexCall(str TestService_HalfDuplexCallServer) error {
headers, trailers, failEarly, failLate := processMetadata(str.Context()) headers, trailers, failEarly, failLate := processMetadata(str.Context())
str.SetHeader(headers) str.SetHeader(headers)
str.SetTrailer(trailers) str.SetTrailer(trailers)
@@ -178,7 +183,7 @@ func (TestServer) HalfDuplexCall(str grpc_testing.TestService_HalfDuplexCallServ
return status.Error(failEarly, "fail") return status.Error(failEarly, "fail")
} }
var reqs []*grpc_testing.StreamingOutputCallRequest var reqs []*StreamingOutputCallRequest
for { for {
if str.Context().Err() != nil { if str.Context().Err() != nil {
return str.Context().Err() return str.Context().Err()
@@ -192,7 +197,7 @@ func (TestServer) HalfDuplexCall(str grpc_testing.TestService_HalfDuplexCallServ
reqs = append(reqs, req) reqs = append(reqs, req)
} }
} }
rsp := &grpc_testing.StreamingOutputCallResponse{} rsp := &StreamingOutputCallResponse{}
for _, req := range reqs { for _, req := range reqs {
rsp.Payload = req.Payload rsp.Payload = req.Payload
if err := str.Send(rsp); err != nil { if err := str.Send(rsp); err != nil {
@@ -251,4 +256,4 @@ func toCode(vals []string) codes.Code {
return codes.Code(i) return codes.Code(i)
} }
var _ grpc_testing.TestServiceServer = TestServer{} var _ TestServiceServer = TestServer{}

View File

@@ -2,19 +2,19 @@ package grpcurl
import ( import (
"bytes" "bytes"
"context"
"fmt" "fmt"
"io" "io"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
"github.com/golang/protobuf/jsonpb" "github.com/golang/protobuf/jsonpb" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/golang/protobuf/proto" "github.com/golang/protobuf/proto" //lint:ignore SA1019 we have to import this because it appears in exported API
"github.com/jhump/protoreflect/desc" "github.com/jhump/protoreflect/desc"
"github.com/jhump/protoreflect/dynamic" "github.com/jhump/protoreflect/dynamic"
"github.com/jhump/protoreflect/dynamic/grpcdynamic" "github.com/jhump/protoreflect/dynamic/grpcdynamic"
"github.com/jhump/protoreflect/grpcreflect" "github.com/jhump/protoreflect/grpcreflect"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata" "google.golang.org/grpc/metadata"
@@ -93,9 +93,17 @@ func InvokeRPC(ctx context.Context, source DescriptorSource, ch grpcdynamic.Chan
if svc == "" || mth == "" { if svc == "" || mth == "" {
return fmt.Errorf("given method name %q is not in expected format: 'service/method' or 'service.method'", methodName) return fmt.Errorf("given method name %q is not in expected format: 'service/method' or 'service.method'", methodName)
} }
dsc, err := source.FindSymbol(svc) dsc, err := source.FindSymbol(svc)
if err != nil { if err != nil {
if isNotFoundError(err) { // return a gRPC status error if hasStatus is true
errStatus, hasStatus := status.FromError(err)
switch {
case hasStatus && isNotFoundError(err):
return status.Errorf(errStatus.Code(), "target server does not expose service %q: %s", svc, errStatus.Message())
case hasStatus:
return status.Errorf(errStatus.Code(), "failed to query for service descriptor %q: %s", svc, errStatus.Message())
case isNotFoundError(err):
return fmt.Errorf("target server does not expose service %q", svc) return fmt.Errorf("target server does not expose service %q", svc)
} }
return fmt.Errorf("failed to query for service descriptor %q: %v", svc, err) return fmt.Errorf("failed to query for service descriptor %q: %v", svc, err)
@@ -219,15 +227,19 @@ func invokeClientStream(ctx context.Context, stub grpcdynamic.Stub, md *desc.Met
return fmt.Errorf("grpc call for %q failed: %v", md.GetFullyQualifiedName(), err) return fmt.Errorf("grpc call for %q failed: %v", md.GetFullyQualifiedName(), err)
} }
if respHeaders, err := str.Header(); err == nil { if str != nil {
handler.OnReceiveHeaders(respHeaders) if respHeaders, err := str.Header(); err == nil {
handler.OnReceiveHeaders(respHeaders)
}
} }
if stat.Code() == codes.OK { if stat.Code() == codes.OK {
handler.OnReceiveResponse(resp) handler.OnReceiveResponse(resp)
} }
handler.OnReceiveTrailers(stat, str.Trailer()) if str != nil {
handler.OnReceiveTrailers(stat, str.Trailer())
}
return nil return nil
} }
@@ -252,8 +264,10 @@ func invokeServerStream(ctx context.Context, stub grpcdynamic.Stub, md *desc.Met
// Now we can actually invoke the RPC! // Now we can actually invoke the RPC!
str, err := stub.InvokeRpcServerStream(ctx, md, req) str, err := stub.InvokeRpcServerStream(ctx, md, req)
if respHeaders, err := str.Header(); err == nil { if str != nil {
handler.OnReceiveHeaders(respHeaders) if respHeaders, err := str.Header(); err == nil {
handler.OnReceiveHeaders(respHeaders)
}
} }
// Download each response message // Download each response message
@@ -276,7 +290,9 @@ func invokeServerStream(ctx context.Context, stub grpcdynamic.Stub, md *desc.Met
return fmt.Errorf("grpc call for %q failed: %v", md.GetFullyQualifiedName(), err) return fmt.Errorf("grpc call for %q failed: %v", md.GetFullyQualifiedName(), err)
} }
handler.OnReceiveTrailers(stat, str.Trailer()) if str != nil {
handler.OnReceiveTrailers(stat, str.Trailer())
}
return nil return nil
} }
@@ -326,8 +342,10 @@ func invokeBidi(ctx context.Context, stub grpcdynamic.Stub, md *desc.MethodDescr
}() }()
} }
if respHeaders, err := str.Header(); err == nil { if str != nil {
handler.OnReceiveHeaders(respHeaders) if respHeaders, err := str.Header(); err == nil {
handler.OnReceiveHeaders(respHeaders)
}
} }
// Download each response message // Download each response message
@@ -354,7 +372,9 @@ func invokeBidi(ctx context.Context, stub grpcdynamic.Stub, md *desc.MethodDescr
return fmt.Errorf("grpc call for %q failed: %v", md.GetFullyQualifiedName(), err) return fmt.Errorf("grpc call for %q failed: %v", md.GetFullyQualifiedName(), err)
} }
handler.OnReceiveTrailers(stat, str.Trailer()) if str != nil {
handler.OnReceiveTrailers(stat, str.Trailer())
}
return nil return nil
} }

View File

@@ -53,18 +53,7 @@ This will create the release in GitHub with provisional release notes that just
### Docker Hub Releases ### Docker Hub Releases
To re-run only the Docker Hub release steps, we need to build an image with the right tag and then push to Docker Hub. To re-run only the Docker Hub release steps, you can manually run through each step in the "Docker" section of `do_release.sh`.
```sh
# from the root of the repo
echo v2.3.4 > VERSION
docker build -t fullstorydev/grpcurl:v2.3.4 .
# now that we have it built, push to Docker Hub
docker push fullstorydev/grpcurl:v2.3.4
# push "latest" tag, too
docker tag fullstorydev/grpcurl:v2.3.4 fullstorydev/grpcurl:latest
docker push fullstorydev/grpcurl:latest
```
If the `docker push ...` steps fail, you may need to run `docker login`, enter your Docker Hub login credentials, and then try to push again. If the `docker push ...` steps fail, you may need to run `docker login`, enter your Docker Hub login credentials, and then try to push again.
@@ -74,7 +63,7 @@ The last step is to update the Homebrew recipe to use the latest version. First,
```sh ```sh
# download the source archive from GitHub # download the source archive from GitHub
URL=https://github.com/fullstorydev/grpcurl/archive/v2.3.4.tar.gz URL=https://github.com/fullstorydev/grpcurl/archive/refs/tags/v2.3.4.tar.gz
curl -L -o tmp.tgz $URL curl -L -o tmp.tgz $URL
# and compute the SHA # and compute the SHA
SHA="$(sha256sum < tmp.tgz | awk '{ print $1 }')" SHA="$(sha256sum < tmp.tgz | awk '{ print $1 }')"

View File

@@ -40,16 +40,22 @@ $PREFIX git checkout go.mod go.sum
# if there are no valid current credentials. # if there are no valid current credentials.
$PREFIX docker login $PREFIX docker login
echo "$VERSION" > VERSION echo "$VERSION" > VERSION
$PREFIX docker build -t "fullstorydev/grpcurl:${VERSION}" .
rm VERSION # Docker Buildx support is included in Docker 19.03
# Below step installs emulators for different architectures on the host
# This enables running and building containers for below architectures mentioned using --platforms
$PREFIX docker run --privileged --rm tonistiigi/binfmt:qemu-v6.1.0 --install all
# Create a new builder instance
export DOCKER_CLI_EXPERIMENTAL=enabled
$PREFIX docker buildx create --use --name multiarch-builder --node multiarch-builder0
# push to docker hub, both the given version as a tag and for "latest" tag # push to docker hub, both the given version as a tag and for "latest" tag
$PREFIX docker push "fullstorydev/grpcurl:${VERSION}" $PREFIX docker buildx build --platform linux/amd64,linux/s390x,linux/arm64,linux/ppc64le --tag fullstorydev/grpcurl:${VERSION} --tag fullstorydev/grpcurl:latest --push --progress plain --no-cache .
$PREFIX docker tag "fullstorydev/grpcurl:${VERSION}" fullstorydev/grpcurl:latest $PREFIX docker buildx build --platform linux/amd64,linux/s390x,linux/arm64,linux/ppc64le --tag fullstorydev/grpcurl:${VERSION}-alpine --tag fullstorydev/grpcurl:latest-alpine --push --progress plain --no-cache --target alpine .
$PREFIX docker push fullstorydev/grpcurl:latest rm VERSION
# Homebrew release # Homebrew release
URL="https://github.com/fullstorydev/grpcurl/archive/${VERSION}.tar.gz" URL="https://github.com/fullstorydev/grpcurl/archive/refs/tags/${VERSION}.tar.gz"
curl -L -o tmp.tgz "$URL" curl -L -o tmp.tgz "$URL"
SHA="$(sha256sum < tmp.tgz | awk '{ print $1 }')" SHA="$(sha256sum < tmp.tgz | awk '{ print $1 }')"
rm tmp.tgz rm tmp.tgz

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,215 +0,0 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// source: testing/jsonpb_test_proto/test_objects.proto
package jsonpb
import (
fmt "fmt"
proto "github.com/golang/protobuf/proto"
any "github.com/golang/protobuf/ptypes/any"
duration "github.com/golang/protobuf/ptypes/duration"
_struct "github.com/golang/protobuf/ptypes/struct"
timestamp "github.com/golang/protobuf/ptypes/timestamp"
wrappers "github.com/golang/protobuf/ptypes/wrappers"
math "math"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
// This is a compile-time assertion to ensure that this generated file
// is compatible with the proto package it is being compiled against.
// A compilation error at this line likely means your copy of the
// proto package needs to be updated.
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
type KnownTypes struct {
An *any.Any `protobuf:"bytes,14,opt,name=an" json:"an,omitempty"`
Dur *duration.Duration `protobuf:"bytes,1,opt,name=dur" json:"dur,omitempty"`
St *_struct.Struct `protobuf:"bytes,12,opt,name=st" json:"st,omitempty"`
Ts *timestamp.Timestamp `protobuf:"bytes,2,opt,name=ts" json:"ts,omitempty"`
Lv *_struct.ListValue `protobuf:"bytes,15,opt,name=lv" json:"lv,omitempty"`
Val *_struct.Value `protobuf:"bytes,16,opt,name=val" json:"val,omitempty"`
Dbl *wrappers.DoubleValue `protobuf:"bytes,3,opt,name=dbl" json:"dbl,omitempty"`
Flt *wrappers.FloatValue `protobuf:"bytes,4,opt,name=flt" json:"flt,omitempty"`
I64 *wrappers.Int64Value `protobuf:"bytes,5,opt,name=i64" json:"i64,omitempty"`
U64 *wrappers.UInt64Value `protobuf:"bytes,6,opt,name=u64" json:"u64,omitempty"`
I32 *wrappers.Int32Value `protobuf:"bytes,7,opt,name=i32" json:"i32,omitempty"`
U32 *wrappers.UInt32Value `protobuf:"bytes,8,opt,name=u32" json:"u32,omitempty"`
Bool *wrappers.BoolValue `protobuf:"bytes,9,opt,name=bool" json:"bool,omitempty"`
Str *wrappers.StringValue `protobuf:"bytes,10,opt,name=str" json:"str,omitempty"`
Bytes *wrappers.BytesValue `protobuf:"bytes,11,opt,name=bytes" json:"bytes,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *KnownTypes) Reset() { *m = KnownTypes{} }
func (m *KnownTypes) String() string { return proto.CompactTextString(m) }
func (*KnownTypes) ProtoMessage() {}
func (*KnownTypes) Descriptor() ([]byte, []int) {
return fileDescriptor_ab4422ec10550c41, []int{0}
}
func (m *KnownTypes) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_KnownTypes.Unmarshal(m, b)
}
func (m *KnownTypes) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_KnownTypes.Marshal(b, m, deterministic)
}
func (m *KnownTypes) XXX_Merge(src proto.Message) {
xxx_messageInfo_KnownTypes.Merge(m, src)
}
func (m *KnownTypes) XXX_Size() int {
return xxx_messageInfo_KnownTypes.Size(m)
}
func (m *KnownTypes) XXX_DiscardUnknown() {
xxx_messageInfo_KnownTypes.DiscardUnknown(m)
}
var xxx_messageInfo_KnownTypes proto.InternalMessageInfo
func (m *KnownTypes) GetAn() *any.Any {
if m != nil {
return m.An
}
return nil
}
func (m *KnownTypes) GetDur() *duration.Duration {
if m != nil {
return m.Dur
}
return nil
}
func (m *KnownTypes) GetSt() *_struct.Struct {
if m != nil {
return m.St
}
return nil
}
func (m *KnownTypes) GetTs() *timestamp.Timestamp {
if m != nil {
return m.Ts
}
return nil
}
func (m *KnownTypes) GetLv() *_struct.ListValue {
if m != nil {
return m.Lv
}
return nil
}
func (m *KnownTypes) GetVal() *_struct.Value {
if m != nil {
return m.Val
}
return nil
}
func (m *KnownTypes) GetDbl() *wrappers.DoubleValue {
if m != nil {
return m.Dbl
}
return nil
}
func (m *KnownTypes) GetFlt() *wrappers.FloatValue {
if m != nil {
return m.Flt
}
return nil
}
func (m *KnownTypes) GetI64() *wrappers.Int64Value {
if m != nil {
return m.I64
}
return nil
}
func (m *KnownTypes) GetU64() *wrappers.UInt64Value {
if m != nil {
return m.U64
}
return nil
}
func (m *KnownTypes) GetI32() *wrappers.Int32Value {
if m != nil {
return m.I32
}
return nil
}
func (m *KnownTypes) GetU32() *wrappers.UInt32Value {
if m != nil {
return m.U32
}
return nil
}
func (m *KnownTypes) GetBool() *wrappers.BoolValue {
if m != nil {
return m.Bool
}
return nil
}
func (m *KnownTypes) GetStr() *wrappers.StringValue {
if m != nil {
return m.Str
}
return nil
}
func (m *KnownTypes) GetBytes() *wrappers.BytesValue {
if m != nil {
return m.Bytes
}
return nil
}
func init() {
proto.RegisterType((*KnownTypes)(nil), "jsonpb.KnownTypes")
}
func init() {
proto.RegisterFile("testing/jsonpb_test_proto/test_objects.proto", fileDescriptor_ab4422ec10550c41)
}
var fileDescriptor_ab4422ec10550c41 = []byte{
// 402 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0xd0, 0xdf, 0x6b, 0xd5, 0x30,
0x14, 0x07, 0x70, 0x96, 0xee, 0x4e, 0xcd, 0x44, 0x25, 0x88, 0x66, 0xd7, 0xa1, 0x22, 0x82, 0xc3,
0x1f, 0x2d, 0xb6, 0xa5, 0xef, 0x0e, 0x11, 0x44, 0x9f, 0xba, 0xe9, 0xeb, 0x48, 0xd6, 0xac, 0x74,
0x64, 0x49, 0x49, 0x4e, 0xee, 0xe8, 0xbf, 0xe6, 0x5f, 0x27, 0x49, 0x73, 0x45, 0x6e, 0xc9, 0xde,
0xee, 0xcd, 0xf7, 0x73, 0xbe, 0x9c, 0x53, 0xfc, 0x11, 0x84, 0x85, 0x41, 0xf5, 0xc5, 0xb5, 0xd5,
0x6a, 0xe4, 0x17, 0xfe, 0xef, 0xc5, 0x68, 0x34, 0xe8, 0x22, 0xfc, 0xd4, 0xfc, 0x5a, 0x5c, 0x82,
0xcd, 0xc3, 0x13, 0x39, 0x98, 0xd5, 0xfa, 0xa8, 0xd7, 0xba, 0x97, 0xa2, 0x08, 0xaf, 0xdc, 0x5d,
0x15, 0x4c, 0x4d, 0x33, 0x59, 0xbf, 0xdc, 0x8d, 0x3a, 0x67, 0x18, 0x0c, 0x5a, 0xc5, 0xfc, 0x78,
0x37, 0xb7, 0x60, 0xdc, 0x25, 0xc4, 0xf4, 0xd5, 0x6e, 0x0a, 0xc3, 0x8d, 0xb0, 0xc0, 0x6e, 0xc6,
0x54, 0xfd, 0xad, 0x61, 0xe3, 0x28, 0x4c, 0xdc, 0xf0, 0xcd, 0x9f, 0x15, 0xc6, 0x3f, 0x94, 0xbe,
0x55, 0xe7, 0xd3, 0x28, 0x2c, 0x79, 0x8b, 0x11, 0x53, 0xf4, 0xd1, 0xeb, 0xbd, 0x93, 0xc3, 0xf2,
0x69, 0x3e, 0xcf, 0xe6, 0xdb, 0xd9, 0xfc, 0x8b, 0x9a, 0x5a, 0xc4, 0x14, 0xf9, 0x80, 0xb3, 0xce,
0x19, 0xba, 0x17, 0xd8, 0xd1, 0x82, 0x7d, 0x8d, 0x17, 0xb4, 0x5e, 0x91, 0x77, 0x18, 0x59, 0xa0,
0x0f, 0x83, 0x7d, 0xbe, 0xb0, 0x67, 0xe1, 0x9a, 0x16, 0x59, 0x20, 0xef, 0x31, 0x02, 0x4b, 0x51,
0x80, 0xeb, 0x05, 0x3c, 0xdf, 0x1e, 0xd6, 0x22, 0xb0, 0xde, 0xca, 0x0d, 0x7d, 0x9c, 0xb0, 0x3f,
0x07, 0x0b, 0xbf, 0x99, 0x74, 0xa2, 0x45, 0x72, 0x43, 0x4e, 0x70, 0xb6, 0x61, 0x92, 0x3e, 0x09,
0xf8, 0xd9, 0x02, 0xcf, 0xd0, 0x13, 0x92, 0xe3, 0xac, 0xe3, 0x92, 0x66, 0x41, 0x1e, 0x2f, 0xef,
0xd2, 0x8e, 0x4b, 0x11, 0x7d, 0xc7, 0x25, 0xf9, 0x84, 0xb3, 0x2b, 0x09, 0x74, 0x3f, 0xf8, 0x17,
0x0b, 0xff, 0x4d, 0x6a, 0x16, 0xf7, 0xf0, 0xce, 0xf3, 0xa1, 0xa9, 0xe9, 0x2a, 0xc1, 0xbf, 0x2b,
0x68, 0xea, 0xc8, 0x87, 0xa6, 0xf6, 0xdb, 0xb8, 0xa6, 0xa6, 0x07, 0x89, 0x6d, 0x7e, 0xfd, 0xef,
0x5d, 0x53, 0x87, 0xfa, 0xaa, 0xa4, 0xf7, 0xd2, 0xf5, 0x55, 0xb9, 0xad, 0xaf, 0xca, 0x50, 0x5f,
0x95, 0xf4, 0xfe, 0x1d, 0xf5, 0xff, 0xbc, 0x0b, 0x7e, 0x9f, 0x6b, 0x2d, 0xe9, 0x83, 0xc4, 0x47,
0x3f, 0xd5, 0x5a, 0xce, 0x3c, 0x38, 0xdf, 0x6f, 0xc1, 0x50, 0x9c, 0xe8, 0x3f, 0x03, 0x33, 0xa8,
0x3e, 0xf6, 0x5b, 0x30, 0xe4, 0x33, 0x5e, 0xf1, 0x09, 0x84, 0xa5, 0x87, 0x89, 0x03, 0x4e, 0x7d,
0x3a, 0x0f, 0xcc, 0xf2, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xab, 0x65, 0x99, 0x5a, 0x8d, 0x03,
0x00, 0x00,
}

View File

@@ -1,59 +0,0 @@
// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2015 The Go Authors. All rights reserved.
// https://github.com/golang/protobuf
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
syntax = "proto2";
import "google/protobuf/any.proto";
import "google/protobuf/duration.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.proto";
package jsonpb;
message KnownTypes {
optional google.protobuf.Any an = 14;
optional google.protobuf.Duration dur = 1;
optional google.protobuf.Struct st = 12;
optional google.protobuf.Timestamp ts = 2;
optional google.protobuf.ListValue lv = 15;
optional google.protobuf.Value val = 16;
optional google.protobuf.DoubleValue dbl = 3;
optional google.protobuf.FloatValue flt = 4;
optional google.protobuf.Int64Value i64 = 5;
optional google.protobuf.UInt64Value u64 = 6;
optional google.protobuf.Int32Value i32 = 7;
optional google.protobuf.UInt32Value u32 = 8;
optional google.protobuf.BoolValue bool = 9;
optional google.protobuf.StringValue str = 10;
optional google.protobuf.BytesValue bytes = 11;
}

Binary file not shown.

View File

@@ -1,19 +1,18 @@
package grpcurl_test package grpcurl_test
import ( import (
"context"
"fmt" "fmt"
"net" "net"
"strings" "strings"
"testing" "testing"
"time" "time"
"golang.org/x/net/context"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/credentials" "google.golang.org/grpc/credentials"
"google.golang.org/grpc/interop/grpc_testing"
. "github.com/fullstorydev/grpcurl" . "github.com/fullstorydev/grpcurl"
grpcurl_testing "github.com/fullstorydev/grpcurl/testing" grpcurl_testing "github.com/fullstorydev/grpcurl/internal/testing"
) )
func TestPlainText(t *testing.T) { func TestPlainText(t *testing.T) {
@@ -27,11 +26,11 @@ func TestPlainText(t *testing.T) {
} }
func TestBasicTLS(t *testing.T) { func TestBasicTLS(t *testing.T) {
serverCreds, err := ServerTransportCredentials("", "testing/tls/server.crt", "testing/tls/server.key", false) serverCreds, err := ServerTransportCredentials("", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "", "") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "", "")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
@@ -46,7 +45,7 @@ func TestBasicTLS(t *testing.T) {
} }
func TestInsecureClientTLS(t *testing.T) { func TestInsecureClientTLS(t *testing.T) {
serverCreds, err := ServerTransportCredentials("", "testing/tls/server.crt", "testing/tls/server.key", false) serverCreds, err := ServerTransportCredentials("", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
@@ -65,11 +64,11 @@ func TestInsecureClientTLS(t *testing.T) {
} }
func TestClientCertTLS(t *testing.T) { func TestClientCertTLS(t *testing.T) {
serverCreds, err := ServerTransportCredentials("testing/tls/ca.crt", "testing/tls/server.crt", "testing/tls/server.key", false) serverCreds, err := ServerTransportCredentials("internal/testing/tls/ca.crt", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "testing/tls/client.crt", "testing/tls/client.key") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "internal/testing/tls/client.crt", "internal/testing/tls/client.key")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
@@ -84,11 +83,11 @@ func TestClientCertTLS(t *testing.T) {
} }
func TestRequireClientCertTLS(t *testing.T) { func TestRequireClientCertTLS(t *testing.T) {
serverCreds, err := ServerTransportCredentials("testing/tls/ca.crt", "testing/tls/server.crt", "testing/tls/server.key", true) serverCreds, err := ServerTransportCredentials("internal/testing/tls/ca.crt", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", true)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "testing/tls/client.crt", "testing/tls/client.key") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "internal/testing/tls/client.crt", "internal/testing/tls/client.key")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
@@ -103,7 +102,7 @@ func TestRequireClientCertTLS(t *testing.T) {
} }
func TestBrokenTLS_ClientPlainText(t *testing.T) { func TestBrokenTLS_ClientPlainText(t *testing.T) {
serverCreds, err := ServerTransportCredentials("", "testing/tls/server.crt", "testing/tls/server.key", false) serverCreds, err := ServerTransportCredentials("", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
@@ -148,8 +147,8 @@ func TestBrokenTLS_ClientPlainText(t *testing.T) {
// but request fails because server closes connection upon seeing request // but request fails because server closes connection upon seeing request
// bytes that are not a TLS handshake // bytes that are not a TLS handshake
cl := grpc_testing.NewTestServiceClient(e.cc) cl := grpcurl_testing.NewTestServiceClient(e.cc)
_, err = cl.UnaryCall(context.Background(), &grpc_testing.SimpleRequest{}) _, err = cl.UnaryCall(context.Background(), &grpcurl_testing.SimpleRequest{})
if err == nil { if err == nil {
t.Fatal("expecting failure") t.Fatal("expecting failure")
} }
@@ -164,15 +163,15 @@ func TestBrokenTLS_ClientPlainText(t *testing.T) {
} }
func TestBrokenTLS_ServerPlainText(t *testing.T) { func TestBrokenTLS_ServerPlainText(t *testing.T) {
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "", "") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "", "")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
e, err := createTestServerAndClient(nil, clientCreds) e, err := createTestServerAndClient(nil, clientCreds)
if err == nil { if err == nil {
t.Fatal("expecting TLS failure setting up server and client")
e.Close() e.Close()
t.Fatal("expecting TLS failure setting up server and client")
} }
if !strings.Contains(err.Error(), "first record does not look like a TLS handshake") { if !strings.Contains(err.Error(), "first record does not look like a TLS handshake") {
t.Fatalf("expecting TLS handshake failure, got: %v", err) t.Fatalf("expecting TLS handshake failure, got: %v", err)
@@ -180,19 +179,19 @@ func TestBrokenTLS_ServerPlainText(t *testing.T) {
} }
func TestBrokenTLS_ServerUsesWrongCert(t *testing.T) { func TestBrokenTLS_ServerUsesWrongCert(t *testing.T) {
serverCreds, err := ServerTransportCredentials("", "testing/tls/other.crt", "testing/tls/other.key", false) serverCreds, err := ServerTransportCredentials("", "internal/testing/tls/other.crt", "internal/testing/tls/other.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "", "") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "", "")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
e, err := createTestServerAndClient(serverCreds, clientCreds) e, err := createTestServerAndClient(serverCreds, clientCreds)
if err == nil { if err == nil {
t.Fatal("expecting TLS failure setting up server and client")
e.Close() e.Close()
t.Fatal("expecting TLS failure setting up server and client")
} }
if !strings.Contains(err.Error(), "certificate is valid for") { if !strings.Contains(err.Error(), "certificate is valid for") {
t.Fatalf("expecting TLS certificate error, got: %v", err) t.Fatalf("expecting TLS certificate error, got: %v", err)
@@ -200,39 +199,39 @@ func TestBrokenTLS_ServerUsesWrongCert(t *testing.T) {
} }
func TestBrokenTLS_ClientHasExpiredCert(t *testing.T) { func TestBrokenTLS_ClientHasExpiredCert(t *testing.T) {
serverCreds, err := ServerTransportCredentials("testing/tls/ca.crt", "testing/tls/server.crt", "testing/tls/server.key", false) serverCreds, err := ServerTransportCredentials("internal/testing/tls/ca.crt", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "testing/tls/expired.crt", "testing/tls/expired.key") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "internal/testing/tls/expired.crt", "internal/testing/tls/expired.key")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
e, err := createTestServerAndClient(serverCreds, clientCreds) e, err := createTestServerAndClient(serverCreds, clientCreds)
if err == nil { if err == nil {
t.Fatal("expecting TLS failure setting up server and client")
e.Close() e.Close()
t.Fatal("expecting TLS failure setting up server and client")
} }
if !strings.Contains(err.Error(), "bad certificate") { if !strings.Contains(err.Error(), "certificate") {
t.Fatalf("expecting TLS certificate error, got: %v", err) t.Fatalf("expecting TLS certificate error, got: %v", err)
} }
} }
func TestBrokenTLS_ServerHasExpiredCert(t *testing.T) { func TestBrokenTLS_ServerHasExpiredCert(t *testing.T) {
serverCreds, err := ServerTransportCredentials("", "testing/tls/expired.crt", "testing/tls/expired.key", false) serverCreds, err := ServerTransportCredentials("", "internal/testing/tls/expired.crt", "internal/testing/tls/expired.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "", "") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "", "")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
e, err := createTestServerAndClient(serverCreds, clientCreds) e, err := createTestServerAndClient(serverCreds, clientCreds)
if err == nil { if err == nil {
t.Fatal("expecting TLS failure setting up server and client")
e.Close() e.Close()
t.Fatal("expecting TLS failure setting up server and client")
} }
if !strings.Contains(err.Error(), "certificate has expired or is not yet valid") { if !strings.Contains(err.Error(), "certificate has expired or is not yet valid") {
t.Fatalf("expecting TLS certificate expired, got: %v", err) t.Fatalf("expecting TLS certificate expired, got: %v", err)
@@ -240,19 +239,19 @@ func TestBrokenTLS_ServerHasExpiredCert(t *testing.T) {
} }
func TestBrokenTLS_ClientNotTrusted(t *testing.T) { func TestBrokenTLS_ClientNotTrusted(t *testing.T) {
serverCreds, err := ServerTransportCredentials("testing/tls/ca.crt", "testing/tls/server.crt", "testing/tls/server.key", true) serverCreds, err := ServerTransportCredentials("internal/testing/tls/ca.crt", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", true)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "testing/tls/wrong-client.crt", "testing/tls/wrong-client.key") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "internal/testing/tls/wrong-client.crt", "internal/testing/tls/wrong-client.key")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
e, err := createTestServerAndClient(serverCreds, clientCreds) e, err := createTestServerAndClient(serverCreds, clientCreds)
if err == nil { if err == nil {
t.Fatal("expecting TLS failure setting up server and client")
e.Close() e.Close()
t.Fatal("expecting TLS failure setting up server and client")
} }
if !strings.Contains(err.Error(), "bad certificate") { if !strings.Contains(err.Error(), "bad certificate") {
t.Fatalf("expecting TLS certificate error, got: %v", err) t.Fatalf("expecting TLS certificate error, got: %v", err)
@@ -260,39 +259,39 @@ func TestBrokenTLS_ClientNotTrusted(t *testing.T) {
} }
func TestBrokenTLS_ServerNotTrusted(t *testing.T) { func TestBrokenTLS_ServerNotTrusted(t *testing.T) {
serverCreds, err := ServerTransportCredentials("", "testing/tls/server.crt", "testing/tls/server.key", false) serverCreds, err := ServerTransportCredentials("", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", false)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "", "testing/tls/client.crt", "testing/tls/client.key") clientCreds, err := ClientTransportCredentials(false, "", "internal/testing/tls/client.crt", "internal/testing/tls/client.key")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
e, err := createTestServerAndClient(serverCreds, clientCreds) e, err := createTestServerAndClient(serverCreds, clientCreds)
if err == nil { if err == nil {
t.Fatal("expecting TLS failure setting up server and client")
e.Close() e.Close()
t.Fatal("expecting TLS failure setting up server and client")
} }
if !strings.Contains(err.Error(), "certificate signed by unknown authority") { if !strings.Contains(err.Error(), "certificate") {
t.Fatalf("expecting TLS certificate error, got: %v", err) t.Fatalf("expecting TLS certificate error, got: %v", err)
} }
} }
func TestBrokenTLS_RequireClientCertButNonePresented(t *testing.T) { func TestBrokenTLS_RequireClientCertButNonePresented(t *testing.T) {
serverCreds, err := ServerTransportCredentials("testing/tls/ca.crt", "testing/tls/server.crt", "testing/tls/server.key", true) serverCreds, err := ServerTransportCredentials("internal/testing/tls/ca.crt", "internal/testing/tls/server.crt", "internal/testing/tls/server.key", true)
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
clientCreds, err := ClientTransportCredentials(false, "testing/tls/ca.crt", "", "") clientCreds, err := ClientTransportCredentials(false, "internal/testing/tls/ca.crt", "", "")
if err != nil { if err != nil {
t.Fatalf("failed to create server creds: %v", err) t.Fatalf("failed to create server creds: %v", err)
} }
e, err := createTestServerAndClient(serverCreds, clientCreds) e, err := createTestServerAndClient(serverCreds, clientCreds)
if err == nil { if err == nil {
t.Fatal("expecting TLS failure setting up server and client")
e.Close() e.Close()
t.Fatal("expecting TLS failure setting up server and client")
} }
if !strings.Contains(err.Error(), "bad certificate") { if !strings.Contains(err.Error(), "bad certificate") {
t.Fatalf("expecting TLS certificate error, got: %v", err) t.Fatalf("expecting TLS certificate error, got: %v", err)
@@ -300,10 +299,10 @@ func TestBrokenTLS_RequireClientCertButNonePresented(t *testing.T) {
} }
func simpleTest(t *testing.T, cc *grpc.ClientConn) { func simpleTest(t *testing.T, cc *grpc.ClientConn) {
cl := grpc_testing.NewTestServiceClient(cc) cl := grpcurl_testing.NewTestServiceClient(cc)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel() defer cancel()
_, err := cl.UnaryCall(ctx, &grpc_testing.SimpleRequest{}, grpc.WaitForReady(true)) _, err := cl.UnaryCall(ctx, &grpcurl_testing.SimpleRequest{}, grpc.WaitForReady(true))
if err != nil { if err != nil {
t.Errorf("simple RPC failed: %v", err) t.Errorf("simple RPC failed: %v", err)
} }
@@ -323,7 +322,7 @@ func createTestServerAndClient(serverCreds, clientCreds credentials.TransportCre
svrOpts = []grpc.ServerOption{grpc.Creds(serverCreds)} svrOpts = []grpc.ServerOption{grpc.Creds(serverCreds)}
} }
svr := grpc.NewServer(svrOpts...) svr := grpc.NewServer(svrOpts...)
grpc_testing.RegisterTestServiceServer(svr, grpcurl_testing.TestServer{}) grpcurl_testing.RegisterTestServiceServer(svr, grpcurl_testing.TestServer{})
l, err := net.Listen("tcp", "127.0.0.1:0") l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil { if err != nil {
return e, err return e, err
@@ -350,7 +349,7 @@ type testEnv struct {
cc *grpc.ClientConn cc *grpc.ClientConn
} }
func (e testEnv) Close() { func (e *testEnv) Close() {
if e.cc != nil { if e.cc != nil {
e.cc.Close() e.cc.Close()
e.cc = nil e.cc = nil